/* AUTO-GENERATED by scripts/build-styles.mjs from styles/src/000-tokens-base.css, styles/src/135-kanban-board.css, styles/src/145-brain-map.css, styles/src/146-story-board.css, styles/src/148-calendar.css, styles/src/151-attachments.css, styles/src/180-dialogs-overlays.css and styles/share-viewer/. Do not edit manually. */
:root {
    /* Tell the UA which scheme is active so NATIVE controls (checkboxes, radios, selects,
       scrollbars, <dialog> canvas) render to match the theme — author CSS can't restyle their
       internals. The dark block flips this to `dark`. Accent unifies the checked/active color
       of those controls with the app accent in both themes. */
    color-scheme: light;
    accent-color: var(--primary-color);

    --bg-app: #ffffff;
    --bg-sidebar: #f4f6fa;
    --bg-list-pane: #f9fbff;
    --bg-editor-pane: #ffffff;
    --bg-pane: #ffffff;
    --border-color: #dfe5ee;
    --pane-divider: #d9e1eb;
    /* Ring marking which pane plain note-list clicks open into (e.g. the focused split screen). */
    --pane-focus-ring: var(--primary-color);
    --primary-color: #007aff; /* Apple-like blue */
    --primary-hover: #0062cc;
    --text-main: #333333;
    --text-muted: #888888;
    --danger-color: #ff3b30;
    --success-color: #15803d;
    --warning-color: #b45309;
    --selection-color: #e5f1ff;
    --item-hover: #eceef1;

    /* Segmented "pill" tab control (the standard for tabbed dialogs — see .app-tabs). Track is a soft
       inset; the active tab is a raised surface pill. Distinct from bg-app/bg-pane (equal in light mode). */
    --tab-track-bg: #eceef1;
    --tab-active-bg: #ffffff;

    /* System design language tokens */
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 14px;

    --shadow-sm: 0 3px 10px rgba(15, 25, 40, 0.07);
    --shadow-md: 0 8px 20px rgba(15, 25, 40, 0.12);
    --shadow-lg: 0 18px 50px rgba(15, 25, 40, 0.18);

    /* Text and icons sitting ON an accent / gradient fill. Stays white in both themes on purpose:
       the fill is the same saturated blue in both. */
    --on-accent: #ffffff;
    /* color-mix() endpoints for "darken a bit" / "lighten a bit" recipes, so a slice never needs a
       raw #000 / #fff to shade a token. */
    --mix-dark: #000000;
    --mix-light: #ffffff;

    /* Accent gradient (glass confirm buttons, progress sweeps, active rails). One source for what
       used to be a dozen copies of linear-gradient(135deg, #2f7cff, #00b3ff). */
    --accent-gradient-start: #2f7cff;
    --accent-gradient-end: #00b3ff;
    --accent-gradient: linear-gradient(135deg, var(--accent-gradient-start), var(--accent-gradient-end));
    --accent-gradient-h: linear-gradient(90deg, var(--accent-gradient-start), var(--accent-gradient-end));

    /* Primary tints: theme-safe alpha recipes over the accent (they follow the user's accent preset,
       which a hard-coded rgba(0, 122, 255, x) never did). */
    --primary-alpha-06: color-mix(in srgb, var(--primary-color) 6%, transparent);
    --primary-alpha-10: color-mix(in srgb, var(--primary-color) 10%, transparent);
    --primary-alpha-14: color-mix(in srgb, var(--primary-color) 14%, transparent);
    --primary-alpha-18: color-mix(in srgb, var(--primary-color) 18%, transparent);
    --primary-alpha-25: color-mix(in srgb, var(--primary-color) 25%, transparent);
    --primary-alpha-38: color-mix(in srgb, var(--primary-color) 38%, transparent);

    /* Dark overlay chrome (lightbox, code-block and SVG viewers, tooltips): dark in BOTH themes by
       design — a viewer floating over content does not flip with the page behind it. */
    --overlay-chrome-bg: rgba(35, 40, 48, 0.92);
    --overlay-chrome-bg-strong: rgba(16, 20, 28, 0.98);
    --overlay-chrome-fg: #e2e8f0;
    --overlay-scrim: rgba(8, 12, 18, 0.72);
    --overlay-danger-bg: rgba(134, 33, 33, 0.95);
    --overlay-danger-border: rgba(255, 151, 151, 0.45);
    --tooltip-bg: rgba(20, 28, 42, 0.94);
    --tooltip-fg: #f0f4ff;

    /* Glass dialog family (the .glass-overlay / .glass-dialog system in 180-dialogs-overlays.css).
       The scrim and rim are deliberately dark-on-dark in both themes; the surfaces themselves mix
       --bg-pane toward transparent, so they follow the theme without a dark block here. */
    --glass-overlay-bg: rgba(6, 10, 18, 0.58);
    --glass-surface-blur: 12px;
    --glass-border: rgba(255, 255, 255, 0.22);
    --glass-radius: 20px;
    --glass-shadow: 0 18px 50px rgba(0, 0, 0, 0.40);
    --glass-confirm-blue-start: var(--accent-gradient-start);
    --glass-confirm-blue-end: var(--accent-gradient-end);
    --glass-confirm-orange-start: #ff7a18;
    --glass-confirm-orange-end: #ff3d6e;
    --glass-confirm-red-start: #e8403a;
    --glass-confirm-red-end: #b41818;

    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;

    --anim-fast: 140ms;
    --anim-base: 180ms;
    --anim-ease: cubic-bezier(.2,.8,.2,1);

    --btn-height: 38px;
    --btn-height-compact: 30px;
    --btn-pad-x: 14px;
    --btn-font-size: 0.92rem;

    --icon-size: 17px;
    --icon-stroke: 1.9;
    --fmt-toolbar-icon-size: 18px;
    --fmt-heading-icon-size: 26px;
    --fmt-heading-icon-scale: 1.12;

    /* Editor/content readability tokens */
    --text-editor: #2b3442;
    --text-editor-muted: #6f7f94;
    --text-placeholder: #8d99ab;
    --blockquote-border: #d4dbe7;

    /* Code readability tokens */
    --code-bg: #f5f7fb;
    --code-fg: #1f2937;
    --code-border: #d7dfeb;
    --inline-code-bg: rgba(15, 23, 42, 0.06);
    --inline-code-fg: #1f2937;

    /* Shell and note-list state tokens */
    --note-card-hover-border: #cfd8e5;
    --note-card-hover-shadow: 0 6px 14px rgba(17, 28, 45, 0.08);
    --note-card-active-border: #c7dcfb;
    --note-card-active-shadow: 0 8px 18px rgba(0, 122, 255, 0.14);
    --note-card-selected-shadow: 0 6px 14px rgba(0, 122, 255, 0.11);
    --note-card-time-color: #8d98a8;
    --note-card-meta-icon-color: #9aa6b5;

    --status-pinned-accent: #d2a400;
    --status-pinned-title-accent: #8a6a00;
    --status-pinned-fg: #7a5a00;
    --status-pinned-bg: #fff6da;
    --status-pinned-border: #f7df94;

    --status-live-fg: #0b5d42;
    --status-live-bg: #e8f7ef;
    --status-live-border: #b9e5c8;

    --status-draft-fg: #4f3f8c;
    --status-draft-bg: #f1ebff;
    --status-draft-border: #d7c8ff;

    --status-pending-fg: #7a4a05;
    --status-pending-bg: #fff2dc;
    --status-pending-border: #f1d29b;

    --status-error-fg: #8b1e2d;
    --status-error-bg: #fdecef;
    --status-error-border: #f7c2cb;
    
    --sidebar-width: 260px;
    --list-width: 300px;
    --reference-width: 50%;   /* split screen opens at half the editor pane; a dragged width is stored in px */
    --nav-rail-width: 48px;

    /* UI font stack (body) and the note body's base text, which the global default text Style Set
       may override per note. */
    --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --note-base-size: 14px;
    --note-base-font: var(--font-ui);
}

.tree-selection-status {
    margin: 2px 8px 8px 8px;
    padding: 3px 8px;
    font-size: 0.76rem;
    color: var(--text-muted);
    background: color-mix(in srgb, var(--primary-color) 8%, transparent);
    border: 1px solid var(--primary-alpha-18);
    border-radius: 999px;
    width: fit-content;
    max-width: calc(100% - 16px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

:root[data-theme="dark"] {
    color-scheme: dark;

    --bg-app: #0f141d;
    --bg-sidebar: #151b25;
    --bg-list-pane: #141b24;
    --bg-editor-pane: #101722;
    --bg-pane: #161f2b;
    --border-color: #2a3547;
    --pane-divider: #273243;
    --text-main: #e7edf7;
    --text-muted: #95a4ba;
    /* Dark counterpart of the light #e5f1ff selection tint (primary blue sunk into the dark
       pane) — without it every selected row/card kept the pale light-mode blue behind light
       text. Fallback only: applyThemeSettings() inlines the accent's selection/selectionDark
       pair on the root, so keep this in sync with ACCENT_PRESETS.blue.selectionDark. */
    --selection-color: #113660;
    --item-hover: #1c2738;

    /* Segmented tab control (dark): recessed track, raised lighter active pill. */
    --tab-track-bg: #0f141d;
    --tab-active-bg: #26313f;

    /* Editor/content readability tokens (dark) */
    --text-editor: #e8eef8;
    --text-editor-muted: #b6c2d4;
    --text-placeholder: #8d9bb0;
    --blockquote-border: #3a4b63;

    /* Code readability tokens (dark) */
    --code-bg: #111a26;
    --code-fg: #e8eef8;
    --code-border: #2e3c52;
    --inline-code-bg: rgba(148, 163, 184, 0.2);
    --inline-code-fg: #eff6ff;

    /* Shell and note-list state tokens (dark) */
    --note-card-hover-border: #3a475d;
    --note-card-hover-shadow: 0 8px 18px rgba(0, 0, 0, 0.22);
    --note-card-active-border: #4d6ea7;
    --note-card-active-shadow: 0 8px 18px rgba(0, 0, 0, 0.34);
    --note-card-selected-shadow: 0 8px 18px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 18px 50px rgba(0, 0, 0, 0.5);
    --note-card-time-color: #8fa0b8;
    --note-card-meta-icon-color: #93a6bf;

    --status-pinned-accent: #f0c24b;
    --status-pinned-title-accent: #f0c24b;
    --status-pinned-fg: #f3d782;
    --status-pinned-bg: #3d3110;
    --status-pinned-border: #7a6221;

    --status-live-fg: #8dd9b3;
    --status-live-bg: #123126;
    --status-live-border: #2f6a52;

    --status-draft-fg: #c6b0ff;
    --status-draft-bg: #2d2147;
    --status-draft-border: #5d4496;

    --status-pending-fg: #f0c48c;
    --status-pending-bg: #3b2710;
    --status-pending-border: #7c5724;

    --status-error-fg: #f1a5b1;
    --status-error-bg: #3b1720;
    --status-error-border: #7c3343;

    --success-color: #46c98b;
    --warning-color: #f0b860;
    /* Dark-tuned danger so state glows (e.g. Cache Board overdue tinge) aren't the harsh
       light-mode red. Light --danger-color is defined in :root; this pairs the dark side. */
    --danger-color: #f1a5b1;
    /* Brighter than the shared accent so the focused-pane ring reads on dark surfaces. */
    --pane-focus-ring: color-mix(in srgb, var(--primary-color) 70%, var(--text-main));
}

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: var(--font-ui);
    background-color: var(--bg-app);
    color: var(--text-main);
    height: 100vh;
    overflow: hidden;
    transition: background-color var(--anim-base) var(--anim-ease), color var(--anim-base) var(--anim-ease);
}

::highlight(qnt-multi-select) {
    background-color: color-mix(in srgb, var(--selection-color) 88%, transparent);
}

::highlight(qnt-ai-agent-selection-hold) {
    background-color: color-mix(in srgb, var(--selection-color) 82%, transparent);
}

/* --- THE CACHE BOARD (Kanban note kind) ---
   Feature-scoped styles for editor/CacheBoardController.js. The board mounts INTO the editor
   content wrapper (replacing the rich-text surface) for notes of kind 'kanban'; its dialogs,
   menus and toast are appended to <body>, so those selectors are global but `cb-`-prefixed.
   All chrome is token-driven; the green/orange/red schedule "tinge" maps to success/warning/
   danger (both themes — see 000-tokens-base.css). Desktop = resizable columns; mobile = a
   segmented tab switcher + swipe-to-advance (Docs/000-cache-board-requirements.md §9.2). */

/* When a board is mounted, hide the rich-text surface that shares the editor wrapper. */
.editor-content-wrapper.cache-board-mode > .note-title-row,
.editor-content-wrapper.cache-board-mode > #format-toolbar,
.editor-content-wrapper.cache-board-mode > .format-toolbar,
.editor-content-wrapper.cache-board-mode > #note-body,
.editor-content-wrapper.cache-board-mode > .note-editor,
.editor-content-wrapper.cache-board-mode #note-backlinks:not(.note-backlinks-floating),
.editor-content-wrapper.cache-board-mode .note-backlinks:not(.note-backlinks-floating) {
    display: none !important;
}

/* Focus mode + a board: columns need real estate, so fill the whole editor pane instead of the
   960px reading column (that column is meant for text notes — see body.focus-mode rule). Same
   override the Brain Map and Story Board use. */
body.focus-mode .editor-content-wrapper.cache-board-mode {
    max-width: none;
    margin: 0;
    padding: 0;
}

.cache-board {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    width: 100%;
    color: var(--text-main);
    font-size: 0.95rem;
}

/* --- header --- */
.cb-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 2px 12px;
    flex-shrink: 0;
}
.cb-icon-btn {
    background: none;
    border: none;
    color: var(--text-main);
    cursor: pointer;
    font-size: 1.3rem;
    line-height: 1;
    padding: 6px 8px;
    border-radius: var(--radius-sm);
}
.cb-icon-btn:hover { background: var(--item-hover); }
.cb-board-name {
    flex: 1;
    min-width: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-main);
    font-size: 1.25rem;
    font-weight: 600;
    padding: 4px 8px;
}
.cb-board-name:hover { border-color: var(--border-color); }
.cb-board-name:focus { outline: none; border-color: var(--primary-color); background: var(--bg-app); }
.cb-sel-count {
    font-size: 0.8rem;
    color: var(--bg-app);
    background: var(--primary-color);
    font-weight: 700;
    padding: 3px 10px;
    border-radius: 12px;
    cursor: pointer;
    flex-shrink: 0;
}
.cb-sel-count[hidden] { display: none; }

/* --- find-a-task search --- */
.cb-search { position: relative; flex-shrink: 0; width: 220px; max-width: 40%; }
.cb-search-input {
    width: 100%;
    background: var(--bg-app);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 7px 10px;
    font-size: 0.88rem;
    font-family: inherit;
}
.cb-search-input:focus { outline: none; border-color: var(--primary-color); }
.cb-search-results {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 4000;
    background: var(--bg-pane);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: 5px;
    max-height: 320px;
    overflow-y: auto;
}
.cb-search-results[hidden] { display: none; }
.cb-search-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.cb-search-item:hover,
.cb-search-item.cb-search-active { background: var(--item-hover); }
.cb-search-item-text { color: var(--text-main); font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cb-search-item-col { color: var(--text-muted); font-size: 0.72rem; flex-shrink: 0; }
.cb-search-empty { padding: 10px; color: var(--text-muted); font-size: 0.85rem; text-align: center; }

/* --- mobile tabs --- */
.cb-tabs {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
    margin-bottom: 10px;
}
.cb-tabs[hidden] { display: none; }
.cb-tab {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: var(--bg-sidebar);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    color: var(--text-muted);
    padding: 8px 6px;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.85rem;
}
.cb-tab-active {
    color: var(--text-main);
    border-color: var(--primary-color);
    background: var(--bg-pane);
}
.cb-tab-count {
    font-size: 0.72rem;
    background: var(--item-hover);
    color: var(--text-main);
    border-radius: 9px;
    padding: 1px 7px;
}
.cb-tab-active .cb-tab-count { background: var(--primary-color); color: var(--bg-app); }

/* --- columns --- */
.cb-columns {
    display: flex;
    flex: 1;
    min-height: 0;
    overflow-x: auto;
    overflow-y: hidden;
    padding-bottom: 6px;
}
.cb-column {
    background: var(--bg-sidebar);
    border-radius: var(--radius-md);
    display: flex;
    flex-direction: column;
    padding: 10px;
    min-width: 180px;
    flex: 1 1 0;
    min-height: 0;
}
.cb-mobile .cb-columns { overflow-x: hidden; }
.cb-mobile .cb-column { min-width: 0; width: 100%; }

.cb-col-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
    flex-shrink: 0;
}
.cb-col-title-wrap { display: flex; align-items: center; gap: 8px; min-width: 0; }
.cb-col-title {
    font-size: 0.95rem;
    margin: 0;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
    color: var(--text-muted);
}
/* task count badge; shows "count/limit" when a WIP limit is set */
.cb-col-count {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--item-hover);
    border-radius: 999px;
    padding: 1px 8px;
    flex-shrink: 0;
}
/* over the WIP limit: header goes amber — advisory only, nothing is blocked */
.cb-col-over-limit .cb-col-title { color: var(--warning-color); }
.cb-col-over-limit .cb-col-count {
    background: color-mix(in srgb, var(--warning-color) 25%, transparent);
    color: var(--warning-color);
}
.cb-tab-over .cb-tab-count {
    background: color-mix(in srgb, var(--warning-color) 30%, transparent);
    color: var(--text-main);
}
.cb-add-btn {
    background: var(--item-hover);
    color: var(--text-main);
    border: none;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm);
    font-size: 1.1rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
}
.cb-add-btn:hover { background: var(--primary-color); color: var(--bg-app); }

/* Archive pseudo-column: visually "storage, not work" — dashed frame, muted title.
   Cards inside carry .cb-card--archived (dimmed, no tinge). */
.cb-column-archive {
    background: transparent;
    border: 1px dashed var(--border-color);
}
.cb-column-archive .cb-col-title { opacity: 0.75; }
.cb-card--archived {
    opacity: 0.72;
    background: var(--bg-sidebar);
}
.cb-card--archived:hover { opacity: 1; }

.cb-resizer {
    width: 14px;
    margin: 0 2px;
    cursor: col-resize;
    flex-shrink: 0;
    display: flex;
    justify-content: center;
    align-self: stretch;
}
.cb-resizer::after {
    content: '';
    width: 2px;
    height: 100%;
    background: transparent;
    border-radius: 2px;
    transition: background-color var(--anim-fast, 0.15s) ease;
}
.cb-resizer:hover::after,
.cb-resizer.cb-resizing::after { background: var(--primary-color); }

.cb-dropzone {
    flex: 1;
    min-height: 60px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    overflow-y: auto;
    overflow-x: hidden;
    padding-right: 4px;
    border: 2px dashed transparent;
    border-radius: var(--radius-sm);
    transition: border-color var(--anim-fast, 0.15s) ease;
}
.cb-dropzone.cb-dragover {
    border-color: var(--primary-color);
    background: color-mix(in srgb, var(--primary-color) 10%, transparent);
}

/* Dragging notes in from the note list adds linked tasks rather than moving a card — a green
   solid edge separates "this creates something" from the blue re-order cue above. */
.cb-dropzone.cb-dragover.cb-dragover-note {
    border-style: solid;
    border-color: var(--success-color);
    background: color-mix(in srgb, var(--success-color) 12%, transparent);
}

/* A single note held over the middle of a card attaches to that task (D2) instead of adding one. */
.cb-card.cb-card--note-target {
    border-color: var(--success-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--success-color) 40%, transparent);
}

/* --- card --- */
.cb-card {
    position: relative;
    background: var(--bg-pane);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 12px 34px 12px 14px;
    cursor: grab;
    user-select: none;
    box-shadow: var(--shadow-sm);
    line-height: 1.4;
    word-break: break-word;
    touch-action: pan-y;
    transition: transform 0.12s ease, box-shadow 0.2s ease, opacity 0.2s ease;
}
.cb-mobile .cb-card { cursor: pointer; }
.cb-card:active { cursor: grabbing; }
.cb-card.cb-dragging { opacity: 0.4; border-style: dashed; border-color: var(--primary-color); }
.cb-card-title { white-space: pre-wrap; font-weight: 500; }
.cb-card-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    margin-top: 8px;
}
.cb-chip {
    font-size: 0.72rem;
    padding: 2px 7px;
    border-radius: 10px;
    background: var(--item-hover);
    color: var(--text-main);
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.cb-chip-alarm { background: color-mix(in srgb, var(--warning-color) 28%, transparent); cursor: default; }
/* attachment badge (shared .att-badge, styles/src/151-attachments.css) in the card's meta row */
.cb-chip-att { display: inline-flex; align-items: center; }

/* --- board picker dialog (Add to Board) --- */
.cb-picker-tabs { display: flex; gap: 6px; margin-bottom: 12px; }
.cb-picker-tab {
    flex: 1;
    background: var(--bg-sidebar);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    color: var(--text-muted);
    padding: 8px 6px;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.85rem;
    font-family: inherit;
}
.cb-picker-tab-active { color: var(--text-main); border-color: var(--primary-color); background: var(--bg-pane); }
.cb-picker-search {
    width: 100%;
    box-sizing: border-box;
    font: inherit;
    color: var(--text-main);
    background: var(--bg-app);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 7px 10px;
    margin-bottom: 10px;
}
.cb-picker-search:focus { outline: none; border-color: var(--primary-color); }
.cb-picker-list { display: flex; flex-direction: column; gap: 6px; max-height: 320px; overflow-y: auto; margin-bottom: 14px; }
.cb-picker-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    text-align: left;
    background: var(--bg-app);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 10px 12px;
    cursor: pointer;
    color: var(--text-main);
    font-family: inherit;
    font-size: 0.92rem;
}
.cb-picker-item:hover { border-color: var(--primary-color); background: var(--item-hover); }
.cb-picker-item-title { font-weight: 500; flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cb-picker-item-meta { display: flex; align-items: center; gap: 8px; flex: 0 1 auto; min-width: 0; max-width: 55%; justify-content: flex-end; }
.cb-picker-item-crumb { font-size: 0.72rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cb-picker-item-ws { font-size: 0.72rem; color: var(--text-muted); flex-shrink: 0; }
.cb-picker-empty { color: var(--text-muted); padding: 14px 4px; }

/* Floating note hover-preview card (link picker). Lives inside the modal <dialog> so it
   renders in the top layer; never takes pointer events so hovering rows doesn't flicker. */
.note-preview-card {
    position: fixed;
    z-index: 100;
    width: 320px;
    max-height: 380px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 14px;
    background: var(--bg-pane);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    box-shadow: 0 10px 30px color-mix(in srgb, var(--mix-dark) 22%, transparent);
    pointer-events: none;
    overflow: hidden;
}
.note-preview-card.hidden { display: none; }
.note-preview-card__title { font-weight: 700; font-size: 0.95rem; color: var(--text-main); line-height: 1.3; }
.note-preview-card__body {
    position: relative;
    font-size: 0.8rem;
    line-height: 1.45;
    color: var(--text-main);
    max-height: 280px;
    overflow: hidden;
    /* Fade the bottom edge to signal the preview is truncated. */
    -webkit-mask-image: linear-gradient(to bottom, var(--mix-dark) 80%, transparent);
    mask-image: linear-gradient(to bottom, var(--mix-dark) 80%, transparent);
}
.note-preview-card__body > :first-child { margin-top: 0; }
.note-preview-card__body img,
.note-preview-card__body video,
.note-preview-card__body table { max-width: 100%; }
.note-preview-card__body img { max-height: 140px; height: auto; }
.note-preview-card__muted { color: var(--text-muted); font-style: italic; }
.note-preview-card__stamps {
    font-size: 0.7rem;
    color: var(--text-muted);
    border-top: 1px solid var(--border-color);
    padding-top: 6px;
}
/* Single task-details icon: a "?" help badge whose hover tooltip lists every filled-in field.
   `cursor: help` signals the hover affordance. */
.cb-info-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border: 1px solid var(--border-color);
    border-radius: 50%;
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1;
    color: var(--text-muted);
    cursor: help;
    transition: color var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease);
}
.cb-info-dot:hover { color: var(--text-main); border-color: var(--text-muted); }

/* manual sticky-note colour: a soft background tint from the user-chosen swatch (inline
   --cb-card-color). Background-only so it never collides with the due-date tinge (which uses
   box-shadow glow + border-color) or the selection outline/padding. */
.cb-card.cb-card--colored {
    background: color-mix(in srgb, var(--cb-card-color) 26%, var(--bg-pane));
}

/* schedule tinge glows (only when a due date exists) */
.cb-tinge-green  { box-shadow: 0 0 9px 1px color-mix(in srgb, var(--success-color) 55%, transparent); border-color: color-mix(in srgb, var(--success-color) 45%, var(--border-color)); }
.cb-tinge-orange { box-shadow: 0 0 10px 1px color-mix(in srgb, var(--warning-color) 60%, transparent); border-color: color-mix(in srgb, var(--warning-color) 50%, var(--border-color)); }
.cb-tinge-red    { box-shadow: 0 0 11px 2px color-mix(in srgb, var(--danger-color) 65%, transparent); border-color: color-mix(in srgb, var(--danger-color) 55%, var(--border-color)); }

@keyframes cbTingeFlash {
    0%, 100% { transform: scale(1); filter: brightness(1); }
    50%      { transform: scale(1.03); filter: brightness(1.5); }
}
.cb-card.cb-flash { animation: cbTingeFlash 250ms ease 3; }
@media (prefers-reduced-motion: reduce) { .cb-card.cb-flash { animation: none; } }

/* mobile swipe affordance */
.cb-card.cb-swipe-advance { box-shadow: 8px 0 0 -2px color-mix(in srgb, var(--success-color) 70%, transparent); }
.cb-card.cb-swipe-regress { box-shadow: -8px 0 0 -2px color-mix(in srgb, var(--text-muted) 60%, transparent); }

.cb-ellipsis-btn {
    position: absolute;
    top: 6px;
    right: 6px;
    background: none;
    border: none;
    color: var(--text-main);
    cursor: pointer;
    font-size: 1.2rem;
    line-height: 1;
    padding: 0 5px;
    opacity: 0.55;
    border-radius: var(--radius-sm);
}
.cb-ellipsis-btn:hover { opacity: 1; background: var(--item-hover); }

.cb-card.cb-selected {
    outline: 2px solid var(--primary-color);
    outline-offset: 1px;
    padding-left: 26px;
}
.cb-card.cb-selected::before {
    content: '✓';
    position: absolute;
    top: 6px;
    left: 6px;
    font-size: 0.8rem;
    color: var(--primary-color);
    font-weight: 700;
    line-height: 1;
}

/* --- floating menus (appended to body) --- */
.cb-menu {
    position: fixed;
    z-index: 4000;
    min-width: 200px;
    background: var(--bg-pane);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: 6px;
}
.cb-menu[hidden] { display: none; }
.cb-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    color: var(--text-main);
    padding: 9px 12px;
    border-radius: var(--radius-sm);
    font-size: 0.92rem;
    cursor: pointer;
}
/* .open = a parent row whose flyout submenu is showing; keep it highlighted like hover. */
.cb-menu-item:hover,
.cb-menu-item.open { background: var(--item-hover); }
.cb-menu-item.cb-danger { color: var(--danger-color); }
.cb-menu-item.cb-menu-disabled { opacity: 0.45; pointer-events: none; cursor: default; }
/* author display:block above beats the UA [hidden] rule, so hide per-open items explicitly */
.cb-menu-item[hidden] { display: none; }
.cb-menu-sep { height: 1px; background: var(--border-color); margin: 5px 4px; }

/* view-only (the split screen — Docs/000-split-app-kind-views-and-backlinks-plan.md): tasks select, copy and open
   their details, but nothing is added, dragged or renamed (column widths can still be adjusted, locally). The task menu
   keeps only its view items. */
.cache-board--readonly .cb-board-name { cursor: default; }
.cache-board--readonly .cb-board-name:hover,
.cache-board--readonly .cb-board-name:focus { border-color: transparent; background: transparent; }
.cache-board--readonly .cb-card,
.cache-board--readonly .cb-card:active { cursor: default; }
.cb-menu--readonly .cb-menu-sep { display: none; }

/* --- task colour swatch menu --- */
.cb-color-menu { min-width: 0; }
.cb-swatches { display: flex; gap: 6px; padding: 2px; }
.cb-swatch {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1px solid var(--border-color);
    cursor: pointer;
    padding: 0;
    transition: transform var(--anim-fast) var(--anim-ease);
}
.cb-swatch:hover { transform: scale(1.12); }
.cb-swatch--none {
    background: var(--bg-app);
    color: var(--text-muted);
    font-size: 0.7rem;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* --- dialogs (appended to body) — mirror the app's standard modal (.modal-box) --- */
.cb-dialog {
    background: var(--bg-pane);
    color: var(--text-main);
    border: none;
    border-radius: 8px;
    padding: 24px;
    width: min(94vw, 560px);
    box-shadow: 0 10px 25px color-mix(in srgb, var(--mix-dark) 20%, transparent);
    /* Centre in the viewport like the app's modals (overrides any UA/global dialog margin). */
    inset: 0;
    margin: auto;
    max-height: 90vh;
    overflow-y: auto;
}
.cb-dialog::backdrop { background: color-mix(in srgb, var(--mix-dark) 50%, transparent); }

/* The Add/Edit Task dialog is user-resizable: drag the bottom-right corner. The controller
   persists the chosen width/height to app settings (survives refresh, restart, hard reset) and
   re-applies it via inline width/height. A native <dialog> only shows a resize grip when it is a
   scroll container, so overflow must be auto/hidden (not the base rule's overflow-y). min/max
   keep it usable and on-screen on small viewports even if a stored size is larger. */
.cb-dialog.cb-task-dialog {
    resize: both;
    overflow: auto;
    min-width: 360px;
    min-height: 340px;
    max-width: 96vw;
    max-height: 92vh;
}
.cb-dialog-title { margin: 0 0 16px; color: var(--text-main); font-size: 1.1rem; font-weight: 600; line-height: 1.3; }
.cb-dialog-hint { font-size: 0.85rem; color: var(--text-muted); margin: 0 0 12px; }

.cb-field { margin-bottom: 14px; position: relative; }
.cb-field label { display: block; font-size: 0.78rem; color: var(--text-muted); margin-bottom: 4px; }
.cb-field-row { display: flex; gap: 14px; }
.cb-field-row .cb-field { flex: 1; }
.cb-field-effort { max-width: 120px; }
.cb-dialog input[type=text],
.cb-dialog input[type=email],
.cb-dialog input[type=number],
.cb-dialog input[type=datetime-local],
.cb-dialog textarea,
.cb-dialog select,
.cb-bulk-input {
    width: 100%;
    background: var(--bg-app);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 9px 10px;
    font-family: inherit;
    font-size: 0.92rem;
}
.cb-dialog input:focus,
.cb-dialog textarea:focus,
.cb-dialog select:focus,
.cb-bulk-input:focus { outline: none; border-color: var(--primary-color); }
.cb-dialog textarea { resize: vertical; min-height: 140px; }
.cb-bulk-input { min-height: 180px; resize: vertical; }
.cb-computed { font-size: 0.7rem; color: var(--text-muted); margin-top: 3px; }
/* one-click due-date preset chips under the due input */
.cb-due-presets { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 5px; }
.cb-due-preset {
    background: var(--item-hover);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    padding: 3px 10px;
    font-size: 0.75rem;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
}
.cb-due-preset:hover { border-color: var(--primary-color); }
.cb-due-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 5px; }
.cb-alarm-btn {
    background: var(--item-hover);
    color: var(--text-muted);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 4px 9px;
    font-size: 0.78rem;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
}
.cb-alarm-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.cb-alarm-btn.cb-armed {
    background: color-mix(in srgb, var(--warning-color) 25%, transparent);
    color: var(--text-main);
    border-color: var(--warning-color);
}
/* Attachments in the task editor: the shared panel (styles/src/151-attachments.css). */
.cb-field-att { margin-bottom: 12px; }

.cb-meta-stamp { font-size: 0.7rem; color: var(--text-muted); margin-bottom: 14px; }

.cb-dialog-controls { display: flex; justify-content: flex-end; gap: 12px; margin-top: 8px; }
/* Match .simple-btn / .simple-btn.primary from 180-dialogs-overlays.css so board dialog
   buttons look exactly like the rest of the app's modals. */
.cb-btn {
    min-height: var(--btn-height);
    padding: 0 var(--btn-pad-x);
    border-radius: var(--radius-md);
    font-size: var(--btn-font-size);
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
    border: 1px solid var(--border-color);
    background: var(--bg-pane);
    color: var(--text-main);
    transition: transform var(--anim-fast) var(--anim-ease), box-shadow var(--anim-fast) var(--anim-ease), background-color var(--anim-fast) var(--anim-ease);
}
.cb-btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.cb-btn-primary { background: var(--accent-gradient); color: var(--mix-light); border-color: transparent; box-shadow: 0 8px 18px color-mix(in srgb, var(--accent-gradient-start) 25%, transparent); }
.cb-btn-primary:hover { box-shadow: 0 10px 20px color-mix(in srgb, var(--accent-gradient-start) 32%, transparent); }
.cb-btn-cancel { background: var(--bg-pane); color: var(--text-main); }
.cb-btn-cancel:hover { background: var(--item-hover); }

/* autocomplete suggestion list (inside a field) */
.cb-ac-list {
    position: absolute;
    z-index: 5000;
    left: 0;
    right: 0;
    top: 100%;
    margin-top: 2px;
    background: var(--bg-pane);
    border: 1px solid var(--primary-color);
    border-radius: var(--radius-sm);
    max-height: 180px;
    overflow-y: auto;
    box-shadow: var(--shadow-md);
}
.cb-ac-list[hidden] { display: none; }
.cb-ac-item { padding: 8px 10px; cursor: pointer; font-size: 0.9rem; }
.cb-ac-item small { color: var(--text-muted); }
.cb-ac-item:hover, .cb-ac-item.cb-ac-active { background: var(--item-hover); }

/* configure-board dialog: one checkbox row per column, with a task count */
.cb-config-dialog { width: min(94vw, 430px); }
.cb-config-list { display: flex; flex-direction: column; gap: 6px; margin: 0 0 12px; }
.cb-config-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.cb-config-row:hover { background: var(--item-hover); }
.cb-config-check { flex-shrink: 0; width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color); }
.cb-config-label { flex: 1; font-weight: 500; color: var(--text-main); }
.cb-config-count {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--bg-app);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    padding: 1px 8px;
}
/* per-column WIP-limit input (blank = no limit). The input.cb-config-limit specificity is
   deliberate: it must beat the dialog-wide `.cb-dialog input[type=number] { width:100% }` rule. */
.cb-dialog input.cb-config-limit {
    width: 58px;
    flex-shrink: 0;
    text-align: center;
    background: var(--bg-app);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 4px 6px;
    font-size: 0.82rem;
    font-family: inherit;
}
.cb-dialog input.cb-config-limit:focus { outline: none; border-color: var(--primary-color); }
.cb-config-note { font-size: 0.8rem; color: var(--warning-color); margin: 0 0 10px; }
.cb-config-note[hidden] { display: none; }

/* archive toolbar: filter + view toggle */
.cb-archive-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
    flex-wrap: wrap;
}
.cb-archive-filter { position: relative; flex: 1 1 200px; min-width: 160px; }
.cb-archive-filter-input {
    width: 100%;
    box-sizing: border-box;
    padding: 8px 30px 8px 12px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-app);
    color: var(--text-main);
    font-size: 0.9rem;
}
.cb-archive-filter-input:focus {
    outline: none;
    border-color: var(--primary-color);
}
.cb-archive-filter-clear {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: none;
    background: none;
    color: var(--text-muted);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    border-radius: var(--radius-sm);
}
.cb-archive-filter-clear:hover { background: var(--item-hover); color: var(--text-main); }
.cb-archive-filter-clear[hidden] { display: none; }

.cb-archive-views {
    display: inline-flex;
    flex-shrink: 0;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.cb-archive-view-btn {
    padding: 7px 14px;
    border: none;
    background: var(--bg-app);
    color: var(--text-muted);
    font-size: 0.86rem;
    font-weight: 500;
    cursor: pointer;
    transition: background-color var(--anim-fast) var(--anim-ease), color var(--anim-fast) var(--anim-ease);
}
.cb-archive-view-btn + .cb-archive-view-btn { border-left: 1px solid var(--border-color); }
.cb-archive-view-btn:hover { background: var(--item-hover); color: var(--text-main); }
.cb-archive-view-btn.is-active { background: var(--primary-color); color: var(--mix-light); }

/* archive list */
.cb-archive-list { list-style: none; padding: 0; margin: 0 0 14px; max-height: 380px; overflow-y: auto; }
.cb-archive-list[hidden] { display: none; }
.cb-archive-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    margin-bottom: 6px;
}
.cb-archive-check { flex-shrink: 0; width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color); }
.cb-archive-main { flex: 1; min-width: 0; }
.cb-archive-title { font-weight: 500; word-break: break-word; }
.cb-archive-sub { font-size: 0.74rem; color: var(--text-muted); margin-top: 3px; }
.cb-archive-menu-btn {
    background: none;
    border: none;
    color: var(--text-main);
    cursor: pointer;
    font-size: 1.2rem;
    line-height: 1;
    padding: 0 6px;
    opacity: 0.55;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
}
.cb-archive-menu-btn:hover { opacity: 1; background: var(--item-hover); }
.cb-archive-empty { color: var(--text-muted); padding: 12px 4px; list-style: none; }

/* archive timeline: day-grouped sequence of archived tasks with a left rail */
.cb-archive-timeline { margin: 0 0 14px; max-height: 380px; overflow-y: auto; }
.cb-archive-timeline[hidden] { display: none; }
.cb-tl-group { position: relative; padding-left: 20px; }
/* the vertical rail runs through the dot centre (8px + 3px radius ≈ 11px) */
.cb-tl-group::before {
    content: "";
    position: absolute;
    left: 3px;
    top: 6px;
    bottom: 0;
    width: 2px;
    background: var(--border-color);
}
.cb-tl-group:last-child::before { bottom: auto; height: 14px; }
.cb-tl-date {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 4px 0 8px;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--text-main);
}
.cb-tl-dot {
    position: absolute;
    left: 0;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--primary-color);
    box-shadow: 0 0 0 2px var(--bg-pane);
}
.cb-tl-date-label { flex: 0 0 auto; }
.cb-tl-count {
    flex: 0 0 auto;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--bg-app);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    padding: 1px 7px;
}
.cb-tl-items { list-style: none; padding: 0; margin: 0 0 10px; max-height: none; overflow: visible; }

/* read-only task-data view (dialog + hover preview share these) */
.cb-taskdata-dialog { width: min(94vw, 440px); }
.cb-taskdata-heading {
    font-weight: 600;
    font-size: 0.98rem;
    color: var(--text-main);
    margin-bottom: 8px;
    word-break: break-word;
}
.cb-taskdata-list {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 4px 14px;
    margin: 0;
}
.cb-taskdata-dt { color: var(--text-muted); font-size: 0.8rem; }
.cb-taskdata-dd { margin: 0; color: var(--text-main); font-size: 0.85rem; word-break: break-word; }
.cb-taskdata-color { display: flex; align-items: center; gap: 8px; margin-top: 10px; font-size: 0.85rem; }
.cb-taskdata-color-label { color: var(--text-muted); font-size: 0.8rem; }
.cb-taskdata-swatch {
    width: 14px;
    height: 14px;
    border-radius: 3px;
    border: 1px solid var(--border-color);
    flex-shrink: 0;
}
.cb-taskdata-color-val { color: var(--text-muted); }
.cb-taskdata-desc-label {
    margin: 12px 0 4px;
    color: var(--text-muted);
    font-size: 0.8rem;
    font-weight: 600;
}
.cb-taskdata-desc {
    color: var(--text-main);
    font-size: 0.85rem;
    white-space: pre-wrap;
    word-break: break-word;
    border-left: 2px solid var(--border-color);
    padding-left: 10px;
}

/* hover preview: floating read-only card of a task's info */
.cb-archive-hover {
    position: fixed;
    z-index: 7000;
    width: 300px;
    max-height: 60vh;
    overflow-y: auto;
    background: var(--bg-pane);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: 12px 14px;
    pointer-events: none;
}
.cb-archive-hover[hidden] { display: none; }
.cb-archive-hover .cb-taskdata-desc { border-left-color: var(--border-color); }

/* --- toast --- */
.cb-toast {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 6000;
    display: flex;
    gap: 14px;
    align-items: center;
    background: var(--bg-pane);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 12px 16px;
    box-shadow: var(--shadow-md);
}
.cb-toast[hidden] { display: none; }
.cb-toast button {
    background: var(--primary-color);
    border: none;
    color: var(--on-accent);
    border-radius: var(--radius-sm);
    padding: 6px 12px;
    cursor: pointer;
    font-weight: 600;
}
.cb-toast button[hidden] { display: none; }
/* --- THE CACHE BRAIN MAP (mindmap note kind) ---
   Feature-scoped styles for editor/BrainMapController.js. The map mounts INTO the editor content
   wrapper (replacing the rich-text surface) for notes of kind 'mindmap'. A hybrid HTML+SVG world:
   HTML .brain-map-note divs sit over an SVG connector layer, both inside one transformed
   .brain-map-world so a single CSS transform pans/zooms everything together. Its node ⋯ menu is
   appended to <body>, so that selector is global but `brain-map-`-prefixed.
   All chrome is token-driven (no hardcoded colours). Spec: Docs/001-cache-brain-map-requirements.md. */

/* When a map is mounted, hide the rich-text surface that shares the editor wrapper. */
.editor-content-wrapper.brain-map-mode > .note-title-row,
.editor-content-wrapper.brain-map-mode > #format-toolbar,
.editor-content-wrapper.brain-map-mode > .format-toolbar,
.editor-content-wrapper.brain-map-mode > #note-body,
.editor-content-wrapper.brain-map-mode > .note-editor,
.editor-content-wrapper.brain-map-mode #note-backlinks:not(.note-backlinks-floating),
.editor-content-wrapper.brain-map-mode .note-backlinks:not(.note-backlinks-floating) {
    display: none !important;
}

/* Focus mode + a map: maps need real estate, so let the canvas fill the whole editor pane instead of
   the 960px reading column (that column is meant for text notes — see body.focus-mode rule). The
   sidebar + note list are already hidden by focus mode, so this gives the map the full window width. */
body.focus-mode .editor-content-wrapper.brain-map-mode {
    max-width: none;
    margin: 0;
    padding: 0;
}

.brain-map {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    width: 100%;
    color: var(--text-main);
    font-size: 0.95rem;
    /* §13.8 sticky-note palette — a fixed "yellow paper" content treatment (like the node-colour
       swatches), feature-scoped here rather than a global token. Both themes provided. */
    --bm-sticky-bg: #fff7c2; /* literal-ok: sticky-note palette, fixed content treatment */
    --bm-sticky-edge: #ecd76a; /* literal-ok: sticky-note palette, fixed content treatment */
    --bm-sticky-text: #4a4320; /* literal-ok: sticky-note palette, fixed content treatment */
}
:root[data-theme="dark"] .brain-map {
    --bm-sticky-bg: #5a5020; /* literal-ok: sticky-note palette, fixed content treatment */
    --bm-sticky-edge: #7c6f2c; /* literal-ok: sticky-note palette, fixed content treatment */
    --bm-sticky-text: #f6edc2; /* literal-ok: sticky-note palette, fixed content treatment */
}

/* --- toolbar --- */
.brain-map-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-color);
    background: var(--bg-pane);
}
/* the map title doubles as a rename button — single click to edit (a pencil hint shows on hover) */
.brain-map-title {
    font: inherit;
    font-weight: 600;
    color: var(--text-main);
    margin-right: auto;
    cursor: text;
    max-width: 40%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: 2px 8px;
    transition: background var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease);
}
.brain-map-title::after {
    content: "✎";
    font-size: 0.85em;
    opacity: 0;
    transition: opacity var(--anim-fast) var(--anim-ease);
}
.brain-map-title:hover, .brain-map-title:focus-visible {
    background: var(--item-hover);
    border-color: var(--border-color);
    outline: none;
}
.brain-map-title:hover::after, .brain-map-title:focus-visible::after { opacity: 0.6; }
.brain-map-title-input {
    margin-right: auto;
    font: inherit;
    font-weight: 600;
    color: var(--text-main);
    background: var(--bg-app);
    border: 1px solid var(--primary-color);
    border-radius: var(--radius-sm);
    padding: 2px 6px;
}
.brain-map-tb-group { display: inline-flex; gap: 6px; align-items: center; }

/* --- find-a-node search --- */
.brain-map-search { position: relative; }
.brain-map-search-input {
    font: inherit;
    font-size: 0.85rem;
    color: var(--text-main);
    background: var(--bg-app);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 5px 9px;
    width: 150px;
}
.brain-map-search-input:focus { outline: none; border-color: var(--primary-color); }
.brain-map-search-results {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 50;
    min-width: 180px;
    max-width: 280px;
    max-height: 260px;
    overflow-y: auto;
    background: var(--bg-pane);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: 4px;
}
.brain-map-search-row {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    color: var(--text-main);
    padding: 6px 9px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 0.85rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.brain-map-search-row:hover, .brain-map-search-row.active { background: var(--item-hover); }
.brain-map-search-empty { padding: 6px 9px; color: var(--text-muted); font-size: 0.82rem; }
.brain-map-btn {
    background: var(--bg-app);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 5px 10px;
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1.2;
}
.brain-map-btn:hover:not(:disabled) { background: var(--item-hover); }
.brain-map-btn:disabled { opacity: 0.4; cursor: default; }

/* --- viewport / world --- */
.brain-map-viewport {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    cursor: grab;
    outline: none;
    background-color: var(--bg-app);
    background-image: radial-gradient(circle, var(--border-color) 1px, transparent 1px);
    background-size: 28px 28px;
    touch-action: none;
    user-select: none;         /* pan / node drags must not highlight node text (edit textarea opts back in) */
    -webkit-user-select: none;
}
.brain-map-viewport.panning { cursor: grabbing; }
.brain-map-viewport--droptarget { box-shadow: inset 0 0 0 3px var(--primary-color); }
.brain-map-world { position: absolute; top: 0; left: 0; transform-origin: 0 0; }

.brain-map-edges { position: absolute; top: 0; left: 0; overflow: visible; pointer-events: none; }
.brain-map-edge { fill: none; stroke: var(--text-muted); stroke-width: 2; }
.brain-map-edge--linking { stroke: var(--primary-color); stroke-dasharray: 6 5; }
.brain-map-edge-handle {
    fill: var(--text-muted);
    opacity: 0.35;
    cursor: grab;
    pointer-events: all;             /* override #edges pointer-events:none */
    transition: opacity var(--anim-fast) var(--anim-ease), fill var(--anim-fast) var(--anim-ease);
}
.brain-map-edge-handle:hover { opacity: 1; fill: var(--primary-color); }
/* wide transparent hit path over each solid connector — easy to hover / Delete-to-detach (§13.7) */
.brain-map-edge-hit {
    fill: none;
    stroke: transparent;
    stroke-width: 14;
    pointer-events: stroke;
    cursor: pointer;            /* signals the connector is interactive (hover → red, Delete to detach) */
}
/* Hovering a solid edge highlights it red + thicker — the "press Delete to detach this branch" cue. */
.brain-map-edge--hover { stroke: var(--danger-color); stroke-width: 3; }

.brain-map-nodes { position: absolute; top: 0; left: 0; }

/* cross-links (§13.3): free-form directed, dashed, arrowed relationship edges */
.brain-map-xlink {
    fill: none;
    stroke: var(--primary-color);
    stroke-width: 2;
    stroke-dasharray: 7 5;
    opacity: 0.85;
}
.brain-map-xlink--drawing { opacity: 1; }
.brain-map-xlink-marker path { fill: var(--primary-color); }
.brain-map-xlink-hit {
    fill: none;
    stroke: transparent;
    stroke-width: 14;
    pointer-events: stroke;     /* the lines stay thin but are easy to hover / Delete+Click */
    cursor: pointer;            /* signals the link is interactive (hover → red, Delete to remove) */
}
/* Hovering a cross-link highlights it red + thicker — the "press Delete to remove this" affordance. */
.brain-map-xlink--hover { stroke: var(--danger-color); stroke-width: 3; opacity: 1; }
.brain-map-xlink-marker--hot path { fill: var(--danger-color); }
/* valid drop target while Ctrl+dragging a new cross-link */
.brain-map-note--xlink-target {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 40%, transparent), var(--shadow-md);
}
.brain-map--xlinking, .brain-map--xlinking .brain-map-note { cursor: crosshair; }

/* --- notes --- */
.brain-map-note {
    position: absolute;
    transform: translate(-50%, -50%);   /* left/top = node CENTER (set by JS) */
    /* width:max-content (capped by max-width) — without it, an absolutely-positioned node inside a
       zero-width container shrinks to MIN-content (one word per line) for long text. JS may set an
       explicit width (manual resize), which overrides both. */
    width: max-content;
    min-width: 90px;
    max-width: 240px;
    padding: 9px 12px;
    background: var(--bg-pane);
    color: var(--text-main);
    border: 2px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    font-size: 0.9rem;
    line-height: 1.35;
    cursor: grab;
    transition: box-shadow var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease);
}
.brain-map-note--root {
    background: color-mix(in srgb, var(--primary-color) 18%, var(--bg-pane));
    border-color: var(--primary-color);
    font-weight: 600;
    min-width: 120px;
}
.brain-map-note--floating { border-style: dashed; }
.brain-map-note.selected {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 30%, transparent), var(--shadow-md);
}
.brain-map-note.dragging { cursor: grabbing; box-shadow: 0 12px 28px color-mix(in srgb, var(--mix-dark) 40%, transparent); }
.brain-map-note--link-target {
    border-color: var(--success-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--success-color) 40%, transparent), var(--shadow-md);
}
.brain-map--linking, .brain-map--linking .brain-map-note { cursor: grabbing; }

/* branch drag (long-press / Shift+drag): every node that will move together gets a lifted ring so the
   locked group is obvious; the held node briefly pulses when the branch locks. */
.brain-map-note--branch-lift {
    cursor: grabbing;
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary-color) 45%, transparent), 0 10px 24px color-mix(in srgb, var(--mix-dark) 32%, transparent);
}
.brain-map-note--branch-armed { animation: brain-map-branch-pop 0.45s ease; }
@keyframes brain-map-branch-pop {
    /* keep the -50%,-50% centering transform (JS positions by node CENTER) while scaling */
    0% { transform: translate(-50%, -50%) scale(1); }
    45% { transform: translate(-50%, -50%) scale(1.07); }
    100% { transform: translate(-50%, -50%) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
    .brain-map-note--branch-armed { animation: none; }
}

/* tooltip on/off switch (next to "?") — a small pill toggle; off by default */
.brain-map-tip-toggle {
    position: relative;
    flex: 0 0 auto;
    align-self: center;
    width: 34px;
    height: 18px;
    padding: 0;
    border: 1px solid var(--border-color);
    border-radius: 999px;
    background: color-mix(in srgb, var(--text-muted) 25%, transparent);
    cursor: pointer;
    transition: background var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease);
}
.brain-map-tip-toggle-knob {
    position: absolute;
    top: 50%;
    left: 2px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--bg-pane);
    transform: translateY(-50%);
    box-shadow: var(--shadow-sm, 0 1px 2px color-mix(in srgb, var(--mix-dark) 30%, transparent));
    transition: left var(--anim-fast) var(--anim-ease);
}
.brain-map-tip-toggle--on {
    background: var(--primary-color);
    border-color: var(--primary-color);
}
.brain-map-tip-toggle--on .brain-map-tip-toggle-knob { left: 18px; }

/* controls & gestures help — a floating, movable (drag the header), resizable (bottom-right grip),
   persisted dialog toggled by the toolbar "?" button. Non-modal: the canvas stays usable behind it. */
.brain-map-help {
    position: absolute;
    z-index: 30;
    display: flex;
    flex-direction: column;
    min-width: 260px;
    min-height: 180px;
    background: var(--bg-pane);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    overflow: hidden;          /* required for the native resize grip + lets the body scroll */
    resize: both;
}
.brain-map-help--dragging { user-select: none; }
.brain-map-help-head {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--border-color);
    cursor: move;
    touch-action: none;        /* let the header own the drag pointer on touch */
    user-select: none;
}
.brain-map-help-close {
    border: none;
    background: transparent;
    color: var(--text-muted);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    padding: 4px 7px;
    border-radius: var(--radius-sm, 6px);
}
.brain-map-help-close:hover {
    color: var(--text-main);
    background: color-mix(in srgb, var(--text-main) 10%, transparent);
}
.brain-map-help-body {
    flex: 1 1 auto;
    padding: 4px 14px 14px;
    overflow: auto;
}
.brain-map-help dl { margin: 0; }
.brain-map-help-group { margin-top: 12px; }
.brain-map-help-group h4 {
    margin: 0 0 6px;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}
.brain-map-help-row {
    display: grid;
    grid-template-columns: minmax(0, 46%) 1fr;
    gap: 10px;
    padding: 4px 0;
    align-items: baseline;
}
.brain-map-help-row dt { font-weight: 600; font-size: 0.82rem; }
.brain-map-help-row dd { margin: 0; color: var(--text-muted); font-size: 0.85rem; }
@media (max-width: 640px) {
    .brain-map-help-row { grid-template-columns: 1fr; gap: 2px; }
}

/* node colour: a left accent bar + subtle tint from the user-chosen swatch (inline --bm-node-accent) */
.brain-map-note--colored {
    border-left: 5px solid var(--bm-node-accent);
    background: color-mix(in srgb, var(--bm-node-accent) 14%, var(--bg-pane));
}

/* §13.8 sticky note: a paper-yellow comment card with a squared top-left and a folded bottom-right
   corner (the "dog-ear"). Still a full node — movable, linkable, deletable. */
.brain-map-note--sticky {
    background: var(--bm-sticky-bg);
    color: var(--bm-sticky-text);
    border-color: var(--bm-sticky-edge);
    border-radius: 2px 2px 2px 0;
    box-shadow: var(--shadow-sm);
}
.brain-map-note--sticky.brain-map-note--colored {
    /* a chosen swatch still tints, but keep the sticky paper base legible */
    background: color-mix(in srgb, var(--bm-node-accent) 16%, var(--bm-sticky-bg));
}
/* folded corner — at the TOP-LEFT (that corner is free; keeps the bottom-right clear for the resize
   grip and the right edge clear for the ＋). Decorative, so it never intercepts pointer events. */
.brain-map-note--sticky::after {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 14px;
    height: 14px;
    background: linear-gradient(315deg, transparent 50%, color-mix(in srgb, var(--bm-sticky-edge) 70%, var(--mix-dark)) 50%);
    border-bottom-right-radius: 3px;
    pointer-events: none;
}
.brain-map-note--sticky .brain-map-note-label.empty::after { color: var(--bm-sticky-text); }

/* flash when a search result is picked (respects reduced motion) */
@keyframes brain-map-flash {
    0%, 100% { box-shadow: var(--shadow-md); }
    50% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--primary-color) 55%, transparent), var(--shadow-md); }
}
.brain-map-note--flash { animation: brain-map-flash 0.4s ease 3; }
@media (prefers-reduced-motion: reduce) {
    .brain-map-note--flash { animation: none; border-color: var(--primary-color); }
}

/* collapse / expand toggle — visible whenever a node has children. Centered on the right margin
   regardless of its (variable) width via right:0 + translateX(50%). */
.brain-map-collapse {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translate(50%, -50%);
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    border-radius: 10px;
    background: var(--bg-app);
    color: var(--text-muted);
    border: 1px solid var(--border-color);
    font-size: 0.72rem;
    line-height: 1;
    cursor: pointer;
    display: none;
    align-items: center;
    justify-content: center;
}
.brain-map-note--haskids .brain-map-collapse { display: inline-flex; }
.brain-map-collapse:hover { color: var(--text-main); background: var(--item-hover); }
.brain-map-note--collapsed { border-style: dashed; }

.brain-map-note-label { pointer-events: none; min-height: 1em; white-space: pre-wrap; word-break: break-word; }

/* image nodes (§13.2): a downscaled thumbnail; the text label becomes an optional caption */
.brain-map-note-img { display: none; }
.brain-map-note--image { padding: 4px; min-width: 0; }
.brain-map-note--image .brain-map-note-img {
    display: block;
    max-width: 160px;
    max-height: 120px;
    border-radius: 6px;
    object-fit: contain;
    pointer-events: none;       /* clicks/drags act on the node, not the image */
}
.brain-map-note--image .brain-map-note-label { text-align: center; font-size: 0.8rem; margin-top: 4px; }
.brain-map-note--image .brain-map-note-label.empty { display: none; }
.brain-map-note--image .brain-map-note-label.empty::after { content: none; }
.brain-map-note-label.empty::after { content: "…"; opacity: 0.4; }
.brain-map-note-input {
    width: 100%;
    border: none;
    outline: none;
    resize: none;
    background: transparent;
    color: inherit;
    font: inherit;
    line-height: inherit;
    padding: 0;
    margin: 0;
    overflow: hidden;
    user-select: text;         /* re-enable inside the no-select viewport so editing can select text */
    -webkit-user-select: text;
}

/* on-node affordances: shown on hover / when selected */
.brain-map-note-menu,
.brain-map-add-btn,
.brain-map-link-dot { display: none; }
.brain-map-note:hover .brain-map-note-menu,
.brain-map-note.selected .brain-map-note-menu,
.brain-map-note:hover .brain-map-add-btn,
.brain-map-note.selected .brain-map-add-btn,
.brain-map-note:hover .brain-map-link-dot,
.brain-map-note.selected .brain-map-link-dot { display: flex; }

.brain-map-note-menu {
    position: absolute;
    top: -10px;
    right: -10px;
    width: 22px;
    height: 22px;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--bg-app);
    color: var(--text-muted);
    border: 1px solid var(--border-color);
    font-size: 0.8rem;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}
.brain-map-note-menu:hover { color: var(--text-main); background: var(--item-hover); }

/* add-child (+): floats just OUTSIDE the right edge (left:100% + a small gap), vertically centred.
   Being fully outside the box means it can never cover the bottom-right resize grip (which sits just
   inside the corner) — on ANY node height. Stacks below the collapse toggle when one is present. */
.brain-map-add-btn {
    position: absolute;
    left: 100%;
    top: 50%;
    margin-left: 7px;
    transform: translateY(-50%);
    width: 24px;
    height: 24px;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--primary-color);
    color: var(--on-accent);
    border: 2px solid var(--bg-app);
    font-size: 1rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
}
.brain-map-note--haskids .brain-map-add-btn { transform: translateY(calc(-50% + 26px)); }

/* manual width resize grip — the conventional bottom-right corner (where users expect it). The ＋
   button floats fully outside the right edge, so it no longer covers this grip on short nodes. */
.brain-map-resize {
    position: absolute;
    right: 2px;
    bottom: 2px;
    width: 12px;
    height: 12px;
    cursor: ew-resize;
    display: none;
    opacity: 0.55;
    background:
        linear-gradient(135deg, transparent 0 55%, var(--text-muted) 55% 65%, transparent 65% 78%, var(--text-muted) 78% 88%, transparent 88%);
}
.brain-map-note.selected .brain-map-resize,
.brain-map-note:hover .brain-map-resize { display: block; }
.brain-map-resize:hover { opacity: 1; }

/* the "string" anchor: drag onto another note to link (§10.2) */
.brain-map-link-dot {
    position: absolute;
    left: -11px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--bg-app);
    border: 2px solid var(--primary-color);
    cursor: grab;
    align-items: center;
    justify-content: center;
}
.brain-map-link-dot:active { cursor: grabbing; }

/* attachment badge (shared .att-badge, styles/src/151-attachments.css) — only on nodes that have
   attachments; sits on the bottom-left corner so it never covers the label */
.brain-map-note-att {
    position: absolute;
    left: -10px;
    bottom: -12px;
    display: none;
    z-index: 2;
}
.brain-map-note--linked .brain-map-note-att { display: inline-flex; }
.brain-map-note-att .att-badge { font-size: 0.66rem; padding: 0 6px 0 4px; box-shadow: var(--shadow-sm); }

/* --- zoom readout + FAB --- */
.brain-map-zoom {
    position: absolute;
    right: 10px;
    bottom: 10px;
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    background: var(--bg-pane);
    border: 1px solid var(--border-color);
    color: var(--text-muted);
    font-size: 0.75rem;
    pointer-events: none;
}
/* --- node ⋯ menu + hamburger (appended to <body>) --- */
.brain-map-menu {
    position: fixed;
    z-index: 10000;
    min-width: 170px;
    background: var(--bg-pane);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: 4px;
}
.brain-map-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    color: var(--text-main);
    padding: 7px 10px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 0.85rem;
}
.brain-map-menu-item:hover { background: var(--item-hover); }
.brain-map-menu-sep { height: 1px; background: var(--border-color); margin: 4px 6px; }

.brain-map-color-menu { min-width: 0; }
.brain-map-swatches { display: flex; gap: 6px; padding: 4px; }
.brain-map-swatch {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1px solid var(--border-color);
    cursor: pointer;
    padding: 0;
}
.brain-map-swatch:hover { transform: scale(1.12); }
.brain-map-swatch--none { background: var(--bg-app); color: var(--text-muted); font-size: 0.7rem; line-height: 1; }

/* --- view-only (the split screen — Docs/000-split-app-kind-views-and-backlinks-plan.md) ---
   Nodes select, collapse and open their linked note, but never drag, add, link, reparent or resize, and
   the title is plain text (no rename hint). */
.brain-map--readonly .brain-map-title { cursor: default; }
.brain-map--readonly .brain-map-title::after { content: none; }
.brain-map--readonly .brain-map-title:hover,
.brain-map--readonly .brain-map-title:focus-visible { background: none; border-color: transparent; }
.brain-map--readonly .brain-map-note { cursor: default; }
.brain-map--readonly .brain-map-add-btn,
.brain-map--readonly .brain-map-link-dot,
.brain-map--readonly .brain-map-resize,
.brain-map--readonly .brain-map-edge-handle { display: none !important; }
.brain-map--readonly .brain-map-edge-hit,
.brain-map--readonly .brain-map-xlink-hit { cursor: default; }

/* --- toast --- */
.brain-map-toast {
    position: absolute;
    left: 50%;
    bottom: 18px;
    transform: translateX(-50%) translateY(8px);
    background: var(--text-main);
    color: var(--bg-app);
    padding: 8px 14px;
    border-radius: var(--radius-md);
    font-size: 0.82rem;
    box-shadow: var(--shadow-md);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--anim-fast) var(--anim-ease), transform var(--anim-fast) var(--anim-ease);
}
.brain-map-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
/* --- THE CACHE STORY BOARD (storyboard note kind) ---
   Feature-scoped styles for editor/StoryBoardController.js. The board mounts INTO the editor content
   wrapper (replacing the rich-text surface) for notes of kind 'storyboard'. It is a stack of
   horizontal swim lanes on a pan/zoom camera: lane bands + absolutely-positioned card divs live
   inside one transformed .story-board-world, so a single CSS transform pans/zooms everything
   together (mirrors the Brain Map). Menus / present overlay / toasts are appended to <body>, so those
   selectors are global but `story-board-`-prefixed. All chrome is token-driven (no hardcoded colours
   except the documented sticky/status content treatments). Spec: Docs/002-cache-story-board-requirements.md. */

/* When a board is mounted, hide the rich-text surface that shares the editor wrapper. */
.editor-content-wrapper.story-board-mode > .note-title-row,
.editor-content-wrapper.story-board-mode > #format-toolbar,
.editor-content-wrapper.story-board-mode > .format-toolbar,
.editor-content-wrapper.story-board-mode > #note-body,
.editor-content-wrapper.story-board-mode > .note-editor,
.editor-content-wrapper.story-board-mode #note-backlinks:not(.note-backlinks-floating),
.editor-content-wrapper.story-board-mode .note-backlinks:not(.note-backlinks-floating) {
    display: none !important;
}

/* Focus mode + a board: give the canvas the whole editor pane (not the 960px text column). */
body.focus-mode .editor-content-wrapper.story-board-mode {
    max-width: none;
    margin: 0;
    padding: 0;
}

.story-board {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    width: 100%;
    color: var(--text-main);
    font-size: 0.95rem;
    /* Card text is not a text document — dragging across cards shouldn't select it, and refocusing
       the window (alt-tab back) shouldn't restore a phantom selection across cards (§16.5). Edit
       fields re-enable selection below. */
    user-select: none;
    -webkit-user-select: none;
    /* Sticky-note palette — a fixed "yellow paper" content treatment (both themes). */
    --sb-sticky-bg: #fff7c2; /* literal-ok: sticky-note palette, fixed content treatment */
    --sb-sticky-edge: #ecd76a; /* literal-ok: sticky-note palette, fixed content treatment */
    --sb-sticky-text: #4a4320; /* literal-ok: sticky-note palette, fixed content treatment */
    /* Status-tag palette (card.color values) — fixed content treatment, both themes. */
    --sb-tag-draft: var(--warning-color);
    --sb-tag-progress: var(--primary-color);
    --sb-tag-final: var(--success-color);
    --sb-tag-accent: #8b5cf6; /* literal-ok: sticky-note palette, fixed content treatment */
}
:root[data-theme="dark"] .story-board {
    --sb-sticky-bg: #5a5020; /* literal-ok: sticky-note palette, fixed content treatment */
    --sb-sticky-edge: #7c6f2c; /* literal-ok: sticky-note palette, fixed content treatment */
    --sb-sticky-text: #f6edc2; /* literal-ok: sticky-note palette, fixed content treatment */
    --sb-tag-accent: #a78bfa; /* literal-ok: sticky-note palette, fixed content treatment */
}
/* re-enable text selection where the user is actually editing text (§16.5) */
.story-board input,
.story-board textarea {
    user-select: text;
    -webkit-user-select: text;
}

/* duration dialog slider (appended to <body>, so global but story-board-prefixed) */
.story-board-dialog-slider {
    width: 100%;
    accent-color: var(--primary-color);
    cursor: pointer;
    margin: 2px 0 4px;
}
.story-board-dialog-slider-ends {
    display: flex;
    justify-content: space-between;
    font-size: 0.72rem;
    color: var(--text-muted);
}

/* --- toolbar --- */
.story-board-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-color);
    background: var(--bg-pane);
    flex: 0 0 auto;
}
.story-board-title {
    font: inherit;
    font-weight: 600;
    color: var(--text-main);
    margin-right: auto;
    cursor: text;
    max-width: 40%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
}
.story-board-title::after {
    content: "✎";
    font-size: 0.8em;
    opacity: 0;
    transition: opacity var(--anim-fast) var(--anim-ease);
}
.story-board-title:hover {
    border-color: var(--border-color);
    background: var(--item-hover);
}
.story-board-title:hover::after { opacity: 0.6; }

/* view-only (the split screen — Docs/000-split-app-kind-views-and-backlinks-plan.md): cards select and open,
   but nothing renames, adds or drags, so the rename hint, add ghosts and lane menus go. */
.story-board--readonly .story-board-title { cursor: default; }
.story-board--readonly .story-board-title::after { content: none; }
.story-board--readonly .story-board-title:hover { border-color: transparent; background: transparent; }
.story-board--readonly .story-board-lane-title,
.story-board--readonly .story-board-card { cursor: default; }
.story-board--readonly .story-board-add-card,
.story-board--readonly .story-board-add-lane,
.story-board--readonly .story-board-lane-menu { display: none !important; }
.story-board-title-input,
.story-board-lane-rename {
    font: inherit;
    font-weight: 600;
    color: var(--text-main);
    padding: 4px 8px;
    border: 1px solid var(--primary-color);
    border-radius: var(--radius-sm);
    background: var(--bg-pane);
}
.story-board-tb-group {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.story-board-btn {
    font: inherit;
    font-size: 0.88rem;
    color: var(--text-main);
    background: var(--bg-pane);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 5px 10px;
    cursor: pointer;
    line-height: 1;
    transition: background var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease);
}
.story-board-btn:hover:not(:disabled) { background: var(--item-hover); border-color: var(--pane-divider); }
.story-board-btn:disabled { opacity: 0.45; cursor: default; }
.story-board-btn[data-act="present"] { color: var(--primary-color); }
.story-board-runtime {
    font-size: 0.82rem;
    color: var(--text-muted);
    margin-left: 4px;
    white-space: nowrap;
}

/* --- viewport / world --- */
.story-board-viewport {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    background:
        radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--border-color) 70%, transparent) 1px, transparent 0);
    background-size: 26px 26px;
    background-color: var(--bg-editor-pane);
    cursor: grab;
    touch-action: none;
    outline: none;
}
.story-board-viewport:active { cursor: grabbing; }
.story-board-world {
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: 0 0;
    will-change: transform;
}
.story-board-lanes,
.story-board-cards {
    position: absolute;
    top: 0;
    left: 0;
}

/* --- lane bands --- */
.story-board-lane {
    position: absolute;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--bg-pane) 70%, transparent);
    box-shadow: var(--shadow-sm);
}
.story-board-lane--colored {
    border-left: 4px solid var(--sb-lane-accent, var(--primary-color));
}
.story-board-lane-header {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    box-sizing: border-box;
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    border-right: 1px dashed var(--border-color);
    background: color-mix(in srgb, var(--bg-pane) 40%, transparent);
}
.story-board-lane-title {
    font-weight: 600;
    color: var(--text-main);
    cursor: text;
    word-break: break-word;
    line-height: 1.25;
}
.story-board-lane-dur {
    font-size: 0.78rem;
    color: var(--text-muted);
}
.story-board-lane-menu {
    margin-top: auto;
    align-self: flex-start;
    font: inherit;
    color: var(--text-muted);
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 2px 6px;
    border-radius: var(--radius-sm);
}
.story-board-lane-menu:hover { background: var(--item-hover); color: var(--text-main); }
.story-board-add-lane {
    position: absolute;
    box-sizing: border-box;
    padding: 10px;
    font: inherit;
    font-size: 0.85rem;
    color: var(--text-muted);
    background: transparent;
    border: 1px dashed var(--border-color);
    border-radius: var(--radius-md);
    cursor: pointer;
}
.story-board-add-lane:hover { color: var(--primary-color); border-color: var(--primary-color); }

/* --- cards --- */
.story-board-card {
    position: absolute;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-pane);
    box-shadow: var(--shadow-sm);
    cursor: grab;
    overflow: hidden;
    transition: box-shadow var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease);
}
.story-board-card:hover { box-shadow: var(--shadow-md); }
/* Selected card = a clear outline + a lifted shadow border + a ✓ tick (parity with Cache Board
   task-select, §16.1). */
.story-board-card.selected {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 22%, transparent), var(--shadow-md);
}
/* the tick: hidden until selected, then a filled primary badge at the top-left corner */
.story-board-card-tick {
    position: absolute;
    top: 5px;
    left: 5px;
    width: 17px;
    height: 17px;
    border-radius: 50%;
    background: var(--primary-color);
    color: var(--on-accent);
    font-size: 0.72rem;
    font-weight: 800;
    line-height: 17px;
    text-align: center;
    z-index: 3;
    display: none;
}
.story-board-card.selected .story-board-card-tick { display: block; }
/* when selected, slide the number badge right so it sits beside the tick instead of under it */
.story-board-card.selected .story-board-card-num { left: 27px; }
.story-board-card--dragging { opacity: 0.85; z-index: 50; cursor: grabbing; box-shadow: var(--shadow-md); }
/* A note dragged from the list over a card: dropping links the card to it (same look as the map). */
.story-board-card--link-target {
    border-color: var(--success-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--success-color) 40%, transparent), var(--shadow-md);
}
.story-board-card--colored { border-left: 4px solid var(--sb-card-accent, var(--primary-color)); }
/* reserve room at the top for the corner number badge on non-image cards (no frame above the title) */
.story-board-card--numbered { padding-top: 28px; }
/* Sticky card = a paper sticky note pinned to the board (§16.4): warm paper, soft drop shadow, a
   faint hand-pinned tilt, and a red push-pin through the top. */
.story-board-card--sticky {
    background:
        linear-gradient(180deg, color-mix(in srgb, var(--sb-sticky-bg) 100%, var(--mix-light) 6%) 0%, var(--sb-sticky-bg) 22%);
    border-color: var(--sb-sticky-edge);
    color: var(--sb-sticky-text);
    border-radius: 3px;                 /* paper corners are crisper than the rounded cards */
    box-shadow: 2px 5px 12px color-mix(in srgb, var(--mix-dark) 20%, transparent);
    transform: rotate(-1.4deg);         /* casually pinned */
    padding-top: 22px;                  /* clearance for the pin head */
    overflow: visible;                  /* let the pin sit above the top edge */
}
/* keep the tilt from being cancelled while dragging, but drop it when the grid re-lays cards out */
.story-board-card--sticky.story-board-card--dragging { transform: rotate(-1.4deg); }
.story-board-card--sticky.story-board-card--numbered { padding-top: 30px; }
.story-board-card--sticky .story-board-card-title,
.story-board-card--sticky .story-board-card-body { color: var(--sb-sticky-text); }
/* the red push-pin: a domed head with a highlight, sitting through the top of the note */
.story-board-card--sticky::before {
    content: "";
    position: absolute;
    top: -8px;
    left: 50%;
    width: 16px;
    height: 16px;
    transform: translateX(-50%);
    border-radius: 50%;
    background: radial-gradient(circle at 34% 30%, #ff9a9a 0%, #e6392f 52%, #a5160f 100%); /* literal-ok: push-pin, fixed content treatment */
    box-shadow: 0 3px 4px rgba(20, 24, 34, 0.4), inset 0 -1px 2px rgba(120, 0, 0, 0.5); /* literal-ok: push-pin, fixed content treatment */
    z-index: 4;
    pointer-events: none;
}
/* a tiny stem/glint under the pin head so it reads as pushed in */
.story-board-card--sticky::after {
    content: "";
    position: absolute;
    top: 4px;
    left: 50%;
    width: 3px;
    height: 6px;
    transform: translateX(-50%);
    background: color-mix(in srgb, var(--sb-sticky-edge) 70%, #8a6a1a 30%); /* literal-ok: sticky-note palette, fixed content treatment */
    border-radius: 0 0 2px 2px;
    z-index: 3;
    pointer-events: none;
}

.story-board-card-num {
    position: absolute;
    top: 6px;
    left: 6px;
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--on-accent);
    background: var(--primary-color);
    border-radius: var(--radius-sm);
    padding: 1px 6px;
    line-height: 1.4;
    z-index: 2;
}
.story-board-card-menu {
    position: absolute;
    top: 4px;
    font: inherit;
    color: var(--text-muted);
    background: color-mix(in srgb, var(--bg-pane) 70%, transparent);
    border: none;
    cursor: pointer;
    padding: 2px 5px;
    border-radius: var(--radius-sm);
    line-height: 1;
    opacity: 0;
    transition: opacity var(--anim-fast) var(--anim-ease);
    z-index: 2;
}
.story-board-card-menu { right: 4px; }
.story-board-card:hover .story-board-card-menu,
.story-board-card.selected .story-board-card-menu { opacity: 1; }
.story-board-card-menu:hover { background: var(--item-hover); color: var(--text-main); }

.story-board-card-frame {
    width: 100%;
    background: color-mix(in srgb, var(--text-muted) 15%, transparent);
    border-radius: var(--radius-sm);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.story-board-card-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.story-board-card-frame-empty { font-size: 0.78rem; color: var(--text-muted); }

/* Attachment badge (shared .att-badge, styles/src/151-attachments.css): sits under the card text. */
.story-board-card-att { align-self: flex-start; margin-top: 2px; }

/* Edit card dialog */
.sb-ce-hint { color: var(--text-muted); font-weight: 400; }
.story-board-card-title {
    font-weight: 600;
    font-size: 0.9rem;
    line-height: 1.25;
    color: var(--text-main);
    word-break: break-word;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.story-board-card-ph { color: var(--text-muted); font-weight: 400; }
.story-board-card-body {
    font-size: 0.82rem;
    line-height: 1.35;
    color: var(--text-muted);
    white-space: pre-wrap;
    word-break: break-word;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
}
.story-board-card-meta,
.story-board-card-dialogue {
    font-size: 0.74rem;
    color: var(--text-muted);
    border-top: 1px dashed var(--border-color);
    padding-top: 4px;
    word-break: break-word;
}
.story-board-card-dialogue { font-style: italic; }
.story-board-card-dur {
    position: absolute;
    bottom: 4px;
    right: 6px;
    font-size: 0.72rem;
    color: var(--text-muted);
    background: color-mix(in srgb, var(--bg-pane) 70%, transparent);
    border-radius: var(--radius-sm);
    padding: 0 4px;
}

/* inline edit form */
.story-board-card--editing { cursor: default; z-index: 40; }
.story-board-edit-title,
.story-board-edit-body {
    font: inherit;
    width: 100%;
    box-sizing: border-box;
    color: var(--text-main);
    background: var(--bg-pane);
    border: 1px solid var(--primary-color);
    border-radius: var(--radius-sm);
    padding: 4px 6px;
}
.story-board-edit-title { font-weight: 600; }
.story-board-edit-body { resize: vertical; min-height: 54px; }

/* trailing "add card" ghost slot */
.story-board-add-card {
    position: absolute;
    box-sizing: border-box;
    font-size: 1.4rem;
    color: var(--text-muted);
    background: transparent;
    border: 1px dashed var(--border-color);
    border-radius: var(--radius-md);
    cursor: pointer;
    opacity: 0.5;
    transition: opacity var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease);
}
.story-board-add-card:hover { opacity: 1; color: var(--primary-color); border-color: var(--primary-color); }

/* drop marker during a card drag */
.story-board-drop-marker {
    position: absolute;
    width: 4px;
    border-radius: 2px;
    background: var(--primary-color);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary-color) 30%, transparent);
    pointer-events: none;
    z-index: 45;
}

/* zoom badge */
.story-board-zoom {
    position: absolute;
    right: 10px;
    bottom: 10px;
    font-size: 0.78rem;
    color: var(--text-muted);
    background: color-mix(in srgb, var(--bg-pane) 80%, transparent);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 2px 8px;
    pointer-events: none;
}

/* --- context / ⋯ menus (appended to body) --- */
.story-board-menu {
    position: fixed;
    z-index: 10000;
    min-width: 190px;
    background: var(--bg-pane);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: 5px;
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.story-board-menu-item {
    font: inherit;
    font-size: 0.9rem;
    text-align: left;
    color: var(--text-main);
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    padding: 7px 10px;
    cursor: pointer;
    white-space: nowrap;
}
.story-board-menu-item:hover { background: var(--item-hover); }
.story-board-menu-item.danger { color: var(--danger-color); }
.story-board-menu-sep {
    height: 1px;
    background: var(--border-color);
    margin: 4px 2px;
}

/* --- present / animatic overlay (appended to body) --- */
.story-board-present {
    position: fixed;
    inset: 0;
    z-index: 10001;
    background: rgba(8, 12, 20, 0.94); /* literal-ok: canvas HUD is dark in both themes */
    display: flex;
    align-items: center;
    justify-content: center;
    color: #f4f7fb; /* literal-ok: canvas HUD is dark in both themes */
}
.story-board-present-stage {
    max-width: 82vw;
    max-height: 78vh;
    display: flex;
    align-items: center;
    justify-content: center;
}
.story-board-present-frame {
    width: min(82vw, 1200px);
    max-height: 78vh;
    background: var(--mix-dark);
    border-radius: var(--radius-md);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.story-board-present-frame img { width: 100%; height: 100%; object-fit: contain; }
.story-board-present-text {
    max-width: 720px;
    padding: 40px 48px;
    text-align: center;
}
.story-board-present-text.sticky {
    background: var(--sb-sticky-bg);
    color: var(--sb-sticky-text);
    border-radius: var(--radius-md);
}
.story-board-present-text h2 { margin: 0 0 16px; font-size: 1.8rem; }
.story-board-present-text p { margin: 0; font-size: 1.1rem; line-height: 1.5; white-space: pre-wrap; }
.story-board-present-caption {
    position: absolute;
    bottom: 40px;
    left: 0;
    right: 0;
    text-align: center;
    font-size: 1rem;
    color: #cdd6e4; /* literal-ok: canvas HUD is dark in both themes */
}
.story-board-present-progress {
    position: absolute;
    top: 24px;
    right: 32px;
    font-size: 0.85rem;
    color: #9aa7bb; /* literal-ok: canvas HUD is dark in both themes */
}
.story-board-present-close {
    position: absolute;
    top: 20px;
    left: 24px;
    font-size: 1.3rem;
    color: #cdd6e4; /* literal-ok: canvas HUD is dark in both themes */
    background: transparent;
    border: none;
    cursor: pointer;
}
.story-board-present-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    font-size: 2.6rem;
    color: #cdd6e4; /* literal-ok: canvas HUD is dark in both themes */
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 0 24px;
}
.story-board-present-nav:hover { color: var(--mix-light); }
.story-board-present-nav.prev { left: 8px; }
.story-board-present-nav.next { right: 8px; }

/* --- toast --- */
.story-board-toast {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%) translateY(10px);
    z-index: 10002;
    background: var(--text-main);
    color: var(--bg-pane);
    font-size: 0.85rem;
    padding: 8px 16px;
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    opacity: 0;
    transition: opacity var(--anim-base) var(--anim-ease), transform var(--anim-base) var(--anim-ease);
    pointer-events: none;
}
.story-board-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* --- mobile --- */
.story-board--mobile .story-board-toolbar { gap: 6px; padding: 6px 8px; }
.story-board--mobile .story-board-title { max-width: 46%; }
.story-board--mobile .story-board-btn { padding: 5px 8px; }
.story-board--mobile .story-board-card-menu { opacity: 1; }
/* --- THE CACHE CALENDAR (calendar note kind) ---
   Feature-scoped styles for editor/CalendarController.js. The calendar mounts INTO the editor content
   wrapper (replacing the rich-text surface) for notes of kind 'calendar'. Unlike the board/map/story
   app-kinds it is NOT a pan/zoom canvas — it is a deterministic grid (month) / time-grid (week/day) /
   list (agenda) laid out from date math. Context menus are appended to <body>, so those selectors are
   global but `cyb-cal-`-prefixed. All chrome is token-driven; the category palette maps colour ids to
   semantic tokens (both themes). Spec: Docs/003-cache-calendar-requirements.md. */

/* When a calendar is mounted, hide the rich-text surface that shares the editor wrapper. */
.editor-content-wrapper.cyb-cal-mode > .note-title-row,
.editor-content-wrapper.cyb-cal-mode > #format-toolbar,
.editor-content-wrapper.cyb-cal-mode > .format-toolbar,
.editor-content-wrapper.cyb-cal-mode > #note-body,
.editor-content-wrapper.cyb-cal-mode > .note-editor,
.editor-content-wrapper.cyb-cal-mode #note-backlinks:not(.note-backlinks-floating),
.editor-content-wrapper.cyb-cal-mode .note-backlinks:not(.note-backlinks-floating) {
    display: none !important;
}
body.focus-mode .editor-content-wrapper.cyb-cal-mode {
    max-width: none;
    margin: 0;
    padding: 0;
}

.cyb-cal {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    width: 100%;
    color: var(--text-main);
    font-size: 0.9rem;
    user-select: none;
    -webkit-user-select: none;
    /* Category palette — colour id → base colour. blue/green/orange/red reuse semantic tokens;
       purple/teal/grey are fixed content treatments (both themes provided). */
    --cyb-c-blue: var(--primary-color);
    --cyb-c-green: var(--success-color);
    --cyb-c-orange: var(--warning-color);
    --cyb-c-red: var(--danger-color);
    --cyb-c-purple: #8b5cf6; /* literal-ok: calendar category palette, fixed content colours */
    --cyb-c-teal: #0d9488; /* literal-ok: calendar category palette, fixed content colours */
    --cyb-c-grey: #6b7280; /* literal-ok: calendar category palette, fixed content colours */
    --cyb-hour-h: 48px;
}
:root[data-theme="dark"] .cyb-cal {
    --cyb-c-purple: #a78bfa; /* literal-ok: calendar category palette, fixed content colours */
    --cyb-c-teal: #2dd4bf; /* literal-ok: calendar category palette, fixed content colours */
    --cyb-c-grey: #9ca3af; /* literal-ok: calendar category palette, fixed content colours */
}
.cyb-cal input,
.cyb-cal textarea,
.cyb-cal select { user-select: text; -webkit-user-select: text; }

/* colour resolver: any element carrying [data-color] exposes --cyb-ev */
.cyb-cal [data-color="blue"] { --cyb-ev: var(--cyb-c-blue); }
.cyb-cal [data-color="green"] { --cyb-ev: var(--cyb-c-green); }
.cyb-cal [data-color="orange"] { --cyb-ev: var(--cyb-c-orange); }
.cyb-cal [data-color="red"] { --cyb-ev: var(--cyb-c-red); }
.cyb-cal [data-color="purple"] { --cyb-ev: var(--cyb-c-purple); }
.cyb-cal [data-color="teal"] { --cyb-ev: var(--cyb-c-teal); }
.cyb-cal [data-color="grey"] { --cyb-ev: var(--cyb-c-grey); }

/* ---------- toolbar ---------- */
.cyb-cal-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-color);
    flex-wrap: wrap;
}
.cyb-cal-title {
    font-size: 1.05rem;
    font-weight: 650;
    color: var(--text-main);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: 3px 8px;
    cursor: text;
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cyb-cal-title:hover { background: var(--item-hover); border-color: var(--border-color); }
.cyb-cal-title::after { content: " ✎"; opacity: 0; font-size: 0.8em; }
.cyb-cal-title:hover::after { opacity: 0.5; }
/* view-only (the split screen — Docs/000-split-app-kind-views-and-backlinks-plan.md): the title is plain text and
   timed events have no resize grip. */
.cyb-cal--readonly .cyb-cal-title { cursor: default; }
.cyb-cal--readonly .cyb-cal-title::after { content: none; }
.cyb-cal--readonly .cyb-cal-title:hover { background: transparent; border-color: transparent; }
.cyb-cal--readonly .cyb-cal-tg-resize { display: none; }
.cyb-cal-title-input {
    font-size: 1.05rem;
    font-weight: 650;
    padding: 3px 8px;
    border: 1px solid var(--primary-color);
    border-radius: var(--radius-sm);
    background: var(--bg-pane);
    color: var(--text-main);
    max-width: 240px;
}
.cyb-cal-nav { display: inline-flex; align-items: center; gap: 6px; }
.cyb-cal-range { font-weight: 600; margin-left: 6px; min-width: 140px; }
.cyb-cal-spacer { flex: 1 1 auto; }
.cyb-cal-quickadd {
    padding: 5px 10px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-pane);
    color: var(--text-main);
    min-width: 180px;
    font-size: 0.85rem;
}
.cyb-cal-quickadd:focus { outline: none; border-color: var(--primary-color); }
.cyb-cal-views { display: inline-flex; border: 1px solid var(--border-color); border-radius: var(--radius-md); overflow: hidden; }
.cyb-cal-views .cyb-cal-btn { border: none; border-radius: 0; border-left: 1px solid var(--border-color); }
.cyb-cal-views .cyb-cal-btn:first-child { border-left: none; }
.cyb-cal-btn {
    padding: 5px 11px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-pane);
    color: var(--text-main);
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1.2;
}
.cyb-cal-btn:hover { background: var(--item-hover); }
.cyb-cal-btn.is-active { background: var(--primary-color); color: var(--mix-light); border-color: var(--primary-color); }
.cyb-cal-btn.cyb-cal-primary { background: var(--primary-color); color: var(--mix-light); border-color: var(--primary-color); font-weight: 600; }
.cyb-cal-btn.cyb-cal-primary:hover { background: var(--primary-hover); }
.cyb-cal-icon { padding: 5px 9px; font-size: 1rem; }

/* ---------- legend ---------- */
.cyb-cal-legend { display: flex; flex-wrap: wrap; gap: 6px; padding: 6px 12px; border-bottom: 1px solid var(--border-color); align-items: center; }
.cyb-cal-legend-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 9px; border: 1px solid var(--border-color); border-radius: 999px;
    background: var(--bg-pane); color: var(--text-main); cursor: pointer; font-size: 0.8rem;
}
.cyb-cal-legend-chip.is-off { opacity: 0.42; text-decoration: line-through; }
.cyb-cal-swatch { width: 11px; height: 11px; border-radius: 3px; background: var(--cyb-ev, var(--primary-color)); }
.cyb-cal-legend-manage { margin-left: auto; background: transparent; border: none; color: var(--text-muted); cursor: pointer; font-size: 0.8rem; }
.cyb-cal-legend-manage:hover { color: var(--text-main); }

/* ---------- body ---------- */
.cyb-cal-body { flex: 1 1 auto; min-height: 0; overflow: hidden; outline: none; display: flex; }
.cyb-cal-body > * { flex: 1 1 auto; min-height: 0; }

/* ---------- MONTH ---------- */
.cyb-cal-month { display: flex; flex-direction: column; height: 100%; }
.cyb-cal-weekhead { display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid var(--border-color); }
.cyb-cal-weekhead-cell { padding: 6px 8px; font-size: 0.72rem; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.cyb-cal-grid { flex: 1 1 auto; display: grid; grid-template-columns: repeat(7, 1fr); grid-auto-rows: 1fr; min-height: 0; }
.cyb-cal-cell {
    border-right: 1px solid var(--border-color);
    border-bottom: 1px solid var(--border-color);
    padding: 3px 4px;
    min-height: 0;
    overflow: hidden;
    cursor: pointer;
    display: flex; flex-direction: column;
    background: var(--bg-pane);
}
.cyb-cal-cell:nth-child(7n) { border-right: none; }
.cyb-cal-cell.is-outside { background: var(--bg-list-pane); color: var(--text-muted); }
.cyb-cal-cell.is-weekend:not(.is-outside) { background: color-mix(in srgb, var(--bg-list-pane) 55%, var(--bg-pane)); }
.cyb-cal-cell:hover { background: var(--item-hover); }
.cyb-cal-cell.is-drop { outline: 2px dashed var(--primary-color); outline-offset: -2px; }
.cyb-cal-cell.cyb-cal-range-sel { background: var(--selection-color); outline: 1px solid var(--primary-color); outline-offset: -1px; }
.cyb-cal-cell.cyb-cal-range-sel.is-today { background: var(--selection-color); }
.cyb-cal-cell.is-droptarget { outline: 2px solid var(--primary-color); outline-offset: -2px; background: var(--selection-color); }
.cyb-cal-cell-head { display: flex; justify-content: flex-end; }
.cyb-cal-cell-num { font-size: 0.78rem; color: var(--text-muted); padding: 1px 4px; border-radius: 999px; }
.cyb-cal-cell.is-today .cyb-cal-cell-num { background: var(--primary-color); color: var(--mix-light); font-weight: 700; }
.cyb-cal-cell-items { display: flex; flex-direction: column; gap: 2px; overflow: hidden; min-height: 0; }

.cyb-cal-event {
    display: flex; align-items: center; gap: 4px;
    border: none; text-align: left; cursor: pointer;
    padding: 1px 5px; border-radius: 4px;
    font-size: 0.76rem; line-height: 1.35;
    background: color-mix(in srgb, var(--cyb-ev, var(--primary-color)) 16%, var(--bg-pane));
    color: var(--text-main);
    border-left: 3px solid var(--cyb-ev, var(--primary-color));
    overflow: hidden; white-space: nowrap;
}
.cyb-cal-event.is-allday { background: var(--cyb-ev, var(--primary-color)); color: var(--mix-light); border-left: none; }
.cyb-cal-event.is-selected { outline: 2px solid var(--primary-color); outline-offset: 1px; }
.cyb-cal-event-time { font-weight: 600; opacity: 0.85; }
.cyb-cal-event-title { overflow: hidden; text-overflow: ellipsis; }
.cyb-cal-event-rep { opacity: 0.7; }

.cyb-cal-note-chip {
    display: flex; align-items: center; gap: 4px;
    border: 1px dashed var(--border-color); text-align: left; cursor: pointer;
    padding: 1px 5px; border-radius: 4px; font-size: 0.74rem;
    background: var(--bg-list-pane); color: var(--text-main);
    overflow: hidden; white-space: nowrap;
}
.cyb-cal-note-chip:hover { background: var(--item-hover); border-color: var(--primary-color); }
.cyb-cal-note-chip.is-dead { opacity: 0.55; font-style: italic; }
.cyb-cal-note-title { overflow: hidden; text-overflow: ellipsis; }
.cyb-cal-note-open { margin-left: auto; opacity: 0.5; }
.cyb-cal-more { border: none; background: transparent; color: var(--text-muted); cursor: pointer; font-size: 0.72rem; text-align: left; padding: 1px 5px; }
.cyb-cal-more:hover { color: var(--primary-color); }

/* ---------- TIME GRID (week / day) ---------- */
.cyb-cal-timegrid { display: flex; flex-direction: column; height: 100%; --cyb-gutter-w: 56px; }
.cyb-cal-tg-header { display: grid; grid-template-columns: var(--cyb-gutter-w) repeat(var(--cyb-day-count), 1fr); border-bottom: 1px solid var(--border-color); }
.cyb-cal-tg-corner { }
.cyb-cal-tg-daybtn {
    display: flex; flex-direction: column; align-items: center; gap: 1px;
    padding: 5px; border: none; border-left: 1px solid var(--border-color);
    background: var(--bg-pane); color: var(--text-main); cursor: pointer;
}
.cyb-cal-tg-daybtn:hover { background: var(--item-hover); }
.cyb-cal-tg-dow { font-size: 0.68rem; color: var(--text-muted); text-transform: uppercase; }
.cyb-cal-tg-dom { font-size: 1.1rem; font-weight: 600; }
.cyb-cal-tg-daybtn.is-today .cyb-cal-tg-dom { background: var(--primary-color); color: var(--on-accent); border-radius: 999px; width: 1.7em; height: 1.7em; display: flex; align-items: center; justify-content: center; }

.cyb-cal-tg-allday { display: grid; grid-template-columns: var(--cyb-gutter-w) repeat(var(--cyb-day-count), 1fr); border-bottom: 1px solid var(--border-color); min-height: 24px; max-height: 88px; overflow-y: auto; }
.cyb-cal-tg-allday-label { font-size: 0.66rem; color: var(--text-muted); padding: 3px; text-align: right; }
.cyb-cal-tg-allday-cell { border-left: 1px solid var(--border-color); padding: 2px; display: flex; flex-direction: column; gap: 2px; }

.cyb-cal-tg-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: grid; grid-template-columns: var(--cyb-gutter-w) 1fr; position: relative; }
.cyb-cal-tg-gutter { }
.cyb-cal-tg-hour { position: relative; border-bottom: 1px solid transparent; }
.cyb-cal-tg-hourlabel { position: absolute; top: -7px; right: 6px; font-size: 0.66rem; color: var(--text-muted); background: var(--bg-editor-pane); padding: 0 2px; }
.cyb-cal-tg-cols { display: grid; grid-template-columns: repeat(var(--cyb-day-count), 1fr); }
.cyb-cal-tg-col { position: relative; border-left: 1px solid var(--border-color); }
.cyb-cal-tg-line { position: absolute; left: 0; right: 0; border-top: 1px solid var(--border-color); opacity: 0.5; pointer-events: none; }
.cyb-cal-tg-now { position: absolute; left: 0; right: 0; border-top: 2px solid var(--danger-color); z-index: 4; pointer-events: none; }
.cyb-cal-tg-now::before { content: ""; position: absolute; left: -3px; top: -4px; width: 7px; height: 7px; border-radius: 50%; background: var(--danger-color); }

.cyb-cal-tg-event {
    position: absolute; overflow: hidden; text-align: left; cursor: pointer;
    border: 1px solid color-mix(in srgb, var(--cyb-ev, var(--primary-color)) 60%, transparent);
    border-left: 3px solid var(--cyb-ev, var(--primary-color));
    background: color-mix(in srgb, var(--cyb-ev, var(--primary-color)) 22%, var(--bg-pane));
    color: var(--text-main); border-radius: 4px; padding: 2px 5px; z-index: 3;
    display: flex; flex-direction: column; gap: 1px; font-size: 0.72rem;
}
.cyb-cal-tg-event.is-selected { outline: 2px solid var(--primary-color); outline-offset: 1px; z-index: 5; }
.cyb-cal-tg-event-time { font-weight: 600; opacity: 0.85; }
.cyb-cal-tg-event-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cyb-cal-tg-resize { position: absolute; left: 0; right: 0; bottom: 0; height: 7px; cursor: ns-resize; }
.cyb-cal-tg-createpreview { position: absolute; left: 2px; right: 2px; z-index: 4; pointer-events: none; border-radius: 4px; border: 1px dashed var(--primary-color); background: color-mix(in srgb, var(--primary-color) 20%, var(--bg-pane)); }
/* Touch long-press feedback: the moment a hold arms a create/move drag, the target lights up so the
   user sees create-mode is live. A plain (un-held) drag scrolls the day and never triggers these. */
.cyb-cal-tg-col.is-armed { background: color-mix(in srgb, var(--primary-color) 12%, transparent); }
.cyb-cal-tg-event.is-dragging { outline: 2px solid var(--primary-color); outline-offset: 1px; opacity: 0.9; z-index: 6; }

/* ---------- AGENDA ---------- */
.cyb-cal-agenda { overflow-y: auto; padding: 6px 12px; height: 100%; }
.cyb-cal-agenda-empty { color: var(--text-muted); padding: 24px; text-align: center; }
.cyb-cal-agenda-day { display: flex; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border-color); }
.cyb-cal-agenda-date { flex: 0 0 46px; text-align: center; }
.cyb-cal-agenda-dom { display: block; font-size: 1.3rem; font-weight: 700; }
.cyb-cal-agenda-mon { display: block; font-size: 0.66rem; color: var(--text-muted); text-transform: uppercase; }
.cyb-cal-agenda-dow { display: block; font-size: 0.66rem; color: var(--text-muted); }
.cyb-cal-agenda-day.is-today .cyb-cal-agenda-dom { color: var(--primary-color); }
.cyb-cal-agenda-list { flex: 1 1 auto; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cyb-cal-agenda-item { display: flex; align-items: center; gap: 8px; padding: 4px 8px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); background: var(--bg-pane); cursor: pointer; text-align: left; color: var(--text-main); }
.cyb-cal-agenda-item:hover { background: var(--item-hover); }
.cyb-cal-agenda-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--cyb-ev, var(--primary-color)); flex: 0 0 auto; }
.cyb-cal-agenda-when { flex: 0 0 72px; color: var(--text-muted); font-size: 0.8rem; }
.cyb-cal-agenda-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- event dialog ---------- */
/* Resizable + persistable (drag the bottom-right corner; size saved to settings). The box is a flex
   column: header + actions stay pinned while the form scrolls. */
/* .modal-box.cyb-cal-dialog: raise specificity so width beats the base .modal-box{width:400px}
   (148 loads before 180 in the cascade, so a single-class selector would lose). */
.modal-box.cyb-cal-dialog {
    width: min(94vw, 480px);
    gap: 12px;
    resize: both;
    overflow: hidden;
    min-width: 340px;
    min-height: 320px;
    max-width: 96vw;
    max-height: 92vh;
}
.cyb-cal-dialog-hd { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.cyb-cal-dialog-actions { flex: 0 0 auto; justify-content: space-between; }
/* Identity block (title + all-day + category): pinned above the tabs, so it shows on every tab. */
.cyb-cal-dialog-ident { flex: 0 0 auto; display: flex; flex-direction: column; gap: 8px; }
/* Tab strip: shared segmented-pill component (.app-tabs / .app-tab, see 180-dialogs-overlays.css);
   only the pinned-in-column behaviour is calendar-specific. */
.cyb-cal-tabs { flex: 0 0 auto; }
/* Tab panels (only the active one shown). display:flex would beat [hidden]; hide it explicitly. */
.cyb-cal-form { display: flex; flex-direction: column; flex: 1 1 auto; overflow-y: auto; min-height: 0; padding-right: 2px; }
.cyb-cal-panel { display: flex; flex-direction: column; gap: 10px; }
.cyb-cal-panel[hidden] { display: none; }
.cyb-cal-f-sound-block { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; padding-top: 10px; border-top: 1px dashed var(--border-color); }
/* Scope to the whole dialog (not just .cyb-cal-form) so the pinned Title + Category in the identity
   block get the same rounded, bordered treatment as the fields inside the tab panels. */
.cyb-cal-dialog input[type="text"],
.cyb-cal-dialog textarea,
.cyb-cal-dialog input[type="date"],
.cyb-cal-dialog input[type="time"],
.cyb-cal-dialog input[type="number"],
.cyb-cal-dialog select {
    padding: 6px 9px; border: 1px solid var(--border-color); border-radius: var(--radius-sm);
    background: var(--bg-pane); color: var(--text-main); font-size: 0.88rem; box-sizing: border-box;
}
.cyb-cal-f-title { font-size: 1.05rem !important; font-weight: 600; }
.cyb-cal-f-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cyb-cal-f-lbl { font-size: 0.78rem; color: var(--text-muted); }
.cyb-cal-f-check { display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; }
.cyb-cal-f-to { color: var(--text-muted); }
.cyb-cal-f-interval-wrap { font-size: 0.82rem; color: var(--text-muted); display: inline-flex; align-items: center; gap: 5px; }
.cyb-cal-f-interval { width: 56px; }
.cyb-cal-f-byday { display: flex; gap: 4px; }
/* These rows carry display:flex, which beats the UA [hidden] rule — gate hiding explicitly so the
   weekday picker and the recurrence-ends row actually collapse for non-recurring events. */
.cyb-cal-f-byday[hidden], .cyb-cal-f-ends[hidden] { display: none; }
.cyb-cal-f-day { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border: 1px solid var(--border-color); border-radius: 50%; font-size: 0.72rem; cursor: pointer; }
.cyb-cal-f-day input { display: none; }
.cyb-cal-f-day.is-on { background: var(--primary-color); color: var(--mix-light); border-color: var(--primary-color); }
.cyb-cal-f-until { width: 150px; }
.cyb-cal-f-count { width: 64px; }
.cyb-cal-f-body { resize: vertical; }
.cyb-cal-f-reminders { display: flex; flex-direction: column; gap: 4px; }
.cyb-cal-f-remind-row { display: flex; gap: 6px; align-items: center; }
.cyb-cal-f-remind-row select { flex: 1 1 auto; }
.cyb-cal-f-remind-x { flex: 0 0 auto; background: transparent; border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-muted); cursor: pointer; padding: 4px 9px; }
.cyb-cal-f-remind-x:hover { color: var(--danger-color); border-color: var(--danger-color); }
.cyb-cal-f-remind-none { font-size: 0.8rem; color: var(--text-muted); font-style: italic; }
.cyb-cal-f-remind-add { align-self: flex-start; background: transparent; border: none; color: var(--primary-color); cursor: pointer; font-size: 0.82rem; padding: 2px 0; }
.cyb-cal-f-remind-add:hover { text-decoration: underline; }
/* alert sound (§13 Q5) — a single dropdown chooses the source; picking a note/playlist/file opens a
   picker, and the chosen item's name + a ▶ preview appear beside it. */
.cyb-cal-f-sound-row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.cyb-cal-f-sound-sel { flex: 0 0 auto; }
.cyb-cal-f-sound-name { flex: 1 1 100px; min-width: 0; font-size: 0.82rem; color: var(--text-main); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cyb-cal-f-sound-name:empty { flex: 0 0 0; }
.cyb-cal-f-sound-preview { flex: 0 0 auto; background: var(--bg-pane); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-main); cursor: pointer; padding: 4px 9px; font-size: 0.8rem; }
.cyb-cal-f-sound-preview:hover { background: var(--item-hover); border-color: var(--primary-color); }

/* playlist picker (Docs/006 §7) — appended to <body> as a modal */
.cyb-cal-plpick { display: flex; flex-direction: column; gap: 2px; }
.cyb-cal-plpick-group { font-size: 0.72rem; font-weight: 650; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); padding: 8px 4px 2px; }
.cyb-cal-plpick-item { display: block; width: 100%; text-align: left; padding: 8px 10px; border: 1px solid transparent; background: transparent; color: var(--text-main); cursor: pointer; border-radius: var(--radius-sm); font-size: 0.88rem; }
.cyb-cal-plpick-item:hover { background: var(--item-hover); border-color: var(--border-color); }
.cyb-cal-plpick-empty { padding: 14px 6px; color: var(--text-muted); font-style: italic; }
/* top row: All-day + Category share one line */
.cyb-cal-f-toprow { justify-content: flex-start; }
.cyb-cal-f-toprow-gap { flex: 1 1 auto; }
.cyb-cal-f-toprow .cyb-cal-f-color { flex: 0 0 auto; min-width: 120px; }

.cyb-cal-event-link { cursor: pointer; opacity: 0.85; }
.cyb-cal-event-link:hover { opacity: 1; }

.cyb-cal-cats .cyb-cal-cat-row { display: flex; gap: 8px; align-items: center; margin-bottom: 6px; }
.cyb-cal-cat-label { flex: 1 1 auto; }

/* ---------- YEAR view (§13 Q2) — 12-month heat-map overview ---------- */
.cyb-cal-year {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14px;
    padding: 14px;
    align-content: start;
}
.cyb-cal-year-month {
    display: flex;
    flex-direction: column;
    gap: 4px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 8px;
    background: var(--bg-pane);
}
.cyb-cal-year-mname {
    font-weight: 650;
    font-size: 0.85rem;
    color: var(--text-main);
    cursor: pointer;
    padding: 1px 3px;
    border-radius: var(--radius-sm);
}
.cyb-cal-year-mname:hover { background: var(--item-hover); color: var(--primary-color); }
.cyb-cal-year-dow { display: grid; grid-template-columns: repeat(7, 1fr); }
.cyb-cal-year-dow-cell { text-align: center; font-size: 0.6rem; color: var(--text-muted); padding-bottom: 2px; }
.cyb-cal-year-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
.cyb-cal-year-cell {
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.66rem;
    color: var(--text-main);
    background: transparent;
    border: none;
    border-radius: 999px;
    cursor: pointer;
    position: relative;
    padding: 0;
}
.cyb-cal-year-cell:hover:not(.is-outside) { background: var(--item-hover); }
.cyb-cal-year-cell.is-outside { color: transparent; cursor: default; pointer-events: none; }
.cyb-cal-year-cell.is-today { background: var(--primary-color); color: var(--mix-light); font-weight: 700; }
.cyb-cal-year-cell.is-marked:not(.is-today)::after {
    content: "";
    position: absolute;
    bottom: 1px;
    left: 50%;
    transform: translateX(-50%);
    width: 4px; height: 4px;
    border-radius: 999px;
    background: var(--primary-color);
}

/* ---------- context menu (appended to <body>) ---------- */
.cyb-cal-menu {
    position: fixed; z-index: 10000; min-width: 180px;
    background: var(--bg-pane); border: 1px solid var(--border-color);
    border-radius: var(--radius-md); box-shadow: var(--shadow-md); padding: 4px;
}
.cyb-cal-menu-item { display: block; width: 100%; text-align: left; padding: 7px 10px; border: none; background: transparent; color: var(--text-main); cursor: pointer; font-size: 0.85rem; border-radius: var(--radius-sm); }
.cyb-cal-menu-item:hover { background: var(--item-hover); }
.cyb-cal-menu-sep { height: 1px; background: var(--border-color); margin: 4px 2px; }

/* ---------- mobile ---------- */
.cyb-cal--mobile .cyb-cal-toolbar { gap: 5px; padding: 6px 8px; }
/* Year view is desktop-only — a 12-month grid is too cramped on a phone (also guarded in JS). */
.cyb-cal--mobile .cyb-cal-views [data-view="year"] { display: none; }
.cyb-cal--mobile .cyb-cal-quickadd { order: 5; flex: 1 1 100%; min-width: 0; }
.cyb-cal--mobile .cyb-cal-title { max-width: 120px; }
@media (max-width: 768px) {
    .cyb-cal-cell-items { gap: 1px; }
    .cyb-cal-event, .cyb-cal-note-chip { font-size: 0.68rem; }
    .cyb-cal-range { min-width: 0; }
    .cyb-cal-year { grid-template-columns: repeat(2, 1fr); gap: 10px; padding: 10px; }
    /* Manual resize is awkward on a phone: full-width sheet, let content flow. */
    .modal-box.cyb-cal-dialog { resize: none; width: min(96vw, 480px); min-width: 0; max-height: 88vh; }
    .cyb-cal-dialog .app-tab { font-size: 0.76rem; padding: 6px 4px; }
}
@media (max-width: 1100px) and (min-width: 769px) {
    .cyb-cal-year { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 460px) {
    .cyb-cal-year { grid-template-columns: 1fr; }
}
/* Shared attachments (notes, web links, files) for every canvas: mind map, Kanban, Story Board,
   calendar. Docs/000-multi-link-attachments-design.md. JS owner: utils/attachments/AttachmentUi.js +
   MediaLightbox.js. Theme tokens only. */

/* ---- the 🔗 badge on an item's face ---- */
.att-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 1px 7px 1px 5px;
    border: 1px solid var(--border-color);
    border-radius: 999px;
    background: var(--bg-app);
    color: var(--text-muted);
    font: inherit;
    font-size: 0.72rem;
    line-height: 1.4;
    cursor: pointer;
    transition: background var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease);
}
.att-badge:hover,
.att-badge:focus-visible { background: var(--item-hover); border-color: var(--primary-color); color: var(--text-main); }
.att-badge-glyphs { letter-spacing: 1px; }
.att-badge-n { font-weight: 700; color: var(--text-main); }

/* ---- chooser (several attachments) and the ＋ Add menu ---- */
.att-chooser,
.att-menu {
    position: fixed;
    inset: auto;                 /* shown as a manual popover (top layer): undo the UA centring */
    margin: 0;
    color: var(--text-main);
    z-index: 6100;
    display: flex;
    flex-direction: column;
    min-width: 200px;
    max-width: min(92vw, 360px);
    max-height: 60vh;
    overflow-y: auto;
    padding: 4px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-pane);
    box-shadow: var(--shadow-md);
}
.att-chooser-item,
.att-menu button {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-main);
    font: inherit;
    font-size: 0.86rem;
    text-align: left;
    cursor: pointer;
}
.att-chooser-item:hover,
.att-chooser-item:focus-visible,
.att-menu button:hover,
.att-menu button:focus-visible { background: var(--item-hover); }
.att-chooser-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.att-chooser-item.is-broken .att-chooser-title { color: var(--text-muted); text-decoration: line-through; }

/* ---- the panel (inside each kind's edit dialog) ---- */
.att-panel { display: flex; flex-direction: column; gap: 6px; }
.att-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 4px; }
.att-head-label { font-size: 0.82rem; font-weight: 600; color: var(--text-muted); }
.att-add,
.att-urlform-actions button {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-app);
    color: var(--text-main);
    font: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
}
.att-add:hover,
.att-urlform-actions button:hover { background: var(--item-hover); border-color: var(--primary-color); }
.att-urlform { display: flex; flex-direction: column; gap: 6px; padding: 8px; border: 1px dashed var(--border-color); border-radius: var(--radius-sm); }
.att-urlform[hidden] { display: none; }
.att-urlform input {
    width: 100%;
    box-sizing: border-box;
    padding: 6px 8px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-app);
    color: var(--text-main);
    font: inherit;
    font-size: 0.86rem;
}
.att-urlform-actions { display: flex; justify-content: flex-end; gap: 6px; }
.att-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; max-height: 260px; overflow-y: auto; }
.att-empty { color: var(--text-muted); font-size: 0.82rem; padding: 8px 2px; }
.att-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px 4px 8px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-pane);
}
.att-row.is-broken { border-style: dashed; }
.att-glyph { flex: 0 0 auto; font-size: 1rem; }
.att-title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 4px 2px;
    border: 0;
    background: transparent;
    color: var(--text-main);
    font: inherit;
    font-size: 0.86rem;
    text-align: left;
    cursor: pointer;
}
.att-title:hover,
.att-title:focus-visible { color: var(--primary-color); text-decoration: underline; }
.att-row.is-broken .att-title { color: var(--text-muted); }
.att-meta { flex: 0 0 auto; font-size: 0.72rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.att-row.is-broken .att-meta { color: var(--warning-color); }
.att-up,
.att-del {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-muted);
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
}
.att-up-gap { flex: 0 0 26px; }
.att-up:hover { background: var(--item-hover); color: var(--primary-color); }
.att-del:hover { background: var(--item-hover); color: var(--danger-color); }

/* ---- standalone dialog (an item with no edit dialog of its own, e.g. a mind-map node) ---- */
.att-dialog { width: min(94vw, 460px); gap: 12px; }
.att-dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; cursor: default; }
.att-dialog-head .modal-title { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.att-dialog-item { font-size: 0.82rem; font-weight: 400; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.att-dialog-body { display: flex; flex-direction: column; }

/* ---- media viewer (video / audio / image) ---- */
.att-lightbox {
    position: fixed;
    inset: 0;
    width: auto;                 /* shown as a manual popover (top layer): fill the viewport */
    height: auto;
    max-width: none;
    max-height: none;
    margin: 0;
    border: 0;
    z-index: 6200;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 32px;
    box-sizing: border-box;
    background: color-mix(in srgb, var(--mix-dark) 82%, transparent);
    backdrop-filter: blur(4px);
}
.att-lightbox-body { display: flex; align-items: center; justify-content: center; max-width: 100%; max-height: 82vh; }
.att-lightbox-media {
    max-width: 100%;
    max-height: 82vh;
    border-radius: var(--radius-md);
    box-shadow: 0 24px 70px color-mix(in srgb, var(--mix-dark) 50%, transparent);
    background: var(--mix-dark);
}
.att-lightbox-audio { width: min(90vw, 480px); }
.att-lightbox-close {
    position: absolute;
    top: 16px;
    right: 20px;
    width: 40px;
    height: 40px;
    border: 0;
    border-radius: 50%;
    background: color-mix(in srgb, var(--bg-pane) 15%, transparent);
    color: var(--on-accent);
    font-size: 1.1rem;
    cursor: pointer;
}
.att-lightbox-close:hover { background: color-mix(in srgb, var(--mix-light) 28%, transparent); }
.att-lightbox-cap { color: color-mix(in srgb, var(--mix-light) 82%, transparent); font-size: 0.86rem; }
/* --- RENAME MODAL --- */

.modal-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: color-mix(in srgb, var(--mix-dark) 50%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 2000;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    /* Visibility snaps ON instantly (0s) so dialogs can focus an input in the
       same tick they un-hide — a transitioning `visibility: hidden` silently
       swallows focus() calls. The fade-out keeps working via the delayed
       visibility flip on .hidden below. */
    transition: opacity 0.18s ease, visibility 0s;
}

.modal-overlay.hidden {
    display: flex !important;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}

.modal-box {
    background: var(--bg-pane);
    width: 400px;
    padding: 24px;
    border-radius: 8px;
    box-shadow: 0 10px 25px color-mix(in srgb, var(--mix-dark) 20%, transparent);
    display: flex;
    flex-direction: column;
    gap: 16px;
    transform: translateY(0) scale(1);
    transition: transform 0.2s ease, opacity 0.2s ease;
    opacity: 1;
}

.modal-overlay.hidden .modal-box {
    transform: translateY(8px) scale(0.98);
    opacity: 0;
}

.modal-title {
    font-size: 1.1rem;
    font-weight: 600;
    line-height: 1.3;
}

.modal-body {
    line-height: 1.5;
}

/* ============================================================================
   Segmented "pill" tabs — the app STANDARD for tabbed dialogs. Reuse these
   classes (not a feature-local copy) whenever a dialog splits content into tabs.
   Markup:
     <div class="app-tabs" role="tablist">
       <button type="button" class="app-tab is-active" role="tab"
               aria-selected="true" data-tab="key">Label</button> …
     </div>
     <!-- one panel per tab; JS toggles .is-active + aria-selected + panel[hidden] -->
   Track is a soft inset (--tab-track-bg); the active tab is a raised surface pill
   (--tab-active-bg) with an accent label. Fully theme-token driven.
   ============================================================================ */

.app-tabs {
    display: flex;
    justify-content: space-between;
    gap: var(--space-1);
    padding: var(--space-1);
    background: var(--tab-track-bg);
    border-radius: 999px;
}

.app-tab {
    /* Content-width pills, evenly distributed across the track (the active pill hugs its label). */
    flex: 0 1 auto;
    min-width: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 999px;
    color: var(--text-muted);
    cursor: pointer;
    padding: 6px 14px;
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: background-color var(--anim-fast) var(--anim-ease), color var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease), box-shadow var(--anim-fast) var(--anim-ease);
}

.app-tab:hover:not(.is-active) { color: var(--text-main); }

.app-tab.is-active {
    background: var(--tab-active-bg);
    color: var(--primary-color);
    border-color: var(--border-color);
    box-shadow: var(--shadow-sm);
}

.app-tab:focus-visible { outline: 2px solid var(--primary-color); outline-offset: 1px; }

.modal-field-label {
    display: block;
    margin-bottom: 8px;
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--text-main);
}

.modal-input {
    min-height: 40px;
    max-height: 100px;
    overflow-y: auto;
    border: 1px solid var(--border-color);
    padding: 8px;
    border-radius: 4px;
    font-family: inherit;
    font-size: 1rem;
}

.modal-input:focus {
    outline: 2px solid var(--primary-color);
    border-color: transparent;
}

.modal-toolbar {
    display: flex;
    gap: 8px;
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 8px;
    margin-bottom: 8px;
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    margin-top: 8px;
}

.modal-actions > button {
    min-height: 38px;
}

.simple-btn {
    min-height: var(--btn-height);
    padding: 0 var(--btn-pad-x);
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: var(--btn-font-size);
    font-weight: 600;
    border: 1px solid var(--border-color);
    background: var(--bg-pane);
    color: var(--text-main);
    transition: transform var(--anim-fast) var(--anim-ease), box-shadow var(--anim-fast) var(--anim-ease), background-color var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease), color var(--anim-fast) var(--anim-ease);
}

.simple-btn.primary {
    background: var(--accent-gradient);
    color: white;
    border-color: transparent;
    box-shadow: 0 8px 18px color-mix(in srgb, var(--accent-gradient-start) 25%, transparent);
}

.simple-btn:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm);
}

.simple-btn.primary:hover {
    box-shadow: 0 10px 20px color-mix(in srgb, var(--accent-gradient-start) 32%, transparent);
}

/* --- GLASSMORPHISM SYSTEM DIALOG --- */

/* The --glass-* tokens live in 000-tokens-base.css with the rest of the theme tokens. */

.modal-overlay.glass-overlay {
    background: var(--glass-overlay-bg);
    backdrop-filter: blur(3px);
    z-index: 5000;
}

/* Dark theme: every glass dialog surface below swaps its white rim for the glass rim + a
   deeper shadow so the dark sheet still separates from the dark backdrop. The surfaces
   themselves are theme-aware via color-mix(var(--bg-pane)) in their base rules. */

:root[data-theme="dark"] #rename-modal .rename-glass-dialog,
:root[data-theme="dark"] #confirm-modal .glass-dialog,
:root[data-theme="dark"] #find-replace-modal .find-replace-glass-dialog,
:root[data-theme="dark"] #import-progress-modal .import-progress-glass-dialog,
:root[data-theme="dark"] .gdrive-folder-import-dialog,
:root[data-theme="dark"] .gdrive-folder-picker-dialog,
:root[data-theme="dark"] #db-loading-overlay .db-loading-glass-dialog,
:root[data-theme="dark"] #data-manager-modal .data-manager-glass-dialog {
    border-color: var(--glass-border);
    box-shadow: var(--glass-shadow);
}

#rename-modal.modal-overlay.glass-overlay {
    z-index: 5600;
}

/* Theme-aware glass (whole dialog family): mixing --bg-pane toward transparent reproduces the
   original white glass exactly in light mode (bg-pane is var(--mix-light) there) and yields dark glass under
   data-theme="dark", where the text tokens already flip — the surfaces must flip with them.
   The dark rim/shadow for these dialogs lives in one shared override further down. */

#rename-modal .rename-glass-dialog {
    width: min(94vw, 560px);
    background: color-mix(in srgb, var(--bg-pane) 90%, transparent);
    border: 1px solid color-mix(in srgb, var(--bg-pane) 65%, transparent);
    box-shadow: 0 18px 50px color-mix(in srgb, var(--mix-dark) 24%, transparent);
}

#rename-modal .rename-glass-dialog.rename-glass-dialog-compact {
    width: min(92vw, 320px);
    padding: 20px;
    gap: 12px;
}

#rename-modal .rename-glass-dialog.rename-glass-dialog-compact .modal-body {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

#rename-modal .rename-glass-dialog.rename-glass-dialog-compact .modal-field-label {
    margin-bottom: 0;
}

#rename-modal .rename-glass-dialog .modal-title {
    color: var(--text-main);
}

#rename-modal .rename-glass-dialog .modal-toolbar {
    border-bottom: 1px solid var(--border-color);
}

#rename-modal .rename-glass-dialog .icon-btn-small {
    color: var(--text-main);
}

#rename-modal .rename-glass-dialog .icon-btn-small:hover {
    color: var(--primary-color);
    background-color: var(--item-hover);
}

.modal-overlay .modal-header .icon-btn-small {
    color: color-mix(in srgb, var(--text-main) 90%, var(--text-main) 10%);
    border-color: color-mix(in srgb, var(--border-color) 70%, var(--mix-dark) 30%);
    background: color-mix(in srgb, var(--bg-pane) 92%, var(--mix-dark) 8%);
}

.modal-overlay .modal-header .icon-btn-small:hover {
    color: color-mix(in srgb, var(--text-main) 70%, var(--primary-color) 30%);
    border-color: color-mix(in srgb, var(--primary-color) 45%, var(--border-color));
    background: color-mix(in srgb, var(--item-hover) 80%, var(--mix-dark) 20%);
}

#rename-modal .rename-glass-dialog .modal-input {
    border: 1px solid var(--border-color);
    background: var(--bg-pane);
    color: var(--text-main);
    border-radius: 10px;
}

#rename-modal .rename-glass-dialog .modal-input.modal-input-single-line {
    min-height: 20px;
    max-height: 44px;
    overflow-y: hidden;
    white-space: nowrap;
}

#rename-modal .rename-glass-dialog .modal-input:focus {
    outline: 2px solid var(--primary-color);
    border-color: transparent;
}

#rename-modal .rename-glass-dialog .modal-actions {
    margin-top: 10px;
}

#rename-modal .rename-glass-dialog.rename-glass-dialog-compact .modal-actions {
    margin-top: 4px;
}

#rename-modal .rename-glass-dialog .glass-btn-cancel {
    background: var(--bg-pane);
    color: var(--text-main);
    border: 1px solid var(--border-color);
}

#rename-modal .rename-glass-dialog .glass-btn-cancel:hover {
    background: var(--item-hover);
}

#confirm-modal .glass-dialog {
    width: min(92vw, 460px);
    border-radius: var(--glass-radius);
    border: 1px solid color-mix(in srgb, var(--bg-pane) 65%, transparent);
    background: color-mix(in srgb, var(--bg-pane) 90%, transparent);
    backdrop-filter: blur(var(--glass-surface-blur));
    box-shadow: 0 18px 50px color-mix(in srgb, var(--mix-dark) 24%, transparent);
    padding: 22px;
    gap: 14px;
}

#confirm-modal.modal-overlay.glass-overlay {
    z-index: 5600;
}

/* The AI Models and AI Preset Manager dialogs are launched from the floating Agent
   Chat (z-index 5200) via its gear menu, so they must stack ABOVE it — otherwise the
   modal opens behind the chat and its backdrop can't block interaction with it. Same
   treatment as #rename-modal / #confirm-modal above. */

#ai-model-manager-modal.modal-overlay.glass-overlay,
#ai-preset-manager-modal.modal-overlay.glass-overlay {
    z-index: 5600;
}

/* The AI Preset *editor* opens stacked on top of the Preset Manager (both are glass
   overlays). Two fixes in one rule:
   1. Stacking: the base overlay is z-index 5000, but the manager is 5600 — so without
      this the editor would open BEHIND its own manager. Lift it above (5700).
   2. Freeze: it must NOT add a second full-viewport backdrop-filter. Two stacked blurs
      compositing at once can stall Chrome's compositor/GPU into a hard freeze (worse
      under an unstable GPU path, e.g. --enable-unsafe-webgpu). The manager beneath
      already supplies the glass blur, so the editor's blur is redundant — drop it and
      keep the dim via the overlay background alone. */

#ai-preset-edit-modal.modal-overlay.glass-overlay {
    z-index: 5700;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

#confirm-modal .glass-dialog .modal-title {
    color: var(--text-main);
    font-size: 1.16rem;
    letter-spacing: 0.01em;
    font-weight: 700;
}

#confirm-modal .glass-dialog-message {
    margin: 0;
    color: var(--text-main);
    font-size: 0.96rem;
    line-height: 1.45;
    white-space: pre-line;
}

#confirm-modal .glass-dialog-actions {
    margin-top: 8px;
    justify-content: flex-end;
    gap: 10px;
}

.glass-btn {
    border-radius: var(--radius-md);
    min-height: var(--btn-height);
    min-width: 108px;
    padding: 0 var(--btn-pad-x);
    font-size: var(--btn-font-size);
    font-weight: 600;
    cursor: pointer;
    transition: transform var(--anim-fast) var(--anim-ease), box-shadow var(--anim-base) var(--anim-ease), opacity var(--anim-fast) var(--anim-ease), background-color var(--anim-fast) var(--anim-ease), border-color var(--anim-fast) var(--anim-ease), color var(--anim-fast) var(--anim-ease);
}

.dialog-body {
    line-height: 1.5;
}

.dialog-footer button,
.modal-actions .glass-btn,
.modal-actions .simple-btn {
    min-height: 38px;
}

.log-dialog[open] {
    animation: dialogPopIn 0.18s ease;
}

@keyframes dialogPopIn {
    from {
        opacity: 0;
        transform: translate(-50%, -46%) scale(0.98);
    }
    to {
        opacity: 1;
        transform: translate(-50%, -50%) scale(1);
    }
}

@media (max-width: 768px) {
    .modal-box {
        width: min(94vw, 560px);
        padding: 16px;
        gap: 12px;
    }

    .modal-title {
        font-size: 1.05rem;
    }

    .modal-actions {
        gap: 8px;
    }

    .modal-actions .glass-btn,
    .modal-actions .simple-btn,
    .dialog-footer button {
        min-height: 42px;
        padding: 10px 14px;
        font-size: 0.92rem;
    }
}

.glass-btn:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--mix-light) 82%, transparent);
    outline-offset: 2px;
}

.glass-btn-cancel {
    background: color-mix(in srgb, var(--bg-pane) 94%, var(--bg-pane) 6%);
    border: 1px solid color-mix(in srgb, var(--border-color) 82%, var(--mix-dark) 18%);
    color: color-mix(in srgb, var(--text-main) 92%, var(--text-main) 8%);
}

.glass-btn-cancel:hover {
    background: var(--item-hover);
}

#confirm-modal .glass-btn-cancel {
    background: var(--bg-pane);
    color: var(--text-main);
    border: 1px solid var(--border-color);
}

#confirm-modal .glass-btn-cancel:hover {
    background: var(--item-hover);
}

#find-replace-modal .glass-btn-cancel {
    background: var(--bg-pane);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    opacity: 1;
}

#find-replace-modal .glass-btn-cancel:hover {
    background: var(--item-hover);
}

#find-replace-modal .glass-btn:disabled {
    opacity: 1;
    cursor: pointer;
}

#confirm-modal .glass-btn:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--accent-gradient-start) 65%, transparent);
}

/* --- FIND / REPLACE MODAL --- */

#find-replace-modal .find-replace-glass-dialog {
    --fr-scale: 1;
    width: min(94vw, 620px);
    border-radius: var(--glass-radius);
    border: 1px solid color-mix(in srgb, var(--bg-pane) 65%, transparent);
    background: color-mix(in srgb, var(--bg-pane) 68%, transparent);
    backdrop-filter: blur(var(--glass-surface-blur));
    box-shadow: 0 18px 50px color-mix(in srgb, var(--mix-dark) 24%, transparent);
    padding: calc(20px * var(--fr-scale));
    gap: calc(12px * var(--fr-scale));
}

#find-replace-modal {
    background: transparent;
    backdrop-filter: none;
    pointer-events: none;
}

#find-replace-modal .find-replace-glass-dialog {
    position: fixed;
    top: 92px;
    right: 20px;
    left: auto;
    width: min(94vw, 620px);
    min-width: 240px;
    min-height: 150px;
    max-width: calc(100vw - 16px);
    max-height: calc(100vh - 16px);
    /* Resizing is via the custom .fnav-resize-handle gripper (touch-friendly);
       the native resize handle is replaced. */
    resize: none;
    /* Header + tab strip stay fixed; only the active panel scrolls so the
       Find & Navigate tabs never scroll out of view. */
    overflow: hidden;
    display: flex;
    flex-direction: column;
    pointer-events: auto;
}

/* No scale/translate pop-in transform on this dialog: getBoundingClientRect would
   reflect the transformed box, baking an offset into the saved drag position and
   causing it to creep on each reopen. The dialog is draggable; the pop-in isn't needed. */

#find-replace-modal .find-replace-glass-dialog,
.modal-overlay.hidden .find-replace-glass-dialog {
    transform: none;
}

#find-replace-modal .find-replace-header,
#find-replace-modal .fnav-tabs {
    flex: 0 0 auto;
}

#find-replace-modal .fnav-panel {
    flex: 1 1 auto;
    overflow-y: auto;
    min-height: 0;
}

.find-replace-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: calc(10px * var(--fr-scale));
    cursor: move;
    user-select: none;
    touch-action: none;
}

.find-replace-body {
    display: flex;
    flex-direction: column;
    gap: calc(10px * var(--fr-scale));
}

.find-replace-field {
    display: flex;
    flex-direction: column;
    gap: calc(6px * var(--fr-scale));
}

.find-replace-inline-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: calc(10px * var(--fr-scale));
}

.find-replace-inline-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: clamp(0.72rem, calc(0.86rem * var(--fr-scale)), 0.86rem);
    color: var(--text-main);
}

.find-replace-label {
    font-size: clamp(0.72rem, calc(0.84rem * var(--fr-scale)), 0.84rem);
    font-weight: 600;
    color: var(--text-muted);
}

.find-replace-input {
    min-height: clamp(30px, calc(38px * var(--fr-scale)), 38px);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    padding: calc(8px * var(--fr-scale)) calc(10px * var(--fr-scale));
    font-family: inherit;
    font-size: clamp(0.75rem, calc(0.95rem * var(--fr-scale)), 0.95rem);
    color: var(--text-main);
    background: var(--bg-pane);
}

.find-replace-input:focus {
    outline: 2px solid color-mix(in srgb, var(--accent-gradient-start) 60%, transparent);
    border-color: transparent;
}

.find-replace-options {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: calc(12px * var(--fr-scale));
    margin-top: 2px;
}

.find-wrap-label {
    display: inline-flex;
    align-items: center;
    gap: calc(6px * var(--fr-scale));
    color: var(--text-main);
    font-size: clamp(0.72rem, calc(0.9rem * var(--fr-scale)), 0.9rem);
}

.find-replace-status {
    font-size: clamp(0.72rem, calc(0.86rem * var(--fr-scale)), 0.86rem);
    color: var(--text-muted);
}

.find-replace-actions-row {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: calc(8px * var(--fr-scale));
    align-items: stretch;
}

.find-replace-actions-row .glass-btn {
    min-width: 0;
    min-height: clamp(28px, calc(40px * var(--fr-scale)), 40px);
    width: 100%;
    justify-self: stretch;
    font-size: clamp(0.72rem, calc(0.95rem * var(--fr-scale)), 0.95rem);
    padding: 0 clamp(6px, calc(10px * var(--fr-scale)), 12px);
}

#find-replace-one,
#find-replace-all {
    grid-column: span 2;
}

/* Find matches are painted with the CSS Custom Highlight API (see
   editor/FindNavigateDialog.js) so a query with thousands of hits costs no DOM
   mutation inside the contenteditable. Both layers use existing semantic tokens,
   so light + dark come along for free. `::highlight()` only accepts colour,
   background-color, text-decoration and text-shadow — no radius or box-shadow. */
::highlight(cyb-find-match) {
    background-color: color-mix(in srgb, var(--status-pinned-bg) 70%, transparent);
}

::highlight(cyb-find-active) {
    background-color: var(--warning-color);
}

/* Browsers without the Custom Highlight API fall back to wrapping the ACTIVE
   match only (one element, not thousands). Kept for that path, and to style any
   stale marker left in older content. */
mark.find-match {
    background: color-mix(in srgb, var(--status-pinned-bg) 70%, transparent);
    color: inherit;
    border-radius: 3px;
    padding: 0 1px;
}

mark.find-match.active {
    background: var(--warning-color);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--warning-color) 35%, transparent);
}

@media (max-width: 768px) {
    .find-replace-actions-row {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    #find-replace-one,
    #find-replace-all {
        grid-column: span 1;
    }
}

/* --- IMPORT PROGRESS MODAL --- */

#import-progress-modal {
    z-index: 5100 !important;
}

#import-progress-modal.import-progress-foreground {
    z-index: 7000 !important;
}

#import-progress-modal .import-progress-glass-dialog {
    width: min(94vw, 720px);
    border-radius: var(--glass-radius);
    border: 1px solid color-mix(in srgb, var(--bg-pane) 65%, transparent);
    background: color-mix(in srgb, var(--bg-pane) 92%, transparent);
    backdrop-filter: blur(var(--glass-surface-blur));
    box-shadow: 0 18px 50px color-mix(in srgb, var(--mix-dark) 24%, transparent);
    padding: 18px;
    gap: 12px;
}

.import-progress-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.import-progress-current {
    display: grid;
    gap: 4px;
    font-size: 0.9rem;
    color: var(--text-main);
}

.import-progress-track {
    position: relative;
    width: 100%;
    height: 12px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--text-muted) 18%, transparent);
    overflow: hidden;
    border: 1px solid color-mix(in srgb, var(--text-muted) 24%, transparent);
}

#import-progress-modal.import-progress-running .import-progress-track::after {
    content: '';
    position: absolute;
    top: 0;
    left: -35%;
    width: 35%;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, color-mix(in srgb, var(--accent-gradient-start) 0%, transparent), color-mix(in srgb, var(--accent-gradient-start) 45%, transparent), color-mix(in srgb, var(--accent-gradient-end) 0%, transparent));
    animation: importProgressTrackSweep 1.25s ease-in-out infinite;
    pointer-events: none;
}

.import-progress-bar {
    width: 0%;
    height: 100%;
    border-radius: 999px;
    background: var(--accent-gradient-h);
    transition: width 0.18s ease;
}

.import-progress-bar.import-progress-bar-running {
    background: linear-gradient(
        120deg,
        var(--accent-gradient-start) 0%,
        var(--accent-gradient-start) 34%,
        color-mix(in srgb, var(--accent-gradient-end) 60%, var(--mix-light)) 48%,
        var(--accent-gradient-start) 62%,
        var(--accent-gradient-end) 100%
    );
    background-size: 220% 100%;
    animation: importProgressSweep 1.1s linear infinite;
}

@keyframes importProgressSweep {
    0% {
        background-position: 180% 0;
    }
    100% {
        background-position: -40% 0;
    }
}

@keyframes importProgressTrackSweep {
    0% {
        left: -35%;
    }
    100% {
        left: 100%;
    }
}

.import-progress-stats {
    display: flex;
    gap: 12px;
    justify-content: space-between;
    color: var(--text-muted);
    font-size: 0.86rem;
}

.import-progress-log {
    min-height: 140px;
    max-height: min(40vh, 300px);
    overflow: auto;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: color-mix(in srgb, var(--bg-pane) 65%, transparent);
    padding: 8px 10px;
    font-size: 0.82rem;
    line-height: 1.35;
}

.import-progress-log-entry {
    margin-bottom: 4px;
    color: var(--text-main);
}

.import-progress-log-entry.warn {
    color: var(--warning-color);
}

.import-progress-log-entry.error {
    color: var(--danger-color);
}

.import-progress-realtime {
    display: grid;
    gap: 4px;
    border: 1px dashed color-mix(in srgb, var(--text-muted) 45%, transparent);
    border-radius: 10px;
    background: color-mix(in srgb, var(--bg-pane) 55%, transparent);
    padding: 8px 10px;
    font-size: 0.8rem;
    line-height: 1.35;
    color: var(--text-muted);
}

.import-progress-live-line {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.import-progress-live-line strong {
    color: var(--text-main);
    font-weight: 600;
}

#import-progress-live-errors.import-progress-live-has-errors {
    color: var(--danger-color);
}

#import-progress-modal .glass-btn-cancel {
    background: var(--bg-pane);
    color: var(--text-main);
    border: 1px solid var(--border-color);
    opacity: 1;
}

#import-progress-modal .glass-btn-cancel:hover {
    background: var(--item-hover);
}

#import-progress-modal .glass-btn-cancel:disabled,
#import-progress-modal .icon-btn-small:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    box-shadow: none;
    transform: none;
}

.glass-btn-confirm {
    border: 1px solid color-mix(in srgb, var(--mix-light) 24%, transparent);
    color: var(--on-accent);
    box-shadow: 0 0 0 color-mix(in srgb, var(--mix-dark) 0%, transparent);
}

.glass-btn-confirm.variant-blue {
    background: linear-gradient(135deg, var(--glass-confirm-blue-start), var(--glass-confirm-blue-end));
    box-shadow: 0 8px 24px color-mix(in srgb, var(--accent-gradient-start) 42%, transparent);
}

.glass-btn-confirm.variant-orange {
    background: linear-gradient(135deg, var(--glass-confirm-orange-start), var(--glass-confirm-orange-end));
    box-shadow: 0 8px 24px color-mix(in srgb, var(--warning-color) 38%, transparent);
}

.glass-btn-confirm.variant-red {
    background: linear-gradient(135deg, var(--glass-confirm-red-start), var(--glass-confirm-red-end));
    box-shadow: 0 8px 24px color-mix(in srgb, var(--danger-color) 40%, transparent);
}

.glass-btn-confirm:hover {
    transform: translateY(-1px);
}

/* Disabled glass buttons (e.g. Delete File after the PC file has been removed) read as inert:
   muted, no lift on hover, no pointer. */

.glass-btn:disabled,
.glass-btn[aria-disabled="true"] {
    opacity: 0.5;
    cursor: default;
    box-shadow: none;
    filter: grayscale(0.35);
}

.glass-btn:disabled:hover,
.glass-btn[aria-disabled="true"]:hover {
    transform: none;
}

/* Icon consistency */

button svg,
.icon-btn svg,
.icon-btn-small svg,
.btn-primary-outline svg,
.simple-btn svg,
.glass-btn svg {
    width: var(--icon-size);
    height: var(--icon-size);
    display: inline-block;
    vertical-align: middle;
    stroke-width: var(--icon-stroke);
}
/* --- SHARE VIEWER SHELL (share/index.html + share/viewer.js) ---
   The public, view-only page a friend opens from a Share Link. scripts/build-styles.mjs bundles this with the theme
   tokens (000-tokens-base.css) and the Brain Map styles (145-brain-map.css) into share/viewer.css — never the whole
   app stylesheet. Token-driven like the app; the theme follows the viewer's system setting (viewer.js sets data-theme). */

html,
body {
    height: 100%;
}

body {
    margin: 0;
    overflow: hidden;
    background: var(--bg-app);
    color: var(--text-main);
}

.share-viewer {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
}

.share-viewer-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    border-bottom: 1px solid var(--border-color);
    background: var(--bg-sidebar);
    font-size: 0.85rem;
}

.share-viewer-brand {
    font-weight: 600;
}

.share-viewer-badge {
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--selection-color);
    color: var(--primary-color);
    font-size: 0.75rem;
}

.share-viewer-stage {
    position: relative;
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
}

.share-viewer-stage > .brain-map,
.share-viewer-stage > .cache-board,
.share-viewer-stage > .story-board,
.share-viewer-stage > .cyb-cal,
.share-viewer-stage > .share-note {
    flex: 1 1 auto;
    min-width: 0;
}

.share-viewer-status {
    display: none;
}

.share-viewer[data-state="loading"] .share-viewer-stage,
.share-viewer[data-state="error"] .share-viewer-stage {
    display: none;
}

.share-viewer[data-state="loading"] .share-viewer-status,
.share-viewer[data-state="error"] .share-viewer-status {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 24px;
    text-align: center;
}

.share-viewer-status-title {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
}

.share-viewer-status-detail {
    margin: 0;
    max-width: 42ch;
    color: var(--text-muted);
}

.share-viewer-retry {
    margin-top: 8px;
    padding: 6px 16px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-pane);
    color: var(--text-main);
    font: inherit;
    cursor: pointer;
}

.share-viewer-retry:hover {
    background: var(--item-hover);
}
/* --- SHARED ORDINARY NOTE (utils/ShareNoteView.js, plan §11 phase 7e) ---
   Read-only typography for a rich-text note opened from a Share Link. Its HTML was rebuilt by utils/ShareNoteHtml.js,
   so only the elements and classes that allowlist keeps need styling here. Token-driven; the page body doesn't scroll
   (010-share-viewer.css), so the article does. */

.share-note {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    box-sizing: border-box;
    padding: 24px 16px 64px;
    background: var(--bg-app);
    color: var(--text-main);
    line-height: 1.6;
    font-size: 1rem;
    overflow-wrap: anywhere;
}

.share-note > * {
    max-width: 760px;
    margin-left: auto;
    margin-right: auto;
}

.share-note-title {
    margin-top: 0;
    margin-bottom: 16px;
    font-size: 1.7rem;
    line-height: 1.25;
}

.share-note-body h1,
.share-note-body h2,
.share-note-body h3,
.share-note-body h4,
.share-note-body h5,
.share-note-body h6 {
    margin: 1.4em 0 0.5em;
    line-height: 1.3;
}

.share-note-body p {
    margin: 0 0 0.8em;
}

.share-note-body a {
    color: var(--primary-color);
}

.share-note-body ul,
.share-note-body ol {
    margin: 0 0 0.8em;
    padding-left: 1.6em;
}

.share-note-body ul.todo-list {
    list-style: none;
    padding-left: 0.2em;
}

.share-note-body ul.todo-list > li {
    position: relative;
    padding-left: 1.7em;
}

.share-note-body ul.todo-list > li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.3em;
    width: 1em;
    height: 1em;
    border: 2px solid var(--border-color);
    border-radius: 4px;
    box-sizing: border-box;
}

.share-note-body ul.todo-list > li.completed {
    color: var(--text-muted);
    text-decoration: line-through;
}

.share-note-body ul.todo-list > li.completed::before {
    border-color: var(--success-color);
    background: var(--success-color);
}

.share-note-body blockquote {
    margin: 0 0 0.8em;
    padding: 4px 14px;
    border-left: 4px solid var(--border-color);
    color: var(--text-muted);
}

.share-note-body pre {
    margin: 0 0 0.8em;
    padding: 12px 14px;
    overflow: auto;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-sidebar);
    font-size: 0.88rem;
    line-height: 1.5;
    white-space: pre;
}

.share-note-body code {
    font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;
}

.share-note-body :not(pre) > code {
    padding: 1px 5px;
    border-radius: 4px;
    background: var(--bg-sidebar);
    font-size: 0.9em;
}

.share-note-body hr {
    margin: 1.4em 0;
    border: 0;
    border-top: 1px solid var(--border-color);
}

.share-note-body .note-table-wrap {
    overflow-x: auto;
}

.share-note-body table {
    margin: 0 0 0.8em;
    border-collapse: collapse;
    max-width: 100%;
}

.share-note-body th,
.share-note-body td {
    padding: 6px 10px;
    border: 1px solid var(--border-color);
    vertical-align: top;
    text-align: left;
}

.share-note-body th {
    background: var(--bg-sidebar);
}

.share-note-body img {
    max-width: 100%;
    height: auto;
    border-radius: var(--radius-sm);
}

/* Pictures keep the note's layout: media cards with their display preset, width and caption. */
.share-note-body .media-card {
    max-width: 100%;
    margin: 0 0 0.8em;
}

.share-note-body .media-card img {
    display: block;
    width: 100%;
}

.share-note-body .media-card[data-display-preset="fit-note-width"],
.share-note-body .media-card.media-card-fit-width {
    width: 100% !important;
}

.share-note-body .media-card[data-display-preset="align-center"] {
    margin-left: auto;
    margin-right: auto;
}

.share-note-body .media-card[data-display-preset="float-left"] {
    float: left;
    margin-right: 16px;
}

.share-note-body .media-card[data-display-preset="float-right"] {
    float: right;
    margin-left: 16px;
}

.share-note-body .media-caption {
    margin-top: 6px;
    color: var(--text-muted);
    font-size: 0.86rem;
    text-align: center;
}

.share-note-body::after {
    content: "";
    display: block;
    clear: both;
}

@media (max-width: 600px) {
    .share-note-body .media-card[data-display-preset="float-left"],
    .share-note-body .media-card[data-display-preset="float-right"] {
        float: none;
        width: 100% !important;
        margin-left: 0;
        margin-right: 0;
    }
}
