        /* THEME-01: the token contract (invariant + per-theme custom properties, all 4-6 presets,
           the light/dark OS-fallback media query and the toggle-icon rules) now lives in
           styles/theme-tokens.css, loaded before this stylesheet on every page. */
        * { box-sizing: border-box; }
        /* The native `hidden` attribute only wins via the UA stylesheet's [hidden]{display:none},
           which any author `display` declaration overrides regardless of specificity — .btn's
           `display:inline-flex` was silently keeping several `hidden`-by-default buttons visible
           (nav overflow toggle, hosted-only Assets-panel controls). This restores `hidden` as an
           always-authoritative way to hide any element, independent of its other classes. */
        [hidden] { display: none !important; }
        [data-icon] { display: inline-flex; align-items: center; justify-content: center; line-height: 0; }
        [data-icon] svg { width: 15px; height: 15px; display: block; }
        .brand-mark[data-icon] svg { width: 14px; height: 14px; }
        *::-webkit-scrollbar { width: 9px; height: 9px; }
        *::-webkit-scrollbar-track { background: transparent; }
        *::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 6px; }
        *::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.18); }
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            background-color: var(--bg-base);
            color: var(--text-main);
            margin: 0; padding: 0;
            display: flex; flex-direction: column;
            height: 100vh; height: 100dvh; overflow: hidden;
        }
        .navbar {
            display: flex;
            background: var(--bg-surface);
            padding: 0 18px;
            height: 52px;
            border-bottom: 1px solid var(--border-color);
            align-items: center;
            flex-shrink: 0;
            gap: 4px;
        }
        .navbar h1 { font-size: 0.95rem; margin-right: 18px; color: var(--text-main); font-weight: 650; letter-spacing: -0.2px; display: flex; align-items: center; gap: 9px; }
        .navbar h1 .brand-mark { width: 22px; height: 22px; border-radius: 6px; background: linear-gradient(135deg, var(--primary), #a855f7); display: inline-flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(99,102,241,0.45); flex-shrink: 0; }
        .app-version-label { font-size: 10px; font-weight: 500; color: var(--text-dim); letter-spacing: 0.2px; vertical-align: middle; margin-left: 4px; padding: 2px 6px; background: var(--bg-surface-2); border-radius: 5px; }
        /* Project navigation cluster: [Projects] [New] next to the brand, before
           the current-project name — compact, single row, no duplicate toolbar. */
        .nav-project-cluster { display: flex; align-items: center; gap: 4px; padding-right: 12px; margin-right: 4px; border-right: 1px solid var(--border-color); }
        .workspace { display: flex; flex-direction: column; flex: 1; overflow: hidden; }
        
        .params-bar {
            display: flex; flex-wrap: nowrap; align-items: stretch;
            gap: 0; background: var(--bg-surface);
            border-bottom: 1px solid var(--border-color);
            flex-shrink: 0; overflow-x: auto; min-height: 48px;
        }
        .params-group {
            display: flex; align-items: center; gap: 7px;
            padding: 7px 14px; border-right: 1px solid var(--border-color); flex-shrink: 0;
        }
        .params-group:last-child { border-right: none; }
        .params-label {
            font-size: 10px; text-transform: uppercase; letter-spacing: 0.6px;
            color: var(--text-dim); font-weight: 700; margin-right: 3px; white-space: nowrap;
        }
        .params-field { display: flex; align-items: center; gap: 5px; }
        .params-field label { font-size: 11px; color: var(--text-muted); white-space: nowrap; font-weight: 500; }
        .params-field input[type="text"] {
            background: var(--bg-input); border: 1px solid var(--border-color);
            color: var(--text-main); padding: 5px 7px; font-size: 12.5px; border-radius: var(--radius-sm);
            width: 56px; transition: border-color 0.15s, box-shadow 0.15s;
        }
        .params-field input[type="text"]:focus { outline: none; border-color: var(--border-focus); box-shadow: var(--ring); }
        .params-field input[type="checkbox"] { width: 14px; height: 14px; cursor: pointer; accent-color: var(--primary); }
        /* Every field in the bar is now a .vector-numeric-control (30px input + 30px chevron,
           see the shared rule below) — the Apply/Collapse buttons match that same 30px so
           nothing in the bar reads taller or shorter than its neighbour. */
        .params-bar .btn { padding: 6px 11px; font-size: 12px; height: 30px; }
        .params-group.save-group { gap: 6px; }
        .params-collapse-icon svg { transition: transform 0.15s ease; }
        /* Base icon (chevronLeft) points left — the expanded-state action ("collapse", which
           tucks the bar back to the left). Collapsed flips it to point right ("expand"). */
        #btnParamsBarCollapse[aria-expanded="false"] .params-collapse-icon svg { transform: rotate(180deg); }
        /* Collapsed: only the Type tabs + Collapse button stay, so the bar becomes a single
           slim row instead of taking a whole toolbar's height when it doesn't fit. */
        .params-bar.params-bar-collapsed #paramsGroupRing,
        .params-bar.params-bar-collapsed #paramsGroupRect,
        .params-bar.params-bar-collapsed #paramsGroupApply { display: none; }
        
        .btn {
            background: var(--secondary); color: var(--text-main);
            border: 1px solid var(--border-color); padding: 7px 13px;
            border-radius: var(--radius-sm); font-size: 12.5px; font-weight: 550;
            cursor: pointer; transition: background 0.15s, border-color 0.15s, box-shadow 0.15s, transform 0.05s;
            display: inline-flex; align-items: center; justify-content: center; gap: 6px;
            white-space: nowrap; line-height: 1;
        }
        .btn:hover:not(:disabled) { background: var(--secondary-hover); border-color: var(--border-strong); }
        .btn:active:not(:disabled) { transform: translateY(0.5px); }
        .btn:focus-visible { outline: none; box-shadow: var(--ring); }
        .btn:disabled { opacity: 0.45; cursor: not-allowed; }
        .btn svg { width: 15px; height: 15px; flex-shrink: 0; }
        .btn-primary { background: var(--primary); color: #fff; border-color: transparent; box-shadow: 0 1px 0 rgba(255,255,255,0.08) inset, 0 2px 8px rgba(99,102,241,0.35); }
        .btn-primary:hover:not(:disabled) { background: var(--primary-hover); border-color: transparent; }
        .btn-accent { background: var(--bg-surface-2); color: var(--accent); border: 1px solid var(--accent-line); font-weight: 600; }
        .btn-accent:hover { background: var(--accent-soft); border-color: var(--accent); }
        .btn-warning { background: var(--bg-surface-2); color: var(--warning); border: 1px solid rgba(245,165,36,0.4); font-weight: 600; }
        .btn-warning:hover { background: rgba(245,165,36,0.12); border-color: var(--warning); }
        .btn-danger { color: var(--danger); }
        .btn-danger:hover { background: rgba(240, 85, 106, 0.1); border-color: var(--danger); }
        .btn-ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
        /* Single split Save button (v46): a primary quick-save half and a chevron half
           that opens a menu covering the rest of the save/version lifecycle. */
        .btn-split { position: relative; display: flex; align-items: stretch; height: 30px; }
        .btn-split .btn-split-main { border-top-right-radius: 0; border-bottom-right-radius: 0; border-right: 1px solid rgba(0,0,0,0.15); height: 30px; padding: 4px 9px; }
        .btn-split .btn-split-toggle { border-top-left-radius: 0; border-bottom-left-radius: 0; height: 30px; padding: 4px 6px; }
        .btn-split .btn-split-toggle svg { width: 12px; height: 12px; }
        .btn-split-menu { position: absolute; top: calc(100% + 4px); left: 0; z-index: 40; display: flex; flex-direction: column; min-width: 200px; padding: 4px; background: var(--bg-surface-2); border: 1px solid var(--border-strong); border-radius: var(--radius); box-shadow: var(--shadow-lg); }
        /* #addLayerSplitBtn sits flush against the Layers panel's right edge (unlike
           #saveSplitBtn in the wide nav bar), so its menu opens right-aligned instead of
           the shared left-aligned default — otherwise it overflows the panel. */
        #addLayerSplitBtn .btn-split-menu { left: auto; right: 0; }
        .btn-split-menu[role="menu"] > button { display: flex; align-items: center; gap: 8px; width: 100%; padding: 7px 10px; border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--text-main); font-size: 12.5px; text-align: left; cursor: pointer; }
        .btn-split-menu[role="menu"] > button:hover { background: var(--secondary-hover); }
        .btn-split-menu[role="menu"] > button svg { width: 15px; height: 15px; flex-shrink: 0; color: var(--text-muted); }
        /* Overflow "…" menu (v46): once the icon-only nav bar still can't fit everything
           (narrow window / iPad-width viewport), lower-priority buttons move in here in
           priority order instead of the bar wrapping to a second row. See
           src/ui/nav-overflow.js — it moves the real button nodes, not clones. */
        .nav-overflow { position: relative; display: flex; align-items: center; }
        #navOverflowMenu { right: 0; left: auto; }
        #navOverflowMenu[role="menu"] > .nav-collapsible { display: flex; }
        .btn-ghost:hover:not(:disabled) { background: var(--bg-surface-2); color: var(--text-main); border-color: transparent; }
        
        .editor-main { flex: 1; display: flex; flex-direction: column; background: var(--bg-base); overflow: hidden; position: relative; width: 100%; }

        .canvas-col { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; overflow: hidden; }
        /* overflow:hidden (not auto): pan/zoom navigate the canvas, and this is the clip
           that keeps viewBox-zoom bleed (SVG overflow:visible) out of the split gap/panels. */
        .canvas-container { flex: 1; padding: 16px; display: flex; justify-content: safe center; align-items: safe center; overflow: hidden; min-height: 0; position: relative; touch-action: none; user-select: none; }
        #editorContainer { display: flex; align-items: safe center; justify-content: safe center; flex: 1; min-width: 0; min-height: 0; touch-action: none; }
        /* Corsair reticle: precise-aiming cursor while hovering the grid (all tool modes).
           Data-URI SVG (white halo + dark core) so it reads on light and dark grids; hotspot centered.
           Survives editor re-renders because it targets the recreated <svg> by selector, not inline style.
           Inline cursors (select-drag grabbing/move) and the panning override below win over this. */
        /* D21/D28: 12×12 hairline scope crosshair (1px strokes, open centre + centre dot),
           white halo + dark core so it reads on light and dark grids; hotspot centered at 6,6.
           Ticket 18: this says "clicking will draw", so it only applies with a Layer active —
           #editorContainer.no-layer-active (toggled by buildEditor) gets a plain pick/pointer
           cursor instead, matching this codebase's existing click-to-select affordance (every
           clickable row/button/dot elsewhere is a bare `cursor: pointer`, e.g. .layer-item). */
        #editorContainer:not(.no-layer-active) svg { cursor: url("data:image/svg+xml,%3Csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20width=%2712%27%20height=%2712%27%20viewBox=%270%200%2012%2012%27%3E%3Cg%20fill=%27none%27%20stroke=%27%23fff%27%20stroke-width=%271.6%27%20stroke-linecap=%27round%27%3E%3Cline%20x1=%276%27%20y1=%270%27%20x2=%276%27%20y2=%274%27/%3E%3Cline%20x1=%276%27%20y1=%278%27%20x2=%276%27%20y2=%2712%27/%3E%3Cline%20x1=%270%27%20y1=%276%27%20x2=%274%27%20y2=%276%27/%3E%3Cline%20x1=%278%27%20y1=%276%27%20x2=%2712%27%20y2=%276%27/%3E%3C/g%3E%3Cg%20fill=%27none%27%20stroke=%27%23111%27%20stroke-width=%270.7%27%20stroke-linecap=%27round%27%3E%3Cline%20x1=%276%27%20y1=%270%27%20x2=%276%27%20y2=%274%27/%3E%3Cline%20x1=%276%27%20y1=%278%27%20x2=%276%27%20y2=%2712%27/%3E%3Cline%20x1=%270%27%20y1=%276%27%20x2=%274%27%20y2=%276%27/%3E%3Cline%20x1=%278%27%20y1=%276%27%20x2=%2712%27%20y2=%276%27/%3E%3C/g%3E%3Ccircle%20cx=%276%27%20cy=%276%27%20r=%270.9%27%20fill=%27%23fff%27%20stroke=%27%23111%27%20stroke-width=%270.4%27/%3E%3C/svg%3E") 6 6, crosshair; }
        #editorContainer.no-layer-active svg { cursor: pointer; }
        body.editor-panning #editorContainer svg { cursor: grabbing; }
        /* D30: Hand armed (tool toggled or Space held) → grab cursor over the canvas. */
        body.hand-armed #editorContainer svg { cursor: grab; }
        body.hand-armed.editor-panning #editorContainer svg { cursor: grabbing; }
        /* Reflect origin marker: over it (hover) a hand says it can be moved; held, a closed one. */
        #editorContainer.reflect-origin-hover svg, #editorContainer.reflect-origin-hover svg * { cursor: grab !important; }
        #editorContainer.reflect-origin-drag svg, #editorContainer.reflect-origin-drag svg * { cursor: grabbing !important; }

        /* Layer Panel — sized by the workspace manager; content only fills its panel.
           Its title lives on the workspace panel tab, the inner header keeps the actions. */
        .layer-panel {
            display: flex; flex-direction: column;
            background: var(--bg-surface);
            overflow: hidden;
            min-width: 0; min-height: 0;
        }
        .layer-panel-header {
            display: flex; align-items: center; justify-content: flex-end;
            padding: 7px 10px; border-bottom: 1px solid var(--border-color);
            flex-shrink: 0; gap: 6px;
            position: relative;
        }
        .layer-panel-btns { display: flex; gap: 5px; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
        #btnLayerMultiSel.active { background: rgba(99,102,241,0.22); color: var(--accent); border-color: var(--accent); }
        .layer-list { overflow-y: auto; overflow-x: hidden; flex: 1; width: 100%; padding: 4px; }
        .layer-item {
            display: flex; align-items: center; gap: 8px;
            padding: 9px 10px; cursor: pointer; border-radius: var(--radius-sm);
            margin-bottom: 3px;
            font-size: 13px; user-select: none;
            border: 1px solid transparent; border-left: 3px solid transparent; transition: background 0.12s, border-color 0.12s;
            max-width: 100%; overflow: hidden;
        }
        .layer-item:hover { background: var(--bg-surface-2); }
        .layer-item.selected { background: var(--accent-soft); border-left: 3px solid var(--accent); color: var(--text-main); }
        .layer-item.multi-sel { background: rgba(99,102,241,0.08); border-left: 3px solid var(--accent-line); }
        .layer-item .layer-cb { display:none; width:15px; height:15px; margin-right:2px; cursor:pointer; accent-color:var(--accent); flex-shrink:0; }
        body.layer-multi-mode .layer-item .layer-cb { display:block; }
        body.layer-multi-mode .layer-item { padding: 10px 10px; }
        .layer-item.layer-hidden { opacity: 0.45; }
        /* ticket 14: the dot now renders as the Layer's grid-type SHAPE (diamond/square/
           triangle/circle) instead of a plain swatch — colour comes from `color` (the icon
           is fill="currentColor") rather than `background`. */
        .layer-color-dot { width: 16px; height: 16px; flex-shrink: 0; cursor: pointer; transition: transform .1s; display: inline-flex; align-items: center; justify-content: center; }
        .layer-color-dot svg { width: 100%; height: 100%; }
        .layer-color-dot:hover { transform: scale(1.12); }
        .layer-color-dot:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 1px; }
        .layer-color-popover { position:fixed; z-index:1200; width:224px; box-sizing:border-box; padding:10px; border:1px solid var(--border-color); border-radius:10px; background:var(--bg-surface-2); box-shadow:0 12px 32px rgba(0,0,0,.34); }
        .layer-color-sv { position:relative; height:132px; overflow:hidden; border-radius:7px; cursor:crosshair; background-color:#f00; background-image:linear-gradient(to top,#000,transparent),linear-gradient(to right,#fff,transparent); touch-action:none; }
        .layer-color-sv:focus-visible { outline:2px solid var(--border-focus); outline-offset:2px; }
        .layer-color-sv-marker { position:absolute; width:12px; height:12px; border:2px solid #fff; border-radius:50%; box-shadow:0 0 0 1px #111,0 1px 3px rgba(0,0,0,.6); transform:translate(-50%,-50%); pointer-events:none; }
        /* The hue track renders its own fixed spectrum gradient, not a theme-tinted accent-color.
           REG-056's third fix (commit 2ce7fe9) already removed the --layer-picker-hue custom
           property that coupled the SV box's background to theme state; this extends the same
           outside-theme-tokens principle to the hue slider itself — do not reintroduce either
           coupling by switching this back to accent-color/theme vars. */
        .layer-color-hue {
            width:100%; margin:10px 0 8px; -webkit-appearance:none; appearance:none;
            height:14px; border-radius:7px; background:transparent; cursor:pointer;
        }
        .layer-color-hue::-webkit-slider-runnable-track {
            height:14px; border-radius:7px;
            background:linear-gradient(to right,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00);
        }
        .layer-color-hue::-moz-range-track {
            height:14px; border-radius:7px;
            background:linear-gradient(to right,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00);
        }
        .layer-color-hue::-webkit-slider-thumb {
            -webkit-appearance:none; appearance:none; margin-top:0;
            width:14px; height:14px; border-radius:50%;
            background:#fff; border:2px solid #111; box-shadow:0 1px 3px rgba(0,0,0,.6);
        }
        .layer-color-hue::-moz-range-thumb {
            width:10px; height:10px; border-radius:50%;
            background:#fff; border:2px solid #111; box-shadow:0 1px 3px rgba(0,0,0,.6);
        }
        .layer-color-hue:focus-visible { outline:none; }
        .layer-color-hue:focus-visible::-webkit-slider-thumb { outline:2px solid var(--border-focus); outline-offset:2px; }
        .layer-color-hue:focus-visible::-moz-range-thumb { outline:2px solid var(--border-focus); outline-offset:2px; }
        .layer-color-value { display:flex; align-items:center; gap:8px; }
        .layer-color-preview { width:30px; height:28px; flex:none; border:1px solid var(--border-color); border-radius:5px; }
        .layer-color-hex { min-width:0; width:100%; box-sizing:border-box; padding:6px 8px; border:1px solid var(--border-color); border-radius:5px; color:var(--text-main); background:var(--bg-input); font:12px ui-monospace,SFMono-Regular,Menlo,monospace; }
        .layer-color-actions { display:flex; justify-content:flex-end; gap:7px; margin-top:10px; }
        .layer-color-actions .btn { min-width:64px; padding:6px 10px; }
        .layer-type-icon { font-size: 11px; flex-shrink: 0; }
        .layer-name { flex: 1; color: var(--text-main); white-space: nowrap; font-size: 13px; cursor: default; user-select: none; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
        .layer-meta { color: var(--text-muted); font-size: 10.5px; font-weight: 650; white-space: nowrap; flex-shrink: 0; font-variant-numeric: tabular-nums; }
        .layer-item.selected .layer-name { cursor: text; color: var(--accent-hover); }
        .layer-item.selected .layer-name:hover { text-decoration: underline dotted rgba(165,176,255,0.5); }
        .layer-pos { font-size: 10px; color: var(--text-muted); min-width: 44px; text-align: right; white-space: nowrap; }
        .layer-btn { background: none; border: none; color: var(--text-muted); cursor: pointer; padding: 4px; font-size: 14px; border-radius: 5px; line-height: 0; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
        .layer-btn:hover { background: var(--bg-surface-2); color: var(--text-main); }
        .layer-btn svg, .layer-lock svg { width: 15px; height: 15px; pointer-events: none; display: block; }
        .layer-btn[data-action="del"]:hover { color: var(--danger); }
        .layer-btn[data-action="invert"] svg { transition: transform 0.15s ease; }
        .layer-btn-invert-on { color: var(--accent); }
        .layer-btn-invert-on svg { transform: rotate(180deg); }
        .layer-field-row {
            flex-basis: 100%;
            display: flex;
            flex-wrap: wrap;
            gap: 4px;
            align-items: center;
            margin-top: 4px;
            padding-top: 4px;
            border-top: 1px dashed var(--border-color);
            font-size: 11px;
            color: var(--text-muted);
        }
        .layer-field-label {
            min-width: 24px;
            color: var(--text-muted);
            font-size: 11px;
            line-height: 1;
        }
        .layer-input-slider { flex-basis: 100%; width: 100%; margin-top: 4px; accent-color: var(--accent); cursor: pointer; }
        .layer-input-group {
            display: inline-flex;
            align-items: stretch;
            min-width: 98px;
            height: 24px;
            border: 1px solid var(--border-color);
            border-radius: 6px;
            overflow: hidden;
            background: var(--bg-input);
        }
        .layer-input-step,
        .layer-input-field {
            height: 24px;
            border: none;
            margin: 0;
            box-sizing: border-box;
        }
        .layer-input-step {
            width: 24px;
            padding: 0;
            background: rgba(255,255,255,0.04);
            color: var(--text-main);
            cursor: pointer;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            line-height: 1;
            flex-shrink: 0;
        }
        .layer-input-step:hover { background: rgba(255,255,255,0.08); }
        .layer-input-step + .layer-input-field,
        .layer-input-field + .layer-input-step { border-left: 1px solid var(--border-color); }
        .layer-input-field {
            width: 50px;
            padding: 0 6px;
            background: transparent;
            color: var(--text-main);
            font-size: 11px;
            text-align: center;
            font-variant-numeric: tabular-nums;
            outline: none;
            min-width: 0;
        }
        .layer-inline-readout {
            min-width: 46px;
            height: 24px;
            padding: 0 8px;
            border: 1px solid var(--border-color);
            border-radius: 6px;
            background: rgba(255,255,255,0.03);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            color: var(--text-dim);
            font-variant-numeric: tabular-nums;
            cursor: default;
            box-sizing: border-box;
        }
        .layer-group-tree {
            flex-basis: 100%;
            margin-top: 5px;
            padding-top: 5px;
            border-top: 1px dashed var(--border-color);
            font-size: 11px;
            color: var(--text-muted);
        }
        .layer-group-header,
        .layer-group-row {
            display: flex;
            align-items: center;
            gap: 6px;
            min-width: 0;
        }
        .layer-group-header {
            justify-content: space-between;
            margin-bottom: 4px;
            font-weight: 700;
            color: var(--text-dim);
        }
        .layer-group-add {
            height: 24px;
            padding: 0 7px;
            border: 1px solid var(--border-color);
            border-radius: 6px;
            background: rgba(255,255,255,0.04);
            color: var(--text-main);
            display: inline-flex;
            align-items: center;
            gap: 4px;
            cursor: pointer;
            font-size: 11px;
            line-height: 1;
        }
        .layer-group-add:disabled {
            opacity: 0.4;
            cursor: default;
        }
        .layer-group-add svg,
        .layer-group-btn svg {
            width: 13px;
            height: 13px;
            pointer-events: none;
            display: block;
        }
        .layer-group-rows {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .layer-group-row {
            min-height: 24px;
            border-radius: 5px;
            padding: 1px 2px;
        }
        .layer-group-row:not(.muted):hover {
            background: rgba(255,255,255,0.05);
        }
        .layer-group-row.muted {
            color: var(--text-dim);
        }
        .layer-groups-title {
            font-weight: 700;
            color: var(--text-dim);
        }
        .layer-group-section + .layer-group-section {
            margin-top: 6px;
        }
        .layer-group-subheader {
            font-weight: 600;
            color: var(--text-dim);
            margin-bottom: 3px;
        }
        /* Ticket 30: a row picked into the transient Combined group selection —
           shift-clicking Cell-group and Asset-group rows together. */
        .layer-group-row.picked {
            background: rgba(129,140,248,0.16);
            outline: 1px solid rgba(129,140,248,0.55);
            outline-offset: -1px;
        }
        .layer-group-dot {
            width: 9px;
            height: 9px;
            border-radius: 50%;
            flex-shrink: 0;
            border: 1px solid rgba(255,255,255,0.28);
        }
        .layer-group-dot.ungrouped {
            background: transparent;
            border-style: dashed;
            border-color: var(--text-dim);
        }
        .layer-group-name {
            flex: 1;
            min-width: 0;
            color: var(--text-main);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .layer-group-row.muted .layer-group-name {
            color: var(--text-dim);
        }
        .layer-group-count {
            min-width: 22px;
            text-align: right;
            font-variant-numeric: tabular-nums;
            color: var(--text-muted);
        }
        .layer-group-btn {
            width: 22px;
            height: 22px;
            padding: 0;
            border: none;
            border-radius: 5px;
            background: transparent;
            color: var(--text-muted);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            flex-shrink: 0;
        }
        .layer-group-btn:hover,
        .layer-group-add:hover:not(:disabled) {
            background: rgba(255,255,255,0.08);
            color: var(--text-main);
        }
        .layer-group-btn.danger:hover {
            color: var(--danger);
        }
        .layer-group-name-input {
            flex: 1;
            min-width: 0;
            height: 22px;
            padding: 0 5px;
            border: 1px solid var(--border-focus);
            border-radius: 5px;
            background: var(--bg-input);
            color: var(--text-main);
            font-size: 11px;
            box-sizing: border-box;
        }
        /* Hide number input spinners */
        .lyr-cell::-webkit-outer-spin-button,
        .lyr-cell::-webkit-inner-spin-button,
        .lyr-circle-id::-webkit-outer-spin-button,
        .lyr-circle-id::-webkit-inner-spin-button,
        .lyr-circle-line::-webkit-outer-spin-button,
        .lyr-circle-line::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
        .lyr-cell,
        .lyr-circle-id,
        .lyr-circle-line { -moz-appearance: textfield; }
        
        /* Symbols panel — vertical, responsive grid: the panel width decides the
           column count (auto-fill), a narrow dock gives 1–2 columns, a wide one
           more; the list scrolls vertically and never widens the workspace. */
        .symbols-panel { display: flex; flex-direction: column; overflow: hidden; background: var(--bg-surface); min-width: 0; min-height: 0; }
        .symbols-panel-toolbar { min-height:36px; display:flex; align-items:center; gap:6px; padding:4px 8px; border-bottom:1px solid var(--border-color); flex-shrink:0; }
        .symbols-panel-summary { min-width:0; flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--text-dim); font-size:10px; font-weight:700; letter-spacing:.4px; text-transform:uppercase; }
        .symbols-panel-action { width:28px; min-width:28px; min-height:28px; padding:4px; font-size:11px; flex-shrink:0; line-height:0; }
        .symbols-panel-action svg { width:16px; height:16px; }
        .symbols-grid {
            flex: 1; min-height: 0; display:flex; flex-direction:column;
            gap: 10px; padding: 8px; align-content: start;
            overflow-y: auto; overflow-x: hidden; touch-action:pan-y;
        }
        .symbols-empty-text { font-size: 12px; color: var(--text-dim); padding: 4px 2px; }
        .symbol-folder-create-row { display:flex; align-items:center; gap:5px; padding:2px 0; }
        .symbol-folder-create-row .design-rename-input { flex:1; min-width:0; font-size:12px; }
        .symbol-folder-create-row .btn { min-height:28px; padding:4px 7px; font-size:11px; }
        .symbol-folder-section { min-width:0; display:flex; flex-direction:column; gap:6px; }
        .symbol-folder-header { min-height:30px; display:flex; align-items:center; gap:4px; border:1px solid var(--border-color); border-radius:6px; background:rgba(255,255,255,.025); padding:1px 3px; transition:background .12s,border-color .12s; }
        .symbol-folder-section.symbol-folder-drop-target .symbol-folder-header { border-color:var(--accent); background:var(--accent-soft); }
        .symbol-folder-toggle { min-width:0; flex:1; min-height:28px; border:0; background:transparent; color:var(--text-main); display:flex; align-items:center; gap:6px; padding:3px 4px; cursor:pointer; text-align:left; }
        .symbol-folder-toggle:focus-visible, .symbol-folder-action:focus-visible, .symbol-menu-btn:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }
        .symbol-folder-icon { display:inline-flex; color:var(--accent); flex-shrink:0; line-height:0; }
        .symbol-folder-icon svg, .symbol-folder-chevron svg { width:14px; height:14px; }
        .symbol-folder-name { min-width:0; flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:11px; font-weight:650; }
        .symbol-folder-count { color:var(--text-muted); font-size:10px; font-variant-numeric:tabular-nums; }
        .symbol-folder-chevron { display:inline-flex; color:var(--text-muted); line-height:0; transition:transform .12s; }
        .symbol-folder-section.collapsed .symbol-folder-chevron { transform:rotate(-90deg); }
        .symbol-folder-section.collapsed .symbol-folder-grid { display:none; }
        .symbol-folder-actions { display:flex; align-items:center; gap:1px; flex-shrink:0; }
        .symbol-folder-action { width:28px; height:28px; padding:0; border:0; border-radius:5px; background:transparent; color:var(--text-muted); cursor:pointer; display:inline-flex; align-items:center; justify-content:center; }
        .symbol-folder-action:hover { color:var(--text-main); background:rgba(255,255,255,.08); }
        .symbol-folder-action.danger:hover { color:var(--danger); }
        .symbol-folder-action svg { width:14px; height:14px; pointer-events:none; }
        .symbol-folder-grid { display:grid; grid-template-columns:repeat(auto-fill,var(--symbol-card-min,116px)); justify-content:center; gap:7px; min-width:0; min-height:18px; max-height:min(42vh,360px); overflow-y:auto; overflow-x:hidden; align-content:start; scrollbar-gutter:stable; padding-right:2px; }
        .hosted-asset-section { min-width:0; display:flex; flex-direction:column; gap:6px; }
        .hosted-asset-heading { margin:0; color:var(--text-main); font-size:11px; font-weight:700; letter-spacing:0; }
        .hosted-asset-group-count { color:var(--text-muted); font-size:10px; font-variant-numeric:tabular-nums; margin-right:auto; }
        .hosted-asset-grid { max-height:none; overflow:visible; }
        /* Ticket 08: drop feedback for dragging a Grid card onto the (foreign) Vector
           group to convert it — highlights the whole section, not a per-card indicator. */
        .hosted-asset-section.hosted-asset-convert-target .hosted-asset-group-header { outline:2px solid var(--accent); outline-offset:1px; background:var(--accent-soft); border-radius:6px; }
        /* Ticket 05: a Grid Asset card whose grid type differs from the Active drawing
           layer's is greyed and refuses placement; rename/delete/export/drag/menu stay usable. */
        .hosted-asset-item.asset-incompatible { opacity: 0.45; }
        .hosted-asset-item.asset-incompatible:hover { transform: none; box-shadow: none; }
        /* Ticket 06: a touch drag on the card itself reorders it rather than scrolling
           the panel — pointermove sets pointer capture and needs no browser gesture racing it. */
        .hosted-asset-item { touch-action: none; }
        /* A per-card checkbox for multi-select export. Hidden until the toolbar's select-mode
           toggle (#btnAssetSelectMode) turns .asset-select-mode on, so tiles stay uncluttered
           until the operator explicitly asks to select. */
        .hosted-asset-select-wrap { display:none; position:absolute; top:3px; left:3px; z-index:3; width:20px; height:20px; align-items:center; justify-content:center; cursor:pointer; }
        .symbols-grid.asset-select-mode .hosted-asset-select-wrap { display:flex; }
        .hosted-asset-select { width:15px; height:15px; margin:0; accent-color:var(--accent); cursor:pointer; }
        .hosted-asset-item.is-selected { border-color:var(--accent); box-shadow:0 0 0 1px var(--accent); }
        .symbol-item {
            width: 100%; aspect-ratio: 108 / 118; min-width: 0;
            background: var(--bg-surface-2); border: 1px solid var(--border-color); border-radius: var(--radius-sm);
            cursor: pointer; display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start;
            gap: 0; padding: 2px; transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s;
            flex-shrink: 0; position: relative; overflow: visible;
        }
        .symbol-item:hover { transform: translateY(-2px); border-color: var(--accent-line); box-shadow: var(--shadow-md); }
        .symbol-item.has-open-menu { z-index:20; }
        .symbol-item:focus-visible { outline: none; box-shadow: var(--ring); }
        .symbol-item.symbol-dragging { opacity: 0.42; transform: scale(0.97); cursor: grabbing; }
        .symbol-item.symbol-drop-before::before,
        .symbol-item.symbol-drop-after::after {
            content: ''; position: absolute; left: -5px; right: -5px; height: 3px;
            border-radius: 2px; background: var(--accent); pointer-events: none; z-index: 3;
        }
        .symbol-item.symbol-drop-before::before { top: -6px; }
        .symbol-item.symbol-drop-after::after { bottom: -6px; }
        .symbol-item.symbol-drop-horizontal::before,
        .symbol-item.symbol-drop-horizontal::after { top:-5px; bottom:-5px; width:3px; height:auto; }
        .symbol-item.symbol-drop-horizontal.symbol-drop-before::before { left:-6px; right:auto; }
        .symbol-item.symbol-drop-horizontal.symbol-drop-after::after { left:auto; right:-6px; }
        /* SVG thumbnail: absolute-fills the wrap. overflow:visible on both the card and the SVG
           ensures nothing is ever clipped by CSS. The viewBox padding (≥3 cells / 25% of bbox)
           guarantees all symbol content stays well inside the element boundaries. */
        .symbol-item-svg-wrap { flex: 1 1 auto; min-height: 0; position: relative; margin: 0; }
        .symbol-item-svg-wrap svg, .symbol-item-svg-wrap img { position:absolute; inset:0; width:100%; height:100%; display:block; object-fit:contain; }
        .symbol-item-name { flex-shrink: 0; width: 100%; font-size: 10px; color: var(--text-muted); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 3px 3px 1px; line-height: 1.3; font-weight: 550; }
        /* D37: retokenized so the card menu button themes (previously a hardcoded dark literal). */
        .symbol-menu-btn { position:absolute; top:3px; right:3px; width:28px; height:28px; display:flex; align-items:center; justify-content:center; padding:0; z-index:3; color:var(--text-main); background:var(--bg-surface-2); border:1px solid var(--border-strong); border-radius:6px; line-height:0; cursor:pointer; }
        @media (hover: hover) {
            .symbol-menu-btn { opacity:0; pointer-events:none; }
            .symbol-item:hover .symbol-menu-btn,
            .symbol-menu-btn:focus-visible,
            .symbol-item.has-open-menu .symbol-menu-btn { opacity:1; pointer-events:auto; }
        }
        .symbol-menu-btn svg { width:14px; height:14px; pointer-events:none; }
        .symbol-item.is-renaming { cursor: text; transform: none; }
        .symbol-item .design-rename-input { flex-shrink: 0; width: 100%; padding: 1px 2px; font-size: 9px; line-height: 1.3; text-align: center; }
        .symbol-action-menu { position:fixed; z-index:1000; width:176px; max-width:calc(100vw - 12px); padding:4px; display:flex; flex-direction:column; gap:1px; background:var(--bg-panel); border:1px solid var(--border-strong); border-radius:7px; box-shadow:var(--shadow-md); }
        .symbol-action-menu button { min-height:28px; padding:4px 7px; border:0; border-radius:5px; background:transparent; color:var(--text-main); text-align:left; font-size:11px; cursor:pointer; }
        .symbol-action-menu button:hover, .symbol-action-menu button:focus-visible { background:var(--bg-surface-2); outline:none; }
        .symbol-action-menu button.danger { color:var(--danger); }
        .symbol-action-menu-label { padding:5px 7px 2px; color:var(--text-dim); font-size:9px; font-weight:700; letter-spacing:.5px; text-transform:uppercase; }
        
        .info-bar { display: none; } /* Perkelta į canvas overlay */
        .drawing-toolbar { display: none; } /* Perkelta į canvas overlay */

        /* D31: canvas info overlay (#canvasInfoOverlay) removed — badge no longer rendered. */
        .drawing-toolbar .toolbar-sep { width: 1px; height: 22px; background: var(--border-color); margin: 0 4px; }
        .drawing-toolbar .btn { padding: 4px 10px; font-size: 12px; height: 28px; }
        .btn-toggle { background: var(--secondary); border-color: var(--border-color); }
        .btn-toggle.active { background: rgba(99,102,241,0.2); border-color: var(--accent); color: var(--accent); }
        .toolbar-hint { font-size: 10px; color: var(--text-muted); }

        /* ── Tools palette (EtnoWorkspace panel content) ─────── */
        /* ── Tools panel redesign (Phase 1): rail + contextual inspector + modes strip ── */
        .tools-panel { display: flex; flex-direction: column; overflow: hidden; background: var(--bg-surface); min-width: 0; min-height: 0; user-select: none; }
        .tools-panel-body {
            flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column;
            gap: 6px; padding: 7px 8px; overflow: hidden;
        }
        .tools-panel-body .btn { padding: 4px 10px; font-size: 12px; height: 28px; }

        /* Active-tool rail — one mutually-exclusive selector. Deterministic orientation
           rule: horizontal when the panel content is at least the width threshold,
           vertical (stacked) below it. Driven by a ResizeObserver, not a viewport query. */
        .tools-rail { display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px; flex: 0 0 auto; }
        .tool-rail-btn {
            display: inline-flex; align-items: center; justify-content: center;
            position: relative;
            width: var(--tool-rail-button-width); height: 32px; padding: 0; cursor: pointer;
            border: 1px solid transparent; border-radius: 6px;
            background: var(--bg-input); color: var(--text-muted);
            transition: background .12s, color .12s, border-color .12s;
        }
        .tool-rail-btn svg { width: 18px; height: 18px; }
        .tool-rail-btn:hover:not(:disabled) { color: var(--text-main); border-color: var(--border-strong); }
        .tool-rail-btn.active { background: var(--accent-soft); color: var(--accent-hover); border-color: var(--accent); }
        #btnToolGroup.has-selection-memory::after {
            content: ''; position: absolute; right: 4px; bottom: 4px;
            width: 6px; height: 6px; border-radius: 50%;
            background: #a1a1aa; box-shadow: 0 0 0 1px var(--bg-input);
        }
        /* D26: mirror toggles read as independent on/off switches (amber), visually distinct
           from the mutually-exclusive Active-tool selection (accent). D30: Hand shares the
           accent style (it is a rail tool, just navigation-only). */
        .tool-rail-toggle.active { background: rgba(245,158,11,0.18); color: #fbbf24; border-color: rgba(245,158,11,0.6); }
        /* PANEL-03: Axis lock is the iPad substitute for the Shift key, so it must be a
           real touch target. PANEL-01 caps the docked rail at a fixed extent (34px of
           content width on a vertical edge, 32px of content height on a horizontal one),
           so the button grows to the repo's 40px touch precedent (.snap-filter-btn) only
           along whichever axis that orientation leaves free — never the fixed one. */
        #btnAxisLock { touch-action: manipulation; }
        .tools-panel[data-rail="vertical"] #btnAxisLock { height: 40px; }
        .tools-panel[data-rail="horizontal"] #btnAxisLock { min-width: 40px; }
        .tool-rail-btn:disabled { opacity: .4; cursor: not-allowed; }
        .tool-rail-btn:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 2px; }
        .tool-rail-sep { width: 1px; align-self: stretch; min-height: 20px; background: var(--border-color); margin: 2px 3px; }
        /* PANEL-01: docked Tools is a fixed-extent rail (see EtnoWorkspace's
           dockedFixed) — its buttons wrap via .tools-rail's own flex-wrap rather
           than a forced single-column axis, so a button-wide docked rail still
           lays out as a natural one-per-row wrap. Only the separator, which reads
           as a divider bar either way, switches orientation. */
        .tools-panel[data-rail="vertical"] .tool-rail-sep { width: 100%; height: 1px; min-height: 0; align-self: auto; margin: 3px 0; }
        /* Issue 07: History actions are their own group past the trailing separator, not
           tool-rail-btn/toggle members (so updateToolRail's .tool-rail-btn active-toggle
           never touches them). display: contents drops the group div's own box so its
           two buttons wrap individually with the rail's own flex-wrap in both the
           horizontal and docked-vertical (button-wide) orientations, same as its siblings. */
        .tools-rail .nav-history-actions { display: contents; }
        .tools-rail .nav-history-actions .btn { width: 30px; height: 30px; padding: 5px; }

        /* Contextual inspector — only the active tool's pane is shown; it scrolls so
           controls stay reachable at the minimum panel size (no fixed-height overflow). */
        .tools-inspector {
            flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
            display: flex; flex-direction: column; gap: 6px; padding-top: 4px;
            border-top: 1px solid var(--border-color); scrollbar-gutter: stable; overscroll-behavior: contain;
        }
        /* D27: the inspector is portalled into a fixed card while open. It must not
           inherit the docked panel's scroll container or contribute to its size. */
        .tools-inspector[hidden] { display: none !important; }
        .tool-popover {
            position: fixed; z-index: 6100; display: flex; flex-direction: column;
            width: min(360px, calc(100vw - 16px)); max-width: calc(100vw - 16px);
            padding: 8px; gap: 7px; box-sizing: border-box;
            background: var(--bg-surface-2); color: var(--text-main);
            border: 1px solid var(--border-strong); border-radius: 9px;
            box-shadow: var(--shadow-lg, 0 16px 36px rgba(0,0,0,.42));
        }
        .tool-popover[hidden] { display: none; }
        .tool-popover-head {
            display: flex; align-items: center; gap: 8px; min-height: 18px;
            color: var(--text-muted); font-size: 10px; font-weight: 800;
            letter-spacing: .08em; line-height: 1; text-transform: uppercase;
        }
        .tool-popover-head strong { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .tool-popover-close {
            display: inline-flex; align-items: center; justify-content: center;
            width: 22px; height: 22px; padding: 0; margin-left: auto; flex: none;
            border: 1px solid transparent; border-radius: 5px;
            background: transparent; color: var(--text-muted); cursor: pointer;
        }
        .tool-popover-close:hover { color: var(--text-main); background: var(--secondary-hover); border-color: var(--border-color); }
        .tool-popover-close:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 1px; }
        .tool-popover-close svg { width: 14px; height: 14px; }
        .tool-popover .tools-inspector {
            flex: 0 0 auto; min-height: 0; overflow: visible; overflow-x: visible;
            padding: 0; border-top: 0; scrollbar-gutter: auto; overscroll-behavior: auto;
        }
        .tool-popover .insp-pane.insp-active { display: flex; }
        .tool-popover .tools-svg-section { max-width: none; }
        .tool-popover .svg-placement-controls,
        .tool-popover .line-tool-controls { flex-basis: auto; }
        /* Ticket 14: shared themed confirm popover — anchored to the triggering control,
           replacing every native confirm(). */
        .confirm-popover {
            position: fixed; z-index: 6200; display: flex; flex-direction: column;
            width: min(320px, calc(100vw - 16px)); max-width: calc(100vw - 16px);
            padding: 12px; gap: 12px; box-sizing: border-box;
            background: var(--bg-surface-2); color: var(--text-main);
            border: 1px solid var(--border-strong); border-radius: 9px;
            box-shadow: var(--shadow-lg, 0 16px 36px rgba(0,0,0,.42));
        }
        .confirm-popover-msg { margin: 0; font-size: 13px; line-height: 1.45; white-space: pre-line; }
        .confirm-popover-actions { display: flex; justify-content: flex-end; gap: 8px; }
        .confirm-popover-actions .btn { min-width: 72px; }
        .confirm-popover-confirm.confirm-popover-danger {
            background: var(--danger, #f87171); border-color: var(--danger, #f87171); color: #fff;
        }
        .confirm-popover-confirm.confirm-popover-danger:hover { filter: brightness(1.08); }
        .confirm-popover-confirm.confirm-popover-danger:focus-visible,
        .confirm-popover-cancel:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 1px; }

        .insp-pane { display: none; flex-wrap: wrap; align-items: center; gap: 5px; min-width: 0; max-width: 100%; }
        .insp-pane.insp-active { display: flex; }
        .insp-hint { margin: 0; font-size: 11px; line-height: 1.4; color: var(--text-muted); }
        .tool-controls { display: flex; }
        .tool-controls[hidden] { display: none; }

        /* Shared node filter: editor-only HUD, never part of project geometry. */
        .snap-filter-hud {
            position: absolute; left: 0; right: 0; bottom: 8px; z-index: 9; display: grid;
            grid-template-columns: minmax(0, 1fr) 48px minmax(0, 1fr); align-items: center;
            padding: 0; pointer-events: none;
            border: 0; border-radius: 0;
            background: transparent; box-shadow: none; touch-action: manipulation;
        }
        .snap-filter-controls, .layer-focus-controls {
            display: inline-flex; align-items: center; gap: 4px; pointer-events: auto;
            white-space: nowrap;
        }
        .snap-filter-controls { grid-column: 1; justify-self: center; }
        .layer-focus-controls { grid-column: 3; justify-self: center; }
        .snap-filter-label {
            position: absolute; width: 1px; height: 1px; overflow: hidden;
            clip: rect(0 0 0 0); white-space: nowrap;
        }
        .snap-filter-btn {
            display: inline-flex; align-items: center; gap: 5px; min-height: 40px; padding: 0 8px;
            border: 0; border-radius: 0;
            background: transparent; color: var(--text-muted); font-size: 11px; cursor: pointer;
        }
        .snap-filter-btn.active { color: var(--text-main); }
        .snap-filter-btn:not(.active) { opacity: .5; }
        .snap-filter-btn:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 2px; }
        .snap-sw { width: 9px; height: 9px; flex: none; }
        .snap-sw-center { background: #818cf8; border-radius: 50%; }
        .snap-sw-vertex { background: #2dd4bf; border-radius: 2px; }
        .snap-sw-edge { background: #f59e0b; clip-path: polygon(50% 0, 100% 100%, 0 100%); }

        /* Ticket 02 — Exceptions tri-state legend. Mirrors snap-filter-hud's own corner/style
           convention (D-02): editor-only HUD, absolute bottom strip, outer wrapper stays
           pointer-events:none so it never intercepts clicks meant for the canvas beneath it —
           unlike snap-filter-hud there are no interactive controls here, so nothing re-opts in. */
        .exceptions-legend {
            /* Stacks directly above the snap-filter-hud strip (its own height is
               min-height:40px + 8px bottom offset) rather than overlapping it — both
               stay visible together in Exceptions mode without collision. */
            position: absolute; left: 0; right: 0; bottom: 48px; z-index: 9;
            display: flex; justify-content: center; gap: 14px;
            padding: 0; pointer-events: none;
            border: 0; border-radius: 0;
            background: transparent; box-shadow: none;
        }
        .exceptions-legend[hidden] { display: none; }
        .exceptions-legend-item {
            display: inline-flex; align-items: center; gap: 5px;
            color: var(--text-muted); font-size: 11px; white-space: nowrap;
        }
        .exceptions-legend-sw { width: 11px; height: 11px; flex: none; border-radius: 2px; }
        /* Same fill treatment the renderer gives inherited/added cells (exceptionsCellFill,
           src/render/editor.js) — solid, the ACTIVE LAYER'S OWN COLOUR. syncExceptionsLegend()
           (src/app/exceptions.js) writes that colour into --exceptions-legend-fill on every
           editor rebuild. The swatches used to hardcode the editor-artwork indigo as a
           "representative sample", which made the legend describe a colour the canvas never
           painted: on an orange Layer nothing on screen matched any swatch. The fallback below
           is only for a legend rendered before any layer resolves. */
        .exceptions-legend-sw-inherited { background: var(--exceptions-legend-fill, #818cf8); }
        /* Same outline affordance exceptionsAddedMarkerSvg draws — solid var(--editor-guide)
           ring over the same fill, told apart from inherited by outline, not colour (D-01). */
        .exceptions-legend-sw-added { background: var(--exceptions-legend-fill, #818cf8); box-shadow: 0 0 0 1.5px var(--editor-guide) inset; }
        /* Same faded dashed echo exceptionsRemovedMarkerSvg draws — no fill, the Layer's own
           colour at reduced opacity. Not var(--editor-mesh): that is the token the background
           mesh itself uses, so a ghost drawn in it disappears into the empty grid. */
        .exceptions-legend-sw-removed {
            background: transparent;
            border: 1.5px dashed var(--exceptions-legend-fill, #818cf8);
            opacity: 0.7;
        }

        /* Ticket 35 / 40: "Focus" slider, sharing the snap HUD strip. A view preference only —
           see src/ui/layer-visibility.js — never part of Project geometry. */
        .layer-vis-label { color: var(--text-muted); font-size: 11px; }
        .layer-vis-slider {
            width: 120px; height: 40px; margin: 0; padding: 0;
            background: transparent; touch-action: manipulation; cursor: pointer;
        }
        .layer-vis-slider:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 2px; }

        /* Always-visible modes strip + layer-actions overflow */
        .tools-modes-strip { flex: 0 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding-top: 5px; border-top: 1px solid var(--border-color); }
        .tools-overflow { position: relative; margin-left: auto; }
        .tools-panel[data-rail="vertical"] .tools-overflow { margin-left: 0; }
        .tools-overflow-menu {
            position: absolute; right: 0; bottom: calc(100% + 4px); min-width: 152px;
            display: flex; flex-direction: column; gap: 2px; padding: 4px; z-index: 40;
            background: var(--bg-surface-2); border: 1px solid var(--border-strong);
            border-radius: 8px; box-shadow: 0 12px 30px -8px rgba(0,0,0,.7);
        }
        .tools-overflow-menu[hidden] { display: none; }
        .overflow-item {
            display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 9px;
            border: 0; border-radius: 6px; background: transparent; color: var(--text-main);
            font-size: 12px; text-align: left; cursor: pointer;
        }
        .overflow-item svg { width: 15px; height: 15px; }
        .overflow-item:hover, .overflow-item:focus-visible { background: var(--accent-soft); outline: none; }
        .overflow-danger:hover, .overflow-danger:focus-visible { background: rgba(240,85,106,.18); color: #fca5a5; }

        /* Reused control-container shims */
        .tools-context-control { min-width: 0; max-width: 100%; }
        .tools-section { min-width: 0; max-width: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }

        /* Editor snap-dot overlay (Phase 1 feedback; editor-only, never persisted/exported) */
        .snap-dot { pointer-events: none; }
        .snap-dot-center { fill: #818cf8; }
        .snap-dot-vertex { fill: #2dd4bf; }
        .snap-dot-edge { fill: #f59e0b; }
        .snap-dot-halo { fill: none; stroke-width: 1.4; }
        .snap-dot-center + .snap-dot-halo, .snap-dot-halo.halo-center { stroke: #818cf8; }
        .svg-placement-controls,
        .line-tool-controls {
            min-width: 0; display: flex; flex: 1 1 330px; flex-wrap: wrap;
            align-items: center; gap: 5px;
        }
        .svg-placement-controls[hidden],
        .line-tool-controls[hidden] { display: none; }
        .line-tool-controls > [hidden] { display: none; }
        .svg-size-target {
            max-width: 112px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
            color: var(--text-muted); font-size: 10px; font-weight: 700; letter-spacing: .03em;
        }
        .svg-size-field {
            display: inline-flex; align-items: center; gap: 3px;
            color: var(--text-muted); font-size: 11px; font-weight: 700;
        }
        .svg-size-field input {
            box-sizing: border-box; width: 54px; height: 26px; padding: 3px 5px;
            border: 1px solid var(--border-color); border-radius: 5px;
            background: var(--bg-input); color: var(--text-main); font-size: 11px;
        }
        .svg-scale-control {
            min-width: 150px; display: inline-flex; flex: 1 1 190px;
            align-items: center; gap: 5px; color: var(--text-muted); font-size: 10px;
        }
        .svg-scale-control input { min-width: 72px; flex: 1; accent-color: var(--accent); cursor: pointer; }
        .svg-scale-control output { min-width: 45px; color: var(--text-main); text-align: right; white-space: nowrap; }
        .svg-placement-controls :disabled,
        .line-tool-controls :disabled { cursor: not-allowed; opacity: .55; }
        .vector-control-card {
            display: block; flex: 0 1 auto; text-align: left;
        }
        .vector-control-grid {
            display: grid; grid-template-columns: 68px max-content; align-items: center;
            justify-content: center; column-gap: 8px; row-gap: 6px;
        }
        .vector-control-label {
            color: var(--text-muted); font-size: 11px; font-weight: 700; text-align: right;
        }
        .vector-numeric-control {
            position: relative; display: inline-grid; grid-template-columns: 62px 28px;
            align-items: stretch;
        }
        .vector-numeric-control > input {
            box-sizing: border-box; width: 62px; height: 30px; padding: 4px 7px;
            border: 1px solid var(--border-color); border-right: 0;
            border-radius: 6px 0 0 6px; outline: 0;
            background: var(--bg-input); color: var(--text-main); font-size: 12px;
        }
        .vector-numeric-control > input:focus {
            border-color: var(--border-focus); box-shadow: 0 0 0 1px var(--border-focus);
        }
        .vector-numeric-chevron {
            display: inline-flex; align-items: center; justify-content: center;
            width: 28px; min-height: 30px; padding: 0; cursor: pointer;
            border: 1px solid var(--border-color); border-radius: 0 6px 6px 0;
            background: var(--bg-input); color: var(--text-muted); font-size: 18px; line-height: 1;
        }
        .vector-numeric-chevron:hover,
        .vector-numeric-chevron[aria-expanded="true"] {
            color: var(--text-main); border-color: var(--border-strong);
            background: var(--secondary-hover);
        }
        .vector-numeric-slider {
            position: absolute; top: calc(100% + 5px); left: 0; z-index: 6100;
            box-sizing: border-box; width: 236px; min-height: 54px; padding: 7px 10px;
            display: grid; grid-template-columns: minmax(150px, 1fr) 52px;
            align-items: center; gap: 8px;
            border: 1px solid var(--border-strong); border-radius: 8px;
            background: var(--bg-panel, #1e1e28); box-shadow: 0 10px 28px rgba(0,0,0,.42);
        }
        .vector-numeric-slider[hidden] { display: none; }
        .vector-numeric-slider input[type="range"] {
            width: 100%; min-width: 0; height: 38px; margin: 0;
            accent-color: var(--accent); cursor: pointer; touch-action: pan-y;
        }
        .vector-numeric-slider output {
            color: var(--text-main); font-size: 11px; text-align: right; white-space: nowrap;
        }
        /* RING-01: the same numeric control inside the params bar. Two things differ there:
           `.params-field input[type="text"]` is more specific than the control's own width
           rule, and `.params-bar` is an `overflow-x: auto` scroll container, which clips an
           absolutely positioned dropdown. The panel is therefore taken out to the viewport
           and placed by placeParamsBarSlider() in src/ui/params-panel.js. */
        .params-field .params-numeric-control > input[type="text"] {
            width: 62px; padding: 4px 7px; font-size: 12px; border-radius: 6px 0 0 6px; border-right: 0;
        }
        .params-numeric-control > .vector-numeric-slider { position: fixed; top: 0; left: 0; }
        .vector-line-finish {
            display: flex; margin: 8px auto 0;
        }
        .vector-line-finish[hidden] { display: none; }
        /* D25: per-layer ⋯ kebab menu (floated to body, positioned at the button). */
        .layer-kebab-menu {
            position: fixed; z-index: 6000; min-width: 148px; padding: 4px;
            background: var(--bg-panel, #1e1e28); border: 1px solid var(--border-strong, #3a3a46);
            border-radius: 8px; box-shadow: 0 10px 30px rgba(0,0,0,0.4); display: flex; flex-direction: column; gap: 1px;
        }
        .layer-kebab-item {
            display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 9px; cursor: pointer;
            border: none; border-radius: 5px; background: transparent; color: var(--text-main, #e6e6ee);
            font-size: 12px; text-align: left;
        }
        .layer-kebab-item:hover:not(:disabled), .layer-kebab-item:focus-visible { background: var(--secondary-hover, rgba(255,255,255,0.07)); outline: none; }
        .layer-kebab-item:disabled { opacity: .5; cursor: default; }
        .layer-kebab-item.layer-kebab-danger { color: var(--danger, #f87171); }
        .layer-kebab-ic { display: inline-flex; width: 15px; height: 15px; flex-shrink: 0; }
        .layer-kebab-ic svg { width: 15px; height: 15px; }
        .line-cap-field, .line-join-field { display: inline-flex; align-items: center; gap: 3px; }
        .line-cap-btn, .line-join-btn {
            display: inline-flex; align-items: center; justify-content: center;
            width: 28px; height: 26px; padding: 0; cursor: pointer;
            border: 1px solid var(--border-color); border-radius: 5px;
            background: var(--bg-input); color: var(--text-muted);
        }
        .line-cap-btn:hover, .line-join-btn:hover { color: var(--text-main); border-color: var(--border-strong); }
        .line-cap-btn.active, .line-join-btn.active { color: var(--accent-hover); border-color: var(--accent); background: var(--accent-soft); }

        .tool-mode-group { display: flex; gap: 2px; align-items: center; }
        .tool-mode-btn {
            padding: 4px 0; font-size: 13px; height: 28px; width: 34px;
            background: var(--secondary); border: 1px solid var(--border-color);
            border-radius: 5px; cursor: pointer; color: var(--text-muted);
            font-weight: 600; transition: all 0.15s;
            display: inline-flex; align-items: center; justify-content: center;
        }
        .tool-mode-btn:hover { color: var(--text-main); background: var(--secondary-hover); }
        .tool-mode-btn.active { background: rgba(255,255,255,0.12); border-color: rgba(255,255,255,0.40); color: #fff; font-weight: 700; }
        .tool-mode-btn.mirror-btn { font-size: 12px; }
        #btnHalfDiamond.active, #btnHalfV.active { background: rgba(99,102,241,0.22); border-color: var(--accent); color: var(--accent); font-weight: 700; }
        /* D32: Pattern ⟷ Exceptions rail-style toggle (icon = current mode). Ticket 35 (v49)
           widened it from a bare square to icon + visible "Mode: …" text — see
           DISCOVERABILITY_FINDINGS #1 — so it no longer relies on hover-only title text to say
           this is a mode switch rather than a view filter. */
        .mode-toggle-btn {
            display: inline-flex; align-items: center; justify-content: center; gap: 6px;
            height: 28px; padding: 0 9px; margin-right: auto; cursor: pointer; /* margin-auto: mode toggle left, layer actions right */
            border: 1px solid var(--border-color); border-radius: 6px;
            background: var(--bg-input); color: var(--text-muted);
            transition: background .12s, color .12s, border-color .12s;
        }
        .mode-toggle-btn svg { width: 16px; height: 16px; }
        /* Same small-label scale as .snap-filter-btn — no new visual language. */
        .mode-toggle-label { font-size: 11px; font-weight: 700; letter-spacing: .2px; white-space: nowrap; }
        .mode-toggle-btn:hover { color: var(--text-main); border-color: var(--border-strong); }
        .mode-toggle-btn.active { background: rgba(245,165,36,0.22); color: var(--warning); border-color: var(--warning); }
        .mode-toggle-btn:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 2px; }
        /* D38: geometry-independent Exceptions signal. It stays outside the SVG so a
           whole-piece Exceptions render cannot drift away from a CSS frame. */
        .exceptions-badge {
            position: absolute; top: 10px; left: 10px; z-index: 8; pointer-events: none;
            padding: 4px 7px; border: 1px solid var(--accent-line); border-radius: 5px;
            background: var(--accent-soft); color: var(--accent); font-size: 10px;
            font-weight: 800; letter-spacing: .7px; line-height: 1; text-transform: uppercase;
            box-shadow: var(--shadow-sm);
        }
        /* D40: editor-only viewport frame over the flat Preview surface. */
        .preview-navigator-frame {
            fill: var(--accent-soft); stroke: var(--accent); stroke-width: 1.5;
            vector-effect: non-scaling-stroke; cursor: grab;
        }
        .preview-navigator-frame:active { cursor: grabbing; }
        /* Ticket 26 — Segment-boundary tick marks in the flat Preview: ruler-style hash marks
           at each Segment's own left edge. Amber (var(--warning)) so they read as "an
           Exceptions entry point" at a glance — the same hue .mode-toggle-btn.active uses —
           and stay visually distinct from #previewNavigatorFrame's accent-blue viewport rect
           (an Exceptions-only overlay ticks are NOT) and from the Ring render's own unrelated
           physical seam marker (a different surface entirely). */
        .segment-tick-mark {
            stroke: var(--warning); stroke-width: 1.5; vector-effect: non-scaling-stroke;
            pointer-events: none;
        }
        .segment-tick-hit { fill: transparent; cursor: pointer; }
        .segment-tick:hover .segment-tick-mark, .segment-tick.active .segment-tick-mark {
            stroke-width: 3;
        }
        /* D36: while a draw/node tool is active, cells inherit the svg scope crosshair instead
           of the pointer finger their inline cursor:pointer forces (!important beats inline). */
        #editorContainer.draw-cursor svg .cell { cursor: inherit !important; }
        /* Viewport zoom keeps grid-line thickness constant: the canvas zooms via the SVG
           viewBox, so non-scaling-stroke makes every stroke a fixed screen width at any zoom
           (a no-op at 1x). */
        #mainSvgCanvas polygon, #mainSvgCanvas line, #mainSvgCanvas circle,
        #mainSvgCanvas path, #mainSvgCanvas rect { vector-effect: non-scaling-stroke; }
        /* D18 — vector-asset strokes (committed lines/circles + draft ghosts) render
           TRUE-TO-SCALE at any zoom: their thickness scales with the viewBox like Preview/
           Export, so the thickness-to-cell ratio always matches the mm ratio. Two-id
           specificity beats the blanket rule above; mesh/guides/handles keep the hairline. */
        #mainSvgCanvas .asset-stroke { vector-effect: none; }
        /* 05/D5 — a DRAWN (filled) cell is artwork like a Vector asset: its stroke scales with
           the viewBox so the loupe magnifies the user's physical-millimetre marks. The empty
           grid mesh, guides, frame and centerline stay on the blanket hairline rule (constant
           screen width). Specificity 1,1,0 beats the 1,0,1 blanket rule. */
        #mainSvgCanvas .drawn-cell { vector-effect: none; }
        /* D34 — editor-only geometric centerline hairline for vector assets (line spine, circle
           ring midline). Non-scaling so it stays a constant, thin screen width at any zoom
           (specificity 1,1,0 beats the blanket rule; covers <polyline> too). */
        #mainSvgCanvas .centerline-hairline { vector-effect: non-scaling-stroke; }

        .sel-info-bar { display: none; align-items: center; gap: 5px; padding: 2px 8px; background: rgba(245,158,11,0.1); border: 1px solid rgba(245,158,11,0.35); border-radius: 5px; font-size: 11px; color: #fcd34d; white-space: nowrap; height: 24px; }
        .sel-info-bar.visible { display: flex; }
        .sel-info-bar .sel-sep { width:1px; height:14px; background:rgba(245,158,11,0.4); margin:0 2px; }

        /* Navbar project indicator */
        /* Canvas-overlay chip in the top-left corner, mirroring the bottom-left
           snap-filter-hud's corner/style — moved out of the nav bar (v46) to free up
           space for an icon-only top bar. */
        #navProjectLabel { display:none; position:absolute; top:10px; left:10px; z-index:8; pointer-events:none; align-items:center; gap:6px; padding:4px 10px; background:var(--accent-soft); border:1px solid var(--accent-line); border-radius:6px; font-size:12px; color:var(--accent); white-space:nowrap; box-shadow: var(--shadow-sm); max-width:min(50%, 320px); overflow:hidden; text-overflow:ellipsis; }
        #navProjectLabel.visible { display:flex; }
        #navProjectLabel #navProjectName { overflow:hidden; text-overflow:ellipsis; }
        #navProjectLabel .prj-dot { width:7px; height:7px; border-radius:50%; background:var(--accent); flex-shrink:0; }
        /* Sit below the project-name chip instead of overlapping it when both show. */
        .exceptions-badge { top: 42px; }
        
        .placement-controls { display: none; align-items: center; flex-wrap: wrap; gap: 4px; }
        .placement-controls.visible { display: flex; }
        .placement-draw-btn.draw-active { background: rgba(99,102,241,0.25); border-color: var(--primary); color: #a5b0ff; }
        .placement-draw-btn.erase-active { background: rgba(239,68,68,0.18); border-color: var(--danger); color: #fca5a5; }
        
        /* Grid Shift Bar */
        .grid-shift-bar { display: flex; align-items: center; justify-content: space-between; padding: 4px 16px; background: rgba(99,102,241,0.04); border-bottom: 1px solid rgba(99,102,241,0.12); flex-shrink: 0; min-height: 38px; }
        .shift-btn { width: 26px; height: 26px; border-radius: 5px; background: var(--secondary); border: 1px solid var(--border-color); color: var(--text-muted); cursor: pointer; font-size: 10px; display: flex; align-items: center; justify-content: center; transition: all 0.15s; padding: 0; line-height: 1; }
        .shift-btn:hover { background: rgba(99,102,241,0.15); border-color: var(--accent); color: var(--accent); }
        .shift-btn:active { transform: scale(0.88); }
        
        /* Canvas controls */
        .vert-shift-btn { position: absolute; left: 50%; width: 40px; height: 14px; transform: translateX(-50%); border: none; background: transparent; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.15s; z-index: 10; padding: 0; }
        .vert-shift-btn::after { content: ''; display: block; width: 0; height: 0; border-style: solid; }
        .vert-shift-btn.vs-up { top: 0; }
        .vert-shift-btn.vs-down { bottom: 0; }
        #shiftUpBtn::after   { border-width: 0 20px 14px 20px; border-color: transparent transparent rgba(99,102,241,0.18) transparent; transition: border-color 0.15s; }
        #shiftDownBtn::after { border-width: 14px 20px 0 20px; border-color: rgba(99,102,241,0.18) transparent transparent transparent; transition: border-color 0.15s; }
        #shiftUpBtn:hover::after   { border-color: transparent transparent rgba(99,102,241,0.55) transparent; }
        #shiftDownBtn:hover::after { border-color: rgba(99,102,241,0.55) transparent transparent transparent; }
        /* Ticket 40: Ring mode with no Layer selected — visibly dimmed, but still clickable
           so the press still reaches shiftActiveLayer and explains itself via toast. */
        .vert-shift-btn.vs-blocked { opacity: 0.3; cursor: not-allowed; }

        .carousel-arrow { position: absolute; top: 50%; width: 14px; height: 40px; transform: translateY(-50%); border: none; cursor: pointer; z-index: 10; background: transparent; display: flex; align-items: center; justify-content: center; transition: background 0.15s; padding: 0; }
        .carousel-arrow::after { content: ''; display: block; width: 0; height: 0; border-style: solid; }
        .carousel-arrow.ca-left { left: 0; }
        .carousel-arrow.ca-left::after { border-width: 20px 14px 20px 0; border-color: transparent rgba(99,102,241,0.18) transparent transparent; transition: border-color 0.15s; }
        .carousel-arrow.ca-right { right: 0; }
        .carousel-arrow.ca-right::after { border-width: 20px 0 20px 14px; border-color: transparent transparent transparent rgba(99,102,241,0.18); transition: border-color 0.15s; }
        .carousel-arrow.ca-left:hover::after { border-color: transparent rgba(99,102,241,0.55) transparent transparent; }
        .carousel-arrow.ca-right:hover::after { border-color: transparent transparent transparent rgba(99,102,241,0.55); }
        
        svg polygon.cell { transition: none; }
        /* Ticket 18: the draw-affordance hover highlight says "clicking will draw", so it is
           suppressed with no Layer active — see the crosshair-cursor rule above for the same
           #editorContainer.no-layer-active gate (toggled by buildEditor). */
        #editorContainer:not(.no-layer-active) svg polygon.cell:not(.ghost-cell):hover { stroke: rgba(255,255,255,0.55) !important; stroke-width: 1.5px !important; }
        svg polygon.ghost-cell { opacity: 0.35; pointer-events: none; }
        svg polygon.placement-ghost { pointer-events: none; }
        svg polygon.cell-selected { stroke: #fbbf24 !important; stroke-width: 2.5 !important; animation: sel-pulse 1.2s ease-in-out infinite; }
        svg polygon.cell-sel-ghost { pointer-events: none; }
        @keyframes sel-pulse { 0%,100%{opacity:0.8} 50%{opacity:0.5} }
        
        /* Preview panel — sized/docked by the workspace manager (any side or floating).
           The inline SVG's own preserveAspectRatio (default xMidYMid meet) scales the
           viewBox to fit and keeps it centered, so the full frame is always visible
           regardless of the panel's shape. (object-fit is a no-op on inline <svg> —
           it's not a replaced element — hence width/height 100%.) */
        .preview-panel { display: flex; flex-direction: column; overflow: hidden; background: var(--bg-panel); min-width: 0; min-height: 0; }
        .preview-svg-wrapper { flex: 1; min-height: 0; min-width: 0; padding: 12px 16px; display: flex; align-items: center; justify-content: center; overflow: hidden; background: #ffffff; }
        .preview-svg-wrapper svg { width: 100%; height: 100%; max-width: 100%; max-height: 100%; display: block; }
        
        /* Modals */
        .sym-picker-overlay { position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,0.65); display: flex; align-items: center; justify-content: center; }
        .sym-picker-modal, .versions-modal { background: var(--bg-panel); backdrop-filter: var(--blur); -webkit-backdrop-filter: var(--blur); border: 1px solid var(--border-color); border-radius: 12px; padding: 20px; box-shadow: 0 10px 25px rgba(0,0,0,0.5); }
        .sym-picker-modal { max-width: 480px; width: 90%; max-height: 75vh; display: flex; flex-direction: column; gap: 10px; }
        .versions-modal { max-width: 640px; width: 95%; max-height: 80vh; display: flex; flex-direction: column; gap: 10px; }
        .sym-picker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 8px; overflow-y: auto; flex: 1; padding: 4px; }
        .sym-picker-item { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 6px 4px; border: 1px solid var(--border-color); border-radius: 6px; cursor: pointer; font-size: 10px; color: var(--text-muted); text-align: center; transition: border-color 0.15s, background 0.15s; }
        .sym-picker-item:hover { border-color: var(--accent); background: rgba(99,102,241,0.1); color: var(--text-main); }
        .version-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 10px 12px; border-bottom: 1px solid var(--border-color); }
        .version-row:last-child { border-bottom: none; }
        .version-preview { width: 80px; height: 36px; background: #fff; border-radius: 4px; overflow: hidden; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
        .version-preview svg { width: 100%; height: 100%; }
        .version-info { flex: 1; min-width: 120px; }
        .version-no { font-weight: 700; font-size: 13px; color: var(--text-main); }
        .version-meta { font-size: 10px; color: var(--text-muted); margin-top: 2px; }
        
        /* Projects view (legacy internal class/id names retained for compatibility) */
        .library-view { padding: 30px; overflow-y: auto; flex: 1; background: var(--bg-base); display: none; }
        .library-view.active { display: block; }
        .designer-view { display: flex; flex-direction: column; flex: 1; overflow: hidden; }
        .grid-library { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px,1fr)); gap: 20px; margin-top: 20px; }
        .projects-folder-toolbar { display:flex; align-items:center; gap:8px; margin-left:auto; }
        .project-folder-section { grid-column:1 / -1; min-width:0; }
        .project-folder-section.collapsed .project-folder-grid { display:none; }
        .project-folder-header { display:flex; align-items:center; gap:6px; min-height:38px; margin-top:4px; padding:3px 6px; border-bottom:1px solid var(--border-color); }
        .project-folder-toggle { min-width:0; flex:1; display:flex; align-items:center; gap:8px; padding:6px 8px; border:0; border-radius:6px; background:transparent; color:var(--text-main); cursor:pointer; text-align:left; }
        .project-folder-toggle:hover, .project-folder-toggle:focus-visible { background:var(--bg-surface-2); outline:2px solid var(--accent); outline-offset:-2px; }
        .project-folder-icon { color:var(--accent); font-size:13px; }
        .project-folder-name { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-weight:700; }
        .project-folder-count { color:var(--text-muted); font-size:11px; }
        .project-folder-chevron { color:var(--text-muted); font-size:15px; transition:transform .15s; }
        .project-folder-section.collapsed .project-folder-chevron { transform:rotate(-90deg); }
        .project-folder-actions { display:flex; gap:3px; }
        .project-folder-action { width:28px; height:28px; padding:0; border:1px solid transparent; border-radius:5px; background:transparent; color:var(--text-muted); cursor:pointer; }
        .project-folder-action:hover, .project-folder-action:focus-visible { border-color:var(--accent); color:var(--text-main); outline:none; }
        .project-folder-action.danger:hover, .project-folder-action.danger:focus-visible { border-color:var(--danger); color:var(--danger); }
        /* Ticket 17: a fixed card track (not minmax(..,1fr)) so card content never
           reflows as the window resizes — only the number of cards per row changes. */
        .project-folder-grid { display:grid; grid-template-columns:repeat(auto-fill,280px); gap:20px; padding-top:12px; }
        .project-folder-header.project-folder-drop-target { border-color:var(--accent); background:var(--accent-soft); }
        .project-new-category-zone { grid-column:1 / -1; display:flex; align-items:center; gap:8px; min-height:38px; margin-top:4px; padding:6px 10px; border:1px dashed var(--border-strong); border-radius:6px; color:var(--text-muted); font-size:12px; font-weight:700; transition:background .12s,border-color .12s,color .12s; }
        .project-new-category-zone.project-folder-drop-target { border-color:var(--accent); border-style:solid; background:var(--accent-soft); color:var(--text-main); }
        .project-new-category-icon { display:inline-flex; color:var(--accent); flex-shrink:0; line-height:0; }
        .project-new-category-icon svg { width:14px; height:14px; }
        .project-new-category-form { flex:1; display:flex; }
        .project-new-category-form input { flex:1; min-width:0; }
        .projects-empty-text { grid-column: 1 / -1; padding: 18px 4px; color: var(--text-muted); font-size: 13px; }
        .lib-card { width:280px; background: var(--bg-panel); border: 1px solid var(--border-color); border-radius: var(--radius); overflow: hidden; cursor: pointer; transition: transform 0.2s, border-color 0.2s; display: flex; flex-direction: column; }
        .lib-card:hover { transform: translateY(-4px); border-color: var(--accent); box-shadow: 0 10px 20px rgba(0,0,0,0.2); }
        .lib-card.lib-card-dragging { position:fixed; z-index:1000; opacity:0.9; cursor:grabbing; box-shadow:var(--shadow-lg); transition:none; pointer-events:none; }
        .lib-card-drag-spacer { visibility:hidden; }
        .lib-card-img { background: var(--bg-base); height: 120px; display: flex; align-items: center; justify-content: center; padding: 10px; border-bottom: 1px solid var(--border-color); }
        .lib-card-img svg, .lib-card-img img { max-width:100%; max-height:100%; width:100%; height:100%; object-fit:contain; }
        .lib-card-info { padding: 15px; display: flex; flex-direction: column; gap: 5px; }
        .lib-card-title-row { display:flex; justify-content:space-between; align-items:center; gap:8px; }
        .lib-card-title { min-width:0; margin: 0; font-size: 15px; font-weight: 600; color: var(--text-main); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
        .lib-card.is-renaming { transform: none; }
        .lib-card.is-editing-clickup { transform:none; }
        /* Ticket 17: the icon-only Share/Rename/Delete row occupies the position the
           per-card "Project" type badge used to hold (badge removed; the category
           header already says "Project" via context, so it was redundant). */
        .lib-card-icon-actions { display:flex; align-items:center; gap:2px; flex-shrink:0; }
        .lib-icon-btn { width:26px; height:26px; padding:0; display:flex; align-items:center; justify-content:center; border:1px solid transparent; border-radius:5px; background:transparent; color:var(--text-muted); cursor:pointer; }
        .lib-icon-btn svg { width:15px; height:15px; }
        .lib-icon-btn:hover, .lib-icon-btn:focus-visible { border-color:var(--accent); color:var(--text-main); outline:none; }
        .lib-icon-btn-danger:hover, .lib-icon-btn-danger:focus-visible { border-color:var(--danger); color:var(--danger); }
        /* Ticket 11: replaces the old "Shared" / "Shared with me" text badge — the
           existing share icon turns amber instead of adding a separate chip. */
        .lib-share-btn.is-shared { color:#f59e0b; }
        .lib-share-btn.is-shared:hover, .lib-share-btn.is-shared:focus-visible { border-color:#f59e0b; color:#f59e0b; }
        .lib-clickup-row { min-height:28px; display:flex; align-items:center; justify-content:flex-end; gap:6px; margin-top:3px; }
        .lib-clickup-slot { min-width:0; flex:1; display:flex; align-items:center; }
        .lib-clickup-link { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--accent); text-decoration:none; font:10px/1.3 monospace; }
        .lib-clickup-empty { color:var(--text-dim); font-size:10px; }
        .lib-clickup-edit { min-height:26px; padding:3px 7px; border:1px solid var(--border-color); border-radius:5px; background:transparent; color:var(--text-muted); font-size:10px; cursor:pointer; flex-shrink:0; }
        .lib-clickup-edit:hover, .lib-clickup-edit:focus-visible { color:var(--text-main); border-color:var(--accent); outline:none; }
        .lib-clickup-input { width:100%; min-width:0; height:26px; padding:3px 6px; border:1px solid var(--border-focus); border-radius:5px; background:var(--bg-input); color:var(--text-main); font:11px/1.2 monospace; }
        .lib-clickup-input.invalid { border-color:var(--danger); }
        .lib-card-date { flex-shrink:0; font-size: 10px; color: var(--text-muted); white-space:nowrap; }

        .nav-shortcuts-btn { width:30px; height:30px; padding:0; font-weight:800; font-size:14px; }
        .shortcut-overlay { position:fixed; inset:0; z-index:3000; display:flex; align-items:center; justify-content:center; padding:20px; background:rgba(4,8,16,.72); backdrop-filter:blur(4px); }
        .shortcut-overlay.hidden { display:none; }
        .shortcut-dialog { width:min(680px,100%); max-height:min(760px,calc(100vh - 40px)); display:flex; flex-direction:column; overflow:hidden; background:var(--bg-panel); border:1px solid var(--border-strong); border-radius:12px; box-shadow:var(--shadow-lg); }
        .shortcut-dialog-header { display:flex; align-items:center; gap:10px; padding:14px 16px 10px; }
        .shortcut-dialog-title { min-width:0; flex:1; margin:0; font-size:17px; }
        .shortcut-dialog-close { width:30px; height:30px; padding:0; border:0; border-radius:6px; background:transparent; color:var(--text-muted); cursor:pointer; font-size:20px; }
        .shortcut-dialog-close:hover, .shortcut-dialog-close:focus-visible { color:var(--text-main); background:var(--bg-surface-2); outline:2px solid var(--accent); }
        .shortcut-search { margin:0 16px 10px; min-height:34px; padding:6px 9px; border:1px solid var(--border-color); border-radius:7px; background:var(--bg-input); color:var(--text-main); font-size:12px; }
        .shortcut-search:focus { border-color:var(--accent); outline:none; }
        .shortcut-list { overflow:auto; padding:0 16px 16px; display:flex; flex-direction:column; gap:14px; }
        .shortcut-category { display:flex; flex-direction:column; gap:4px; }
        .shortcut-category-title { margin:0 0 2px; color:var(--text-dim); font-size:10px; font-weight:800; letter-spacing:.55px; text-transform:uppercase; }
        .shortcut-row { min-height:32px; display:grid; grid-template-columns:minmax(150px,1fr) auto; align-items:center; gap:12px; padding:5px 7px; border-radius:6px; }
        .shortcut-row:hover { background:var(--bg-surface-2); }
        .shortcut-label { min-width:0; font-size:12px; color:var(--text-main); }
        .shortcut-description { display:block; margin-top:1px; color:var(--text-dim); font-size:10px; }
        .shortcut-keys { display:flex; justify-content:flex-end; gap:3px; flex-wrap:wrap; }
        .shortcut-key { min-width:24px; padding:3px 6px; border:1px solid var(--border-strong); border-bottom-width:2px; border-radius:5px; background:var(--bg-surface); color:var(--text-muted); font:10px/1.2 monospace; text-align:center; }
        .shortcut-empty { padding:20px 4px; color:var(--text-dim); font-size:12px; text-align:center; }
        .design-rename-input {
            min-width: 0; width: 100%; padding: 5px 7px; border-radius: 5px;
            border: 1px solid var(--accent); background: var(--bg-input); color: var(--text-main);
            font: inherit; font-size: 14px; outline: 2px solid rgba(99,102,241,0.2);
        }
        .design-rename-input.invalid { border-color: var(--danger); outline-color: rgba(239,68,68,0.2); }
        /* RING-01: ring size + band width, one quiet line above the date. */
        .lib-card-ring { font-size: 12px; color: var(--text-dim); white-space: nowrap; }
        .type-badge { display: inline-block; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: bold; text-transform: uppercase; }
        .type-project { background: rgba(99,102,241,0.2); color: var(--primary); }
        .type-symbol { background: rgba(99,102,241,0.2); color: var(--accent); }
        .lib-card-share-row { min-height:0; display:flex; align-items:center; gap:6px; }
        .share-badge { display:inline-block; padding:2px 6px; border-radius:4px; font-size:10px; font-weight:bold; letter-spacing:.4px; text-transform:uppercase; }
        .share-badge-shared { background:rgba(34,197,94,0.18); color:#4ade80; }
        .share-badge-received { background:rgba(56,189,248,0.18); color:#38bdf8; }
        .share-badge-unseen { background:rgba(250,204,21,0.18); color:#facc15; }
        
        #toastMsg { position: fixed; bottom: 24px; right: 24px; background: var(--bg-surface-2); color: var(--text-main); border: 1px solid var(--border-strong); border-radius: var(--radius); padding: 12px 18px; z-index: 9999; display: none; font-size: 13.5px; font-weight: 500; box-shadow: var(--shadow-lg); pointer-events: none; max-width: 360px; }
        /* One custom tooltip, positioned by src/ui/tooltip.js, replacing native `title`
           tooltips app-wide with a much shorter, consistent show delay. */
        .etno-tooltip { position: fixed; display: none; z-index: 10000; pointer-events: none; background: var(--bg-surface-2); color: var(--text-main); border: 1px solid var(--border-strong); border-radius: var(--radius-sm); padding: 5px 9px; font-size: 11.5px; font-weight: 500; line-height: 1.35; box-shadow: var(--shadow-lg); max-width: 260px; white-space: normal; }
        /* Richer tip content (title + description) — see `data-tip-desc` in src/ui/tooltip.js. */
        .etno-tooltip-title { font-weight: 700; }
        .etno-tooltip-desc { margin-top: 3px; font-weight: 400; font-size: 11px; color: var(--text-muted); }
        /* Blocking/validation tips (e.g. a tool that needs a different layer selected first) —
           see `data-tip-warning` in src/ui/tooltip.js — read as a warning, not a neutral tip. */
        .etno-tooltip-warning { color: var(--warning); border-color: var(--warning); }
        .etno-tooltip-warning .etno-tooltip-desc { color: var(--warning); }
        #recoveryDraftPrompt { position: fixed; bottom: 24px; left: 24px; background: var(--bg-surface-2); color: var(--text-main); border: 1px solid var(--border-strong); border-radius: var(--radius); padding: 12px 16px; z-index: 9999; display: flex; flex-direction: column; gap: 10px; font-size: 13px; font-weight: 500; box-shadow: var(--shadow-lg); max-width: 320px; }
        .recovery-draft-actions { display: flex; gap: 8px; justify-content: flex-end; }
        .hidden { display: none !important; }

        /* Hosted-runtime app shell + sign-in gate (BR-05). #appShell mirrors the
           flex layout body used to give .navbar/.workspace/.library-view directly -
           src/app/auth-gate.js toggles .hidden on this and #authGate, never both. */
        #appShell { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: hidden; }
        #authGate { position: fixed; inset: 0; z-index: 2000; background: var(--bg-base); display: flex; align-items: center; justify-content: center; }
        .auth-gate-card { display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; width: 340px; max-width: 90vw; padding: 32px 28px; background: var(--bg-panel); border: 1px solid var(--border-color); border-radius: 14px; box-shadow: 0 16px 48px rgba(0,0,0,0.6); }
        .auth-gate-card h1 { margin: 0; font-size: 18px; font-weight: 700; color: var(--text-main); display: flex; align-items: center; gap: 9px; }
        .auth-gate-tagline { margin: 0; font-size: 13.5px; color: var(--text-muted); }
        .auth-gate-button { min-height: 40px; display: flex; align-items: center; justify-content: center; }
        .auth-gate-error { margin: 0; font-size: 12.5px; color: #f87171; }
        .nav-identity { display: flex; align-items: center; gap: 8px; padding-right: 8px; margin-right: 2px; border-right: 1px solid var(--border-color); }
        .nav-identity #navIdentityName { font-size: 12px; color: var(--text-muted); max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

        /* New Project modal */
        #newProjOverlay { position:fixed;inset:0;z-index:1200;background:rgba(0,0,0,0.72);display:flex;align-items:center;justify-content:center; }
        #newProjModal {
            background:var(--bg-panel);border:1px solid var(--border-color);border-radius:14px;
            padding:24px 28px;box-shadow:0 16px 48px rgba(0,0,0,0.6);
            width:420px;max-width:95vw;display:flex;flex-direction:column;gap:16px;
        }
        #newProjModal h2 { margin:0;font-size:17px;font-weight:700;color:var(--text-main);display:flex;align-items:center;gap:9px; }
        .np-field { display:flex;flex-direction:column;gap:5px; }
        .np-field label { font-size:11px;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.4px; }
        .np-field input, .np-field select, .np-field textarea {
            background:var(--bg-input);color:var(--text-main);border:1px solid var(--border-color);
            border-radius:6px;padding:7px 10px;font-size:13px;outline:none;transition:border-color .15s;
        }
        .np-field textarea { resize:vertical;font-family:inherit; }
        .np-field input:focus, .np-field select:focus, .np-field textarea:focus { border-color:var(--accent); }
        .np-params-grid { display:grid;grid-template-columns:1fr 1fr;gap:10px; }
        #npParamsRing .np-params-grid { grid-template-columns:repeat(3,minmax(0,1fr)); }
        .np-params-grid .np-field label { font-size:10px; }
        .np-section-label { font-size:10px;text-transform:uppercase;letter-spacing:0.5px;color:var(--text-muted);border-bottom:1px solid var(--border-color);padding-bottom:5px;margin-bottom:2px; }
        .np-actions { display:flex;gap:8px;justify-content:flex-end;margin-top:4px; }
        .np-type-tabs { display:flex;gap:4px; }
        .np-type-tab { padding:5px 14px;font-size:12px;border-radius:6px;border:1px solid var(--border-color);background:var(--secondary);color:var(--text-muted);cursor:pointer;font-weight:600;transition:all .15s; }
        .np-type-tab.active { background:rgba(99,102,241,0.22);border-color:var(--accent);color:var(--accent); }
        /* Projekto tipo perjungiklis */
        .proj-type-tabs { display: flex; gap: 2px; background: rgba(0,0,0,0.3); border-radius: 6px; padding: 2px; }
        .proj-type-tab { padding: 3px 10px; font-size: 11px; border-radius: 4px; border: none; background: transparent; color: var(--text-muted); cursor: pointer; transition: all 0.15s; font-weight: 500; }
        .proj-type-tab.active { background: rgba(99,102,241,0.25); color: var(--accent); font-weight: 700; }
        .proj-type-tab:hover:not(.active) { background: rgba(255,255,255,0.06); color: var(--text-main); }
