
        /* ═══════════════════════════════════════════════════════════════════════
           THEME SYSTEM — single source of truth for the main SPA.
           The app ships EXACTLY two themes: `light` (default) and `dark`, defined
           in the block below. They share every token name + the same blueprint-blue
           accent, so switching is a one-attribute DOM change (data-theme on <html>;
           browser repaints in <1ms). The admin/standalone pages mirror these exact
           values via admin-shell.css's --canvas/--paper/--ink tokens so the whole
           product reads as ONE app in both themes. Do NOT add a third theme.
           ═══════════════════════════════════════════════════════════════════════ */

        /* PR-RISK-TOKENS (2026-05-27): theme-stable risk classification.
           Same green means ON TRACK in every theme, same amber means AT
           RISK, same rose means LATE — the office's eye carries learned
           meaning across themes (light/dark/walnut/etc.). Defined on a
           plain :root so EVERY theme inherits the same hex unless it
           explicitly overrides (which no theme currently does).
           Replaces ~52 hardcoded #16a34a / #b45309 / #b8475a sites in
           .prodp-risk-pill / .schedp-* / .ipd-prog-* / .adm-pill /
           .adm-action. */
        :root {
            --risk-on-track: #16a34a;   /* green-600 — ON TRACK   */
            --risk-at-risk:  #b45309;   /* amber-700 — AT RISK    */
            --risk-late:     #b8475a;   /* rose-600  — LATE/PAST  */
        }

        /* ═══════════════════════════════════════════════════════════════════════
           THEME SYSTEM — exactly TWO themes: Light (default) + Dark.
           2026-07-18: consolidated from the prior 9-theme sprawl (forge /
           forge-light / cabforge / precision-light / walnut / dark / shop /
           test / exgf) down to one clean light/dark pair. They are true
           siblings: SAME token names, SAME blueprint-blue accent identity,
           SAME semantic status hues — only the neutral surface ramp flips.
           Switching is a one-attribute DOM change (data-theme on <html>);
           legacy saved ids are migrated to light/dark in the boot scripts
           (index.html head, admin-shell.js) and in app-core.js.

           The CSS `:root` fallback (no data-theme) resolves to LIGHT — the
           same as the default theme — so there is never a flash of a
           different palette before the boot script runs.
           ═══════════════════════════════════════════════════════════════════════ */

        /* ─── LIGHT (default) — bright drafting-paper engineering canvas ───────── */
        :root, :root[data-theme="light"] {
            --bg:    #F3F5F8;   /* page ground — drafting paper                      */
            --sf:    #E9EDF2;   /* topbar / sidebar / statusbar chrome               */
            --pn:    #FFFFFF;   /* cards, panels, data containers                    */
            --pn-h:  #F0F3F7;   /* card / row hover                                  */
            --inp:   #FFFFFF;   /* form-input background                             */
            --bdr:   #D9DFE7;   /* default hairline border                          */
            --bdr-h: #AAB3C0;   /* hover / focus / active border                    */
            --acc:   #2563EB;   /* blueprint blue — CTA, selection, focus (AA on --pn) */
            --acc2:  #1D4FD8;   /* accent hover — deeper blue                        */
            --acc-ink: #FFFFFF; /* ink on the accent fill                           */
            --txt:   #1A222E;   /* primary text — ~13:1 on --bg (AAA)               */
            --dim:   #5A6573;   /* secondary text / labels — ~5.4:1 (AA)            */
            --muted: #8C95A0;   /* placeholders, disabled, em-dash empties          */
            --white: #0D1118;   /* highest-emphasis ink (darkest token in light)    */
            --ink:   var(--white); /* body-text ink token — darkest for legibility  */
            --ok:    #0E9D6E;   --ok-ink:   #FFFFFF;   /* success / on-track green   */
            --warn:  #C77700;   --warn-ink: #FFFFFF;   /* at-risk / low-stock amber  */
            --no:    #D33A4B;   --no-ink:   #FFFFFF;   /* late / danger / delete rose */
            --lime:  #0E9D6E;   --lime-ink: #FFFFFF;   /* status-complete (=--ok)     */
        }

        /* ─── DARK — near-black engineering canvas, SAME blueprint-blue accent ─── */
        :root[data-theme="dark"] {
            --bg:    #000000;   /* page ground — true black (AMOLED)                 */
            --sf:    #000000;   /* topbar / sidebar / statusbar — coplanar black     */
            --pn:    #16181C;   /* cards, panels — lifted a hair off black           */
            --pn-h:  #1E2127;   /* card / row hover — a real lift                    */
            --inp:   #202327;   /* inputs, filter chips, command bar                 */
            --bdr:   #2F3336;   /* 1px hairline — the white-outline on black         */
            --bdr-h: #3E4348;   /* hover / focus / active border                    */
            --acc:   #4C8DFF;   /* blueprint blue (lightened for dark) — same family as light */
            --acc2:  #6AA5FF;   /* accent hover — brighter blue                      */
            --acc-ink: #05070D; /* near-black ink on the bright-blue fill            */
            --txt:   #E7E9EA;   /* primary text — near-white                         */
            --dim:   #9AA3B0;   /* secondary text / labels                          */
            --muted: #6B7480;   /* placeholders, disabled, em-dash empties          */
            --white: #FFFFFF;   /* highest-emphasis headings                        */
            --ink:   var(--txt); /* body-text ink token — bright on dark surfaces    */
            --ok:    #34D399;   --ok-ink:   #06281D;   /* success / on-track green   */
            --warn:  #F0B429;   --warn-ink: #2A1E03;   /* at-risk / low-stock amber  */
            --no:    #F2566B;   --no-ink:   #2A0810;   /* late / danger / delete rose */
            --lime:  #34D399;   --lime-ink: #06281D;   /* status-complete (=--ok)     */
        }

        /* ─── Theme-stable derived tokens ───────────────────────────────────────
           Defined once on plain :root; they reference the active theme's core
           tokens (var() resolves at use-time against the winning cascade), so
           they follow light/dark automatically. This keeps older consumers
           (schedule / lifecycle pills, the SVG drafting canvas) resolving after
           the multi-theme consolidation removed the themes that used to own
           the --status-* / --canvas-* names. */
        :root {
            --status-draft:        var(--dim);
            --status-draft-ink:    var(--bg);
            --status-scheduled:    var(--warn);
            --status-scheduled-ink: var(--warn-ink);
            --status-progress:     var(--acc);
            --status-progress-ink: var(--acc-ink);
            --status-complete:     var(--ok);
            --status-complete-ink: var(--ok-ink);
            --status-alert:        var(--no);
            --status-alert-ink:    var(--no-ink);

            --canvas-viewport:       var(--bg);
            --canvas-grid-minor:     var(--pn-h);
            --canvas-grid-major:     var(--bdr);
            --canvas-model-default:  #D1D1D1;
            --canvas-select-fill:    var(--acc);
            --canvas-select-outline: var(--acc2);
            --canvas-dim-text:       var(--txt);
            --canvas-snap:           var(--acc2);
            --canvas-axis-x:         #E06B6B;
            --canvas-axis-y:         #6BC97A;
            --canvas-axis-z:         var(--acc);
        }

        *{margin:0;padding:0;box-sizing:border-box;}
        body{
            font-family:'Inter','Segoe UI',-apple-system,BlinkMacSystemFont,Roboto,sans-serif;
            font-feature-settings:'cv11','ss01','ss03';   /* Inter: cleaner 'l', single-story 'a', open '4' */
            font-variant-numeric:tabular-nums;            /* lock digit width so dimensions + counts line up */
            font-size:14px;
            font-weight:400;
            background:var(--bg); color:var(--txt); line-height:1.6;
            -webkit-font-smoothing:antialiased;
            -moz-osx-font-smoothing:grayscale;
            text-rendering:optimizeLegibility;
        }

        /* ═════════════════════════════════════════════════════════════════════
           TYPOGRAPHY — Inter type ramp.
           Scoped overrides matching the design spec:
             • Logo / brand     → SemiBold 24px
             • Page heading h1  → SemiBold 28px (drawer/login: 24px)
             • Section title h2 → Medium    20px
             • Subsection h3    → Medium    16px (was 14px — tightened)
             • Body / .txt      → Regular   14–15px
             • Small label .lbl → Medium    12px tabular
             • Buttons / nav    → Medium    14px (.bs stays 12px)
           ════════════════════════════════════════════════════════════════════ */
        h1{font-family:'Inter',inherit;font-weight:600;font-size:28px;letter-spacing:-.01em;line-height:1.25;}
        h2{font-family:'Inter',inherit;font-weight:500;font-size:20px;letter-spacing:-.005em;line-height:1.3;}
        h3{font-family:'Inter',inherit;font-weight:500;font-size:16px;letter-spacing:0;line-height:1.35;}
        button,.btn,.tab,.nav-btn{font-family:'Inter',inherit;font-weight:500;font-size:14px;letter-spacing:.1px;}
        .bs{font-size:12px;font-weight:500;}     /* small variants stay compact */
        .li-m,.dim,.sub,.cv-hint{font-weight:500;font-size:12px;letter-spacing:.1px;}
        /* Tabular figures everywhere a number is shown so columns of dims/counts align */
        .st-n,.li-m,.fg input[type="number"],.cutlist-out,#scene-hud{font-variant-numeric:tabular-nums;}
        .hidden{display:none!important;}
        a{color:var(--acc);text-decoration:none;}

        /* ---- Login ---- */
        .login-wrap{display:flex;align-items:center;justify-content:center;height:100vh;background:radial-gradient(ellipse at 50% 30%,#1a2040 0%,#12131a 70%);}
        .login-box{background:var(--pn);padding:48px;border-radius:16px;width:100%;max-width:400px;border:1px solid var(--bdr);box-shadow:0 24px 80px rgba(0,0,0,.6);}
        .login-box h1{color:var(--acc2);margin-bottom:4px;font-size:24px;letter-spacing:1px;}
        .login-box .sub{color:var(--dim);margin-bottom:32px;font-size:13px;}
        .login-box .err{color:var(--no);margin-top:12px;font-size:12px;}

        /* ---- Form ---- */
        .fg{margin-bottom:14px;}
        .fg label{display:block;margin-bottom:5px;color:var(--dim);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.8px;}
        /* PR-CUST-8 (2026-06-10) — customer-form section headers. The old
           collapsed <details> "Advanced" buried the (now live-math)
           Discount % per the operator's UX complaint; the form is flat
           sections with full-width labeled rules instead. Same visual
           vocabulary as .fg label so it reads as a heading from tablet
           distance without new tokens. */
        .cust-section-head{font-size:10px;font-weight:700;letter-spacing:1.2px;text-transform:uppercase;color:var(--dim);border-bottom:1px solid var(--bdr);padding-bottom:5px;margin:18px 0 12px;}
        .cust-section-head.cust-section-danger{color:var(--no);border-bottom-color:var(--no);}
        /* UX-DO — Door-order focus-mode polish. Per 2026 form-design
           research (NN/G + DesignStudio): label-above-field, single-
           column within a section, generous input padding, clear focus
           ring. Scoped to #pg-door so the rest of the app stays on its
           current density. Hours-at-a-time use: the operator's eye
           lands cleanly on the next required field every time. */
        #pg-door .fg input,
        #pg-door .fg select,
        #pg-door .fg textarea{
            /* A11Y-fix (2026-04-22): raised from 8px to 14px top/bottom padding.
               Computes to ~48 CSS px tap target, meeting WCAG 2.5.5 AAA (44 px
               minimum) with 4 px margin for gloved-thumb mis-fires. */
            font-size:14px;padding:14px 10px;
            border-radius:6px;border:1px solid var(--bdr);
            background:var(--inp);color:var(--txt);
            transition:border-color .12s,box-shadow .12s;
        }
        #pg-door .fg input:focus,
        #pg-door .fg select:focus,
        #pg-door .fg textarea:focus{
            outline:none;
            border-color:var(--acc2);
            box-shadow:0 0 0 3px color-mix(in srgb, var(--acc2) 15%, transparent);
        }
        #pg-door .fg input:invalid,
        #pg-door .fg input[aria-invalid="true"]{
            border-color:var(--no);
            box-shadow:0 0 0 3px rgba(255,85,85,.12);
        }
        /* Sticky validation message — follows the operator's scroll so
           a lengthy form never hides the current error. */
        #sg-validation-msg:not(:empty){
            position:sticky;bottom:0;z-index:4;
            background:var(--sf);padding:4px 0;
        }
        /* Library-source hint: small chip next to a form-field label
           telling the operator which library backs the dropdown.
           Prevents the "why are these both here?" confusion when two
           dropdowns with similar labels actually pull from different
           libraries (e.g. Panel Stock \u2192 Sheet Goods, Frame Lumber \u2192 Lumber). */
        .fg label .lib-src{display:inline-block;margin-left:8px;color:var(--dim);font-weight:500;font-size:9px;text-transform:none;letter-spacing:.2px;opacity:.75;padding:1px 6px;border:1px solid var(--bdr);border-radius:4px;vertical-align:1px;}
        /* PR-UI-18 (2026-04-27): tokenized transition + theme-flowing focus
           ring. Was `rgba(0,188,212,.15)` (hardcoded cyan glow that broke
           on light/amber themes); now uses `color-mix(in srgb, var(--acc)
           18%, transparent)` so every theme produces a 18%-saturation
           glow of its own --acc color. Same visual on Onyx; correct on
           every other theme.  */
        .fg input,.fg select,.fg textarea{width:100%;padding:9px 12px;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;color:var(--txt);font-size:13px;font-family:inherit;transition:border-color var(--dur-standard) var(--ease-out),box-shadow var(--dur-standard) var(--ease-out);}
        .fg input:focus,.fg select:focus,.fg textarea:focus{outline:none;border-color:var(--acc);box-shadow:0 0 0 3px color-mix(in srgb,var(--acc) 18%,transparent);}
        .fg textarea{resize:vertical;min-height:60px;}
        .fr{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:14px;}

        /* Primary form field — spans 2 grid columns in an .fr row and
         * gets louder label + input chrome than the default .fg. Used on
         * the single most-important field in a section (e.g. Customer /
         * Builder on the Order Info row, where everything else is
         * optional contact metadata). Routes through tokens so it adapts
         * to every theme. */
        .fg-primary { grid-column: span 2; }
        @media (max-width: 700px) {
            /* Narrow viewports — .fr auto-fit can collapse to 1 col;
             * don't force a 2-col span that would do nothing. */
            .fg-primary { grid-column: auto; }
        }
        .fg-primary label {
            color: var(--txt);
            font-size: 12px;
            font-weight: var(--fw-bold, 700);
            letter-spacing: 0.6px;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .fg-primary .fg-req {
            display: inline-block;
            padding: 2px 7px;
            background: color-mix(in srgb, var(--acc) 18%, transparent);
            color: var(--acc);
            border: 1px solid color-mix(in srgb, var(--acc) 45%, var(--bdr));
            border-radius: 999px;
            font-size: 9px;
            font-weight: var(--fw-bold, 700);
            letter-spacing: 0.08em;
            text-transform: uppercase;
            line-height: 1;
        }
        .fg-primary input {
            border-width: 1.5px;
            border-color: color-mix(in srgb, var(--acc) 30%, var(--bdr));
            font-size: 14px;
            font-weight: var(--fw-medium, 500);
        }
        .fg-primary input:hover:not(:focus) {
            border-color: color-mix(in srgb, var(--acc) 55%, var(--bdr));
        }
        /* When the compat gate marks the field as error (empty required),
         * .compat-error should still WIN over the accent tint so the
         * operator sees "hey fill me" not "yeah I'm already highlighted." */
        .fg-primary input.compat-error,
        .fg-primary input:invalid:not(:focus):not(:placeholder-shown) {
            border-color: var(--no);
        }

        /* ---- Buttons ---- */
        /* PR-UI-16 (2026-04-27): tokenized transition + tactile press scale.
           Every .btn/.ba/.bg/.bk/.br/.bw/.bs across the app inherits the
           --dur-quick + --spring-snappy timing and the 0.985 active scale.
           Consistent feel from Hub buttons → Cabinet inspector → Door studio
           → Reports modal → Shop drawings toolbar. Reduced-motion users
           get instant snap because --dur-quick is zeroed in tokens.css. */
        button,.btn{padding:9px 18px;border:none;border-radius:8px;cursor:pointer;font-size:12px;font-weight:600;transition:background var(--dur-quick) var(--ease-out),color var(--dur-quick) var(--ease-out),border-color var(--dur-quick) var(--ease-out),box-shadow var(--dur-quick) var(--ease-out),transform var(--dur-quick) var(--spring-snappy);letter-spacing:.3px;}
        button:active,.btn:active{transform:scale(0.985);}
        /* PR-FORGE-CAB-BUTTONS (2026-06-13): button family hovers were the
           last off-brand bits — a CYAN glow on .ba (flashed wrong on the blue
           forge accent) + hardcoded green/red hovers. Now all token-derived. */
        .ba{background:var(--acc);color:var(--acc-ink);}.ba:hover{background:var(--acc2);}
        .bg{background:var(--inp);color:var(--acc);border:1px solid var(--bdr);}.bg:hover{background:var(--bdr);}
        .bk{background:var(--ok);color:var(--ok-ink);}.bk:hover{background:color-mix(in srgb, var(--ok) 82%, #fff);}
        .br{background:var(--no);color:#fff;}.br:hover{background:color-mix(in srgb, var(--no) 82%, #fff);}
        .bw{background:var(--warn);color:#000;}
        .bs{padding:5px 10px;font-size:11px;border-radius:6px;}
        .bf{width:100%;}.brow{display:flex;gap:10px;margin-top:14px;flex-wrap:wrap;}

        /* ====================================================================== */
        /* PR-UI-15 (2026-04-27) — UNIVERSAL FOCUS-VISIBLE SYSTEM                  */
        /* ====================================================================== */
        /* One source of truth for keyboard-focus visibility across every page.   */
        /* Replaces the dozen+ ad-hoc :focus / :focus-visible rules that used     */
        /* hardcoded rgba(0,188,212,...) glows. Now everything routes to var(--acc).*/
        /* `:focus-visible` (not :focus) means the ring only appears on KEYBOARD   */
        /* navigation — mouse clicks don't trigger the ring, which keeps shop-   */
        /* floor tablet UX clean. Reduced-motion users get the same ring (no      */
        /* animation involved). Specificity is tight: this rule wins over the    */
        /* per-component :focus rules already in the file.                       */
        button:focus-visible,
        .btn:focus-visible,
        .bg:focus-visible,
        .ba:focus-visible,
        .bk:focus-visible,
        .br:focus-visible,
        .bw:focus-visible,
        .bs:focus-visible,
        a:focus-visible,
        [role="button"]:focus-visible,
        [role="tab"]:focus-visible,
        [role="menuitem"]:focus-visible,
        [tabindex]:not([tabindex="-1"]):focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
            box-shadow: 0 0 0 4px color-mix(in srgb, var(--acc) 18%, transparent);
        }
        /* Inputs already have border-color+box-shadow on :focus per their
           component rules. Add :focus-visible only when the existing rule
           doesn't already match — the [tabindex] selector above covers
           most cases. Forms surfaces use the per-component .fg rule. */

        /* ---- Panel ---- */
        /* PR-UI-24: panel radius 14px → 8px. .pn wraps every panel in
           the app — Hub, Cabinet, Door Studio, Settings. Tighter radius
           shifts the entire app from "consumer card app" toward QuickBooks
           density. */
        .pn{background:var(--pn);border:1px solid var(--bdr);border-radius:8px;padding:28px;margin-bottom:24px;}
        .pn h3{color:var(--white);font-size:14px;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--bdr);display:flex;align-items:center;gap:8px;}
        .pn h3 .badge{background:var(--acc);color:var(--acc-ink);padding:2px 8px;border-radius:10px;font-size:10px;font-weight:700;}

        /* ---- Stats ---- */
        .sg{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:20px;margin-bottom:32px;}
        .st{background:var(--pn);border:1px solid var(--bdr);border-radius:8px;padding:24px;text-align:center;}
        .st-n{font-size:26px;font-weight:700;color:var(--acc2);}.st-l{color:var(--dim);font-size:11px;margin-top:4px;text-transform:uppercase;letter-spacing:.5px;}

        /* ---- List ---- */
        /* PR-UI-19: list item — used in customer/project lists across pages. */
        .li{background:var(--inp);padding:14px 18px;border-radius:10px;border-left:3px solid var(--acc);display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;transition:background var(--dur-standard) var(--ease-out),transform var(--dur-quick) var(--spring-snappy);}
        .li:hover{background:var(--bdr);}.li-t{color:var(--white);font-weight:600;font-size:13px;}.li-m{color:var(--dim);font-size:11px;margin-top:2px;}

        /* ---- Pages ---- */
        .pg{display:none;flex-direction:column;height:100vh;}.pg.on{display:flex;}
        .scroll{flex:1;overflow-y:auto;padding:36px 40px;}
        /* PR-CABSTUDIO-FIT (2026-07-03): #pg-cab is display:block (shell.css:809)
           and .pg forces height:100vh, but its scroll host #app-workspace is only
           100vh-88px (56px topbar + 32px status bar). The 88px overhang let you
           scroll into a blank strip and pushed the bottom controls below the fold.
           Cap the page box to the workspace height (100%). NOT a grid restructure
           (see feedback_no_cab_editor_grid_layout_changes) — page-container height
           only; display stays block, the 3-column grid is untouched. */
        body[data-page="cab"] #pg-cab{height:100%;}

        /* ---- Tabs ---- */
        .tabs{display:flex;background:var(--sf);border-bottom:1px solid var(--bdr);padding:0 36px;gap:8px;}
        /* PR-UI-19 (2026-04-27): tokenize raw .2s. Used in Hub tabs,
           Reports modal tabs, Library sub-tabs — every page that has tabs. */
        .tab{padding:14px 22px;background:none;border:none;color:var(--dim);cursor:pointer;font-size:12px;font-weight:600;border-bottom:2px solid transparent;transition:color var(--dur-standard) var(--ease-out),border-color var(--dur-standard) var(--ease-out);letter-spacing:.3px;}
        .tab:hover{color:var(--acc);}.tab.on{color:var(--acc2);border-bottom-color:var(--acc);}
        .tc{display:none;}.tc.on{display:block;}
        /* PR-CLEAN-7 / RELOCATE-TO-CAB-DASH (2026-05-31): top-level Design
           Dashboard tab panels inside #pg-cab. Same display:none/block pattern
           as .tc — single-class selector so specificity matches the existing
           .tc rule. (Previously this rule was .jobs-tc on pg-hub Main Hub
           before the relocation — see [[feedback_verify_ui_page_target]].) */
        .cab-tc{display:none;}.cab-tc.on{display:block;}

        /* ---- Studio Home Dashboard ---- */
        /* All hardware-accelerated transforms / opacity transitions only — no layout reflow on hover */
        .qc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px;margin-bottom:22px;}
        /* PR-UI-19: quick-card — Hub home recent project tiles. */
        .qc{background:var(--pn);border:1px solid var(--bdr);border-radius:8px;padding:22px;cursor:pointer;display:flex;align-items:center;gap:16px;transition:transform var(--dur-chrome) var(--spring-snappy),border-color var(--dur-chrome) var(--ease-out),box-shadow var(--dur-chrome) var(--ease-out);will-change:transform;}
        .qc:hover{border-color:var(--bdr-h);background:var(--pn-h);} /* PR-FORGE-CAB: flat hover */
        .qc-icon{width:52px;height:52px;border-radius:12px;background:var(--inp);display:flex;align-items:center;justify-content:center;color:var(--acc);flex-shrink:0;}
        .qc-icon svg{width:28px;height:28px;}
        .qc-body h4{color:var(--white);font-size:16px;margin-bottom:4px;font-weight:600;}
        .qc-body p{color:var(--dim);font-size:12px;line-height:1.4;}
        /* ---- Studio ---- */
        .shdr{background:var(--sf);border-bottom:1px solid var(--bdr);padding:10px 24px;display:flex;justify-content:space-between;align-items:center;}
        .shdr h1{font-family:'Inter',inherit;font-weight:600;font-size:24px;color:var(--acc2);letter-spacing:-.005em;}
        .shdr .sub{color:var(--dim);font-size:12px;font-weight:500;}
        /* Door-icon header button — single-element interactive logo, GPU-composited hover */
        .logo-btn{width:42px;height:42px;border-radius:10px;background:var(--inp);border:1px solid var(--bdr);color:var(--acc);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform var(--dur-chrome) var(--spring-snappy),border-color var(--dur-chrome) var(--ease-out),color var(--dur-chrome) var(--ease-out);will-change:transform;padding:0;}
        .logo-btn svg{width:24px;height:24px;}
        .logo-btn:hover{transform:translateY(-1px);border-color:var(--acc);color:var(--acc2);}
        .logo-btn:active{transform:translateY(0);}
        /* PR-UI-24: was a 24px-radius pill with linear-gradient — the
           combination of pill shape + gradient was the strongest "child-
           like" signal in the topbar. Flattened to 6px square corners +
           solid accent, matching QuickBooks/Xero primary-button pattern. */
        .home-btn{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--acc);color:var(--acc-ink);border:none;border-radius:6px;font-weight:600;font-size:13px;letter-spacing:0;cursor:pointer;transition:transform var(--dur-chrome) var(--spring-snappy),box-shadow var(--dur-chrome) var(--ease-out),background var(--dur-chrome) var(--ease-out);will-change:transform;box-shadow:0 1px 2px rgba(0,0,0,.18);}
        .home-btn svg{width:18px;height:18px;stroke:currentColor;}
        .home-btn:hover{transform:translateY(-1px);box-shadow:0 4px 14px rgba(0,0,0,.28);filter:brightness(1.05);}
        .home-btn:active{transform:translateY(0);box-shadow:0 1px 4px rgba(0,0,0,.2);}
        .scmds{display:flex;gap:8px;align-items:center;}

        /* ---- Table ---- */
        table{width:100%;border-collapse:collapse;font-size:12px;}
        th{text-align:left;padding:9px 12px;background:var(--inp);color:var(--acc);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.5px;border-bottom:2px solid var(--bdr);}
        td{padding:9px 12px;border-bottom:1px solid rgba(46,49,80,.5);}
        /* PR-UI-21: every <tr> across every table now uses tokenized
           transition; hover background flows through theme via color-mix
           on var(--acc) instead of hardcoded cyan. */
        tr{transition:background var(--dur-chrome) var(--ease-out);cursor:pointer;}tr:hover td{background:color-mix(in srgb,var(--acc) 6%,transparent);}
        .row-active td{background:color-mix(in srgb,var(--acc) 12%,transparent);border-left:2px solid var(--acc);}

        /* ---- Messages ---- */
        .msg{padding:10px 14px;border-radius:8px;margin-bottom:10px;font-size:12px;}
        .msg-ok{background:rgba(76,175,80,.12);color:var(--ok);border:1px solid rgba(76,175,80,.3);}
        .msg-err{background:rgba(239,83,80,.12);color:var(--no);border:1px solid rgba(239,83,80,.3);}
        .msg-warn{background:rgba(255,179,0,.12);color:#ffb300;border:1px solid rgba(255,179,0,.32);}
        .msg-info{background:rgba(77,166,255,.12);color:var(--acc2,#4da6ff);border:1px solid rgba(77,166,255,.3);}

        /* ---- Modal / Side Drawer ---- */
        /* Drawer overlay: lightweight backdrop so the editor canvas stays
         * visible BEHIND open drawers. Previous 60% black wash made it
         * look like the app had crashed every time a panel opened. The
         * panel itself sits on the right with a strong shadow so it still
         * reads as foreground without darkening everything else. Click on
         * the slim backdrop area still closes the drawer. */
        .drawer-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.18);backdrop-filter:blur(1.5px);-webkit-backdrop-filter:blur(1.5px);z-index:100;display:flex;justify-content:flex-end;}
        .drawer{width:520px;max-width:90vw;height:100vh;background:var(--sf);border-left:1px solid var(--bdr);overflow-y:auto;padding:24px;box-shadow:-12px 0 50px rgba(0,0,0,.6);}
        /* PR-CLEAN-4 / NEWJOB-ISLAND (2026-05-31): centered-card overlay for
           the Jobs-page New job entry. Backdrop uses color-mix on var(--bg)
           rather than an rgba literal so the scrim respects the active
           theme per [[feedback_strict_color_tokens]]. The legacy
           .drawer-overlay above keeps its rgba literal for now (separate
           cleanup arc) but the new code follows the strict-token rule. */
        .island-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:color-mix(in srgb, var(--bg) 70%, transparent);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);z-index:120;display:flex;align-items:center;justify-content:center;padding:24px;}
        .island-card{position:relative;width:min(640px,94vw);max-height:88vh;background:var(--sf);border:1px solid var(--bdr);border-radius:14px;display:flex;flex-direction:column;box-shadow:0 30px 80px color-mix(in srgb, var(--bg) 80%, transparent), 0 0 0 1px var(--bdr);overflow:hidden;}
        /* PR-HOME-BENCH (2026-06-13): Settings floating island — wider + matches
           the .island-card chrome (radius 14, +1px border, same shadow). */
        .settings-island{position:relative;width:min(720px,94vw);max-height:88vh;overflow-y:auto;background:var(--sf);border:1px solid var(--bdr);border-radius:14px;box-shadow:0 30px 80px color-mix(in srgb, var(--bg) 80%, transparent), 0 0 0 1px var(--bdr);padding:28px 30px;}
        .set-logo-preview{width:44px;height:44px;border-radius:10px;border:1px solid var(--bdr);background:var(--inp);display:inline-flex;align-items:center;justify-content:center;overflow:hidden;flex:0 0 auto;}
        .set-logo-preview img{width:100%;height:100%;object-fit:contain;}
        .set-logo-mono{color:var(--dim);font-size:18px;}
        .wg-plan-box.wg-expanded{position:fixed;inset:24px;z-index:130;background:var(--sf);border:1px solid var(--bdr);border-radius:14px;box-shadow:0 0 0 100vmax color-mix(in srgb, var(--bg) 70%, transparent), 0 30px 80px color-mix(in srgb, var(--bg) 80%, transparent);padding:18px;overflow:auto;margin:0 !important;}
        .wg-plan-box.wg-expanded svg{max-height:calc(100vh - 150px) !important;}
        .island-close{position:absolute;top:14px;right:14px;width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;background:transparent;border:none;color:var(--dim);cursor:pointer;font-size:18px;line-height:1;border-radius:8px;transition:background var(--dur-chrome) var(--ease-out),color var(--dur-chrome) var(--ease-out);}
        .island-close:hover{background:var(--inp);color:var(--acc);}
        .island-head{padding:22px 28px 14px;border-bottom:1px solid var(--bdr);}
        .island-progress{display:flex;gap:0;list-style:none;padding:16px 28px 6px;margin:0;border-bottom:1px solid var(--bdr);background:var(--bg);}
        .island-step-dot{flex:1;display:flex;flex-direction:column;align-items:center;gap:6px;color:var(--dim);font-size:11px;font-weight:500;letter-spacing:.3px;text-transform:uppercase;position:relative;}
        .island-step-dot:not(:last-child)::after{content:"";position:absolute;top:11px;left:calc(50% + 14px);right:calc(-50% + 14px);height:2px;background:var(--bdr);}
        .island-step-dot.on::after,.island-step-dot.done::after{background:var(--acc);}
        .island-dot-num{width:24px;height:24px;border-radius:50%;background:var(--inp);border:1px solid var(--bdr);display:inline-flex;align-items:center;justify-content:center;color:var(--dim);font-size:11px;font-weight:700;font-variant-numeric:tabular-nums;transition:background var(--dur-chrome) var(--ease-out),border-color var(--dur-chrome) var(--ease-out),color var(--dur-chrome) var(--ease-out);}
        .island-step-dot.on  .island-dot-num{background:var(--acc);border-color:var(--acc);color:var(--acc-ink);}
        .island-step-dot.done .island-dot-num{background:transparent;border-color:var(--acc);color:var(--acc);}
        .island-step-dot.on  .island-dot-label,.island-step-dot.done .island-dot-label{color:var(--acc2);}
        .island-body{flex:1;overflow-y:auto;padding:22px 28px;}
        .island-step{display:block;}
        .island-step[hidden]{display:none;}
        .island-field{display:flex;flex-direction:column;gap:6px;margin-bottom:14px;}
        .island-field label{color:var(--white);font-size:12px;font-weight:500;letter-spacing:.2px;}
        .island-field input,.island-field textarea,.island-field select{background:var(--inp);border:1px solid var(--bdr);border-radius:8px;padding:10px 12px;color:var(--txt);font-size:13px;font-family:inherit;outline:none;transition:border-color var(--dur-chrome) var(--ease-out),box-shadow var(--dur-chrome) var(--ease-out);}
        .island-field input:focus,.island-field textarea:focus,.island-field select:focus{border-color:var(--acc);box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 18%, transparent);}
        .island-row{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
        @media (max-width:560px){.island-row{grid-template-columns:1fr;}}
        .island-defaults-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;}
        .island-defaults-grid > div{background:var(--inp);border:1px solid var(--bdr);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:2px;}
        .island-defaults-grid .ki-l{color:var(--dim);font-size:10px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;}
        .island-defaults-grid .ki-v{color:var(--white);font-size:13px;font-weight:500;font-variant-numeric:tabular-nums;}
        .island-review{display:grid;grid-template-columns:140px 1fr;gap:8px 14px;margin:0;}
        .island-review dt{color:var(--dim);font-size:11px;font-weight:600;letter-spacing:.4px;text-transform:uppercase;align-self:center;}
        .island-review dd{margin:0;color:var(--white);font-size:13px;}
        .island-foot{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:16px 28px;border-top:1px solid var(--bdr);background:var(--bg);}
        .island-foot .ba:disabled,.island-foot .bg:disabled{opacity:.4;cursor:not-allowed;}
        /* PR-NEWJOB-1SCREEN (2026-06-17): defaults chip + collapsible "More". */
        .island-chip{width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;padding:10px 12px;color:var(--white);font-size:13px;font-family:inherit;cursor:pointer;text-align:left;transition:border-color var(--dur-chrome) var(--ease-out),background var(--dur-chrome) var(--ease-out);}
        .island-chip:hover{border-color:var(--acc);background:color-mix(in srgb, var(--acc) 6%, var(--inp));}
        .island-chip-arrow{color:var(--acc2);font-size:11px;font-weight:600;white-space:nowrap;letter-spacing:.2px;}
        .island-more-toggle{display:block;width:100%;text-align:left;background:transparent;border:none;color:var(--acc2);font-size:12px;font-weight:600;letter-spacing:.2px;padding:4px 0 2px;margin:2px 0 8px;cursor:pointer;font-family:inherit;}
        .island-more-toggle:hover{color:var(--acc);}
        #nji-more-section{border-top:1px solid var(--bdr);padding-top:12px;margin-top:2px;}
        /* UX-1a — Job Defaults tile picker for construction style.
           Three tiles side-by-side. Active tile gets amber ring + filled
           icon bg so the operator can see their commitment at a glance. */
        .jd-tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:4px;}
        /* PR-UI-19: jobs-dashboard tile — every job/project card in Hub. */
        .jd-tile{background:var(--inp);border:1px solid var(--bdr);border-radius:10px;padding:14px 10px;color:var(--txt);cursor:pointer;text-align:center;transition:transform var(--dur-quick) var(--spring-snappy),border-color var(--dur-panel) var(--ease-out),background var(--dur-panel) var(--ease-out);font-family:inherit;}
        .jd-tile:hover{border-color:var(--acc2);background:var(--pn-h);}
        .jd-tile.on{border-color:var(--acc2);background:color-mix(in srgb, var(--acc2) 8%, transparent);box-shadow:0 0 0 1px var(--acc2) inset;}
        .jd-tile .jd-tile-icon{font-size:28px;line-height:1;margin-bottom:6px;color:var(--acc2);}
        .jd-tile .jd-tile-label{color:var(--white);font-size:13px;font-weight:600;letter-spacing:.2px;}
        .jd-tile .jd-tile-sub{color:var(--dim);font-size:10px;margin-top:2px;}
        /* Inline unit chip on labels + help-icon hover tooltip. data-help
           text lives in HTML; CSS ::after positions a dark tooltip above
           the icon. Plain-text, no JS needed — keeps the tooltip honest. */
        .jd-unit{color:var(--dim);font-size:10px;font-weight:400;margin-left:4px;font-family:ui-monospace,monospace;}
        .jd-help{display:inline-block;margin-left:6px;color:var(--acc2);cursor:help;position:relative;font-size:11px;border:1px solid var(--acc2);border-radius:50%;width:14px;height:14px;line-height:12px;text-align:center;font-weight:600;}
        .jd-help:hover::after{content:attr(data-help);position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);background:#111;color:#fff;padding:6px 10px;border-radius:6px;font-size:11px;font-weight:400;white-space:normal;min-width:200px;max-width:320px;line-height:1.4;box-shadow:0 4px 12px rgba(0,0,0,.5);z-index:10;}
        .jd-help:hover::before{content:"";position:absolute;bottom:calc(100% + 1px);left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#111;z-index:10;}
        /* Conditional-visibility root: drop-into-view animation so the
           operator notices when fields appear instead of them just
           popping in silently. */
        #jd-frameframe-group{transition:opacity .15s ease,max-height .2s ease;overflow:hidden;}
        #jd-frameframe-group.jd-hidden{opacity:0;max-height:0;margin:0;pointer-events:none;}
        /* UX-1d — Cabinet Inspector override row: library-select field
           with an inheritance-state badge below. Two-tone kitchen use
           case (walnut lowers + painted uppers in one job). Industry
           convention (Cabinet Solutions, MaxCut): once overridden, the
           cabinet is isolated from that field's job default until Reset.
           Visible as an amber dot vs. a dim dot. */
        .insp-override-row{margin-bottom:10px;}
        .insp-inherit-row{display:flex;align-items:center;gap:8px;margin-top:4px;font-size:10px;line-height:1.3;}
        .insp-badge{display:inline-flex;align-items:center;padding:2px 7px;border-radius:8px;font-weight:500;letter-spacing:.2px;}
        .insp-badge.insp-inherits{color:var(--dim);background:rgba(255,255,255,.04);border:1px solid var(--bdr);}
        .insp-badge.insp-overridden{color:#1a1203;background:var(--acc2);font-weight:600;}
        .insp-reset{font-size:10px;padding:2px 8px;border-radius:4px;border:1px solid var(--bdr);background:var(--inp);color:var(--white);cursor:pointer;font-family:inherit;}
        .insp-reset:hover{background:var(--acc2);color:#1a1203;border-color:var(--acc2);}

        /* ── PR-CSS-5b (2026-05-29) — inheritance popover ───────────────
           Cascade-ladder display answering "where did this come from?"
           Backend: GET /api/projects/:p/rooms/:r/cabinets/:c/inheritance
           Spec: docs/CSS_5b_UI_SPEC.md
           Strict token compliance per [[feedback_strict_color_tokens]] —
           every color = var(--token), zero hex. */
        .insp-override-row[data-tier="cabinet"]{
            border-left:3px solid var(--acc);
            padding-left:6px;
            margin-left:-9px;
        }
        .insp-why-btn{
            font-size:10px;padding:2px 7px;border-radius:4px;
            border:1px solid var(--bdr);background:transparent;
            color:var(--dim);cursor:pointer;font-family:inherit;
            margin-left:auto;
        }
        .insp-why-btn:hover{color:var(--acc);border-color:var(--acc);}
        .inh-popover-backdrop{
            position:fixed;inset:0;background:var(--bg);opacity:0;
            transition:opacity 180ms ease;z-index:1000;pointer-events:none;
        }
        .inh-popover-backdrop[data-open="true"]{
            opacity:.68;pointer-events:auto;
        }
        .inh-popover{
            position:fixed;left:50%;bottom:0;transform:translate(-50%,100%);
            width:min(420px,calc(100vw - 32px));max-height:70vh;
            background:var(--pn);border:1px solid var(--bdr);
            border-bottom:none;border-radius:10px 10px 0 0;
            box-shadow:0 -8px 24px var(--bdr);
            transition:transform 220ms cubic-bezier(.2,.8,.2,1);
            z-index:1001;display:flex;flex-direction:column;
            font-family:inherit;
        }
        .inh-popover[data-open="true"]{transform:translate(-50%,0);}
        .inh-pop-hdr{
            padding:14px 16px 10px;
            border-bottom:1px solid var(--bdr);
            display:flex;align-items:center;justify-content:space-between;
            gap:8px;flex:0 0 auto;
        }
        .inh-pop-title{
            font-size:13px;font-weight:600;color:var(--ink);
            line-height:1.3;
        }
        .inh-pop-close{
            background:transparent;border:1px solid var(--bdr);
            color:var(--dim);width:28px;height:28px;border-radius:6px;
            font-size:16px;cursor:pointer;line-height:1;
            display:flex;align-items:center;justify-content:center;
            font-family:inherit;flex:0 0 auto;
        }
        .inh-pop-close:hover{color:var(--ink);border-color:var(--acc);}
        .inh-pop-cascade{
            list-style:none;margin:0;padding:8px 0;
            overflow-y:auto;flex:1 1 auto;
        }
        .inh-pop-row{
            display:grid;grid-template-columns:28px 80px 1fr auto;
            align-items:center;gap:10px;padding:10px 16px;
            border-left:3px solid transparent;
            font-size:12px;line-height:1.3;
        }
        .inh-pop-row.dim{color:var(--dim);}
        .inh-pop-row.active{
            border-left-color:var(--acc);
            background:var(--bg);
        }
        .inh-pop-row.active .inh-tier-name,
        .inh-pop-row.active .inh-tier-val{color:var(--ink);font-weight:600;}
        .inh-tier-num{
            width:24px;height:24px;border-radius:50%;
            border:1px solid var(--bdr);
            display:flex;align-items:center;justify-content:center;
            font-size:10px;font-weight:600;
        }
        .inh-pop-row.active .inh-tier-num{
            background:var(--acc);color:var(--bg);
            border-color:var(--acc);
        }
        .inh-tier-name{
            font-size:10px;font-weight:600;letter-spacing:.06em;
            text-transform:uppercase;
        }
        .inh-tier-val{
            font-size:12px;
            overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
        }
        .inh-set-tag{
            font-size:9px;font-weight:700;letter-spacing:.08em;
            background:var(--acc);color:var(--bg);
            padding:2px 6px;border-radius:3px;
        }
        .inh-pop-actions{
            display:flex;gap:8px;padding:12px 16px;
            border-top:1px solid var(--bdr);flex:0 0 auto;
        }
        .inh-pop-btn{
            flex:1;padding:12px 14px;border-radius:6px;
            border:1px solid var(--bdr);background:var(--pn);
            color:var(--ink);font-size:13px;font-weight:500;
            cursor:pointer;font-family:inherit;min-height:44px;
        }
        .inh-pop-btn.primary{
            background:var(--acc);color:var(--bg);border-color:var(--acc);
        }
        .inh-pop-btn:hover{border-color:var(--acc);}
        .inh-pop-btn.primary:hover{filter:brightness(1.1);}
        @media (max-width: 480px){
            .inh-popover{width:100vw;border-radius:10px 10px 0 0;}
        }
        .drawer h2{color:var(--white);font-size:18px;margin-bottom:6px;}.drawer .sub{color:var(--dim);font-size:12px;margin-bottom:20px;}
        /* PR-AUDIT-UX-P1 (2026-05-09): WCAG 2.5.5 / shop-floor 44px tap target. Pre-PR ~32px on a gloved tablet sat below the iOS Safari touch threshold; modal close was the escape hatch when an operator opened the wrong modal. */
        .drawer-close{position:absolute;top:16px;right:16px;background:none;border:none;color:var(--dim);font-size:20px;cursor:pointer;padding:12px 16px;min-width:44px;min-height:44px;}
        .drawer-close:hover{color:var(--no);}

        /* ---- Order Table ---- */
        .order-table th{font-size:10px;padding:7px 8px;}
        .order-table td{padding:7px 8px;font-size:12px;}
        .order-table input,.order-table select{padding:5px;font-size:11px;}

        /* ---- Cutlist ---- */
        /* 2026-04-23 scaling fix: pre-wrap was wrapping the 80-char-wide
           cutlist columns when the container narrowed (split mode / narrow
           viewport), making labels collide and the report look "gone".
           `pre` preserves columns; `overflow-x:auto` adds a horizontal
           scroll when the viewport can't fit the full width. Shops that
           print the cutlist still get full width on the printed page. */
        .cutlist-out{background:var(--inp);border:1px solid var(--bdr);border-radius:8px;padding:16px;font-family:'Cascadia Code','Fira Code','Courier New',monospace;font-size:11px;white-space:pre;max-height:min(80vh,720px);overflow:auto;color:var(--txt);line-height:1.5;}

        /* Door Style Builder — 2-column split with live preview */
        .ds-split{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:18px;align-items:start;}
        .ds-form{min-width:0;}
        /* Tighter vertical rhythm inside the Door Style panel so the whole batch
           setup fits on-screen without mouse travel. Targets only the form rows
           inside .ds-form to keep the rest of the app's spacing intact. */
        .ds-pn{padding:14px 18px 16px;}
        .ds-pn h3{margin-bottom:10px;}
        .ds-form .fr{margin-bottom:8px;gap:10px;}
        .ds-form .fg{margin-bottom:0;}
        .ds-form .fg label{margin-bottom:3px;font-size:10px;letter-spacing:.3px;text-transform:uppercase;}
        .ds-form .fg input,.ds-form .fg select{padding:6px 9px;font-size:12px;}
        /* Legacy .ds-preview / .ds-split rules removed 2026-04-22.
           The old Door Studio preview used a single flat-accent style on
           .ds-preview; the new drafting preview scopes under
           .ds-preview-canvas with proper weighted strokes. No remaining
           HTML carries class="ds-preview" or "ds-split" — confirmed via
           grep before deletion. */

        /* ── Frame Geometry section (Bundle 5, added 2026-04-22) ──
           Stile/rail inputs moved into Bundle 5 alongside piece entry
           per user feedback "the stile and rail widths should be with
           size entry." The section wraps the head (title + Apply Typical
           button), the guidance line (per-style defaults), and the
           4-card sr-cards grid. Tokens-only, zero hex/rgba per standing
           CSS rule. */
        .sg-frame-section {
            margin: 0 0 var(--sp-3);
            padding: var(--sp-3);
            background: color-mix(in srgb, var(--acc) 3%, var(--inp));
            border: 1px solid color-mix(in srgb, var(--bdr) 70%, transparent);
            border-radius: var(--radius-md);
        }
        .sg-frame-section-head {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: var(--sp-2);
            margin-bottom: var(--sp-1);
        }
        .sg-frame-section-title {
            font-family: var(--ff-ui);
            font-size: 11px;
            font-weight: var(--fw-semibold);
            color: var(--dim);
            letter-spacing: 0.08em;
            text-transform: uppercase;
        }
        .sg-frame-apply-typical {
            font-family: var(--ff-ui);
            font-size: 11px;
            font-weight: var(--fw-semibold);
            letter-spacing: 0.04em;
            color: var(--acc);
            background: color-mix(in srgb, var(--acc) 10%, var(--inp));
            border: 1px solid color-mix(in srgb, var(--acc) 55%, var(--bdr));
            border-radius: var(--radius-sm);
            padding: 5px 10px;
            cursor: pointer;
            transition: background var(--dur-chrome) var(--ease-out),
                        border-color var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out);
        }
        .sg-frame-apply-typical:hover {
            background: color-mix(in srgb, var(--acc) 18%, var(--inp));
            border-color: var(--acc);
            transform: translateY(-1px);
        }
        .sg-frame-apply-typical:active {
            transform: translateY(0);
            background: color-mix(in srgb, var(--acc) 22%, var(--inp));
        }
        .sg-frame-apply-typical:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }
        .sg-frame-guidance {
            display: flex;
            align-items: center;
            gap: 6px;
            font-family: var(--ff-ui);
            font-size: 12px;
            color: var(--dim);
            padding: 4px 2px;
        }
        .sg-frame-guidance svg {
            color: var(--acc);
            flex-shrink: 0;
        }
        .sg-frame-guidance #sg-frame-guidance-text {
            color: color-mix(in srgb, var(--dim) 80%, var(--txt));
        }

        /* Drawer-box size-row help text (shown only when item type = DRAWER_BOX).
           Reinforces the "finished dimensions, not opening sizes" rule so
           operators don't enter opening measurements and wait for the system
           to subtract slide clearance — that's not what this form does. */
        .sg-db-size-help {
            display: flex;
            align-items: flex-start;
            gap: 6px;
            margin-top: var(--sp-3);
            padding: var(--sp-2) var(--sp-3);
            background: color-mix(in srgb, var(--acc) 6%, var(--inp));
            border: 1px solid color-mix(in srgb, var(--acc) 35%, var(--bdr));
            border-radius: var(--radius-sm);
            font-family: var(--ff-ui);
            font-size: 12px;
            line-height: 1.45;
            color: color-mix(in srgb, var(--dim) 60%, var(--txt));
        }
        .sg-db-size-help svg {
            color: var(--acc);
            flex-shrink: 0;
            margin-top: 2px;
        }
        .sg-db-size-help strong {
            color: var(--txt);
            font-weight: var(--fw-semibold);
        }

        /* Stile/Rail width cards — compact but visually distinct from other form fields.
           The whole card is clickable (cursor:text) — clicking anywhere inside focuses
           and selects the input via srCardFocus(). These cards now live inside
           .sg-frame-section in Bundle 5 (retired Bundle 3 2026-04-22). */
        .sr-cards {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: var(--sp-2);
            margin: var(--sp-3) 0 var(--sp-2);
        }
        .sr-card {
            position: relative;
            background: linear-gradient(180deg,
                color-mix(in srgb, var(--inp) 92%, var(--bg)) 0%,
                var(--inp) 100%);
            border: 1.5px solid var(--bdr);
            border-radius: var(--radius-sm);
            padding: var(--sp-2) var(--sp-3);
            text-align: center;
            cursor: text;
            transition: border-color var(--dur-chrome) var(--ease-out),
                        background var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out);
            box-shadow: 0 1px 0 color-mix(in srgb, var(--bg) 50%, transparent) inset;
            min-height: 72px;
            display: flex;
            flex-direction: column;
            align-items: stretch;
            justify-content: flex-start;
            gap: 2px;
        }
        .sr-card:hover {
            border-color: color-mix(in srgb, var(--acc) 70%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 5%, var(--inp));
            transform: translateY(-1px);
        }
        .sr-card:focus-within {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 8%, var(--inp));
            box-shadow:
                0 0 0 1px var(--acc) inset,
                0 3px 10px color-mix(in srgb, var(--acc) 22%, transparent);
            transform: translateY(-1px);
        }
        .sr-card > input {
            background: transparent;
            border: none;
            color: var(--txt);
            font-family: var(--ff-mono);
            font-size: 17px;
            font-weight: var(--fw-semibold);
            letter-spacing: 0.01em;
            text-align: center;
            width: 100%;
            padding: 0;
            outline: none;
            cursor: text;
            /* No transition on value text per gate 12 — numeric input
               value must snap on every keystroke. */
        }
        .sr-card > input:focus {
            color: var(--acc);
        }
        .sr-label {
            color: var(--dim);
            font-family: var(--ff-ui);
            font-size: 10px;
            font-weight: var(--fw-semibold);
            letter-spacing: 0.08em;
            text-transform: uppercase;
            pointer-events: none;
        }
        /* sr-preview sits between the label and the Apply-to-all toggle.
           Mono face matches the input value above so the "parsed" read
           line visually belongs to the same number. */
        .sr-preview {
            font-family: var(--ff-mono);
            font-size: 11px;
        }
        .sr-toggle {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: 4px;
            color: var(--dim);
            font-family: var(--ff-ui);
            font-size: 9px;
            font-weight: var(--fw-medium);
            cursor: pointer;
            user-select: none;
            text-transform: uppercase;
            letter-spacing: 0.04em;
            line-height: 1;
            margin-top: auto;                 /* push to bottom of card */
            padding: 3px 4px;
            border-radius: 3px;
            transition: color var(--dur-chrome) var(--ease-out),
                        background var(--dur-chrome) var(--ease-out);
        }
        .sr-toggle:hover {
            color: var(--txt);
            background: color-mix(in srgb, var(--acc) 8%, transparent);
        }
        .sr-toggle input {
            margin: 0;
            width: 10px;
            height: 10px;
            cursor: pointer;
            accent-color: var(--acc);
        }

        /* Add Door bar — segmented pill of sizes + accent button. Grouped tight, inputs
           tinted with a subtle accent background so they pop against the form's regular fields. */
        /* Add Door bar — Bundle 5 CTA row. The last thing the operator
           touches before committing a piece. Premium, confident, unified
           with Bundle 1/2/3 picker aesthetic. Tokens only.
           Row shape: [Qty] [W"] [H"] [D" (drawer box only)] [spacer] [Add Door]
           Focus-within lifts a subtle accent halo around the whole bar
           so the operator sees "the row is active" even when focus is
           inside a 60px-wide qty field. */
        .add-door-bar {
            display: flex;
            align-items: stretch;
            flex-wrap: wrap;                  /* wraps if 4 fields + button overflow narrow panels */
            gap: 0;
            background: linear-gradient(180deg,
                color-mix(in srgb, var(--inp) 92%, var(--bg)) 0%,
                var(--inp) 100%);
            border: 1.5px solid var(--bdr);
            border-radius: var(--radius-md);
            padding: var(--sp-2);
            margin-top: var(--sp-4);
            transition: border-color var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out);
            box-shadow: 0 1px 0 color-mix(in srgb, var(--bg) 50%, transparent) inset;
        }
        .add-door-bar:focus-within {
            border-color: var(--acc);
            box-shadow:
                0 0 0 1px var(--acc) inset,
                0 3px 12px color-mix(in srgb, var(--acc) 25%, transparent);
        }
        .add-door-bar .ad-field {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            padding: var(--sp-2) var(--sp-2);   /* tighter horiz padding so 4 fields fit */
            border-right: 1px solid color-mix(in srgb, var(--bdr) 80%, transparent);
            min-width: 0;
            gap: 3px;
            flex: 0 0 auto;                       /* don't shrink — wrap instead via .add-door-bar flex-wrap */
        }
        .add-door-bar .ad-field:last-of-type {
            border-right: none;
        }
        .add-door-bar .ad-field label {
            color: var(--dim);
            font-family: var(--ff-ui);
            font-size: 10px;
            letter-spacing: 0.08em;
            margin: 0;
            font-weight: var(--fw-semibold);
            text-transform: uppercase;
        }
        .add-door-bar .ad-field input {
            background: var(--bg);
            border: 1.5px solid var(--bdr);
            color: var(--txt);
            font-family: var(--ff-mono);
            font-weight: var(--fw-semibold);
            font-size: 19px;
            letter-spacing: 0.01em;
            text-align: center;
            padding: var(--sp-2) var(--sp-3);
            border-radius: var(--radius-sm);
            outline: none;
            transition: background var(--dur-chrome) var(--ease-out),
                        border-color var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out);
            width: 92px;                  /* tightened from 112 so 4 fields + CTA fit a 480px-min panel */
            min-height: 52px;             /* tap-target friendly + prominent */
        }
        .add-door-bar .ad-field input::placeholder {
            color: color-mix(in srgb, var(--dim) 70%, transparent);
        }
        .add-door-bar .ad-field input:hover:not(:focus) {
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 3%, var(--bg));
        }
        .add-door-bar .ad-field input:focus {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 6%, var(--bg));
            color: var(--txt);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 20%, transparent);
        }
        .add-door-bar .ad-field.qty input {
            width: 60px;
        }

        /* Piece row click-to-select highlight + cutlist freshness banner */
        .piece-row{cursor:pointer;transition:background var(--dur-panel) var(--ease-out);}
        .piece-row:hover{background:color-mix(in srgb, var(--acc) 4%, transparent);}
        .piece-row-sel{background:color-mix(in srgb, var(--acc) 10%, transparent);box-shadow:inset 3px 0 0 var(--acc);}
        .piece-row-sel td:first-child{color:var(--acc);font-weight:700;}
        .cutlist-stale,.cutlist-fresh{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:6px;font-size:12px;margin-bottom:8px;}
        .cutlist-stale{background:rgba(255,180,0,.08);border:1px solid rgba(255,180,0,.4);color:#ffb84d;}
        .cutlist-fresh{background:rgba(80,200,120,.06);border:1px solid rgba(80,200,120,.3);color:#7cc78b;}
        .cutlist-stale .dot,.cutlist-fresh .dot{width:8px;height:8px;border-radius:50%;flex:none;}
        .cutlist-stale .dot{background:#ffb84d;animation:pulse 2s infinite;}
        .cutlist-fresh .dot{background:#7cc78b;}
        .cutlist-stale .ba{margin-left:auto;padding:4px 12px;}
        @keyframes pulse{0%,100%{opacity:1;}50%{opacity:.45;}}
        @keyframes csp-sp{to{transform:rotate(360deg);}}

        /* Reports split layout — when both cutlist and pricing are open they sit side by side */
        /* 2026-04-23: default to stacked reports — a shop-floor tablet
           at 1024-1366 wide can't fit a readable cutlist + pricing
           side-by-side. Split mode only kicks in at 1500px+ (wide
           desktop), and even then the cutlist keeps its 11px font so
           the 80-col table stays legible. Operators hit the cutlist
           most — give it real-estate priority. */
        .do-reports{display:block;}
        .do-reports.split{display:grid;grid-template-columns:1fr 1fr;gap:18px;align-items:start;}
        .do-reports.split>div{min-width:0;}
        @media(max-width:1500px){.do-reports.split{grid-template-columns:1fr;}}

        /* Pricing report — invoice/quote-like table */
        .pricing-table{width:100%;border-collapse:collapse;margin-top:8px;font-size:12px;}
        .pricing-table th{text-align:left;padding:8px 10px;border-bottom:1px solid var(--bdr);color:var(--dim);font-weight:500;font-size:10px;text-transform:uppercase;letter-spacing:.4px;}
        .pricing-table td{padding:8px 10px;border-bottom:1px solid rgba(255,255,255,.04);color:var(--txt);}
        .pricing-table .num{text-align:right;font-variant-numeric:tabular-nums;color:var(--white);}
        .pricing-group-hdr{background:color-mix(in srgb, var(--acc) 6%, transparent);padding:10px 12px;border-radius:6px;margin-top:14px;display:flex;justify-content:space-between;align-items:center;}
        .pricing-group-hdr .name{color:var(--white);font-weight:600;font-size:13px;}
        .pricing-group-hdr .meta{color:var(--dim);font-size:11px;}
        .pricing-group-sub{display:flex;justify-content:space-between;padding:8px 10px;border-top:2px solid var(--bdr);color:var(--white);font-weight:600;}
        .pricing-grand{margin-top:18px;padding:14px 16px;background:linear-gradient(135deg,var(--acc),var(--acc2));color:var(--bg);border-radius:8px;display:flex;justify-content:space-between;align-items:center;font-weight:700;font-size:16px;letter-spacing:.3px;}
        .pricing-grand .lbl{font-size:11px;text-transform:uppercase;letter-spacing:.6px;font-weight:600;opacity:.85;}
        .pricing-empty{color:var(--dim);padding:24px;text-align:center;font-size:12px;}

        /* Hub home — two studios side by side; each studio card and its recent-projects
           panel are now visually separate (gap between them, all four corners rounded).
           Color differentiation: Cabinet uses warm amber (--acc2), Door uses cool teal (--acc).
           Both colors come from theme variables so they re-skin with every theme. */
        .studios-split{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-bottom:24px;align-items:start;}
        .studio-col{display:flex;flex-direction:column;gap:14px;}
        /* PR-UI-19: tokenize .15s ease cluster. Hub home — Cabinet/Door Studio cards. */
        .studio-card{background:var(--pn);border:1px solid var(--bdr);border-radius:8px;padding:28px 24px;cursor:pointer;transition:border-color var(--dur-chrome) var(--ease-out),transform var(--dur-chrome) var(--spring-snappy),background var(--dur-chrome) var(--ease-out),box-shadow var(--dur-chrome) var(--ease-out);text-align:center;position:relative;overflow:hidden;}
        .studio-card::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:var(--studio-color,var(--acc));opacity:.85;}
        .studio-card:hover{border-color:var(--studio-color,var(--acc));background:var(--studio-tint,color-mix(in srgb, var(--acc) 4%, transparent));} /* PR-FORGE-CAB-BUTTONS: flat hover (no lift/shadow) */
        .studio-card .studio-img{font-size:44px;margin-bottom:12px;line-height:1;filter:drop-shadow(0 2px 8px rgba(0,0,0,.25));}
        .studio-card h4{color:var(--white);font-size:18px;margin:0 0 6px;font-weight:600;}
        .studio-card p{color:var(--dim);font-size:12px;margin:0 0 16px;line-height:1.5;}
        .studio-card .studio-cta{display:inline-block;color:var(--studio-color,var(--acc));font-weight:600;font-size:12px;letter-spacing:.3px;padding:6px 14px;border:1px solid var(--studio-color,var(--acc));border-radius:18px;transition:background var(--dur-chrome) var(--ease-out),color var(--dur-chrome) var(--ease-out);}
        .studio-card:hover .studio-cta{background:var(--studio-color,var(--acc));color:var(--bg);}
        .studio-recent{background:var(--pn);border:1px solid var(--bdr);border-radius:10px;padding:14px 18px 16px;flex:1;border-left:3px solid var(--studio-color,var(--acc));}
        .studio-recent .recent-hdr{color:var(--studio-color,var(--dim));font-size:10px;text-transform:uppercase;letter-spacing:.5px;margin-bottom:10px;font-weight:700;}
        .studio-recent .li{padding:8px 10px;}
        .studio-recent .li-t{font-size:13px;}
        .studio-recent .li-m{font-size:11px;}
        .studio-recent .empty{color:var(--dim);font-size:11px;padding:8px 10px;font-style:italic;}
        /* Studio-specific color tokens — set on the column so both card AND recent panel inherit */
        .studio-col.col-cab{--studio-color:var(--acc2);--studio-tint:color-mix(in srgb, var(--acc2) 6%, transparent);}
        .studio-col.col-door{--studio-color:var(--acc);--studio-tint:color-mix(in srgb, var(--acc) 6%, transparent);}
        @media(max-width:1000px){.studios-split{grid-template-columns:1fr;}}

        /* Cabinet Studio — hub header with New Job action on the right */
        .cab-hub-head{display:flex;justify-content:space-between;align-items:flex-end;gap:16px;padding:6px 0;}
        /* PR-LAYOUT-JOBNAME (2026-07-29): the Job Hub title (#cab-job-name) sits in a
           nested flex next to the "← Jobs" back button. Without min-width:0 + nowrap +
           ellipsis it wraps word-by-word into a tall vertical column ("job name down the
           side") at laptop widths, where the right-hand action buttons squeeze the title.
           These rules truncate it to one line instead; min-width:0 lets the flex item
           shrink below its content width so the ellipsis engages. Applies to every page
           that reuses .cab-hub-head. The inline <div style="…flex…"> wrapper gets
           min-width:0 in index.html so the shrink propagates to the h2. */
        .cab-hub-head h2 { min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
        /* Orders list header copy (2026-04-22 polish) */
        .hub-head-copy { min-width: 0; flex: 1; }
        .hub-head-copy h2 {
            margin: 0 0 4px;
            color: var(--txt);
            font-family: var(--ff-ui);
            font-size: var(--fs-xl);
            font-weight: var(--fw-semibold);
            letter-spacing: -0.005em;
            line-height: 1.2;
        }
        .hub-head-copy p {
            margin: 0;
            color: var(--dim);
            font-family: var(--ff-ui);
            font-size: var(--fs-sm);
            line-height: 1.5;
            max-width: 52ch;
        }
        /* Bulk checkbox label in the filter bar */
        .fb-bulk-toggle {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            color: var(--dim);
            font-family: var(--ff-ui);
            font-size: 12px;
            cursor: pointer;
            padding: 4px 6px;
            border-radius: 4px;
            transition: color var(--dur-chrome) var(--ease-out),
                        background var(--dur-chrome) var(--ease-out);
        }
        .fb-bulk-toggle:hover {
            color: var(--txt);
            background: color-mix(in srgb, var(--acc) 8%, transparent);
        }
        .fb-bulk-toggle input {
            cursor: pointer;
            accent-color: var(--acc);
        }
        /* Report tiles — tablet-friendly big touch targets on the Job
           Reports grid. High contrast, chunky, and hover-glow for the
           pointer-using operator. `.on` is the active/selected report. */
        /* PR-UI-19: report tile — Reports modal grid. Faster transform per
           original spec (was .08s); kept tight for tactile click-feel. */
        /* PR-CLEAN-9 / TILE-GRID-REGROUP (2026-05-31): 12 report tiles
           organized into 4 named categories. Section title sits above
           each sub-grid; sub-grid keeps the existing .rep-tile markup +
           CSS unchanged so all hover/active/on states still work. */
        /* PR-REPORTS-POLISH (2026-06-14): report tiles rebuilt as left-aligned
           cards — an accent icon chip + a bold label + a one-line description —
           so the grid reads as a scannable menu instead of a wall of unlabeled
           icons. Wider min cell to fit the description; the icon, label, and
           desc share the .rt-text column. Markup: .rep-tile > .rt-icon + .rt-text(.rt-label + .rt-desc). */
        #cab-job-report-tiles{display:flex;flex-direction:column;gap:var(--sp-4);margin-bottom:14px;}
        .rep-tile-section{display:flex;flex-direction:column;gap:var(--sp-2);}
        .rep-tile-section-title{margin:0;font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:var(--dim);}
        .rep-tile-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(208px,1fr));gap:10px;}
        .rep-tile{display:flex;flex-direction:row;align-items:center;gap:12px;text-align:left;padding:13px 14px;background:var(--pn);border:1px solid var(--bdr);border-radius:12px;cursor:pointer;transition:background var(--dur-panel) var(--ease-out),border-color var(--dur-panel) var(--ease-out),box-shadow var(--dur-panel) var(--ease-out),transform var(--dur-quick) var(--spring-snappy);min-height:64px;color:var(--txt);font-family:inherit;}
        .rep-tile:hover{background:color-mix(in srgb, var(--acc) 6%, var(--pn));border-color:color-mix(in srgb, var(--acc) 55%, var(--bdr));transform:translateY(-1px);box-shadow:0 6px 18px rgba(0,0,0,.14);}
        .rep-tile:active{transform:translateY(0);box-shadow:none;}
        .rep-tile.on{background:color-mix(in srgb, var(--acc) 11%, var(--pn));border-color:var(--acc);}
        /* icon chip — tinted square so the accent reads at a glance even on the
           light theme. PR-UI-28: inline SVG (currentColor) renders identically
           cross-platform (no emoji font drift). */
        .rep-tile .rt-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:10px;background:color-mix(in srgb, var(--acc) 13%, transparent);color:var(--acc);}
        .rep-tile .rt-icon svg{width:20px;height:20px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round;}
        .rep-tile.on .rt-icon{background:color-mix(in srgb, var(--acc) 22%, transparent);}
        .rep-tile .rt-text{display:flex;flex-direction:column;gap:2px;min-width:0;}
        .rep-tile .rt-label{font-size:13px;font-weight:700;letter-spacing:.2px;line-height:1.2;color:var(--txt);}
        .rep-tile .rt-desc{font-size:11px;font-weight:400;line-height:1.3;color:var(--dim);}
        /* Report viewer body — shop-floor readable. Larger font than the
           rest of the UI, clean section dividers, sticky Print bar. */
        .jr-viewer{background:var(--sf);border:1px solid var(--bdr);border-radius:10px;overflow:hidden;}
        .jr-viewer-head{position:sticky;top:0;background:var(--sf);z-index:2;display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--bdr);gap:10px;flex-wrap:wrap;}
        .jr-viewer-title{color:var(--white);font-size:16px;font-weight:700;letter-spacing:.2px;}
        .jr-viewer-sub{color:var(--dim);font-size:12px;}
        .jr-viewer-body{padding:16px 18px 24px;font-size:13.5px;line-height:1.55;color:var(--txt);}
        .jr-section{margin-top:20px;}
        .jr-section:first-child{margin-top:4px;}
        .jr-section h4{margin:0 0 8px;color:var(--white);font-size:14px;letter-spacing:.3px;text-transform:uppercase;border-bottom:1px solid var(--bdr);padding-bottom:6px;}
        .jr-table{width:100%;border-collapse:collapse;font-size:13px;}
        .jr-table th{text-align:left;color:var(--dim);font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:.6px;padding:8px 10px;border-bottom:1px solid var(--bdr);background:var(--pn);position:sticky;top:0;}
        .jr-table td{padding:9px 10px;border-bottom:1px solid rgba(255,255,255,0.04);}
        .jr-table tr:hover td{background:rgba(255,255,255,0.02);}
        .jr-table .num{text-align:right;font-variant-numeric:tabular-nums;color:var(--white);font-weight:600;}
        .jr-table .sku{color:var(--dim);font-size:11px;font-family:'Consolas','Courier New',monospace;}
        .jr-empty{color:var(--dim);padding:24px;text-align:center;font-size:13px;}
        .jr-footer{color:var(--dim);font-size:11px;padding:10px 16px;border-top:1px solid var(--bdr);background:var(--pn);}
        /* View-mode pill: "Combined" vs. "Split". One glance, no nested menus.
           Combined = single printable doc; Split = each section prints alone.
           The active segment uses the amber accent so the operator sees at a
           glance which view is live. */
        .jr-view-toggle{display:inline-flex;background:var(--inp);border:1px solid var(--bdr);border-radius:999px;padding:2px;gap:0;}
        .jr-view-toggle button{background:transparent;border:none;color:var(--dim);font-size:12px;font-weight:600;letter-spacing:.2px;padding:5px 14px;border-radius:999px;cursor:pointer;transition:background var(--dur-panel) var(--ease-out),color var(--dur-panel) var(--ease-out);}
        .jr-view-toggle button.on{background:var(--acc2);color:#1a1203;}
        .jr-view-toggle button:not(.on):hover{color:var(--white);}
        /* Per-section Print button shows only in Split view. Positioned in the
           section's h4 row so the operator can fire a print for just that
           category (doors-only, hardware-only, etc.) without toggling modes. */
        .jr-section-print{float:right;font-size:11px;padding:3px 10px;border-radius:4px;border:1px solid var(--bdr);background:var(--inp);color:var(--white);cursor:pointer;margin-top:-3px;}
        .jr-section-print:hover{background:var(--acc2);color:#1a1203;border-color:var(--acc2);}
        /* PR-CNC-DOWNLOADS (2026-06-14): machine-file download strip on the CNC
           report — native exports (.CID / .CIX / .MPR / G-code / bore CSV) that
           the operator drops straight onto the controller. Screen-only (hidden
           in print). Each button auth-fetches the server export → Blob → save. */
        .jr-dl{margin:0 0 6px;padding:14px 16px;background:color-mix(in srgb, var(--acc) 5%, var(--pn));border:1px solid var(--bdr);border-radius:10px;}
        .jr-dl-head{font-size:11px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--dim);margin-bottom:4px;}
        .jr-dl-note{font-size:11.5px;color:var(--dim);line-height:1.4;margin-bottom:11px;}
        .jr-dl-grid{display:flex;flex-wrap:wrap;gap:8px;}
        .jr-dl-btn{display:inline-flex;align-items:center;gap:7px;padding:9px 14px;background:var(--inp);border:1px solid var(--bdr);border-radius:9px;color:var(--txt);font-family:inherit;font-size:12.5px;font-weight:600;cursor:pointer;transition:background var(--dur-panel) var(--ease-out),border-color var(--dur-panel) var(--ease-out),transform var(--dur-quick) var(--spring-snappy);}
        .jr-dl-btn:hover{background:color-mix(in srgb, var(--acc) 12%, var(--inp));border-color:var(--acc);transform:translateY(-1px);}
        .jr-dl-btn:active{transform:translateY(0);}
        .jr-dl-btn .jr-dl-ico{flex:0 0 auto;color:var(--acc);font-size:14px;line-height:1;}
        .jr-dl-btn .jr-dl-ext{color:var(--dim);font-weight:400;font-size:11px;}
        /* When printing a single section we add `jr-print-solo` to the viewer
           body and `jr-print-me` to the target section; @media print rules
           hide every other section so only the chosen one paginates. */
        /* Print — every Job Report uses this stylesheet when the operator
           hits the Print button. Strips dark theme, uses crisp black-on-
           white, keeps tables together on a page. */
        @media print{
            body *{visibility:hidden;}
            #jr-print-area,#jr-print-area *{visibility:visible;}
            #jr-print-area{position:absolute;top:0;left:0;width:100%;background:white;color:black;padding:20px;}
            #jr-print-area .jr-viewer{border:none;}
            #jr-print-area .jr-viewer-head{border-bottom:2px solid black;padding:0 0 12px 0;margin-bottom:12px;position:static;background:white;}
            #jr-print-area .jr-viewer-title{color:black;}
            #jr-print-area .jr-viewer-sub{color:#444;}
            #jr-print-area .jr-section h4{color:black;border-bottom:1px solid #666;}
            #jr-print-area .jr-table th{background:white;color:black;border-bottom:2px solid black;}
            #jr-print-area .jr-table td{color:black;border-bottom:1px solid #ccc;}
            #jr-print-area .jr-table .num{color:black;}
            #jr-print-area .jr-table .sku{color:#555;}
            #jr-print-area .jr-footer{background:white;color:#444;border-top:1px solid #888;}
            #jr-print-area .jr-print-btn,#jr-print-area .jr-close-btn{display:none;}
            #jr-print-area .jr-view-toggle,#jr-print-area .jr-section-print,#jr-print-area .jr-dl{display:none;}
            .jr-section{page-break-inside:avoid;}
            /* Single-section print: hide siblings so Print-this-section
               emits only the chosen category. `.jr-print-me` is the one
               to keep; everyone else in `.jr-print-solo` is suppressed. */
            #jr-print-area.jr-print-solo .jr-section{display:none;}
            #jr-print-area.jr-print-solo .jr-section.jr-print-me{display:block;}
            /* PR-3D-P3-svg-fix-2 (Slice 10): print-all-walls container.
               When `jr-print-active` is set, this div takes over the
               printed page (same body * { visibility: hidden } pattern
               as #jr-print-area). Each `.rep-el-print-page` child is a
               wall elevation SVG; CSS page-break-before keeps walls on
               separate sheets. Letter portrait orientation matches
               typical AWI cabinet-elevation paper convention. */
            #reports-print-all-area.jr-print-active,
            #reports-print-all-area.jr-print-active *{visibility:visible;}
            #reports-print-all-area.jr-print-active{position:absolute;top:0;left:0;width:100%;background:white;}
            #reports-print-all-area.jr-print-active .rep-el-print-page{padding:0.4in;}
            @page{size:letter portrait;margin:0;}
        }
        /* Recent-jobs cards with amber accent (matches the cabinet studio color token) */
        #cab-plist .li,#cab-job-rooms .li{transition:background .12s ease,border-color .12s ease;}
        #cab-plist .li:hover{background:color-mix(in srgb, var(--acc2) 6%, transparent);border-color:var(--acc2);}
        #cab-job-rooms .li:hover{background:color-mix(in srgb, var(--acc2) 6%, transparent);border-color:var(--acc2);cursor:pointer;}
        #cab-plist .cab-job-card{display:flex;justify-content:space-between;align-items:center;padding:12px 14px;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;margin-bottom:8px;cursor:pointer;border-left:3px solid var(--acc2);transition:transform .12s ease,border-color .12s ease,background .12s ease;}
        #cab-plist .cab-job-card:hover{background:color-mix(in srgb, var(--acc2) 5%, transparent);border-color:var(--bdr-h);}
        #cab-plist .cab-job-card .left{flex:1;min-width:0;}
        #cab-plist .cab-job-card .job-name{color:var(--white);font-weight:600;font-size:14px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}
        #cab-plist .cab-job-card .job-meta{color:var(--dim);font-size:11px;margin-top:2px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}
        #cab-plist .cab-job-card .job-stats{color:var(--acc2);font-size:11px;font-weight:600;padding:4px 10px;background:color-mix(in srgb, var(--acc2) 10%, transparent);border-radius:12px;flex:none;}

        /* ═══════════════════════════════════════════════════════════════════
           STUDIO DASHBOARD COCKPIT — table-driven per-customer command center.
           Breadcrumbs, compressed metrics ribbon, filter bar, jobs data table,
           QR modal, skeleton loader. Designed for shop-floor speed + density.
           ═══════════════════════════════════════════════════════════════════ */
        /* Breadcrumb trail (Main Hub > Customers > {Name}) */
        .crumbs{display:flex;align-items:center;gap:6px;color:var(--dim);font-size:12px;font-weight:500;letter-spacing:.2px;margin-bottom:6px;}
        .crumbs a{color:var(--dim);text-decoration:none;cursor:pointer;transition:color var(--dur-panel) var(--ease-out);}
        .crumbs a:hover{color:var(--acc);}
        .crumbs .sep{color:var(--bdr);}
        .crumbs .here{color:var(--white);}

        /* New-job CTA — vibrant teal pill, top-right of dashboard header */
        .cab-new-job-btn {
            padding: var(--sp-3) var(--sp-6);
            min-height: 48px;
            font-family: var(--ff-ui);
            font-size: var(--fs-base);
            font-weight: var(--fw-bold);
            letter-spacing: 0.03em;
            background: var(--acc);
            color: var(--acc-ink);
            border: 1.5px solid var(--acc);
            border-radius: var(--radius-sm);
            cursor: pointer;
            box-shadow: 0 3px 12px color-mix(in srgb, var(--acc) 28%, transparent);
            transition: background var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out),
                        filter var(--dur-chrome) var(--ease-out);
        }
        .cab-new-job-btn:hover {
            filter: brightness(1.06);
            transform: translateY(-1px);
            box-shadow: 0 5px 18px color-mix(in srgb, var(--acc) 40%, transparent);
        }
        .cab-new-job-btn:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--acc) 80%, transparent);
            outline-offset: 3px;
        }

        /* PR-CLEAN-8 / JOB-HEADER-REWORK (2026-05-31): action cluster on the
           Design Dashboard header. Standards chip (quick-jump shortcut) +
           ⋯ More menu (less-used actions: import / archive / templates) +
           primary New Job CTA. Every color via var(--token); backdrop
           and shadows via color-mix per [[feedback_strict_color_tokens]]. */
        .cab-std-chip{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;color:var(--dim);font-size:12px;font-weight:500;cursor:pointer;font-family:inherit;transition:color var(--dur-chrome) var(--ease-out),border-color var(--dur-chrome) var(--ease-out),background var(--dur-chrome) var(--ease-out);}
        .cab-std-chip:hover{color:var(--acc);border-color:var(--acc);background:color-mix(in srgb, var(--acc) 8%, var(--inp));}
        .cab-std-chip svg{flex-shrink:0;color:var(--acc);}
        .cab-more-btn{width:36px;height:36px;display:inline-flex;align-items:center;justify-content:center;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;color:var(--dim);cursor:pointer;font-size:16px;line-height:1;font-family:inherit;transition:color var(--dur-chrome) var(--ease-out),border-color var(--dur-chrome) var(--ease-out),background var(--dur-chrome) var(--ease-out);}
        .cab-more-btn:hover{color:var(--acc);border-color:var(--acc);background:color-mix(in srgb, var(--acc) 8%, var(--inp));}
        .cab-more-btn[aria-expanded="true"]{color:var(--acc);border-color:var(--acc);}
        .cab-more-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:220px;background:var(--sf);border:1px solid var(--bdr);border-radius:10px;box-shadow:0 12px 36px color-mix(in srgb, var(--bg) 70%, transparent);padding:6px;z-index:50;display:flex;flex-direction:column;gap:2px;}
        .cab-more-menu[hidden]{display:none;}
        .cab-more-item{display:flex;align-items:center;gap:10px;padding:9px 12px;background:transparent;border:none;border-radius:6px;color:var(--txt);font-size:13px;font-weight:500;font-family:inherit;cursor:pointer;text-align:left;transition:background var(--dur-chrome) var(--ease-out),color var(--dur-chrome) var(--ease-out);}
        .cab-more-item:hover{background:var(--inp);color:var(--acc);}
        .cab-more-icon{flex-shrink:0;font-size:14px;width:18px;text-align:center;}

        /* Account-type chip next to customer name */
        .acct-chip{display:inline-flex;align-items:center;gap:6px;padding:3px 9px;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;font-size:11px;color:var(--dim);font-weight:500;margin-left:8px;}
        .acct-chip .dot{width:6px;height:6px;border-radius:50%;background:var(--ok);}

        /* Compressed metrics ribbon — single horizontal row, clickable cells */
        .metrics-ribbon{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:1px;background:var(--bdr);border:1px solid var(--bdr);border-radius:12px;overflow:hidden;margin:14px 0;}
        .metric-cell{background:var(--pn);padding:12px 16px;cursor:pointer;display:flex;flex-direction:column;gap:2px;transition:background var(--dur-panel) var(--ease-out);position:relative;}
        .metric-cell:hover{background:var(--inp);}
        .metric-cell.active{background:color-mix(in srgb, var(--acc) 8%, transparent);box-shadow:inset 0 -2px 0 var(--acc);}
        .metric-cell .mv{font-size:24px;font-weight:600;color:var(--white);font-variant-numeric:tabular-nums;line-height:1.1;}
        .metric-cell .ml{font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:var(--dim);font-weight:600;}
        .metric-cell .mctx{font-size:11px;color:var(--warn);font-weight:500;margin-top:2px;}
        .metric-cell .mctx.muted{color:var(--dim);}
        .metric-cell .mctx.good{color:var(--ok);}
        .metric-cell .mi{position:absolute;top:10px;right:10px;width:14px;height:14px;color:var(--dim);opacity:.5;}

        /* Search + filter bar above the jobs table */
        .filter-bar{display:flex;gap:10px;align-items:center;background:var(--pn);border:1px solid var(--bdr);border-radius:10px;padding:10px 12px;margin-bottom:14px;flex-wrap:wrap;}
        .filter-bar .fb-search{flex:1;min-width:200px;display:flex;align-items:center;gap:8px;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;padding:6px 10px;}
        .filter-bar .fb-search input{flex:1;background:transparent;border:none;outline:none;color:var(--txt);font-family:inherit;font-size:13px;}
        .filter-bar .fb-search input::placeholder{color:var(--dim);}
        .filter-bar .fb-search svg{width:14px;height:14px;color:var(--dim);}
        .filter-bar select{background:var(--inp);border:1px solid var(--bdr);color:var(--txt);font-family:inherit;font-size:12px;padding:7px 10px;border-radius:8px;cursor:pointer;outline:none;}
        .filter-bar select:focus{border-color:var(--acc);}
        .filter-bar .fb-label{font-size:11px;color:var(--dim);text-transform:uppercase;letter-spacing:.5px;font-weight:600;}

        /* Jobs data table — compact, scannable, hover-row accent */
        .jobs-table{width:100%;border-collapse:collapse;font-size:13px;table-layout:fixed;}
        .jobs-table thead th{text-align:left;color:var(--dim);font-size:10px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;padding:8px 10px;border-bottom:1px solid var(--bdr);background:var(--pn);position:sticky;top:0;z-index:1;cursor:pointer;user-select:none;}
        .jobs-table thead th .sort-ind{color:var(--acc);font-size:10px;margin-left:4px;}
        .jobs-table tbody tr{cursor:pointer;transition:background var(--dur-quick) var(--ease-out),border-color var(--dur-quick) var(--ease-out);border-left:3px solid transparent;}
        .jobs-table tbody tr:hover{background:var(--inp);border-left-color:var(--acc);}
        .jobs-table tbody td{padding:9px 10px;border-bottom:1px solid var(--bdr);color:var(--txt);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
        .jobs-table tbody tr:last-child td{border-bottom:none;}
        .jobs-table .col-name{font-weight:500;color:var(--txt);display:flex;align-items:center;gap:8px;min-width:0;}
        .jobs-table .col-name svg{width:14px;height:14px;color:var(--acc);flex-shrink:0;}
        .jobs-table .col-name .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}
        .jobs-table .col-client{color:var(--dim);font-size:12px;}
        .jobs-table .col-progress{color:var(--dim);font-size:12px;font-variant-numeric:tabular-nums;display:flex;gap:10px;align-items:center;}
        .jobs-table .col-progress .pg-item{display:inline-flex;align-items:center;gap:4px;}
        .jobs-table .col-progress svg{width:12px;height:12px;color:var(--dim);}
        .jobs-table .col-when{color:var(--dim);font-size:12px;font-variant-numeric:tabular-nums;font-family:'Inter',ui-monospace,monospace;}
        .jobs-table .col-value{color:var(--white);font-size:12px;font-variant-numeric:tabular-nums;font-weight:500;text-align:right;font-family:'Inter',ui-monospace,monospace;}
        .jobs-table .col-actions{text-align:right;white-space:nowrap;}
        /* PR-RENDER-DAY1-POLISH (2026-05-08): WCAG 2.5.5 minimum
           touch target = 44×44 CSS px. Pre-PR ic-btn was 26×26 — way
           below floor, AND fires destructive actions (delete job /
           duplicate). Bumped to 44×44. The icon SVG inside stays at
           14×14 so visual weight is unchanged; only the hit area grows. */
        .jobs-table .col-actions .ic-btn{background:transparent;border:none;color:var(--dim);width:44px;height:44px;border-radius:6px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:14px;line-height:1;transition:color var(--dur-quick) var(--ease-out),background var(--dur-quick) var(--ease-out);}
        .jobs-table .col-actions .ic-btn:hover{color:var(--acc);background:var(--bg);}
        .jobs-table .col-actions .ic-btn svg{width:14px;height:14px;}

        /* Status pills tuned for studio status set */
        .pill-st-draft{background:color-mix(in srgb, var(--acc) 12%, transparent);color:#00E5C0;}
        .pill-st-design{background:rgba(255,204,92,0.15);color:#FFCC5C;}
        .pill-st-production{background:rgba(74,144,226,0.18);color:#4A90E2;}
        .pill-st-delivered{background:rgba(170,170,170,0.15);color:#AAAAAA;}
        .pill-st-completed{background:var(--lime);color:var(--lime-ink);}
        .pill-st-archived{background:rgba(170,170,170,0.10);color:#888888;}

        /* Inline action menu (3-dot dropdown) */
        .row-menu{position:absolute;background:var(--sf);border:1px solid var(--bdr);border-radius:8px;box-shadow:0 16px 40px rgba(0,0,0,0.55);padding:4px;z-index:50;min-width:160px;}
        .row-menu button{display:block;width:100%;text-align:left;background:transparent;border:none;color:var(--txt);font-family:inherit;font-size:12px;padding:7px 12px;border-radius:6px;cursor:pointer;}
        .row-menu button:hover{background:var(--inp);color:var(--acc);}
        .row-menu button.danger:hover{background:rgba(255,77,77,0.12);color:var(--no);}

        /* Skeleton loader — same row geometry as data rows so the layout doesn't shift */
        .skel-row td{padding:9px 10px;border-bottom:1px solid var(--bdr);}
        .skel-bar{height:12px;border-radius:4px;background:linear-gradient(90deg,var(--inp) 0%,var(--bdr) 50%,var(--inp) 100%);background-size:200% 100%;animation:skel-shimmer 1.4s ease-in-out infinite;}
        @keyframes skel-shimmer{0%{background-position:200% 0;}100%{background-position:-200% 0;}}
        @keyframes lib-spin{to{transform:rotate(360deg);}}
        .skel-w-30{width:30%;}.skel-w-50{width:50%;}.skel-w-70{width:70%;}.skel-w-90{width:90%;}

        /* Empty state — illustrative icon + helpful prompt */
        .empty-state{text-align:center;padding:42px 20px;color:var(--dim);}
        .empty-state .ei{font-size:38px;opacity:.4;margin-bottom:10px;}
        .empty-state .et{color:var(--white);font-size:14px;font-weight:500;margin-bottom:4px;}
        .empty-state .es{font-size:12px;line-height:1.5;max-width:300px;margin:0 auto 14px;}

        /* QR modal */
        .qr-modal{position:fixed;inset:0;background:rgba(0,0,0,0.7);backdrop-filter:blur(4px);z-index:300;display:flex;align-items:center;justify-content:center;}
        .qr-modal.hidden{display:none;}
        .qr-modal .qr-panel{background:var(--sf);border:1px solid var(--bdr);border-radius:14px;padding:24px;max-width:340px;width:90vw;text-align:center;}
        .qr-modal h3{margin:0 0 6px;color:var(--white);font-size:16px;}
        .qr-modal .sub{color:var(--dim);font-size:12px;margin-bottom:16px;}
        .qr-modal .qr-img{background:#fff;padding:14px;border-radius:10px;display:inline-block;margin-bottom:16px;}
        .qr-modal .qr-img canvas,.qr-modal .qr-img svg{display:block;}
        .qr-modal .qr-url{font-family:ui-monospace,monospace;font-size:10px;color:var(--dim);background:var(--bg);padding:6px 10px;border-radius:6px;margin-bottom:14px;word-break:break-all;}

        /* PR-NEWROOM-REWORK (2026-07-17): the shape picker is a COMPACT wrapping STRIP of
           small tiles (a toolbar) instead of a big grid — it collapses the shapes section
           so the live PLAN CANVAS becomes the hero of the modal. The description moves to
           the tile's hover title. */
        .wall-preset-grid{display:flex;flex-wrap:wrap;gap:8px;}
        .wall-preset{flex:0 0 auto;width:100px;background:var(--inp);border:2px solid var(--bdr);border-radius:8px;padding:8px 6px;cursor:pointer;text-align:center;transition:border-color var(--dur-chrome) var(--ease-out),transform var(--dur-chrome) var(--spring-snappy),background var(--dur-chrome) var(--ease-out);}
        .wall-preset:hover{border-color:var(--acc2);background:var(--pn-h);}
        .wall-preset.sel{border-color:var(--acc2);background:color-mix(in srgb, var(--acc2) 8%, transparent);}
        .wall-preset svg{width:44px;height:34px;margin-bottom:3px;overflow:visible;}
        /* Shape-gallery thumbnails as thick architectural poché walls (match the plan). */
        .wall-preset svg [stroke-width="3"]{stroke:var(--plan-poche);stroke-width:6.5;stroke-linejoin:round;stroke-linecap:round;}
        .wall-preset.sel svg [stroke-width="3"]{stroke:var(--acc2);}
        .wall-preset .name{color:var(--white);font-size:11px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
        .wall-preset .desc{display:none;} /* → the tile's hover title now */
        /* Roomier type / fields; the plan is the hero, so shapes stay compact even in the modal. */
        .nr-card h3{font-size:14.5px;font-weight:700;margin-top:16px;}
        .nr-card p{font-size:12px;line-height:1.5;}
        .nr-card .fg > label{font-size:11.5px;letter-spacing:.3px;}
        .nr-card input[type=text],.nr-card input[type=number],.nr-card select{font-size:14.5px;padding:9px 12px;min-height:42px;}
        .nr-card .nr-preview-panel{padding:12px;}
        .nr-card .wall-preset{width:106px;padding:9px 7px;}
        .nr-card .wall-preset svg{width:48px;height:36px;}
        .nr-card .wall-preset .name{font-size:12px;}
        .nr-card .wall-preset-grid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;}
        .nr-card .wall-len-card{padding:12px 14px;}
        .nr-card .wall-len-card label{font-size:11px;}
        .nr-card .wall-len-card input{font-size:22px;}
        /* PR-NEWROOM-REWORK (2026-07-17): canvas-first — the plan is the HERO, inputs a compact left rail. */
        @media (min-width:900px){.nr-card .nr-edit-row{grid-template-columns:minmax(0,300px) minmax(0,1fr);}}
        /* Per-wall length inputs — one tile per wall in the selected preset */
        .wall-lens-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px;}
        /* PR-NEWROOM-REWORK: compact inputs LEFT, dominant live plan RIGHT (was 1fr/300px = form-first). */
        .nr-edit-row{display:grid;grid-template-columns:minmax(0,320px) minmax(0,1fr);gap:14px;align-items:start;}
        .nr-preview-panel{border:1px solid var(--bdr);border-radius:8px;padding:8px;position:sticky;top:8px;}
        /* Stack on narrow screens with the CANVAS FIRST (order:-1) — you see the room, then the inputs. */
        @media (max-width:620px){.nr-edit-row{grid-template-columns:1fr;}.nr-edit-row .nr-preview-panel{order:-1;}}
        /* PR-NEWROOM-REWORK (2026-07-17): the TWO-PANE canvas-first SHELL — a compact
           controls rail (left) + the live plan canvas as the hero (right), sticky footer.
           The modal is a flex column (header / .nr-shell / footer); .nr-shell is the grid. */
        .nr-shell{flex:1 1 auto;min-height:0;display:grid;grid-template-columns:minmax(268px,288px) minmax(0,1fr);overflow:hidden;}
        .nr-rail{overflow-y:auto;padding:16px 20px;border-right:1px solid var(--bdr);}
        .nr-rail h3{margin-top:14px;margin-bottom:6px;}
        .nr-canvas-pane{overflow:hidden;padding:14px 18px;display:flex;flex-direction:column;min-height:0;background:color-mix(in srgb, var(--bg) 55%, transparent);}
        .nr-canvas-pane .nr-preview-panel{position:static;top:auto;}       /* not sticky inside the pane */
        /* PR-NEWROOM-REWORK (2026-07-17): make the plan FILL the pane (was letterboxed to
           58vh / calc(92vh-195px) by the shared SVG string). The SVG has a fixed 440×360
           viewBox + default preserveAspectRatio="xMidYMid meet", so height:100% fills one
           axis and centers — no distortion, no math change. Scoped to the creation canvas
           so the in-room inspector's SVG (which sits beside the 3D view) is untouched. The
           wgPlanSvg wrapper div must flex to give the SVG a real height box. */
        .nr-canvas-pane #nr-preview{display:flex;flex-direction:column;min-height:0;}
        .nr-canvas-pane #nr-preview > div{flex:1 1 auto;min-height:0;}
        .nr-canvas-pane #nr-preview svg{max-height:none !important;width:100% !important;height:100% !important;}
        @media (max-width:760px){
            .nr-card .nr-shell{grid-template-columns:1fr;grid-template-rows:minmax(240px,38vh) 1fr;}
            .nr-canvas-pane{order:-1;border-bottom:1px solid var(--bdr);border-right:none;}
            .nr-rail{border-right:none;}
        }
        .wall-len-card{background:var(--inp);border:1px solid var(--bdr);border-radius:6px;padding:8px 10px;border-left:3px solid var(--acc2);}
        .wall-len-card label{display:block;color:var(--dim);font-size:10px;text-transform:uppercase;letter-spacing:.4px;margin-bottom:3px;font-weight:600;}
        .wall-len-card input{width:100%;padding:5px 7px;font-size:13px;font-weight:600;background:transparent;border:1px solid transparent;color:var(--white);border-radius:4px;text-align:center;}
        .wall-len-card input:focus{background:color-mix(in srgb, var(--acc2) 8%, transparent);border-color:var(--acc2);outline:none;}
        .wall-len-card .unit{color:var(--dim);font-size:10px;margin-left:3px;}
        /* PR-ROOM-DESIGNER-PRO (2026-07-16): architect's-drawing palette for the plan
           canvas — theme-INDEPENDENT "paper" so the plan reads the same in every app
           theme. Grounded in ISO 128 line-weight hierarchy + architectural poché. */
        :root{
          --plan-paper:#F6F5F1; --plan-floor:#FBFAF7; --plan-grid:#DCE0E4; --plan-grid-maj:#C4CBD2;
          --plan-poche:#6E7378; --plan-ink:#1A1D20; --plan-face-int:#0E9F8E;
          --plan-dim:#4A4F55; --plan-dim-text:#20262C; --plan-dim-edit:#C0392B;
          --plan-door:#B45309; --plan-glass:#2E86AB; --plan-slope:#D98A1F;
          --plan-handle:#1A1D20; --plan-handle-core:#FFFFFF; --plan-sel:#E0A73A; --plan-snap:#22C58B;
        }
        /* PR-ROOM-DESIGNER (2026-07-16): tap-to-edit dimension chips on the plan
           canvas + the inline numeric editor that opens over a tapped chip. */
        .wg-dim rect{transition:fill-opacity var(--dur-chrome) var(--ease-out),stroke-opacity var(--dur-chrome) var(--ease-out);}
        .wg-dim:hover rect{fill-opacity:0.96;stroke-opacity:0.95;}
        .wg-dim:hover text{fill:var(--acc);}
        .wg-ang circle{transition:stroke var(--dur-chrome) var(--ease-out);}
        .wg-ang:hover circle{stroke:var(--acc);}
        .wg-ang:hover text{fill:var(--acc);}
        /* Right-click context menu on the plan canvas */
        .wg-ctx{position:absolute;z-index:150;min-width:170px;background:var(--sf);border:1px solid var(--bdr);border-radius:8px;box-shadow:0 8px 26px rgba(0,0,0,.4);padding:5px;overflow:hidden;}
        .wg-ctx button{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:transparent;border:none;color:var(--pn);font-size:13px;font-family:inherit;padding:8px 10px;border-radius:6px;cursor:pointer;}
        .wg-ctx button:hover{background:var(--inp);color:var(--acc);}
        .wg-ctx .wg-ctx-danger:hover{color:var(--no);}
        .wg-ctx-sep{height:1px;background:var(--bdr);margin:4px 6px;}
        .wg-dim-editor{position:absolute;z-index:140;width:72px;padding:3px 5px;font-size:13px;font-weight:700;text-align:center;color:var(--white);background:var(--sf);border:1.5px solid var(--acc2);border-radius:5px;box-shadow:0 4px 14px rgba(0,0,0,.35);outline:none;}
        .wg-drag-hud{position:absolute;z-index:141;pointer-events:none;background:var(--sf);color:var(--white);border:1px solid var(--acc2);border-radius:5px;padding:2px 7px;font-size:11px;font-weight:700;white-space:nowrap;box-shadow:0 3px 10px rgba(0,0,0,.35);}
        /* Free-draw "Draw walls" tool control strip (bottom-left of the canvas). */
        .wg-draw-strip{position:absolute;left:8px;bottom:8px;display:flex;align-items:center;gap:6px;flex-wrap:wrap;max-width:calc(100% - 16px);background:color-mix(in srgb, var(--sf) 92%, transparent);border:1px solid var(--bdr);border-radius:8px;padding:6px 8px;box-shadow:0 3px 12px rgba(0,0,0,.3);}
        .wg-draw-strip button{white-space:nowrap;}
        .wg-draw-sep{width:1px;height:18px;background:var(--bdr);margin:0 2px;}
        /* Full-screen Room Designer for the New-Room modal (mirrors .wg-expanded). */
        .nr-preview-panel.nr-designer-expanded{position:fixed;inset:24px;z-index:145;background:var(--sf);border:1px solid var(--bdr);border-radius:14px;box-shadow:0 0 0 100vmax color-mix(in srgb, var(--bg) 72%, transparent),0 30px 80px color-mix(in srgb, var(--bg) 80%, transparent);padding:18px;overflow:auto;}
        .nr-preview-panel.nr-designer-expanded #nr-preview svg{max-height:calc(100vh - 170px) !important;}
        .nr-designer-actions{display:none;}
        .nr-preview-panel.nr-designer-expanded .nr-designer-actions{display:flex;align-items:center;gap:10px;margin-top:12px;padding-top:12px;border-top:1px solid var(--bdr);}

        /* ── PR-NEWROOM-FUSION (2026-07-17): Fusion-360 × Apple premium visual system ──
           A dark "engineering" plan canvas + a glass floating toolbar + a glass status
           pill + premium glowing corner handles. EVERYTHING is scoped to .nr-card so the
           in-room room editor (#wg-plan-svg, which lives OUTSIDE .nr-card) keeps its light
           architect's-paper palette untouched. The shared wgPlanSvg reads --plan-canvas,
           which is DEFINED ONLY here — everywhere else it falls back to --plan-paper. */
        .nr-card{
          --plan-canvas:#0D1117; --plan-paper:#0D1117; --plan-floor:#141A22;
          --plan-grid:rgba(255,255,255,0.055); --plan-grid-maj:rgba(255,255,255,0.12);
          --plan-poche:#2A313C; --plan-ink:#D8DDE8; --plan-face-int:#1D9BF0;
          --plan-dim:#8FA3B8; --plan-dim-text:#B8C4D2; --plan-dim-edit:#F0B429;
          --plan-door:#E0943A; --plan-glass:#5AB4E0; --plan-slope:#F0A93A;
          --plan-handle:#9DB0C4; --plan-handle-core:#0D1117; --plan-sel:#1D9BF0; --plan-snap:#34E0A1;
        }
        .nr-card .nr-canvas-pane{background:radial-gradient(130% 100% at 50% 0%, #10151D 0%, #0A0D12 68%, #06090D 100%);}
        .nr-card .nr-preview-panel{position:relative;}
        /* Frosted glass primitive — floating chrome over the dark canvas. */
        .nr-glass-pill{background:rgba(13,17,23,0.80);backdrop-filter:blur(16px) saturate(170%);-webkit-backdrop-filter:blur(16px) saturate(170%);border:1px solid rgba(255,255,255,0.10);box-shadow:0 10px 34px rgba(0,0,0,0.5),inset 0 1px 0 rgba(255,255,255,0.06);}
        @supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.nr-glass-pill{background:rgba(15,20,28,0.97);}}
        /* Floating toolbar — centered at the top of the canvas. */
        .nr-fab-toolbar{position:absolute;top:12px;left:50%;transform:translateX(-50%);z-index:22;display:flex;align-items:center;gap:2px;height:46px;padding:0 9px;border-radius:13px;animation:nrFabIn .34s var(--spring-snappy,cubic-bezier(.22,1,.36,1));}
        .nr-fab-toolbar button{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;min-width:44px;height:38px;padding:0 9px;background:transparent;border:none;border-radius:9px;color:#9DB0C4;font-family:inherit;font-size:16px;line-height:1;cursor:pointer;transition:background .13s var(--ease-out,ease),color .13s var(--ease-out,ease),transform .09s var(--ease-out,ease);}
        .nr-fab-toolbar button .fab-lbl{font-size:8.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;opacity:.92;}
        .nr-fab-toolbar button:hover{background:rgba(29,155,240,0.13);color:#EAF2FB;}
        .nr-fab-toolbar button:active{transform:scale(.9);}
        .nr-fab-toolbar button:disabled{opacity:.32;cursor:default;pointer-events:none;}
        /* PR-PLAN-IMPORT (2026-07-18): the New-Room "upload a plan" dropzone. */
        .nr-plan-drop{display:flex;align-items:center;gap:10px;padding:11px 13px;margin-bottom:12px;border:1.5px dashed var(--bdr);border-radius:10px;background:color-mix(in srgb,var(--acc) 5%,transparent);cursor:pointer;transition:border-color .15s var(--ease-out,ease),background .15s var(--ease-out,ease);}
        .nr-plan-drop:hover{border-color:var(--acc);background:color-mix(in srgb,var(--acc) 10%,transparent);}
        .nr-plan-drop.drag{border-color:var(--acc);background:color-mix(in srgb,var(--acc) 16%,transparent);}
        .nr-fab-toolbar button.is-active{background:rgba(29,155,240,0.20);color:#4BAEF5;box-shadow:inset 0 -2px 0 #1D9BF0;}
        .nr-fab-toolbar button.nr-fab-primary{color:#EAF2FB;}
        .nr-fab-sep{width:1px;height:24px;background:rgba(255,255,255,0.11);margin:0 5px;flex:0 0 auto;}
        /* Glass status pill (bottom-left) — validity + dims + area + wall count. */
        .nr-card .nr-status-strip{animation:nrPillIn .34s var(--spring-snappy,cubic-bezier(.22,1,.36,1));}
        @keyframes nrFabIn{from{opacity:0;transform:translateX(-50%) translateY(-9px);}to{opacity:1;transform:translateX(-50%) translateY(0);}}
        @keyframes nrPillIn{from{opacity:0;transform:translateY(7px);}to{opacity:1;transform:translateY(0);}}

        /* 3-column editor grid: library | viewer | parameters */
        /* Slimmer sidebars (260→218 left, 280→236 right ≈ 17–18% reduction) +
           glassmorphic surface so the panels read as floating over the viewport
           instead of two more boxes. The viewport gradient bleeds through. */
        /* PR-CAB-LAYOUT-CALC (2026-05-29, refined): the 56px in this
           calc was originally only the OUTER app header height. Later
           someone added `.shdr` inside #pg-cab but never updated the
           calc. Refined .shdr height estimate: padding 10px + h1 (24px
           font × ~1.2 line-height = ~29px) + sub div (12px font × ~1.4
           line-height = ~17px) + padding 10px + border 1px ≈ 67-68px,
           not the 46px I first guessed. First-pass calc(100vh - 102px)
           closed most of the gap but operator confirmed "still some
           scroll" remained — undershot by ~20px. Bumped to 125px to
           cover 56 outer + ~68 .shdr + small safety margin.
           If still off, nudge the constant ±5px; do NOT restructure
           the flex/grid (see [[feedback_no_cab_editor_grid_layout_changes]]:
           two attempts to restructure broke the page hard). */
        /* PR-CAB-PANE-CONTRAST (2026-06-16): left rail widened 218→248px and the
           right (Parameters) rail 236→252px so cabinet names + wall-property
           labels stop crowding the edges and read at a glance. Width tweak only —
           the grid structure is unchanged (see feedback_no_cab_editor_grid_layout_changes). */
        /* PR-STUDIO-FIT (2026-07-08): height-only fix (columns unchanged, per
           feedback_no_cab_editor_grid_layout_changes). FILL the positioned
           parent (#app-workspace is position:fixed between the 56px topbar and
           the status bar) instead of the fragile height:calc(100vh - 125px)
           magic guess, which overflowed the viewport — operator had to scroll to
           reach the bottom control bar — whenever the real chrome differed from
           125px (status bar / migration banner / taller topbar). 100% adapts to
           whatever space the fixed parent actually has; grid stays overflow:
           hidden and each pane scrolls internally. */
        /* PR-CAB-LEFT-SLIM (2026-07-29): default left library width trimmed
           248 → 212 so the 3D viewport is bigger before the operator touches
           anything (operator: "takes up too much screen before you can select a
           cabinet and see it"). Drag-to-resize still overrides via inline --cab-lw. */
        .cab-editor-grid{display:grid;grid-template-columns:var(--cab-lw,212px) 1fr var(--cab-rw,252px);height:100%;max-height:100%;min-height:0;overflow:hidden;background:var(--bg);position:relative;transition:grid-template-columns var(--dur-standard) var(--ease-out);}
        /* PR-CAB-RESIZE (2026-06-28): drag-to-resize rails (widths persist). */
        .cab-resizer{position:absolute;top:0;bottom:0;width:9px;cursor:col-resize;z-index:6;background:transparent;touch-action:none;transition:background var(--dur-quick) var(--ease-out);}
        .cab-resizer:hover,.cab-resizer.drag{background:color-mix(in srgb, var(--acc) 45%, transparent);}
        .cab-resizer.cab-rz-l{left:var(--cab-lw,212px);transform:translateX(-50%);}
        .cab-resizer.cab-rz-r{right:var(--cab-rw,252px);transform:translateX(50%);}
        .cab-editor-grid.cab-expanded .cab-resizer{display:none;}
        .cab-editor-grid.cab-dragging{transition:none;}
        /* PR-CAB-LAYOUT: expanded viewport mode — hides both side rails
           so the 3D viewport fills the available space. Triggered by the
           ⊞ toolbar button or pressing F. Mozaik-style "maximize 3D".
           Side panes fade out via opacity so the canvas reflows cleanly
           via the ResizeObserver. */
        .cab-editor-grid.cab-expanded{grid-template-columns:0 1fr 0;}
        .cab-editor-grid.cab-expanded .cab-pane{overflow:hidden;pointer-events:none;opacity:0;border:none;transition:opacity .14s ease;}
        @media (prefers-reduced-motion: reduce){
            .cab-editor-grid,.cab-editor-grid.cab-expanded .cab-pane{transition:none;}
        }
        /* PR-CAB-PANE-CONTRAST (2026-06-16): background was a hardcoded dark
           glass (rgba(18,18,18,0.78)) that ignored the theme. In light mode it
           painted a muddy medium-gray panel while the theme's dark text tokens
           (--txt / --dim) sat on top → unreadable labels in BOTH the Cabinet
           Library (left) and Parameters (right) rails. Route through --pn so the
           panel flips with the theme (ivory/white in light mode, near-black in
           dark) while keeping a hint of translucency for the floating-glass feel
           the blur provides. */
        /* PR-EDITOR-BLACK (2026-07-19): route the editor rails to true black
           (var(--bg)) instead of a color-mixed --pn + glass blur — the operator
           wants consistent pure-black dark mode. Cards inside (--pn #16181C)
           still give subtle depth. */
        .cab-pane{background:var(--bg);display:flex;flex-direction:column;border-right:1px solid var(--bdr);overflow:hidden;min-width:0;}
        .cab-pane-right{border-right:none;border-left:1px solid var(--bdr);}
        .cab-pane-hdr{padding:10px 14px;border-bottom:1px solid var(--bdr);display:flex;align-items:center;gap:8px;background:var(--bg);flex:none;}
        .cab-room-info{padding:6px 14px;color:var(--acc2);font-size:11px;font-weight:600;background:color-mix(in srgb, var(--acc2) 6%, transparent);border-bottom:1px solid var(--bdr);}
        .cab-pane-body{overflow:hidden;overflow-x:hidden;padding:10px;flex:1;display:flex;flex-direction:column;min-height:0;}
        /* PR-CAB-PANE-CONTRAST (2026-06-16): hide the scrollbar in the editor
           rails — it still scrolls, just without the chrome the operator found
           intrusive. Applies to the pane body and any inner scroll regions. */
        .cab-pane-body,.cab-pane-body *{scrollbar-width:none;-ms-overflow-style:none;}
        .cab-pane-body::-webkit-scrollbar,.cab-pane-body *::-webkit-scrollbar{display:none;width:0;height:0;}
        .cab-pane-body .pn{margin-bottom:0;}
        /* The global .fr uses minmax(140px,…) so in these ~230px rails the
           Quick-Add W/H/D fields each grabbed a full row and stacked vertically,
           burying the Cabinet Library list and Placed section below the fold.
           Tighten the track minimum INSIDE the cab rails so the three dimension
           fields sit on one row — everything fits without scrolling on a normal
           screen. Width-only scope; no structural change. */
        .cab-pane .fr{grid-template-columns:repeat(auto-fit,minmax(58px,1fr));gap:8px;margin-bottom:8px;}
        .cab-pane .fg{margin-bottom:8px;}
        .cab-pane .fg label{margin-bottom:3px;}
        /* Tighten the gap between the stacked sections (Cabinet Library /
           Quick Add / Placed) so all three are reachable with minimal scroll. */
        .cab-pane-body .pn + .pn{margin-top:8px !important;}
        .cab-viewer{display:flex;flex-direction:column;overflow:hidden;background:#080810;position:relative;min-width:0;}
        .cab-canvas-wrap{flex:1;position:relative;min-height:0;}
        .cab-canvas-wrap canvas{display:block;width:100%;height:100%;}
        /* PR-CAB-TOOLBAR-FIT (2026-05-29): was overflow-x:auto which
           forced operators to horizontally scroll the toolbar to reach
           Eco/Balanced/Best perf-tier buttons on common laptop widths.
           flex-wrap:wrap lets buttons spill to a second row when needed,
           so every viewport setting is visible without scrolling the
           viewport area itself (only the sidebars should scroll). */
        /* PR-EDITOR-FLOAT (2026-07-19): Apple-style. The toolbar is now a FLOATING
           VIEW PILL centered at the bottom of the canvas (view controls only) + a
           floating ACTION cluster top-right (Edit/Apply/Island/Placed/Save). No
           bordered .cv-group boxes, no wrap — a calm frosted pill on pure black. */
        .cab-view-bar{position:absolute;left:50%;bottom:16px;transform:translateX(-50%);z-index:8;
            display:flex;flex-wrap:nowrap;align-items:center;gap:2px;max-width:calc(100% - 28px);
            padding:6px 8px;background:color-mix(in srgb, var(--pn) 80%, transparent);
            -webkit-backdrop-filter:blur(22px) saturate(150%);backdrop-filter:blur(22px) saturate(150%);
            border:1px solid var(--bdr);border-radius:15px;box-shadow:0 14px 42px rgba(0,0,0,.55);}
        .cab-view-bar .cv-group{background:transparent;border:none;padding:0;margin:0 2px 0 0;gap:2px;display:inline-flex;align-items:center;}
        .cab-view-bar .cv-group:empty{display:none;margin:0;}
        .cab-view-bar #vc-view{min-height:34px!important;padding:5px 9px!important;border-radius:8px!important;}
        .cab-view-bar #cv-expand{margin-left:2px!important;}
        .cab-view-bar .cv-help-btn{margin-left:0!important;}
        /* Floating ACTION cluster (top-right of the canvas). */
        .cab-act-cluster{position:absolute;right:16px;top:16px;z-index:8;
            display:flex;align-items:center;gap:4px;padding:5px 6px;
            background:color-mix(in srgb, var(--pn) 80%, transparent);
            -webkit-backdrop-filter:blur(22px) saturate(150%);backdrop-filter:blur(22px) saturate(150%);
            border:1px solid var(--bdr);border-radius:13px;box-shadow:0 12px 32px rgba(0,0,0,.5);}
        #cab-placed-count{background:var(--acc);color:var(--acc-ink);border-radius:6px;padding:1px 6px;font-size:11px;font-weight:700;}
        /* Apple-clean ghost buttons inside both floating containers. */
        .cab-view-bar .cv-btn,.cab-act-cluster .cv-btn{background:transparent;border:none;color:var(--dim);min-height:36px;padding:0 12px;border-radius:8px;font-weight:600;}
        .cab-view-bar .cv-btn:hover,.cab-act-cluster .cv-btn:hover{background:color-mix(in srgb, var(--txt) 9%, transparent);border-color:transparent;color:var(--txt);}
        .cab-view-bar .cv-btn.active,.cab-act-cluster .cv-btn.active{background:color-mix(in srgb, var(--acc) 16%, transparent);color:var(--acc);border-color:transparent;font-weight:700;}
        .cab-act-cluster .cv-btn.cv-btn-primary{background:var(--acc);color:var(--acc-ink);font-weight:700;}
        .cab-act-cluster .cv-btn.cv-btn-primary:hover{filter:brightness(1.06);background:var(--acc);color:var(--acc-ink);}
        /* Floating PLACED-CABINETS panel (opened by the Placed toggle). */
        .cab-placed-panel{position:fixed;z-index:1300;width:290px;max-height:min(62vh,470px);display:flex;flex-direction:column;
            background:color-mix(in srgb, var(--pn) 92%, transparent);-webkit-backdrop-filter:blur(20px) saturate(150%);backdrop-filter:blur(20px) saturate(150%);
            border:1px solid var(--bdr);border-radius:13px;box-shadow:0 18px 48px rgba(0,0,0,.6);overflow:hidden;}
        .cab-placed-panel[hidden]{display:none;}
        .cab-placed-panel .cpp-head{display:flex;align-items:center;justify-content:space-between;padding:11px 14px;border-bottom:1px solid var(--bdr);flex:none;}
        .cab-placed-panel .cpp-head h3{font-size:13px;font-weight:600;margin:0;color:var(--txt);}
        .cab-placed-panel .cpp-head #cab-count{color:var(--dim);font-weight:400;}
        .cab-placed-panel .cpp-close{background:transparent;border:none;color:var(--dim);font-size:16px;cursor:pointer;padding:2px 7px;border-radius:6px;line-height:1;}
        .cab-placed-panel .cpp-close:hover{color:var(--txt);background:color-mix(in srgb, var(--txt) 8%, transparent);}
        .cab-placed-panel #cab-items{flex:1;min-height:0;max-height:none;overflow-y:auto;padding:8px;}
        .cab-placed-panel .cpp-foot{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--bdr);flex:none;}
        .cab-placed-panel .cpp-foot button{flex:1;margin:0;}
        /* Collapsible Quick-Add header (press "A" to open the typed form). */
        .cab-qa-toggle{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;background:transparent;border:none;
            color:var(--txt);font-size:12px;font-weight:600;padding:0 0 8px;margin:0;cursor:pointer;text-align:left;}
        .cab-qa-toggle:hover{color:var(--acc);}
        .cab-qa-toggle[aria-expanded="true"]{color:var(--acc);}
        .cab-qa-toggle kbd{font-family:inherit;font-size:10px;font-weight:600;color:var(--dim);background:color-mix(in srgb,var(--txt) 8%,transparent);
            border:1px solid var(--bdr);border-radius:5px;padding:1px 6px;line-height:1.5;}
        #cab-quickadd-form[hidden]{display:none;}
        /* PR-UI-28: cv-btn now hosts inline SVGs alongside text labels.
           Icons sized at 14px to match the 11px label without dominating. */
        /* PR-RENDER-DAY1-POLISH (2026-05-08): WCAG 2.5.5 — bumped
           padding from 6px 12px (~31px tall) to 11px 14px (~44px) so
           toolbar buttons (iso/top/front/side/sketch/walk) clear the
           floor. Font-size and gap unchanged so the visible content
           stays the same; only the hit area grows. */
        .cv-btn{background:var(--inp);border:1px solid var(--bdr);color:var(--white);padding:11px 14px;border-radius:6px;font-size:11px;cursor:pointer;transition:background var(--dur-panel) var(--ease-out),border-color var(--dur-panel) var(--ease-out);white-space:nowrap;display:inline-flex;align-items:center;gap:5px;min-height:44px;}
        .cv-btn svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0;}
        .cv-btn:hover{background:color-mix(in srgb, var(--acc2) 10%, transparent);border-color:var(--acc2);}
        .cv-btn.active{background:var(--acc2);color:var(--bg);border-color:var(--acc2);font-weight:600;}
        /* PR-STUDIO-P2 #10d/#10e (2026-07-16): material swatch dot on the finish
           chips (paint the current finish), + the Save button accented as the
           highest-stakes action. */
        .cv-btn .cv-swatch{display:inline-block;width:11px;height:11px;border-radius:50%;margin-right:2px;vertical-align:middle;border:1px solid rgba(0,0,0,0.28);box-shadow:inset 0 0 0 1px rgba(255,255,255,0.18);flex:0 0 auto;}
        .cv-btn.cv-btn-primary{background:var(--acc);border-color:var(--acc);color:#fff;font-weight:600;}
        .cv-btn.cv-btn-primary:hover{filter:brightness(1.08);}
        /* PR-STUDIO-P2 #9b (2026-07-16): live-cost HUD recompute shimmer + narrow
           tablet width clamp. The sweep overlays the existing numbers (host is
           overflow:hidden) so stale figures never blank while the nester runs. */
        #cw-live-cost.cw-recalc::after{content:"";position:absolute;inset:0;background:linear-gradient(100deg,transparent 30%,rgba(255,255,255,0.12) 50%,transparent 70%);animation:cwLcSweep 900ms ease-in-out infinite;pointer-events:none;}
        @keyframes cwLcSweep{0%{transform:translateX(-100%);}100%{transform:translateX(100%);}}
        @media (max-width:480px){#cw-live-cost{max-width:calc(100vw - 24px);right:12px;}}
        .cv-sep{width:1px;height:18px;background:var(--bdr);margin:0 4px;flex:none;}
        .cv-hint{color:var(--dim);font-size:10px;white-space:nowrap;}

        /* Cabinet library — single-column tile rows with side-by-side
           icon+text. Was a 2-column grid (`grid-template-columns:1fr 1fr`)
           which crushed names like "Lazy Susan Corner Base" into
           ellipsis-truncated half-words ("Lazy") in the right column.
           Single column at 218px gives ~190px of usable width for the
           name — enough to fit every cabinet name without truncation.
           Each row is shorter than the old 2-col tile (icon goes inline
           on the left at 38px instead of stacked at 46px above the
           text), so the visible row count stays similar. */
        #cab-lib-items{display:grid;grid-template-columns:1fr;gap:6px;flex:1 1 auto;min-height:0;overflow-y:auto;}
        /* UX-2 — Category section header spans both columns. Sticky so
           the section name stays visible while scrolling through a
           long list of widths. Tiny + muted so it reads as a label,
           not a tile. */
        /* PR-LIB-SCROLL-FIX (2026-05-28): was top:-1px which left a 1px
           gap that triggered reflow on every scroll tick (the items
           appeared to "jump"). top:0 keeps the header flush to the
           scroll container's top edge. */
        /* PR-CAB-LIB-COMPACT (2026-07-29): brighter, larger section headers.
           Operator: "where it shows base 11 … make it easier to read, bright white
           or super black". --txt is the theme's max-contrast body color (near-white
           in dark, near-black in light), so it flips correctly with the theme. */
        .cab-lib-section-header{grid-column:1 / -1;font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.6px;color:var(--txt);padding:10px 6px 6px;border-bottom:1px solid var(--bdr);margin-top:6px;background:var(--sf);position:sticky;top:0;z-index:2;}
        .cab-lib-section-header:first-child{margin-top:0;}
        /* PR-CAB-LIB-COMPACT (2026-07-29): compact type/shape dropdowns + small
           Browse-all link that replaced the two rows of large filter pills. */
        .cab-lib-filter-row{display:flex;gap:6px;margin-bottom:6px;}
        .cab-lib-sel{flex:1;min-width:0;height:34px;background:var(--inp);border:1px solid var(--bdr);border-radius:6px;color:var(--txt);padding:0 6px;font-size:12px;font-weight:600;cursor:pointer;}
        .cab-lib-sel:focus{border-color:var(--acc);outline:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--acc) 25%,transparent);}
        .cab-lib-browse-link{width:fit-content;margin:0 0 8px auto;background:none;border:none;color:var(--acc2);font-size:11px;font-weight:600;cursor:pointer;padding:2px 2px;}
        .cab-lib-browse-link:hover{color:var(--acc);text-decoration:underline;}
        /* Cabinet-library tile — 2026-04-23 token refactor: was
         * background:rgba(31,31,31,0.55) (dark gray that didn't flip
         * in light mode, rendering as muddy gray on the new white page
         * background). Now routes through --pn so the tile blends
         * seamlessly on any theme — pure white panel on light mode,
         * near-black on the dark theme.
         *
         * .name: was color:var(--white) which is theme-specific. Route
         * through --txt for proper contrast in both light and dark.
         * .icn backdrop: dark-theme's (--pn, --bg) gradient worked
         * because both are near-black; in light mode --pn is white and
         * --bg is off-white, which reads as a barely-visible wash. Swap
         * to color-mix for a proper subtle fill on both themes. */
        /* PR-CAB-LAYOUT: side-by-side icon + text. 38px square icon on
           the left, name + dims stacked vertically on the right. Fixes
           the previous "Lazy Susan" → "Lazy" truncation by giving the
           text column the full row width minus the icon. */
        .cab-lib-item{display:flex;flex-direction:row;align-items:center;gap:var(--sp-3,12px);padding:0 var(--sp-3,12px);border:1px solid var(--bdr);border-radius:var(--radius-sm,6px);background:var(--pn);cursor:grab;transition:border-color var(--dur-panel) var(--ease-out),background var(--dur-panel) var(--ease-out),transform var(--dur-panel) var(--spring-snappy);position:relative;min-height:54px;}
        .cab-lib-item:focus-visible{outline:var(--focus-ring-w,2px) solid var(--acc);outline-offset:var(--focus-ring-offset,2px);}
        /* PR-CAB-STRIPE (2026-06-28): a category accent rail on the right edge so
           the cabinet TYPE is glanceable on a dusty screen (decorative — the type
           is also in the section header + name, so it never carries sole meaning). */
        .cab-lib-item::before{content:"";position:absolute;right:5px;top:11px;bottom:11px;width:var(--stripe-w,3px);border-radius:var(--radius-xs,3px);background:var(--cab-cat,var(--acc-cabinet,#c19a6b));pointer-events:none;}
        /* PR-STUDIO-LIB-FAVS (2026-07-16): pin star, clear of the ::before category
           stripe (right:5px). Hidden until tile hover for UNpinned; pinned = always
           gold-visible. Mouse pattern — on touch (no hover) the pinned stars still
           show, but pinning is a desktop power move. */
        .cab-lib-item .cab-fav{position:absolute;top:5px;right:11px;font-size:13px;line-height:1;cursor:pointer;color:var(--dim);opacity:0;transition:opacity 120ms ease,color 120ms ease,transform 90ms ease;z-index:2;user-select:none;}
        .cab-lib-item:hover .cab-fav,.cab-lib-item .cab-fav.on{opacity:1;}
        .cab-lib-item .cab-fav.on{color:var(--acc2);}
        .cab-lib-item .cab-fav:hover{transform:scale(1.2);}
        /* PR-STUDIO-P1B #6 (2026-07-16): frame the 3D canvas as a drop target while a
           palette card is being dragged. The ghost is the primary feedback; this is a
           quiet green frame so the operator knows the canvas will accept the drop. */
        #bevy-canvas.cab-drop-active{outline:2px solid rgba(34,197,94,0.55);outline-offset:-2px;transition:outline 80ms ease;}
        .cab-lib-item[data-cat="Base"],.cab-lib-item[data-cat="Vanity"]{--cab-cat:var(--acc-cabinet,#c19a6b);}
        .cab-lib-item[data-cat="Wall"]{--cab-cat:#8fbc8f;}
        .cab-lib-item[data-cat="Tall"]{--cab-cat:var(--acc-sheet,#b8860b);}
        .cab-lib-item[data-cat="Appliance"]{--cab-cat:#9aa6b4;}
        /* PR-CAB-GAPBAR (2026-06-28): wall-run strip in the wall inspector —
           the cabinets on the active wall, proportionally sized + clickable,
           with the aggregate space-to-fill called out. Read-only; the filler
           edit stays on the per-cabinet inspector. */
        .cab-run-wrap{margin:0 0 12px;}
        .cab-run-head{display:flex;justify-content:space-between;align-items:baseline;font-size:10px;color:var(--dim);margin-bottom:5px;text-transform:uppercase;letter-spacing:.06em;}
        .cab-run-rem{font-family:var(--ff-mono);font-variant-numeric:tabular-nums;font-weight:600;letter-spacing:0;text-transform:none;}
        .cab-run-rem.gap{color:var(--warn);}
        .cab-run-rem.over{color:var(--no);}
        .cab-run-rem.flush{color:var(--ok);}
        .cab-run-bar{position:relative;height:46px;border-radius:var(--radius-sm,6px);background:repeating-linear-gradient(90deg, color-mix(in srgb, var(--bdr) 22%, transparent) 0 1px, transparent 1px 12px), color-mix(in srgb, var(--bdr) 12%, var(--sf));border:1px solid var(--bdr);overflow:hidden;}
        .cab-run-chip{position:absolute;top:3px;bottom:3px;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;padding:0 2px;border:1px solid var(--bdr-h);border-radius:var(--radius-xs,3px);background:var(--pn);color:var(--txt);cursor:pointer;overflow:hidden;transition:background var(--dur-fast,.12s),border-color var(--dur-fast,.12s);}
        .cab-run-chip:hover{background:var(--pn-h);border-color:var(--bdr-h);}
        .cab-run-chip.sel{border-color:var(--acc);background:color-mix(in srgb, var(--acc) 14%, var(--pn));}
        .cab-run-n{font-size:9px;color:var(--acc2);font-weight:700;line-height:1;}
        .cab-run-w{font-family:var(--ff-mono);font-size:11px;font-variant-numeric:tabular-nums;line-height:1;}
        .cab-lib-item:hover{border-color:var(--acc2);background:color-mix(in srgb, var(--acc) 8%, var(--pn));}
        .cab-lib-item:active{cursor:grabbing;}
        .cab-lib-item .icn{flex:0 0 44px;width:44px;height:44px;background:color-mix(in srgb, var(--bdr) 35%, var(--pn));border-radius:var(--radius-sm,6px);display:flex;align-items:center;justify-content:center;border:1px solid color-mix(in srgb, var(--bdr) 50%, transparent);}
        .cab-lib-item .icn svg{width:32px;height:32px;}
        .cab-lib-item .info{min-width:0;flex:1;display:flex;flex-direction:column;gap:1px;}
        .cab-lib-item .name{color:var(--txt);font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;letter-spacing:-.005em;}
        .cab-lib-item .dims{color:var(--txt);font-family:var(--ff-mono);font-size:var(--fs-sm,12px);font-weight:var(--fw-medium,500);font-variant-numeric:tabular-nums;letter-spacing:.01em;line-height:1.25;}
        /* Right-aligned tabular size chip — the WIDTH (or W×H) is the real per-SKU
           identifier, so a column of aligned sizes lets a section of look-alike rows
           scan like a table. Full W×H×D stays in the hover preview + properties. */
        .cab-lib-item .cab-lib-size{flex:none;margin-left:8px;margin-right:13px;font-family:var(--ff-mono);font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:.01em;color:var(--dim);white-space:nowrap;}
        .cab-lib-item:hover .cab-lib-size{color:var(--txt);}

        /* Hover preview — floating glass card with larger icon + full dims */
        .cab-lib-preview{position:fixed;z-index:60;background:rgba(18,18,18,0.95);backdrop-filter:blur(16px) saturate(160%);-webkit-backdrop-filter:blur(16px) saturate(160%);border:1px solid var(--bdr);border-radius:10px;padding:12px;width:200px;box-shadow:0 18px 48px rgba(0,0,0,0.6);pointer-events:none;animation:libpv-in .15s ease-out;}
        @keyframes libpv-in{0%{opacity:0;transform:translateY(4px) scale(.97);}100%{opacity:1;transform:translateY(0) scale(1);}}
        .cab-lib-preview .pv-icn{width:100%;height:130px;background:linear-gradient(180deg,var(--pn),var(--bg));border-radius:6px;display:flex;align-items:center;justify-content:center;margin-bottom:8px;border:1px solid rgba(255,255,255,0.04);}
        .cab-lib-preview .pv-icn svg{width:100px;height:100px;}
        .cab-lib-preview .pv-name{color:var(--white);font-size:13px;font-weight:600;margin-bottom:4px;}
        .cab-lib-preview .pv-meta{color:var(--dim);font-size:11px;font-variant-numeric:tabular-nums;line-height:1.4;}
        .cab-lib-preview .pv-meta b{color:var(--acc2);font-weight:600;}

        /* Shape filter chips — Straight / L / U / Corner row above the type chips
           PR-CAB-LAYOUT: same nowrap + horizontal-scroll fix as .lib-chips above. */
        .lib-shape-chips{display:flex;gap:3px;margin-bottom:6px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;}
        .lib-shape-chips::-webkit-scrollbar{display:none;}
        /* PR-PICKER-PERFECT (2026-07-15): 36px min tap target (was ~26px, below
           the shop-floor gloved-hand floor) + legible 11px. */
        .lib-shape-chip{flex:0 0 auto;white-space:nowrap;display:inline-flex;align-items:center;min-height:36px;background:var(--inp);border:1px solid var(--bdr);color:var(--dim);font-size:11px;font-weight:600;padding:6px 11px;border-radius:5px;cursor:pointer;text-transform:uppercase;letter-spacing:.3px;transition:color var(--dur-panel) var(--ease-out),border-color var(--dur-panel) var(--ease-out),background var(--dur-panel) var(--ease-out);}
        .lib-shape-chip:hover{border-color:var(--acc2);color:var(--white);}
        .lib-shape-chip.active{background:color-mix(in srgb, var(--acc2) 12%, transparent);border-color:var(--acc2);color:var(--acc2);}

        /* Skeleton loader for the cabinet library */
        .cab-lib-skel{padding:6px;border:1px solid var(--bdr);border-radius:6px;background:var(--inp);}
        .cab-lib-skel .sk-icn{width:100%;height:46px;border-radius:4px;background:linear-gradient(90deg,var(--inp) 0%,var(--bdr) 50%,var(--inp) 100%);background-size:200% 100%;animation:skel-shimmer 1.4s ease-in-out infinite;margin-bottom:4px;}
        .cab-lib-skel .sk-bar{height:8px;border-radius:3px;background:linear-gradient(90deg,var(--inp) 0%,var(--bdr) 50%,var(--inp) 100%);background-size:200% 100%;animation:skel-shimmer 1.4s ease-in-out infinite;margin-top:3px;}
        .cab-lib-skel .sk-bar.short{width:60%;}

        /* Placed cabinet rows in left panel */
        /* PR-PLACE-5 2026-04-25 (Feature 1 — shop-floor tablet ergonomics):
           min-height 48px so a gloved tap reliably hits the row. The
           `.sel` state gets a 3px amber left bar so the operator can spot
           the active cabinet without reading text — matches the cyan halo
           around the selected cabinet in the 3D view. */
        #cab-items .li{padding:8px 8px;font-size:11px;cursor:pointer;border:1px solid transparent;border-left:3px solid transparent;border-radius:5px;margin-bottom:3px;display:flex;align-items:center;justify-content:space-between;min-height:48px;}
        #cab-items .li > div:first-child{flex:1;min-width:0;}
        #cab-items .li:hover{background:color-mix(in srgb, var(--acc2) 6%, transparent);}
        #cab-items .li.sel{background:color-mix(in srgb, var(--acc2) 12%, transparent);border-color:var(--acc2);border-left:3px solid var(--acc2);}
        #cab-items .li-t{font-size:11px;}
        #cab-items .li-m{font-size:10px;color:var(--dim);}
        /* PR-CAB-SIDEBAR-UX (2026-05-29) ─ per-row info density.
           Type chip + warning dot per cabinet-shop-ux-specialist audit.
           Strict token compliance per [[feedback_strict_color_tokens]]. */
        #cab-items .li-chip{
            display:inline-block;padding:2px 8px;margin-right:6px;
            border-radius:8px;font-size:11px;font-weight:600;
            letter-spacing:.04em;text-transform:uppercase;
            background:var(--pn);color:var(--dim);
            border:1px solid var(--bdr);
        }
        /* PR-PICKER-PERFECT (2026-07-15): the per-row edit/link/delete icon
           buttons had NO dedicated CSS — they fell through to the global button
           rule (~30px). Give them a 36px square tap zone inside the 48px row. */
        #cab-items .li-act{
            min-width:36px;min-height:36px;padding:0;
            display:inline-flex;align-items:center;justify-content:center;
            flex:0 0 auto;font-size:14px;line-height:1;
        }
        /* PR-PICKER-PERFECT (2026-07-15): a delete row marked pending-delete
           (first tap) reads clearly so the second tap confirms — no accidental
           gloved-hand deletes, no keyboard-only Ctrl+Z dependency. */
        #cab-items .li-del.pending-del{
            background:color-mix(in srgb, var(--no) 22%, transparent);
            border-color:var(--no);color:var(--white);
        }
        #cab-items .li-warn-dot{
            display:inline-block;width:8px;height:8px;border-radius:50%;
            background:var(--no);margin-right:6px;flex:0 0 auto;
            box-shadow:0 0 4px var(--no);
        }
        /* PR-PICKER-PERFECT (2026-07-15): the "Browse all cabinets" overlay
           shipped with ZERO css — every cba-* / cab-browse-* class was undefined,
           so the full ~100-item catalog rendered as unstyled HTML with sub-30px
           buttons and no scroll container. Full styling: a scrollable 2-col card
           grid with 44px+ tap targets, shop-floor legible. */
        .cab-browse{position:absolute;inset:0;z-index:20;display:flex;flex-direction:column;background:var(--pn);}
        .cab-browse.hidden{display:none;}
        .cab-browse-hdr{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:12px;border-bottom:1px solid var(--bdr);}
        .cab-browse-hdr h3{margin:0;font-size:15px;font-weight:700;}
        .cba-close{min-width:44px;min-height:44px;display:inline-flex;align-items:center;justify-content:center;font-size:18px;background:var(--inp);border:1px solid var(--bdr);border-radius:6px;cursor:pointer;}
        .cab-browse-controls{padding:10px 12px;border-bottom:1px solid var(--bdr);display:flex;flex-direction:column;gap:8px;}
        .cba-filter-row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;}
        .cba-filter-label{font-size:11px;color:var(--dim);font-weight:600;min-width:52px;}
        .cba-open-btn{width:100%;min-height:44px;display:flex;align-items:center;justify-content:space-between;padding:0 12px;background:var(--inp);border:1px solid var(--bdr);border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;}
        .cba-open-btn:hover{border-color:var(--acc2);}
        .cba-grid{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;display:grid;grid-template-columns:repeat(2,1fr);gap:8px;padding:12px;align-content:start;}
        .cba-card{display:flex;flex-direction:column;gap:6px;min-height:96px;padding:10px;border:1px solid var(--bdr);border-radius:8px;background:var(--inp);}
        .cba-card:hover{border-color:var(--acc2);}
        .cba-thumb{width:100%;height:44px;display:flex;align-items:center;justify-content:center;font-size:22px;background:var(--pn);border-radius:5px;color:var(--dim);}
        .cba-name{font-size:12px;font-weight:600;line-height:1.2;}
        .cba-dims{font-size:11px;color:var(--dim);}
        .cba-badge{display:inline-block;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:1px 6px;border-radius:6px;background:color-mix(in srgb,var(--acc2) 14%,transparent);color:var(--acc2);}
        .cba-actions{display:flex;gap:6px;margin-top:auto;}
        .cba-place{flex:1;min-height:44px;display:inline-flex;align-items:center;justify-content:center;gap:4px;background:var(--acc2);border:none;border-radius:6px;color:#0b0e14;font-size:12px;font-weight:700;cursor:pointer;}
        .cba-place:hover{filter:brightness(1.08);}
        .cba-info{min-width:44px;min-height:44px;display:inline-flex;align-items:center;justify-content:center;background:var(--pn);border:1px solid var(--bdr);border-radius:6px;color:var(--dim);cursor:pointer;font-size:14px;}
        .cba-detail{font-size:11px;color:var(--dim);line-height:1.35;}
        .cba-detail-type{font-weight:600;}
        .cba-features{display:flex;flex-wrap:wrap;gap:4px;}
        .cba-empty{grid-column:1/-1;text-align:center;color:var(--dim);padding:40px 12px;font-size:13px;}
        .cab-browse-footer{padding:10px 12px;border-top:1px solid var(--bdr);display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:12px;color:var(--dim);}
        /* PR-STUDIO-SIDEBAR-SCROLL (2026-07-17): the left pane stacked the Cabinet
           Library, Quick Add and Placed list in ONE scroll, so the 67-item library
           grew unbounded — you scrolled forever to browse, and ADDING a cabinet
           scroll-jumped the whole pane down to Placed ("drops me to placed, scroll up
           forever"). Give the Library grid and the Placed list their OWN bounded
           internal scroll so both stay reachable and a placed-row scrollIntoView stays
           inside the Placed box, and re-show a slim scrollbar on those two boxes (the
           pane hides all scrollbars by default via .cab-pane-body *). */
        /* PR-EDITOR-LIB2 (2026-07-19): #cab-lib-items must NOT be its own scroll
           container. With its height cap removed it never overflows — and as an
           overflow:auto element pinned at its scroll boundary, `overscroll-behavior:
           contain` SWALLOWED the wheel and refused to chain it to the real scroller
           (.cab-pane-body), so the mouse wheel only worked over the far-right gutter.
           Fix: make it a plain grid. .cab-pane-body is the single scroll region and
           the wheel now works over the whole tile area. */
        #cab-lib-items{padding-right:2px;}
        #cab-items{max-height:32vh;overflow-y:auto;overscroll-behavior:contain;padding-right:2px;}
        /* PR-EDITOR-LIB3 (2026-07-19): fixed filter header + a single scrolling tile
           list + @container-driven list<->grid keyed on the RESIZABLE pane width.
           The Library .pn owns the pane's leftover height as a flex column AND is the
           @container (container-type goes on the .pn — a container query styles the
           container's DESCENDANTS, not the container itself). Quick Add is a flex:none
           footer so the Fixtures palette stays reachable without stealing list height. */
        #cab-lib-pn{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden;container:cablib / inline-size;}
        #cab-lib-pn .cab-lib-head{flex:0 0 auto;}
        /* cap the Quick Add / Fixtures footer so a short pane can't starve the tile
           list — it scrolls internally past 42% of the pane height. */
        #cab-qa-pn{flex:0 0 auto;max-height:42%;overflow-y:auto;}
        /* #cab-lib-items is the single scroller — give IT the slim visible scrollbar
           (it was hidden by `.cab-pane-body *`) + a stable gutter so rows don't reflow. */
        .cab-pane-body #cab-lib-items{scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--bdr) 75%,transparent) transparent;scrollbar-gutter:stable;}
        .cab-pane-body #cab-lib-items::-webkit-scrollbar{display:block;width:8px;height:8px;}
        .cab-pane-body #cab-lib-items::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--bdr) 75%,transparent);border-radius:8px;}
        /* generated front-elevation thumbnail fills the icon box; currentColor line-art
           inherits the 2-theme palette + hover/selected states. */
        .cab-lib-item .icn{color:var(--dim);}
        .cab-lib-item:hover .icn{color:var(--txt);}
        .cab-lib-item .icn .cab-thumb{width:100%;height:100%;display:block;}
        /* PR-CAB-LIB-LISTONLY (2026-07-29): the adaptive @container reflow into a
           2-column picture-card grid was REMOVED per operator request. At the normal
           rail width it flipped every section into a grid where tall/many/long-named
           SKUs (Appliances especially) went ragged and looked like they collided —
           "see how it changes so drastically". The single-column LIST (base
           `.cab-lib-item` row + `#cab-lib-items` 1-col grid above) is now the layout at
           EVERY width, so every section reads the same clean way. If a 2-column grid is
           ever wanted again, reinstate an `@container cablib` block here with
           EQUAL-height cards (fixed card height, not align-items:start) to avoid the
           raggedness that caused this revert. */
        /* PR-STUDIO-BROWSEALL-THUMB (2026-07-17): the Browse-All card thumb held an
           <svg viewBox="0 0 32 32"> with NO width/height and no CSS size, so it
           defaulted to ~300px and the wood silhouettes overflowed across the tiles.
           Constrain the svg to the 44px thumb + clip. */
        .cba-thumb{overflow:hidden;}
        .cba-thumb svg{width:auto;height:100%;max-width:100%;object-fit:contain;display:block;}
        /* PR-CAB-SIDEBAR-UX (2026-05-29) ─ left-pane collapse.
           Independent collapse from cab-expanded (which hides BOTH).
           Per [[feedback_strict_color_tokens]] no hex anywhere. */
        .cab-editor-grid.cab-left-collapsed{grid-template-columns:0 1fr 252px;}
        .cab-editor-grid.cab-left-collapsed .cab-pane-left{
            overflow:hidden;pointer-events:none;opacity:0;border:none;
            transition:opacity .14s ease;
        }
        @media (prefers-reduced-motion: reduce) {
            .cab-editor-grid.cab-left-collapsed .cab-pane-left{transition:none;}
        }
        #cab-left-toggle{padding:2px 8px;font-size:14px;}
        /* PR-CAB-LEFT-RAIL (2026-07-29): when the library is collapsed the pane
           itself goes to width:0 / opacity:0, so its own ‹ toggle is unreachable.
           This slim tab is pinned to the grid's left edge (grid is position:relative)
           and is the always-visible reopen affordance — no more hunting for the
           toolbar hamburger. Fullscreen keeps its own #cv-left-pill, so hide the tab
           there to avoid two reopen controls. */
        .cab-left-reopen{display:none;position:absolute;left:0;top:50%;transform:translateY(-50%);
            z-index:7;flex-direction:column;align-items:center;gap:8px;
            padding:14px 5px;border:1px solid var(--bdr);border-left:none;
            border-radius:0 10px 10px 0;background:var(--pn);color:var(--txt);
            cursor:pointer;font-size:13px;font-weight:700;line-height:1;
            box-shadow:2px 0 12px rgba(0,0,0,.30);}
        .cab-left-reopen:hover{background:var(--inp);color:var(--acc);}
        .cab-left-reopen .clr-label{writing-mode:vertical-rl;text-orientation:mixed;letter-spacing:.05em;font-size:11px;font-weight:600;}
        .cab-editor-grid.cab-left-collapsed .cab-left-reopen{display:flex;}
        .cab-editor-grid.cab-fullscreen.cab-left-collapsed .cab-left-reopen{display:none;}

        /* PR-CAB-PARAMS-SCROLL (2026-07-29): the right Parameters pane must scroll.
           The generic .cab-pane-body is overflow:hidden + display:flex — the LEFT pane
           delegates scrolling to its inner #cab-lib-items, but the RIGHT pane has no
           inner scroller, so on desktop the inspector's lower half (Mount & Position,
           Front Face, Inside the Cabinet, Advanced, Copy/Done) was clipped and could
           not be reached (operator: "i cant see the bottom or edit everything"). The
           ≤900px stacked layout already scrolls; this restores it at desktop widths too.
           Block layout so the stacked sections take natural height and the body scrolls;
           a visible thin scrollbar (overriding the pane's hidden-scrollbar rule) makes
           it obvious there's more below. renderCabParams already reads this element's
           scrollTop to preserve position across edits, so scrolling now works end-to-end. */
        #cab-params-body{display:block;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--bdr) 75%,transparent) transparent;scrollbar-gutter:stable;}
        #cab-params-body::-webkit-scrollbar{display:block;width:8px;height:8px;}
        #cab-params-body::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--bdr) 75%,transparent);border-radius:8px;}

        /* Parameters panel form */
        #cab-params-form .fg{margin-bottom:8px;}
        #cab-params-form .fg label{font-size:10px;}
        #cab-params-form .fr{gap:8px;margin-bottom:8px;}

        /* Responsive: collapse sidebars at narrower widths */
        @media(max-width:1200px){.cab-editor-grid:not([style*="--cab-lw"]){--cab-lw:196px;--cab-rw:232px;}}
        @media(max-width:900px){.cab-editor-grid{grid-template-columns:1fr;grid-template-rows:auto 1fr auto;height:100%;min-height:0;}.cab-pane{max-height:240px;border-right:none;border-bottom:1px solid var(--bdr);}.cab-pane-right{border-left:none;border-top:1px solid var(--bdr);}.cab-viewer{min-height:220px;}
            /* PR-EDITOR-LIB3: on the short tablet pane, DON'T use the fixed-header flex
               (the Fixtures footer + header would starve the tile list); fall back to
               the whole pane scrolling as one region. */
            .cab-pane-body{overflow-y:auto;display:block;min-height:auto;}
            #cab-lib-pn{flex:none;display:block;overflow:visible;}
            #cab-lib-pn .cab-lib-head{position:sticky;top:0;z-index:3;background:var(--bg);}
            #cab-lib-items{overflow:visible;min-height:auto;}
            /* PR-EDITOR-FLOAT2 (2026-07-19): the bar is a floating pill now, not the
               old docked strip (the quality picker / reports / save it used to carry
               moved into the top-right Settings menu). Keep it floating on narrow
               screens but let it WRAP + center so the slimmed content never clips
               under .cab-viewer{overflow:hidden}. Do NOT re-introduce position:sticky
               / opaque background / border-top — those fought the pill. */
            .cab-view-bar{max-width:calc(100% - 16px);flex-wrap:wrap;justify-content:center;row-gap:4px;}
        }
        .add-door-bar .ad-spacer {
            flex: 1;
            min-width: var(--sp-3);
        }
        /* Primary CTA — last thing the operator touches before commit.
           Overrides the app-wide .ba base (rgba shadow on hover) with a
           token-based confident-green button. Larger, more presence than
           a generic .ba button deserves here; it's the shop-floor gate
           to committing $50 walnut. */
        .add-door-bar .ad-go {
            min-height: 56px;
            min-width: 130px;             /* trimmed from 160 to make room for D field */
            padding: 0 var(--sp-4);
            font-family: var(--ff-ui);
            font-size: 14px;
            font-weight: var(--fw-bold);
            letter-spacing: 0.04em;
            flex: 0 0 auto;
            margin-left: auto;            /* push CTA to right; spacer becomes optional */
            border-radius: var(--radius-sm);
            border: 1.5px solid var(--acc);
            background: var(--acc);
            color: var(--acc-ink);
            cursor: pointer;
            margin-right: var(--sp-1);
            transition: filter var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out);
            box-shadow: 0 3px 10px color-mix(in srgb, var(--acc) 30%, transparent);
        }
        .add-door-bar .ad-go:hover:not([data-compat-blocked="true"]):not(:disabled) {
            filter: brightness(1.08);
            transform: translateY(-1px);
            box-shadow: 0 4px 14px color-mix(in srgb, var(--acc) 40%, transparent);
        }
        .add-door-bar .ad-go:active:not([data-compat-blocked="true"]):not(:disabled) {
            transform: translateY(0);
            filter: brightness(0.95);
        }
        .add-door-bar .ad-go:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--acc) 80%, transparent);
            outline-offset: 3px;
        }
        /* .ds-split media query removed 2026-04-22 — class unused. */

        /* ═════════════════════════════════════════════════════════════════════
           DASHBOARD WIDGETS — home-page modular grid.
           Sizes: small=4 cols, medium=6 cols, large=8 cols, wide=12 cols.
           Each widget is a self-contained panel with a header (drag handle +
           title + close button) and a content slot. Drag-and-drop reorder
           uses HTML5 drag API; layout persists to localStorage.
           ════════════════════════════════════════════════════════════════════ */
        /* PR-CLEAN-2 / WIDGET-PURGE (2026-05-31): .dash-bar, .widget*,
           .add-widget-card, .widget-resize-handle, .edit-dock and the
           dock-pop keyframe deleted — customizable widget grid retired.
           .widget-empty kept below because filterGlobalSearch still uses it. */
        .widget-empty{color:var(--dim);font-size:12px;font-style:italic;padding:8px 0;}
        /* ═════════════════════════════════════════════════════════════════════
           DASHBOARD REFACTOR — Linear/Figma-grade chrome.
           Global search, active-tab indicator, glassmorphism hero overlays,
           hover quick-action bar, recent-work table styling, utility palette.
           ════════════════════════════════════════════════════════════════════ */
        /* Global search bar in the header — ⌘K affordance */
        .global-search{position:relative;display:flex;align-items:center;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;padding:6px 10px 6px 12px;width:280px;transition:border-color var(--dur-chrome) var(--ease-out),box-shadow var(--dur-chrome) var(--ease-out),width var(--dur-standard) var(--ease-out);}
        .global-search:focus-within{border-color:var(--acc);box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 12%, transparent);width:340px;}
        .global-search svg{width:14px;height:14px;color:var(--dim);flex-shrink:0;}
        .global-search input{flex:1;background:transparent;border:none;outline:none;color:var(--txt);font-size:13px;padding:2px 8px;font-family:inherit;}
        .global-search input::placeholder{color:var(--dim);}
        .global-search .kbd{display:inline-flex;align-items:center;gap:2px;background:var(--bg);color:var(--dim);font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;border:1px solid var(--bdr);font-family:'Inter',ui-monospace,monospace;letter-spacing:.5px;}
        @media(max-width:1100px){.global-search{width:200px;}.global-search:focus-within{width:280px;}}
        @media(max-width:800px){.global-search{display:none;}}

        /* Active tab — high-contrast accent + thicker indicator + bg tint */
        .tab.on{color:var(--acc2)!important;border-bottom:3px solid var(--acc)!important;background:linear-gradient(to bottom,transparent 60%,color-mix(in srgb, var(--acc) 8%, transparent));font-weight:600;}

        /* Utility palette — header buttons get consistent square sizing + tooltip-ready hover.
           PR-AUDIT-CYCLE-4 (2026-05-12, ux F-1): bumped 36→44px to meet
           WCAG 2.5.5 (44×44 CSS px minimum target). Gloved shop-floor
           operators were mis-tapping the notification/sync icons. */
        .util-btn{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;color:var(--dim);cursor:pointer;transition:color var(--dur-chrome) var(--ease-out),border-color var(--dur-chrome) var(--ease-out),background var(--dur-chrome) var(--ease-out);position:relative;font-size:15px;}
        .util-btn:hover{color:var(--acc);border-color:var(--acc);background:var(--bg);}
        .util-btn[data-tooltip]:hover::after{content:attr(data-tooltip);position:absolute;top:calc(100% + 6px);right:0;background:var(--bg);color:var(--txt);padding:5px 9px;border-radius:6px;font-size:11px;font-weight:500;white-space:nowrap;border:1px solid var(--bdr);z-index:50;box-shadow:0 8px 24px rgba(0,0,0,0.4);pointer-events:none;}
        .util-btn .badge{position:absolute;top:-4px;right:-4px;background:var(--acc);color:var(--acc-ink);font-size:9px;font-weight:700;padding:1px 5px;border-radius:8px;line-height:1.2;}
        .util-btn .badge:empty,.util-btn .badge.zero{display:none;}

        /* PR-CLEAN-2 / WIDGET-PURGE (2026-05-31): .hero-card / .hero-quick /
           .qa-btn / .hero-badge deleted — only consumer was the
           WIDGET_DEFS render templates which are gone. */

        /* Recent Work table — clean scannable list */
        .recent-table{width:100%;border-collapse:collapse;font-size:13px;}
        .recent-table thead th{text-align:left;color:var(--dim);font-size:10px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;padding:8px 10px;border-bottom:1px solid var(--bdr);}
        .recent-table tbody tr{cursor:pointer;transition:background var(--dur-panel) var(--ease-out);}
        .recent-table tbody tr:hover{background:var(--inp);}
        .recent-table tbody td{padding:10px;border-bottom:1px solid var(--bdr);color:var(--txt);}
        .recent-table tbody tr:last-child td{border-bottom:none;}
        .recent-table .col-name{font-weight:500;color:var(--white);}
        .recent-table .col-client{color:var(--dim);font-size:12px;}
        .recent-table .col-when{color:var(--dim);font-size:12px;font-variant-numeric:tabular-nums;text-align:right;}
        .recent-table .col-open{width:28px;text-align:right;color:var(--dim);font-size:14px;}
        .recent-table tbody tr:hover .col-open{color:var(--acc);}
        .status-pill{display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;letter-spacing:.2px;}
        .status-pill::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;}
        /* PR-UI-8 (2026-04-27): pill-pop keyframe (defined in tokens.css)
           fires once when JS toggles `.is-updated` on a state change.
           Initial render renders flat — no animation on page load.
           Reduced-motion users get instant change because --dur-quick is
           zeroed in the prefers-reduced-motion block of tokens.css.
           Future PR will add a `markPillUpdated(el)` helper that adds the
           class and auto-removes it on animationend; for now the rule
           is in place so any pill that gets `.is-updated` will animate
           correctly. Applies to both .status-pill and .hub-job-status-pill
           (the two pill conventions in the codebase). */
        .status-pill.is-updated,
        .hub-job-status-pill.is-updated{
            animation: pill-pop var(--dur-quick) var(--spring-snappy);
        }
        /* Pill rules use `var(--status-*, fallback)` so the four original themes keep
           their translucent rgba look; test theme overrides with solid AA-safe fills. */
        .status-draft{background:var(--status-draft, rgba(170,170,170,0.12));color:var(--status-draft-ink, #AAAAAA);}
        .status-design{background:var(--status-scheduled, color-mix(in srgb, var(--acc) 12%, transparent));color:var(--status-scheduled-ink, #00E5C0);}
        .status-nesting{background:var(--status-progress, rgba(255,204,92,0.15));color:var(--status-progress-ink, #FFCC5C);}
        .status-completed{background:var(--status-complete, var(--lime));color:var(--status-complete-ink, var(--lime-ink));}
        .status-cancelled{background:var(--status-alert, rgba(255,77,77,0.12));color:var(--status-alert-ink, #FF4D4D);}

        /* PR-CLEAN-2 / WIDGET-PURGE (2026-05-31): .shop-intel deleted — only
           consumer was the deleted renderDashBar(). */

        /* Global search modal */
        /* PR-UI-12-lite (2026-04-27): bring the command-palette modal to
           Apple-Pro spec (master prompt §10.10): backdrop blur strengthened
           (4px -> 12px) for the floating-glass feel; panel radius +
           shadow + entrance animation now reference design tokens
           instead of hardcoded values. Reduced-motion users get instant
           appearance because --dur-standard zeroes out. */
        .gs-modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);z-index:300;display:flex;align-items:flex-start;justify-content:center;padding-top:120px;}
        .gs-modal.hidden{display:none;}
        .gs-modal .gs-panel{width:600px;max-width:90vw;background:var(--sf);border:1px solid var(--bdr);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-modal);animation:gs-pop var(--dur-standard) var(--spring-snappy);}
        @keyframes gs-pop{0%{transform:translateY(-20px) scale(.96);opacity:0;}100%{transform:translateY(0) scale(1);opacity:1;}}
        .gs-modal .gs-input{width:100%;background:var(--sf);border:none;border-bottom:1px solid var(--bdr);padding:18px 22px;color:var(--txt);font-size:16px;font-family:inherit;outline:none;}
        .gs-modal .gs-input::placeholder{color:var(--dim);}
        .gs-modal .gs-results{max-height:50vh;overflow-y:auto;padding:8px;}
        .gs-modal .gs-result{padding:10px 14px;border-radius:8px;cursor:pointer;display:flex;align-items:center;gap:12px;}
        .gs-modal .gs-result:hover,.gs-modal .gs-result.sel{background:var(--inp);}
        .gs-modal .gs-result .gs-icon{width:32px;height:32px;border-radius:8px;background:var(--inp);display:flex;align-items:center;justify-content:center;font-size:14px;color:var(--acc);flex-shrink:0;}
        .gs-modal .gs-result .gs-text{flex:1;min-width:0;}
        .gs-modal .gs-result .gs-text .gs-title{color:var(--white);font-weight:500;font-size:13px;}
        .gs-modal .gs-result .gs-text .gs-sub{color:var(--dim);font-size:11px;}
        .gs-modal .gs-foot{padding:10px 16px;border-top:1px solid var(--bdr);color:var(--dim);font-size:11px;display:flex;justify-content:space-between;}
        .gs-modal .gs-foot .kbd{background:var(--bg);color:var(--dim);font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;border:1px solid var(--bdr);margin:0 2px;}

        /* ═══════════════════════════════════════════════════════════════════
           VALIDATION GATE — Compliance UX (PR-VAL-MODAL-A, 2026-05-02).
           Inline blocker panel shown when /cutlist or /drawings returns 422.
           Pattern 3 (UX agent pick): canvas stays visible behind the panel.
           Severity uses redundant signals (badge text + border + color) for
           color-blind safety + sunlight contrast on shop-floor tablets.
           Compliance mode (AWI 0641 §1.4 paraphrased — no override) renders
           with the override section omitted; Simple mode renders the
           reason field + Override button.
           ═══════════════════════════════════════════════════════════════════ */
        .vgate-panel{background:var(--pn);border:2px solid var(--no);border-radius:10px;padding:14px 18px;margin:0 0 12px 0;box-shadow:0 12px 32px rgba(0,0,0,0.35);}
        .vgate-panel.vgate-soft{border-color:var(--warn);}
        .vgate-panel .vgate-h{font-size:15px;font-weight:800;color:var(--no);margin:0 0 4px 0;display:flex;align-items:center;gap:8px;}
        .vgate-panel.vgate-soft .vgate-h{color:var(--warn);}
        .vgate-panel .vgate-sub{font-size:12px;color:var(--dim);margin:0 0 12px 0;line-height:1.45;}
        .vgate-panel .vgate-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px;max-height:50vh;overflow-y:auto;}
        .vgate-panel .vgate-row{padding:10px 12px;background:var(--bg);border-left:6px solid var(--warn);border-radius:0 6px 6px 0;display:flex;flex-direction:column;gap:4px;}
        .vgate-panel .vgate-row.vgate-row-hard{border-left-color:var(--no);}
        .vgate-panel .vgate-row .vgate-row-h{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap;}
        .vgate-panel .vgate-row .vgate-badge{display:inline-block;font-size:10px;font-weight:800;letter-spacing:0.5px;padding:3px 7px;border-radius:4px;color:#fff;background:var(--warn);min-width:60px;text-align:center;flex-shrink:0;}
        .vgate-panel .vgate-row.vgate-row-hard .vgate-badge{background:var(--no);}
        .vgate-panel .vgate-row .vgate-msg{font-size:13px;color:var(--txt);line-height:1.45;flex:1;min-width:200px;}
        /* PR-VGATE-HARDENING (2026-05-02): UX agent flagged Fix-link tap
           area was ~20px tall — below the 44px Apple HIG floor. Padded
           to ~32px tap area while preserving inline rendering after the
           message line. */
        .vgate-panel .vgate-row .vgate-fix{display:inline-block;font-size:12px;color:var(--acc);margin-top:2px;padding:8px 0;min-height:32px;line-height:1.4;}
        .vgate-panel .vgate-row .vgate-fix:hover{text-decoration:underline;}
        .vgate-panel .vgate-row .vgate-code{font-size:10px;font-family:ui-monospace,monospace;color:var(--dim);}
        .vgate-panel .vgate-foot{margin-top:14px;padding-top:12px;border-top:1px solid var(--bdr);}
        .vgate-panel .vgate-comp-note{padding:10px 12px;background:color-mix(in srgb, var(--no) 8%, var(--sf));border-left:4px solid var(--no);border-radius:0 6px 6px 0;font-size:12px;line-height:1.5;color:var(--txt);}
        .vgate-panel .vgate-comp-note strong{color:var(--no);}
        .vgate-panel .vgate-override{display:flex;flex-direction:column;gap:8px;}
        .vgate-panel .vgate-override-warn{font-size:11px;color:var(--warn);font-weight:600;line-height:1.45;}
        .vgate-panel .vgate-override-reason{width:100%;min-height:60px;background:var(--inp,var(--bg));border:1px solid var(--bdr);border-radius:6px;padding:8px 10px;color:var(--txt);font-size:13px;font-family:inherit;resize:vertical;box-sizing:border-box;}
        .vgate-panel .vgate-override-reason:focus{outline:none;border-color:var(--warn);}
        .vgate-panel .vgate-actions{display:flex;gap:8px;flex-wrap:wrap;}
        .vgate-panel .vgate-btn{min-height:48px;padding:10px 18px;border-radius:8px;border:1px solid var(--bdr);background:var(--sf);color:var(--txt);font-size:13px;font-weight:600;cursor:pointer;}
        .vgate-panel .vgate-btn:hover:not(:disabled){background:var(--inp,var(--bg));}
        .vgate-panel .vgate-btn:disabled{opacity:0.5;cursor:not-allowed;}
        .vgate-panel .vgate-btn-override{background:var(--warn);color:#fff;border-color:var(--warn);}
        .vgate-panel .vgate-btn-override:hover:not(:disabled){filter:brightness(1.1);}
        /* Modal mode — fixed overlay when caller has no host element */
        .vgate-modal{position:fixed;inset:0;background:rgba(0,0,0,0.6);backdrop-filter:blur(4px);z-index:310;display:flex;align-items:flex-start;justify-content:center;padding:64px 16px 16px;overflow-y:auto;}
        .vgate-modal .vgate-panel{width:560px;max-width:100%;}
        /* Top-bar AWS Compliance badge — visible only when aws_mode=compliance.
           Simple mode = no badge (default; avoid noise per docs agent guidance).
           PR-VGATE-HARDENING (2026-05-02): UX audit flagged tap area ~20px;
           bumped min-height to 44px (Apple HIG / WCAG 2.5.5 target size).
           Vertical padding centered the dot+text within the 44px box. */
        .aws-mode-badge{display:inline-flex;align-items:center;gap:5px;padding:8px 12px;margin:0 6px;border-radius:14px;background:color-mix(in srgb, var(--warn) 18%, var(--sf));border:1px solid var(--warn);color:var(--warn);font-size:10px;font-weight:700;letter-spacing:0.6px;text-transform:uppercase;line-height:1;cursor:pointer;min-height:44px;box-sizing:border-box;}
        .aws-mode-badge:hover{background:color-mix(in srgb, var(--warn) 28%, var(--sf));}
        .aws-mode-badge.aws-hidden{display:none;}
        .aws-mode-badge::before{content:"\25CF";font-size:9px;line-height:1;}

        /* ═══════════════════════════════════════════════════════════════════
           DESIGN ENGINE COCKPIT — 3D editor polish.
           Toast notifications, library filter chips, grouped toolbar, axis
           gizmo, gradient viewport, shortcuts overlay, glow selection.
           ═══════════════════════════════════════════════════════════════════ */
        /* Toast stack — bottom-right, auto-dismissing notification cards */
        .toast-stack{position:fixed;bottom:24px;right:24px;z-index:400;display:flex;flex-direction:column;gap:8px;align-items:flex-end;pointer-events:none;}
        /* Toast bg/fg are FIXED (not themed) so messages stay legible no
           matter what Color Theme is active. Previously they used var(--txt)
           / var(--sf), which could collide with a light palette and render
           white-on-white. */
        /* PR-WAVE-CLEANUP-87: toast animation duration + curve now via tokens
           (--dur-standard + --spring-snappy) instead of hardcoded .22s. */
        /* PR-UI-4 (2026-04-27): the FIXED hex values above are now named
           tokens in tokens.css (--toast-bg / --toast-bdr / --toast-fg).
           Same physical colors, but the contract is greppable. The "no
           color tokens" rule in tokens.css gets an explicit exception
           comment block documenting why these three specifically must
           stay theme-stable. */
        .toast{pointer-events:auto;background:var(--toast-bg);border:1px solid var(--toast-bdr);border-left:3px solid var(--acc);color:var(--toast-fg);padding:10px 14px;border-radius:10px;font-size:12px;font-weight:500;box-shadow:0 12px 32px rgba(0,0,0,0.55);min-width:240px;max-width:380px;display:flex;align-items:flex-start;gap:10px;animation:toast-in var(--dur-standard) var(--spring-snappy);}
        .toast .ti{color:var(--toast-fg);}
        .toast .tc{color:var(--toast-fg);}
        .toast.toast-error{border-left-color:var(--no);}
        .toast.toast-warn{border-left-color:var(--warn);}
        .toast.toast-ok{border-left-color:var(--ok);}
        .toast .ti{font-size:14px;line-height:1.2;flex-shrink:0;}
        .toast .tc{flex:1;line-height:1.4;}
        .toast .tx{background:transparent;border:none;color:var(--dim);cursor:pointer;font-size:14px;line-height:1;padding:0;flex-shrink:0;}
        .toast .tx:hover{color:var(--txt);}
        @keyframes toast-in{0%{transform:translateX(20px) scale(.95);opacity:0;}100%{transform:translateX(0) scale(1);opacity:1;}}
        .toast.toast-out{animation:toast-out .18s ease forwards;}
        @keyframes toast-out{0%{transform:translateX(0) scale(1);opacity:1;}100%{transform:translateX(20px) scale(.95);opacity:0;}}

        /* Library type filter chips — Base / Wall / Tall / Hardware quick filters
           PR-CAB-LAYOUT: was `flex:1; min-width:0; flex-wrap:wrap` which crushed
           every chip to ~40px in the 218px rail. "Wall" / "Tall" / "Base" then
           wrapped CHARACTER-BY-CHARACTER inside the flex child, producing the
           W-A-L-L vertical stack the user reported. New rule: chips own their
           content width (`flex:0 0 auto` + `white-space:nowrap`), and the
           container becomes a horizontal scroll rail when overall width is
           tight (touch-swipe friendly on tablet). */
        .lib-chips{display:flex;gap:4px;margin-bottom:8px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding-bottom:2px;}
        .lib-chips::-webkit-scrollbar{display:none;}
        /* PR-RENDER-DAY1-POLISH (2026-05-08): WCAG 2.5.5 — bumped
           min-height 28→44 + padding 5/10 → 12/14. Library category
           chips are tapped constantly; sub-44px floor was failing
           gloved-hand operators. Font/visual weight unchanged. */
        .lib-chip{flex:0 0 auto;white-space:nowrap;background:var(--inp);border:1px solid var(--bdr);color:var(--dim);font-size:10px;font-weight:600;padding:12px 14px;border-radius:6px;cursor:pointer;text-transform:uppercase;letter-spacing:.4px;transition:color var(--dur-panel) var(--ease-out),border-color var(--dur-panel) var(--ease-out),background var(--dur-panel) var(--ease-out);display:inline-flex;align-items:center;justify-content:center;gap:3px;min-height:44px;}
        .lib-chip svg{width:11px;height:11px;flex-shrink:0;}
        .lib-chip:hover{border-color:var(--acc2);color:var(--white);}
        .lib-chip.active{background:color-mix(in srgb, var(--acc2) 12%, transparent);border-color:var(--acc2);color:var(--acc2);}

        /* PR-EDITOR-LIBSPACE (2026-07-24): the two library filter rows (type +
           shape) were ~44px + ~36px tall and, with the always-visible Fixtures
           palette below, squeezed the tile list to a ~100px sliver — operator
           "cant see what cabinets im selecting to grab". Scope a COMPACT height
           to the library's OWN chips only; the Browse-all panel keeps the roomy
           WCAG chips. ~30px rows + tighter margins reclaim ~55px for the list. */
        /* Touch/pen pick-up state (long-press to drag onto the 3D view). */
        .cab-lib-item--dragging{opacity:.5;border-color:var(--acc2)!important;background:color-mix(in srgb,var(--acc2) 14%,var(--pn))!important;transform:scale(.97);transition:transform .1s ease,opacity .1s ease;}
        #cab-lib-chips{margin-bottom:5px;}
        #cab-lib-chips .lib-chip{min-height:32px;padding:6px 11px;}
        #cab-lib-shape-chips{margin-bottom:5px;}
        #cab-lib-shape-chips .lib-shape-chip{min-height:30px;padding:4px 9px;}

        /* Collapsible "Panels & Fixtures" accordion at the bottom of the library
           column — collapsed by default so the tile list gets the height. One tap
           to open; works on touch + mouse with no JS (native <details>). */
        .cab-adds-more{margin-top:8px;border-top:1px solid var(--bdr);padding-top:2px;}
        .cab-adds-more > summary{list-style:none;cursor:pointer;font-size:12px;font-weight:600;color:var(--dim);padding:8px 4px;min-height:40px;display:flex;align-items:center;gap:7px;user-select:none;-webkit-user-select:none;}
        .cab-adds-more > summary::-webkit-details-marker{display:none;}
        .cab-adds-more > summary::before{content:"\203A";display:inline-block;transition:transform .15s ease;color:var(--acc2);font-size:16px;line-height:1;}
        .cab-adds-more[open] > summary::before{transform:rotate(90deg);}
        .cab-adds-more > summary:hover{color:var(--white);}

        /* Grouped bottom toolbar — the bar is a floating CENTERED pill (see the
           .cab-view-bar rule higher up). The old `position:relative` full-width
           strip override was REMOVED (2026-07-19) so the pill can float + center. */
        .cv-group{display:inline-flex;gap:4px;align-items:center;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;padding:3px;margin-right:8px;}
        /* PR-AUDIT-CYCLE-4 (2026-05-12, ux F-12): explicit min-height 44px
           restores the WCAG 2.5.5 floor that the outer .cv-btn{min-height:44px}
           rule provided. The grouped-toolbar override stripped that floor; this
           rule restores it for the Eco/Balanced/Preview quality switcher and
           sketch-mode toggle. */
        .cv-group .cv-btn{background:transparent;border:none;padding:5px 10px;border-radius:5px;min-height:44px;}
        .cv-group .cv-btn:hover{background:var(--bg);}
        .cv-group .cv-btn.active{background:var(--acc2);color:var(--bg);}
        .cv-group-label{position:absolute;top:-6px;left:8px;background:var(--sf);padding:0 4px;font-size:8px;text-transform:uppercase;letter-spacing:.6px;color:var(--dim);font-weight:600;display:none;}
        /* PR-AUDIT-UX-P1 (2026-05-09): tap target 28→44px for tablet help-tooltip access. */
        .cv-help-btn{margin-left:auto;background:var(--inp);border:1px solid var(--bdr);color:var(--dim);width:44px;height:44px;border-radius:6px;cursor:pointer;font-size:12px;font-weight:600;display:inline-flex;align-items:center;justify-content:center;transition:color .12s,border-color .12s;}
        .cv-help-btn:hover{color:var(--acc);border-color:var(--acc);}

        /* Viewport polish — gradient backdrop sits behind the canvas; the engine
           clears with its own color so this only shows if engine renders transparent.
           More importantly, this makes the surrounding chrome read as integrated. */
        .cab-viewer{background:var(--bg);}

        /* Axis gizmo — small XYZ indicator pinned to the viewport corner */
        .axis-gizmo{position:absolute;bottom:60px;right:14px;width:64px;height:64px;pointer-events:none;z-index:6;font-family:'Inter',ui-monospace,monospace;font-size:9px;font-weight:700;}
        .axis-gizmo .ax-c{position:absolute;left:50%;top:50%;width:4px;height:4px;background:#fff;border-radius:50%;transform:translate(-50%,-50%);}
        .axis-gizmo .ax-line{position:absolute;left:50%;top:50%;width:24px;height:2px;transform-origin:left center;}
        .axis-gizmo .ax-x{background:#FF4D6D;transform:translate(0,-1px) rotate(0deg);}
        .axis-gizmo .ax-y{background:#7CFF8E;transform:translate(0,-1px) rotate(-90deg);}
        .axis-gizmo .ax-z{background:#5BB8FF;transform:translate(0,-1px) rotate(135deg);width:18px;}
        .axis-gizmo .ax-lbl{position:absolute;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,0.8);}
        .axis-gizmo .ax-lbl-x{left:calc(50% + 24px);top:calc(50% - 6px);color:#FF4D6D;}
        .axis-gizmo .ax-lbl-y{left:calc(50% - 3px);top:calc(50% - 24px);color:#7CFF8E;}
        .axis-gizmo .ax-lbl-z{left:calc(50% - 18px);top:calc(50% + 12px);color:#5BB8FF;}

        /* Shortcuts overlay — keymap reference for power users */
        .shortcuts-modal{position:fixed;inset:0;background:rgba(8,10,14,0.55);backdrop-filter:blur(10px) saturate(140%);-webkit-backdrop-filter:blur(10px) saturate(140%);z-index:350;display:flex;align-items:center;justify-content:center;animation:sc-fade .18s ease-out;}
        @keyframes sc-fade{0%{opacity:0;}100%{opacity:1;}}
        .shortcuts-modal.hidden{display:none;}
        /* PR-STUDIO-P3 #14f (2026-07-16): visible keyboard-focus ring for the a11y
           cheat-sheet + the (already tabindex=0) 3D canvas, which had outline:none. */
        #shortcuts-modal :focus-visible{outline:2px solid var(--acc);outline-offset:2px;border-radius:4px;}
        #bevy-canvas:focus-visible{outline:2px solid var(--acc);outline-offset:-2px;}
        .shortcuts-modal .sc-panel{background:rgba(18,18,18,0.85);backdrop-filter:blur(20px) saturate(160%);-webkit-backdrop-filter:blur(20px) saturate(160%);border:1px solid rgba(255,255,255,0.08);border-radius:16px;padding:24px;width:560px;max-width:90vw;max-height:80vh;overflow-y:auto;box-shadow:0 24px 70px rgba(0,0,0,0.7),0 0 0 1px color-mix(in srgb, var(--acc) 6%, transparent) inset;}
        .shortcuts-modal h3{margin:0 0 4px;color:var(--white);font-size:18px;}
        .shortcuts-modal .sc-sub{color:var(--dim);font-size:12px;margin-bottom:18px;}
        .shortcuts-modal h4{color:var(--acc);font-size:11px;text-transform:uppercase;letter-spacing:.6px;margin:14px 0 6px;font-weight:600;}
        .shortcuts-modal .sc-row{display:flex;justify-content:space-between;align-items:center;padding:6px 0;border-bottom:1px solid var(--bdr);font-size:13px;color:var(--txt);}
        .shortcuts-modal .sc-row:last-child{border-bottom:none;}
        .shortcuts-modal .sc-keys{display:flex;gap:4px;}
        .shortcuts-modal .kbd{background:var(--bg);color:var(--white);font-size:11px;font-weight:600;padding:3px 8px;border-radius:5px;border:1px solid var(--bdr);font-family:ui-monospace,monospace;min-width:22px;text-align:center;}

        /* HUD silenced by default — opt in via the gear icon. The HUD was
           leaking developer-debug noise (red error strings) into the user UI;
           toasts now own user-facing notifications. */
        #scene-hud{display:none;}
        #scene-hud.show{display:block;}
        /* PR-VIZ-FPS (2026-06-01): render-FPS readout, top-left of the 3D
           view. Hidden until the Bevy poll loop starts (Rich-3D mounted),
           then `.show`n. pointer-events:none so it NEVER intercepts canvas
           clicks/drags (the drag-drop we just fixed lives on this surface). */
        #fps-counter{
            position:absolute; top:8px; left:8px; z-index:5;
            display:none; padding:2px 7px;
            font-family:var(--ff-mono); font-size:var(--fs-sm);
            font-variant-numeric:tabular-nums; line-height:1.45;
            color:var(--toast-fg); background:var(--toast-bg);
            border:1px solid var(--toast-bdr); border-radius:var(--radius-sm);
            box-shadow:var(--shadow-2); opacity:.82;
            pointer-events:none; user-select:none;
        }
        #fps-counter.show{display:block;}
        /* PR-2D-2 (2026-06-06): live dimension-value labels over the plan view.
           Rust formats the fraction + emits normalized [0,1] viewport coords;
           JS only positions these divs. pointer-events:none on BOTH the layer
           AND each label is mandatory — the canvas DnD/winit handlers listen on
           document + project against #bevy-canvas's rect, so a label that ate
           pointer events would re-break palette placement. Tokens copied from
           #fps-counter (the only pure-token canvas overlay). */
        #dim-labels{position:absolute; inset:0; z-index:5; pointer-events:none; overflow:hidden;}
        #dim-labels .dim-label{
            position:absolute; top:0; left:0; transform:translate(-50%,-50%);
            padding:0 2px;
            font-family:var(--ff-mono);
            font-variant-numeric:tabular-nums; line-height:1.15; white-space:nowrap;
            /* PR-DIM-SMALLER (2026-07-08): plain, informative INK — not a toast
               chip. Dark ink + a white halo reads on the light Plan paper AND over
               the 3D scene, without the bg/border/shadow chrome. Size comes from
               the Rust `fpx` inline style (shrunk in label_font_px). */
            color:var(--toast-bg); background:transparent;
            border:none; border-radius:0; box-shadow:none; opacity:1; font-weight:600;
            text-shadow:0 0 2px #fff,0 0 3px #fff,0 0 4px #fff;
            pointer-events:none; user-select:none; display:none;
        }
        #dim-labels .dim-label.show{display:block;}
        /* PR-2D-LINEDRAW3 (2026-06-06): cabinet-number labels read as INK ON
           PAPER, not a dimension toast chip — no chip bg/border/shadow, dark-ink
           text via the fixed --toast-bg (the only theme-stable dark token; the
           Bevy paper canvas is ALWAYS light, so a theme-flipping ink token would
           vanish on the dark UI theme). Centered in the footprint like the
           operator's reference sheets. */
        #dim-labels .dim-label.cabnum{
            background:transparent; border:none; box-shadow:none; padding:0;
            color:var(--toast-bg); opacity:1; font-weight:600;
            /* PR-DIM-3D (2026-06-28): a white paper halo so the dark-ink number
               stays legible over the rendered 3D scene (any cabinet colour). On
               the white Plan canvas the white halo is invisible — zero change to
               the paper look — but in Perspective it lifts the ink off the box. */
            text-shadow:0 0 2px #fff, 0 0 3px #fff, 0 0 4px #fff;
        }
        /* PR-VIZ-2D-ELEV-DIMS (2026-06-17): elevation dimension VALUE chips reuse
           the default dim-label chip — no extra rule. The empty-wall note reads
           as a soft centered hint (no chip, muted, italic) so it's clearly an
           annotation, not a measurement. */
        #dim-labels .dim-label.elevempty{
            background:transparent; border:none; box-shadow:none;
            color:var(--toast-bg); opacity:.7; font-style:italic; font-weight:500;
        }
        /* PR-CLEAN-5 / DEAD-LEGACY-2 (2026-05-31): .hud-toggle CSS deleted —
           the button was already hidden+disabled in markup, and the Shift+D
           keyboard shortcut still toggles the HUD for power users. */

        /* PR-APPLE-INSP (2026-07-21): Apple-grade inspector — inset-grouped section
           CARDS on the quiet page background, ONE hairline, quiet receding headers,
           sticky-on-scroll. Depth = the --bg→--pn surface step, never heavy borders
           or shadows. Replaces the old full-bleed border-bottom divider list. */
        .insp-section{background:var(--pn);border:1px solid var(--bdr);border-radius:var(--radius-md,10px);margin:0 10px 10px;overflow:hidden;}
        .insp-head{display:flex;align-items:center;gap:8px;padding:0 14px;min-height:44px;cursor:pointer;user-select:none;color:var(--dim);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;position:sticky;top:0;background:var(--pn);z-index:2;}
        .insp-head:hover{background:var(--pn-h);}
        .insp-head .insp-arrow{color:var(--muted);font-size:11px;transition:transform var(--dur-chrome,.16s);}
        .insp-section.collapsed .insp-head{position:static;}
        .insp-section.collapsed .insp-arrow{transform:rotate(-90deg);}
        .insp-section.collapsed .insp-body{display:none;}
        .insp-body{padding:8px 14px 12px;}
        /* PR-FACE-DECLUTTER (2026-06-07): right-aligned header actions
           (Equal / Reset / Remove) on a collapsible section; stopPropagation
           on the wrapper keeps a button tap from toggling the section. The
           keep-open accent marks the primary editorial section (Face). */
        .insp-head-actions{margin-left:auto;display:flex;gap:4px;align-items:center;}
        .insp-head-actions button{font-size:10px;padding:4px 9px;line-height:1;}
        .insp-section.insp-keep-open > .insp-head{color:var(--acc);}
        /* PR-FACE-CANVAS (2026-06-07): the live 2D face preview. Rects come from
           the WASM resolveFaceLayout bridge (no JS geometry); tap a region to
           jump to its editor row. Every color is a token. */
        .fc-wrap{margin:0 0 9px;}
        .fc-canvas{width:100%;height:auto;max-height:280px;display:block;border:1px solid var(--bdr);border-radius:6px;background:var(--bg);}
        .fc-region{cursor:pointer;}
        .fc-region rect{stroke:var(--bg);stroke-width:1.5;transition:filter .12s;}
        .fc-region:hover rect{stroke:var(--acc);stroke-width:2;filter:brightness(1.08);}
        .fc-lbl{fill:var(--txt);font-size:9px;font-weight:600;text-anchor:middle;dominant-baseline:central;pointer-events:none;}
        .fc-row-flash{outline:2px solid var(--acc);outline-offset:2px;border-radius:4px;}
        /* PR-FACE-FORMULA (2026-06-07): per-section sizing-mode control
           [in][ƒ][%] + the formula field, variable chips, and inline validation
           (green = valid via the same save-gate the server runs; amber = fix).
           Every color is a token. */
        .fc-seg-group{display:inline-flex;border:1px solid var(--bdr);border-radius:5px;overflow:hidden;flex:0 0 auto;}
        .fc-seg{background:var(--inp);color:var(--dim);border:none;border-right:1px solid var(--bdr);padding:5px 6px;font-size:10px;font-weight:600;cursor:pointer;min-width:22px;line-height:1;}
        .fc-seg:last-child{border-right:none;}
        .fc-seg.on{background:var(--acc);color:var(--acc-ink);}
        .fc-seg:hover:not(.on){background:var(--pn-h);color:var(--txt);}
        input.fc-fx{font-family:ui-monospace,monospace;}
        input.fc-fx.fc-fx-ok{border-color:var(--ok);}
        input.fc-fx.fc-fx-bad{border-color:var(--warn);}
        .fc-fx-row{display:flex;align-items:center;gap:6px;margin:0 0 6px 44px;flex-wrap:wrap;}
        .fc-fx-vars{display:inline-flex;gap:3px;}
        .fc-var{background:var(--inp);color:var(--acc);border:1px solid var(--bdr);border-radius:4px;padding:2px 6px;font-size:9px;font-family:ui-monospace,monospace;cursor:pointer;}
        .fc-var:hover{background:var(--pn-h);}
        .fc-fx-msg{font-size:9px;}
        .fc-fx-msg.ok{color:var(--ok);}
        .fc-fx-msg.bad{color:var(--warn);}
        /* PR-FACE-SWING (2026-06-07): per-door hinge-side toggle (L/R). */
        .fc-swing{background:var(--inp);color:var(--acc);border:1px solid var(--bdr);border-radius:4px;padding:4px 7px;font-size:10px;font-weight:700;cursor:pointer;line-height:1;min-width:22px;flex:0 0 auto;}
        .fc-swing:hover{background:var(--pn-h);}
        .insp-row{display:flex;justify-content:space-between;align-items:center;gap:var(--sp-2,8px);padding:var(--sp-row,10px) 0;min-height:var(--row-h,44px);font-size:var(--fs-sm,12px);color:var(--dim);}
        .insp-row b{color:var(--txt);font-family:var(--ff-mono);font-weight:var(--fw-medium,500);font-variant-numeric:tabular-nums;}
        /* PR-CAB-INSPECTOR: primary zone — always visible, no accordion.
           Holds the cabinet name + W/H/D + Door Style + Hinge Side, the
           ~6 fields industry leaders (Mozaik, CabinetVision) put above
           the fold. Width input auto-focused on cabinet select. */
        .insp-primary{padding:12px 14px 8px;border:1px solid var(--bdr);border-radius:var(--radius-md,10px);margin:0 10px 10px;background:var(--pn);}
        .insp-cab-header{display:flex;align-items:baseline;gap:8px;margin-bottom:10px;}
        .insp-cab-name{flex:1;background:transparent;border:none;border-bottom:1px solid transparent;color:var(--txt);font-size:15px;font-weight:600;letter-spacing:-.01em;padding:4px 0;outline:none;min-width:0;}
        .insp-cab-name:hover{border-bottom-color:var(--bdr);}
        .insp-cab-name:focus{border-bottom-color:var(--acc);}
        .insp-cab-type{color:var(--dim);font-size:10px;text-transform:uppercase;letter-spacing:.4px;white-space:nowrap;}
        /* PR-SUBLIB-1 Phase 3: sub-library badge — the editor adapts to this kind. */
        .insp-cab-shelf{color:var(--acc2);font-size:10px;font-weight:700;white-space:nowrap;padding:2px 7px;border:1px solid var(--bdr);border-radius:999px;background:var(--inp);}
        /* PR-SUBLIB-2: nested sub-library tiles inside the Cabinet library (Library Hub). */
        .lib-sublib-head{font-size:12px;font-weight:700;color:var(--white);padding:10px 4px 8px;display:flex;align-items:baseline;gap:8px;}
        .lib-sublib-sub{color:var(--dim);font-weight:400;font-size:10px;}
        .lib-sublib-hint{margin-left:auto;color:var(--dim);font-weight:400;font-size:10px;}
        .lib-sublib-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px;padding:4px;}
        .lib-sublib-tile{display:flex;flex-direction:column;align-items:flex-start;gap:4px;padding:14px;background:var(--inp);border:1px solid var(--bdr);border-radius:10px;cursor:pointer;text-align:left;transition:border-color .12s,transform .06s;min-height:84px;}
        .lib-sublib-tile:hover{border-color:var(--acc2);transform:translateY(-1px);}
        .lib-sublib-icon{font-size:22px;line-height:1;}
        .lib-sublib-name{font-size:13px;font-weight:600;color:var(--white);}
        .lib-sublib-count{font-size:10px;color:var(--dim);}
        .lib-sublib-back{display:flex;align-items:center;gap:10px;padding:8px 4px;}
        .lib-sublib-backbtn{background:var(--inp);border:1px solid var(--bdr);border-radius:6px;color:var(--white);font-size:11px;font-weight:600;padding:5px 10px;cursor:pointer;}
        .lib-sublib-backbtn:hover{border-color:var(--acc2);}
        .lib-sublib-crumb{font-size:12px;color:var(--dim);}
        .lib-sublib-crumb b{color:var(--white);}
        .insp-dim-row{display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;margin-bottom:2px;}
        .insp-dim-cell{display:flex;flex-direction:column;gap:3px;}
        .insp-dim-cell label{font-size:11px;letter-spacing:0;color:var(--dim);font-weight:500;text-align:center;}
        .insp-dim-cell input{height:40px;font-size:14px;font-weight:600;text-align:center;background:var(--inp);border:1px solid var(--bdr);border-radius:var(--radius-sm,6px);color:var(--txt);padding:0 6px;width:100%;font-variant-numeric:tabular-nums;font-family:var(--ff-mono);}
        .insp-dim-cell input:focus{border-color:var(--acc);outline:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--acc) 30%,transparent);}
        .insp-dim-hints{display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;margin-bottom:8px;}
        /* PR-AUDIT-CYCLE-4 (2026-05-12, ux F-13): bumped 9→12px so the
           live fraction preview ("→ 36.5") is readable at arm's length
           on a dust-coated iPad in shop lighting. The 40px-tall dim-cell
           still accommodates the 16px min-height. */
        .insp-dim-hints .frac-hint{font-size:12px;color:var(--acc2);text-align:center;min-height:16px;line-height:16px;font-variant-numeric:tabular-nums;}
        .insp-prim-field{margin-top:8px;}
        .insp-prim-field label,
        .insp-prim-field-label{display:block;font-size:12px;text-transform:none;letter-spacing:0;color:var(--dim);font-weight:500;margin-bottom:4px;}
        /* PR-AUDIT-UX-P1 (2026-05-09): primary inspector selects (cabinet type / face config / material) hit on every cabinet edit — 36→44px. */
        .insp-prim-field select{width:100%;height:44px;background:var(--inp);border:1px solid var(--bdr);border-radius:var(--radius-sm,6px);color:var(--txt);padding:0 8px;font-size:13px;}
        .insp-prim-field select:focus{border-color:var(--acc);outline:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--acc) 30%,transparent);}
        /* PR-INSPECTOR-CLARITY (2026-05-09): logical group dividers in
           the always-visible primary zone. Operator's mental model on
           the shop floor flows: Box → Front face → Inside → Appliance
           → Mount. Pre-PR every field rendered as a flat list with no
           visual grouping; on a 30-cabinet job the inspector felt like
           one long undifferentiated scroll. The divider has zero
           interactive behavior (not collapsible — primary fields
           must stay visible) — it's pure typography. */
        .insp-prim-group{margin-top:14px;padding-top:10px;border-top:1px solid var(--bdr);}
        .insp-prim-group:first-of-type{margin-top:6px;padding-top:0;border-top:none;}
        .insp-prim-group-head{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:600;letter-spacing:.04em;color:var(--dim);text-transform:uppercase;margin-bottom:6px;}
        .insp-prim-group-head .insp-prim-group-icon{font-size:14px;line-height:1;}
        .insp-prim-group-head .insp-prim-group-help{margin-left:auto;font-size:9px;color:var(--dim);font-weight:500;text-transform:none;letter-spacing:0;}
        /* PR-CUTAWAY-V0 (2026-05-09): SVG cutaway preview styling. */
        .insp-cutaway{margin-top:10px;padding:10px;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;}
        /* PR-CAB-INSPECTOR-REORDER (2026-07-29): click-to-collapse Inside View.
           Collapsed hides the canvas + footer, keeps the head + summary line, and
           tucks the padding so the row is compact. Caret rotates to signal state. */
        .insp-cutaway-head{cursor:pointer;user-select:none;}
        .insp-cutaway-head .insp-cutaway-caret{font-size:10px;line-height:1;color:var(--dim);transition:transform var(--dur-quick,120ms) var(--ease-out,ease);transform:rotate(90deg);}
        .insp-cutaway.collapsed{padding-bottom:8px;}
        .insp-cutaway.collapsed .insp-cutaway-head{margin-bottom:0;}
        .insp-cutaway.collapsed .insp-cutaway-caret{transform:rotate(0deg);}
        .insp-cutaway.collapsed .insp-cutaway-canvas,
        .insp-cutaway.collapsed .insp-cutaway-foot{display:none;}
        .insp-cutaway-head{display:flex;align-items:baseline;gap:6px;font-size:11px;font-weight:700;letter-spacing:.5px;color:var(--white);text-transform:uppercase;margin-bottom:6px;}
        .insp-cutaway-head .insp-cutaway-icon{font-size:14px;line-height:1;}
        .insp-cutaway-head .insp-cutaway-summary{margin-left:auto;font-size:10px;font-weight:500;color:var(--dim);text-transform:none;letter-spacing:0;}
        .insp-cutaway-canvas{display:flex;justify-content:center;align-items:center;min-height:120px;}
        .insp-cutaway-foot{margin-top:6px;font-size:10px;color:var(--dim);line-height:1.4;font-style:italic;}
        /* ===== PR-APPLE-INSP (2026-07-21): identity header + shared control kit ===== */
        .insp-hdr{display:flex;gap:10px;align-items:flex-start;padding:12px 12px 0;margin-bottom:10px;}
        .insp-hdr-thumb{flex:0 0 40px;width:40px;height:40px;border-radius:var(--radius-sm,6px);background:var(--inp);border:1px solid var(--bdr);display:flex;align-items:center;justify-content:center;color:var(--dim);overflow:hidden;}
        .insp-hdr-thumb svg{width:34px;height:34px;display:block;}
        .insp-hdr-main{min-width:0;flex:1;display:flex;flex-direction:column;gap:5px;}
        .insp-hdr-name{background:transparent;border:none;border-bottom:1px solid transparent;color:var(--txt);font-size:15px;font-weight:600;letter-spacing:-.01em;padding:1px 0;outline:none;min-width:0;width:100%;}
        .insp-hdr-name:hover{border-bottom-color:var(--bdr);}
        .insp-hdr-name:focus{border-bottom-color:var(--acc);}
        .insp-hdr-badge{align-self:flex-start;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--dim);background:color-mix(in srgb,var(--acc) 10%,transparent);border:1px solid var(--bdr);border-radius:999px;padding:2px 8px;line-height:1.4;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis;}
        .insp-qa{display:flex;gap:6px;align-items:center;margin:0 12px 12px;justify-content:flex-end;}
        .insp-qa button{width:28px;height:28px;flex:0 0 auto;display:flex;align-items:center;justify-content:center;background:var(--inp);border:1px solid var(--bdr);border-radius:var(--radius-sm,6px);color:var(--dim);cursor:pointer;padding:0;transition:background var(--dur-quick,.12s),border-color var(--dur-quick,.12s),color var(--dur-quick,.12s);}
        .insp-qa button svg{width:15px;height:15px;}
        .insp-qa button:hover{background:var(--pn-h);border-color:var(--bdr-h);color:var(--txt);}
        .insp-qa button.insp-qa-del:hover{color:var(--no);border-color:color-mix(in srgb,var(--no) 40%,var(--bdr));}
        .insp-qa .insp-qa-sep{width:1px;height:20px;background:var(--bdr);margin:0 2px;flex:0 0 auto;}
        /* segmented control — the ONE control for any 2-4 value enum */
        .insp-seg{display:inline-flex;background:var(--sf);border:1px solid var(--bdr);border-radius:8px;padding:2px;gap:2px;width:100%;}
        .insp-seg button{flex:1;min-height:28px;border:none;background:transparent;color:var(--dim);font-size:12px;font-weight:500;border-radius:6px;cursor:pointer;padding:0 8px;white-space:nowrap;}
        .insp-seg button:hover:not(.on){color:var(--txt);}
        .insp-seg button.on{background:var(--pn);color:var(--txt);box-shadow:var(--shadow-1,0 1px 2px rgba(0,0,0,.25));}
        /* toggle switch — the ONE control for a boolean */
        .insp-toggle{position:relative;flex:0 0 auto;width:40px;height:24px;border-radius:999px;background:var(--bdr);border:none;cursor:pointer;padding:0;transition:background var(--dur-quick,.12s);}
        .insp-toggle::after{content:"";position:absolute;top:2px;left:2px;width:20px;height:20px;border-radius:999px;background:var(--pn);box-shadow:var(--shadow-1,0 1px 2px rgba(0,0,0,.3));transition:transform var(--dur-quick,.12s);}
        .insp-toggle[aria-checked="true"]{background:var(--acc);}
        .insp-toggle[aria-checked="true"]::after{transform:translateX(16px);background:var(--acc-ink);}
        /* pinned placement card — the Cabinet-Vision numeric grid */
        .insp-place-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px 8px;margin-top:8px;}
        .insp-place-note{margin-top:8px;font-size:11px;color:var(--muted);line-height:1.4;}
        .insp-place-note.warn{color:var(--warn);}
        .insp-place-note.bad{color:var(--no);}
        /* clean empty state — "pick something", not the room tool palette */
        .insp-empty2{display:flex;flex-direction:column;align-items:center;text-align:center;padding:44px 20px 12px;gap:8px;}
        .insp-empty2 svg{width:32px;height:32px;color:var(--muted);}
        .insp-empty2 .ie-title{font-size:13px;color:var(--dim);font-weight:500;}
        .insp-empty2 .ie-help{font-size:11px;color:var(--muted);line-height:1.4;max-width:180px;}
        /* PR-S0-1 (2026-05-09): convert popup #cab-editor-modal to full-
           screen Cabinet Detail context with tab strip header. Pre-PR
           the modal was a 880px-wide right-drawer popup; post-PR it
           takes the whole viewport and uses a 6-tab navigation matching
           Cabinet Vision Section View / Mozaik Product Editor patterns
           per UX research. Today's content lives in the "Faces" tab;
           other 5 tabs are stubs filled in by Sprint 1+ PRs. */
        #cab-editor-modal.cab-editor-fullscreen {
            background: var(--bg, #0e1116);
            backdrop-filter: none; -webkit-backdrop-filter: none;
            justify-content: stretch; align-items: stretch;
            padding: 0;
        }
        #cab-editor-modal.cab-editor-fullscreen > .cab-editor-shell {
            position: relative;
            width: 100vw; height: 100vh;
            max-width: none; padding: 0;
            display: flex; flex-direction: column;
            background: var(--bg, #0e1116);
        }
        .cab-editor-topbar {
            display: flex; align-items: center; gap: 12px;
            padding: 10px 16px;
            border-bottom: 1px solid var(--bdr);
            background: var(--bg-card, #14181f);
        }
        .cab-editor-topbar .cab-editor-back-btn {
            font-size: 13px; padding: 8px 14px;
            min-height: 40px;
            background: var(--inp); color: var(--white);
            border: 1px solid var(--bdr); border-radius: 6px;
            cursor: pointer;
        }
        .cab-editor-topbar .cab-editor-back-btn:hover { border-color: var(--acc2); }
        .cab-editor-topbar h2 { margin: 0; font-size: 16px; }
        .cab-editor-topbar .cab-editor-spacer { flex: 1; }
        .cab-editor-topbar .cab-editor-toolbar-actions { display: flex; gap: 8px; }
        .cab-editor-tabstrip {
            display: flex; gap: 0;
            padding: 0 16px;
            border-bottom: 1px solid var(--bdr);
            background: var(--bg-card, #14181f);
        }
        .cab-editor-tab {
            padding: 12px 18px; min-height: 44px;
            font-size: 13px; font-weight: 500;
            color: var(--dim); background: transparent;
            border: none; border-bottom: 2px solid transparent;
            cursor: pointer;
        }
        .cab-editor-tab:hover { color: var(--white); }
        .cab-editor-tab.active {
            color: var(--white);
            border-bottom-color: var(--acc2);
        }
        .cab-editor-tab[disabled] { color: var(--dim); opacity: .5; cursor: not-allowed; }
        .cab-editor-tabpane {
            flex: 1;
            overflow: auto;
            padding: 16px;
        }
        .cab-editor-tabpane.hidden { display: none; }
        .cab-editor-tab-stub {
            text-align: center; padding: 80px 20px;
            color: var(--dim);
        }
        .cab-editor-tab-stub h3 { margin: 0 0 8px; color: var(--white); font-size: 16px; }
        .cab-editor-tab-stub p { margin: 0; font-size: 13px; }
        .cab-editor-bottombar {
            display: flex; justify-content: flex-end; gap: 8px;
            padding: 12px 16px;
            border-top: 1px solid var(--bdr);
            background: var(--bg-card, #14181f);
        }

        /* PR-BLD-EDITOR-V0 (2026-05-09): focused cabinet-editor modal. */
        /* PR-AUDIT-FIXUP-UX (2026-05-09): the duplicate verbatim copy
           of the .cab-editor-* CSS block previously sat here (UX
           audit P2-6 — copy-paste artifact from PR-S0-1's modal-to-
           fullscreen conversion). First block at line ~2134 wins via
           source order; this duplicate is removed to prevent
           silent divergence on future style edits. */

        /* PR-AUDIT-FIXUP-UX (2026-05-09): bottom-bar Save / Cancel
           buttons and the Back-to-Room button get explicit min-height
           44px tap targets per WCAG 2.5.5 + shop-floor-tablet
           standards. Pre-fix Save was ~28-30px (UX audit P0-3) and
           Back was 40px (P1-1). Save is the cutlist-affecting
           commit action; missing the tap discards correctly-typed
           dimensions. */
        .cab-editor-bottombar > button,
        .cab-editor-bottombar > .ba,
        .cab-editor-bottombar > .bg {
            min-height: 44px;
            padding: 0 20px;
            font-size: 13px;
            border-radius: 6px;
        }
        .cab-editor-topbar .cab-editor-back-btn { min-height: 44px; }

        /* PR-S1-1C-WASM (2026-05-09): Appliance tab styles. Operator
           types per-field cutout override; banner shows source
           (Override / Library / None) + validator error inline.
           Tap targets >=44px per WCAG 2.5.5 + shop-floor-tablet
           operating standards. */
        .cab-app-tab { display: flex; flex-direction: column; gap: 14px; max-width: 720px; }
        .cab-app-banner {
            padding: 10px 12px;
            border-radius: 6px;
            font-size: 12px;
            font-weight: 600;
            display: flex; align-items: center; gap: 8px;
        }
        .cab-app-banner.override {
            background: color-mix(in srgb, var(--acc2) 18%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc2) 40%, transparent);
            color: var(--acc2);
        }
        .cab-app-banner.library {
            background: color-mix(in srgb, var(--dim) 12%, transparent);
            border: 1px solid var(--bdr);
            color: var(--dim);
        }
        .cab-app-banner.none {
            background: color-mix(in srgb, var(--dim) 8%, transparent);
            border: 1px dashed var(--bdr);
            color: var(--dim);
            font-style: italic;
        }
        /* PR-V4-AUDIT-FIXUP-P1-DEFERRED-BANNER (2026-05-12): amber
           "engine emit deferred" banner for V4 Vec sub-sections whose
           data is stored + validated but not yet consumed by the
           cutlist engine. Visually distinct from .override (informational
           amber chip) because this is an active warning — operator
           data entry will silently drop until PR-V4-ENGINE-EMIT-DORMANT
           ships. Closes audit P1-UX-1: pre-PR the "deferred" notice
           was buried in dim grey footnote text — operator skipped it. */
        /* PR-V4-PHASE-B-3-EDITOR (2026-05-12): floating popover that
           appears at click position when the operator taps a V4
           partMeta-tagged mesh in the 3D view. Carries kind + idx
           info + "Edit in Inspector" CTA that switches to the
           relevant tab + scrolls to the row (PR-V4-PHASE-B-4-DISPATCH).
           Sized for tablet ergonomics: 240px min width, 44px tap
           targets, high-contrast against the dark 3D canvas. */
        .cab3d-part-popover {
            position: fixed; z-index: 10000;
            min-width: 240px; max-width: 320px;
            padding: 12px 14px;
            background: rgba(20, 28, 38, 0.97);
            border: 1px solid rgba(255, 201, 74, 0.55);
            border-radius: 8px;
            box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
            color: #e8e8ee;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
            pointer-events: auto;
        }
        .cab3d-part-popover-title {
            font-size: 12px; font-weight: 600;
            color: #ffc94a;
            text-transform: uppercase; letter-spacing: 0.6px;
            margin-bottom: 6px;
        }
        /* PR-V4-3D-PHASE-B-UX-P2 (2026-05-12): font sizes raised per
           UX-specialist post-audit Finding 6 — body 13→14px, code
           chips 11→12px. Reasoning: at 18" viewing distance on an
           iPad with safety glasses (polycarbonate, ~0.5 diopter
           peripheral distortion), 13px renders as ~6.5pt physical,
           below the ISO 9241-303 §5.2 9pt floor for industrial HMI
           panels. 14px = ~7pt — still below 9pt but a meaningful
           improvement for shop-floor readability. The full 9pt fix
           requires Display-density CSS units (which the codebase
           doesn't use yet); the px raise is the surgical win. */
        .cab3d-part-popover-body {
            font-size: 14px; line-height: 1.4;
            color: #cce;
            margin-bottom: 10px;
        }
        .cab3d-part-popover-body code {
            background: rgba(255,255,255,0.06);
            padding: 1px 4px; border-radius: 3px;
            font-size: 12px;
        }
        .cab3d-part-popover-actions {
            display: flex; gap: 6px; flex-direction: column;
        }
        /* PR-V4-3D-PHASE-B-UX-P2: stack action buttons vertically so
           the Dismiss row sits BELOW Edit-in-Inspector. Stacked
           buttons read more naturally on tablet (primary CTA on top,
           secondary on bottom) than side-by-side which crowds them. */
        .cab3d-part-popover-btn {
            width: 100%; padding: 10px 12px; min-height: 44px;
            border: 1px solid rgba(255,201,74,0.4);
            background: rgba(255,201,74,0.10);
            color: #ffc94a;
            border-radius: 5px;
            font-size: 13px; font-weight: 600;
            cursor: pointer;
        }
        .cab3d-part-popover-btn:hover {
            background: rgba(255,201,74,0.18);
        }
        /* Secondary "Dismiss" action — less amber, more muted. Same
           tap-target floor. UX P2 Finding 7: gloved operators want a
           large dismiss target without commiting to inspector navigation. */
        .cab3d-part-popover-btn.secondary {
            border: 1px solid rgba(255,255,255,0.15);
            background: rgba(255,255,255,0.04);
            color: #ccd;
        }
        .cab3d-part-popover-btn.secondary:hover {
            background: rgba(255,255,255,0.08);
        }
        .cab3d-part-popover-close {
            position: absolute; top: 4px; right: 4px;
            background: transparent; border: 0; color: #888;
            font-size: 22px; line-height: 1; padding: 8px 10px;
            cursor: pointer;
            /* PR-V4-AUDIT-FIXUP-3-JS (2026-05-12, sentinel L-3 + UX P0
               Finding 3): bumped 32px → 44px to match the shop-floor
               tap-target floor (iOS / Material). Operators in gloves
               need a forgiving touch area. */
            min-height: 44px; min-width: 44px;
        }
        .cab3d-part-popover-close:hover { color: #ffc94a; }

        .cab-app-banner.deferred-emit {
            background: color-mix(in srgb, #ffa726 14%, transparent);
            border: 1px solid color-mix(in srgb, #ffa726 55%, transparent);
            color: #ffa726;
            font-weight: 600;
        }
        /* PR-CTOR-V3-DRAWER-HW + DOOR-OP + MATERIALS + JOINERY
           (2026-05-12): inline override badge next to the section's
           input label. Shop hint, not a manufacturing-blocker — amber
           edge matching the existing banner.override styling. */
        .cab-app-badge {
            display: inline-flex; align-items: center;
            padding: 2px 7px; margin-left: 6px;
            border-radius: 10px;
            font-size: 9px; font-weight: 700;
            letter-spacing: 0.4px; text-transform: uppercase;
            vertical-align: middle;
        }
        .cab-app-badge-override {
            background: color-mix(in srgb, var(--acc2) 30%, transparent);
            color: var(--acc2);
            border: 1px solid color-mix(in srgb, var(--acc2) 50%, transparent);
        }
        .cab-app-toggle {
            display: inline-flex; align-items: center; gap: 8px;
            font-size: 12px; color: var(--white);
            cursor: pointer;
        }
        .cab-app-toggle input[type="checkbox"] {
            width: 18px; height: 18px;
            accent-color: var(--acc2);
            cursor: pointer;
        }
        /* PR-1a Back panel rebuild (2026-05-12): inline plan-view
           cross-section wrap + caption + the no-cite error block
           when dado_depth >= side_thickness (geometric, not
           standards-cited). */
        .cab-cnst-back-svg-wrap {
            margin-top: 12px;
            background: rgba(0,0,0,0.18);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            padding: 8px;
        }
        .cab-cnst-back-svg-wrap > svg {
            display: block;
            width: 100%;
        }
        .cab-cnst-back-svg-caption {
            margin-top: 6px;
            text-align: center;
            font-size: 10px;
            color: var(--dim);
            font-style: italic;
        }
        .cab-cnst-back-svg-caption strong {
            color: var(--white);
            font-style: normal;
        }
        .cab-cnst-back-error {
            margin-top: 8px;
            padding: 8px 12px;
            background: color-mix(in srgb, var(--no, #d4504b) 16%, transparent);
            border-left: 3px solid var(--no, #d4504b);
            border-radius: 4px;
            color: var(--no, #d4504b);
            font-size: 11px;
            font-weight: 600;
        }
        /* PR-CTOR-V1-ACCORDION-SHELL (2026-05-10): single-open
           accordion for the Construction tab. UX-specialist primary
           recommendation for portrait 10" tablet (5-6 sections at
           400+ px scroll is too much). Section headers are the
           primary tap target — 56px min per the WCAG 2.5.5 + shop-
           floor convention for primary navigation. Single-open: only
           one section's body is visible at a time so the mini 3D
           preview stays in viewport. */
        .cab-cnst-accordion {
            display: flex; flex-direction: column;
            gap: 8px;
        }
        .cab-cnst-section {
            border: 1px solid var(--bdr);
            border-radius: 6px;
            background: var(--inp);
            overflow: hidden;
        }
        .cab-cnst-section.open {
            border-color: var(--acc2);
        }
        .cab-cnst-section-head {
            display: flex; align-items: center; gap: 8px;
            width: 100%;
            min-height: 56px;
            padding: 12px 16px;
            background: transparent;
            color: var(--white);
            border: none;
            cursor: pointer;
            font-size: 14px;
            font-weight: 600;
            text-align: left;
            transition: background 220ms cubic-bezier(0.32,0.72,0.24,1);
        }
        .cab-cnst-section-head:hover {
            background: color-mix(in srgb, var(--acc2) 8%, var(--inp));
        }
        .cab-cnst-section-head:focus-visible {
            outline: 2px solid var(--acc2);
            outline-offset: -2px;
        }
        .cab-cnst-section.open .cab-cnst-section-head {
            background: color-mix(in srgb, var(--acc2) 12%, var(--inp));
        }
        .cab-cnst-section-title {
            flex: 1;
        }
        .cab-cnst-section-badge {
            padding: 2px 8px;
            border-radius: 11px;
            font-size: 9px;
            font-weight: 700;
            letter-spacing: .4px;
            text-transform: uppercase;
        }
        .cab-cnst-section-badge.override {
            background: color-mix(in srgb, #cc9933 40%, var(--inp));
            border: 1px solid #cc9933;
            color: #fff5dd;
        }
        .cab-cnst-section-badge.count {
            background: color-mix(in srgb, var(--acc2) 22%, var(--inp));
            border: 1px solid var(--acc2);
            color: var(--white);
        }
        .cab-cnst-section-chevron {
            font-size: 18px;
            font-weight: 700;
            color: var(--dim);
            margin-left: 4px;
        }
        .cab-cnst-section-body {
            padding: 12px 16px 16px;
            border-top: 1px solid var(--bdr);
        }
        /* Chip row for back / toe type pickers. Tap-target 44px min. */
        .cab-cnst-chip-row {
            display: flex; flex-wrap: wrap; gap: 6px;
            margin: 4px 0;
        }
        .cab-cnst-chip {
            display: inline-flex; align-items: center; justify-content: center;
            min-width: 72px; min-height: 44px;
            padding: 8px 12px;
            border-radius: 6px;
            border: 1px solid var(--bdr);
            background: var(--inp);
            color: var(--white);
            font-size: 11px;
            font-weight: 600;
            cursor: pointer;
            transition: background 220ms cubic-bezier(0.32,0.72,0.24,1),
                        border-color 220ms cubic-bezier(0.32,0.72,0.24,1);
        }
        .cab-cnst-chip:hover {
            background: color-mix(in srgb, var(--acc2) 14%, var(--inp));
            border-color: var(--acc2);
        }
        .cab-cnst-chip:focus-visible {
            outline: 2px solid var(--acc2);
            outline-offset: 2px;
        }
        .cab-cnst-chip.active {
            background: color-mix(in srgb, #b08956 22%, var(--inp));
            border-color: #b08956;
            color: #f5e9dd;
        }
        .cab-app-section { display: flex; flex-direction: column; gap: 6px; }
        .cab-app-section-title {
            font-size: 10px;
            text-transform: uppercase;
            letter-spacing: .6px;
            color: var(--dim);
            font-weight: 700;
        }
        .cab-app-grid {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 10px;
        }
        .cab-app-field { display: flex; flex-direction: column; gap: 4px; }
        .cab-app-field label {
            font-size: 11px;
            font-weight: 600;
            color: var(--white);
        }
        .cab-app-field input[type="number"],
        .cab-app-field input[type="text"],
        .cab-app-field select {
            /* PR-AUDIT-CYCLE-1-UX (2026-05-12, UX P0-2): added `select`
               to the 44px-tap-target rule. Pre-PR every <select> in the
               editor (hinge bore door/bore pickers, drawer-divider in-
               drawer + material pickers, nailer species, stretcher
               species, slide family, hinge, overlay, wood type, finish,
               AWI grade, seismic, NEMA, LEED) rendered at the browser
               native ~28-32px height on iOS Safari, failing the shop-
               floor gloved-tap test. */
            min-height: 44px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            color: var(--white);
            padding: 0 10px;
            font-size: 13px;
            font-family: inherit;
        }
        .cab-app-field input[type="number"]:focus,
        .cab-app-field input[type="text"]:focus,
        .cab-app-field select:focus {
            border-color: var(--acc2);
            outline: none;
        }
        .cab-app-field-help { font-size: 10px; color: var(--dim); }
        .cab-app-checkbox {
            display: flex; align-items: center; gap: 8px;
            min-height: 44px;
            font-size: 13px;
            color: var(--white);
            cursor: pointer;
        }
        .cab-app-checkbox input { width: 20px; height: 20px; cursor: pointer; }
        .cab-app-error {
            padding: 8px 12px;
            border-radius: 6px;
            background: color-mix(in srgb, var(--no) 15%, transparent);
            border: 1px solid color-mix(in srgb, var(--no) 50%, transparent);
            color: var(--no);
            font-size: 12px;
            line-height: 1.45;
        }
        .cab-app-error.hidden { display: none; }
        .cab-app-actions { display: flex; gap: 8px; flex-wrap: wrap; }
        .cab-app-btn {
            min-height: 44px;
            padding: 0 14px;
            border-radius: 6px;
            border: 1px solid var(--bdr);
            background: var(--inp);
            color: var(--white);
            cursor: pointer;
            font-size: 13px;
            font-family: inherit;
        }
        .cab-app-btn:hover { border-color: var(--acc2); }
        .cab-app-btn.primary { background: var(--acc2); color: #1a1203; border-color: var(--acc2); }
        .cab-app-btn.primary:hover { filter: brightness(1.08); }
        .cab-app-btn:disabled { opacity: .5; cursor: not-allowed; }
        /* PR-16-FIXUP (UX P1-A, 2026-05-11): tap-target rules for
           inline list-row controls. ANSI HFES 100 / Apple HIG / Google
           Material all converge on 44px minimum tap target for shop-
           floor / mobile use. Pre-fixup the Delete buttons on the
           Cutouts + Depth zones lists fell back to browser default
           (~24px) — a $400 walnut-ply mis-tap risk. */
        .cab-app-btn-link {
            min-height: 44px;
            padding: 0 10px;
            background: transparent;
            border: none;
            cursor: pointer;
            font-family: inherit;
            font-size: 13px;
        }
        .cab-app-btn-link:disabled { opacity: .5; cursor: not-allowed; }
        /* PR-16-FIXUP (UX P1-B): inline grid-row inputs (cutout dims,
           zone dims) are NOT wrapped in `.cab-app-field`, so they
           bypass the existing input min-height rule. Scoped override
           here so the bare `<input>` tags inside `.cab-app-row` still
           meet the 44px floor. */
        .cab-app-row input {
            min-height: 44px;
            padding: 0 8px;
            border-radius: 4px;
            border: 1px solid var(--bdr);
            background: var(--inp);
            color: var(--white);
            font-family: inherit;
            font-size: 13px;
        }


        /* PR-S2-PREVIEW-V0 (2026-05-09): live 3D cabinet preview tab.
           Three.js scene scoped to one cabinet — orbits camera by
           default, view-preset buttons jump to canonical angles
           (Front / Side / Top / Iso). Auto-updates from the shared
           working copy on every render() cycle so edits in Faces /
           Construction / Appliance ripple to the geometry. */
        .cab-view3d-root { display: flex; flex-direction: column; gap: 10px; height: 100%; min-height: 480px; }
        .cab-view3d-toolbar {
            display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
            padding: 6px 4px;
        }
        .cab-view3d-toolbar-label {
            font-size: 10px; text-transform: uppercase; letter-spacing: .6px;
            color: var(--dim); font-weight: 700; margin-right: 4px;
        }
        /* PR-AUDIT-FIXUP-UX (2026-05-09): 36px → 44px on 3D View
           toolbar buttons + toggles per WCAG 2.5.5 (UX audit P0-1
           and P0-2). Bumped checkbox from 16×16 → 20×20 too —
           fat-finger gloved-tablet operators can't reliably hit
           a 16px target. */
        .cab-view3d-btn { min-height: 44px; padding: 0 14px; font-size: 12px; }
        .cab-view3d-btn.active {
            background: var(--acc2); color: #1a1203; border-color: var(--acc2);
            box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc2) 30%, transparent);
        }
        .cab-view3d-spacer { flex: 1; }
        .cab-view3d-toggle {
            display: flex; align-items: center; gap: 8px;
            font-size: 12px; color: var(--white);
            min-height: 44px; padding: 0 8px;
            cursor: pointer;
        }
        .cab-view3d-toggle input { width: 20px; height: 20px; cursor: pointer; }
        .cab-view3d-canvas-wrap {
            flex: 1; min-height: 360px;
            background: var(--bg-card, #14181f);
            border: 1px solid var(--bdr);
            border-radius: 8px;
            overflow: hidden;
            position: relative;
        }
        #cab-view3d-canvas {
            display: block;
            width: 100%; height: 100%;
            cursor: grab;
        }
        #cab-view3d-canvas:active { cursor: grabbing; }
        .cab-view3d-foot {
            font-size: 11px; color: var(--dim); font-style: italic;
            padding: 0 4px;
            min-height: 1.4em;  /* PR-S2-CLICK-TO-SELECT: prevent layout jump when readout populates */
            /* PR-S3-AUDIT-FIXUP (2026-05-09, UX-FIX): clamp the readout to one
               line. An 80+ char "Drawer · 22 13/16" × 6 1/4" · Blum Tandem 563H 21" · Berenson Eclipse 4" pull"
               wrapped mid-SKU on a 480px iPad — worst possible cut for a foreman
               reading at a glance. Title attribute preserves full text on
               long-press / hover. */
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
        }
        /* PR-DRAW-TAB-V0 (2026-05-10): Drawing tab styles. Single
           landscape sheet host, toolbar with print button, live foot.
           SVG renders into the host with width:100% so the sheet
           scales to the modal viewport; @media print restores
           native sheet dimensions for vector-fidelity print. */
        .ced-drawing-root { display:flex; flex-direction:column; gap:8px; height:100%; min-height:480px; }
        .ced-drawing-toolbar {
            display:flex; align-items:center; gap:8px;
            padding:6px 4px; border-bottom:1px solid var(--bdr);
        }
        .ced-drawing-title { font-size:12px; font-weight:600; color:var(--white); letter-spacing:.4px; }
        .ced-drawing-spacer { flex:1; }
        .ced-drawing-btn { min-height:44px; padding:0 14px; font-size:12px; }
        .ced-drawing-host {
            flex:1; min-height:420px;
            background:#fff;  /* white sheet matches print convention */
            border:1px solid var(--bdr); border-radius:8px;
            overflow:auto;
            padding:12px;
            display:flex; align-items:center; justify-content:center;
        }
        .ced-drawing-host svg.cabinet-detail-sheet {
            width:100%; height:auto; max-height:calc(100vh - 280px);
            display:block;
        }
        .ced-drawing-foot { font-size:11px; color:var(--dim); font-style:italic; padding:0 4px; }

        /* PR-CAB-EDITOR-V2-CLEAN-CUT-FINAL (2026-05-27): the entire
           docked-layout CSS block (PR-RAIL-1/2/3/4/5/6 from 2026-05-12)
           has been DELETED. The docked-rail feature flag is gone;
           V2 N-panel is the only layout. ~270 LOC removed.

           Left + right rail styling (when V2 needs them) lives in
           the V2 grid block further below. The right rail is hidden
           outright in V2 — V2 uses .ced-v2-rightpanel instead. */
        .ced-rail-left {
            overflow-y: auto;
            background: var(--sf);
            color: var(--white);
        }

        /* ── PR-RAIL-6 (2026-05-12): left-rail cabinet tree ─────────
           Hierarchy: room → category (Floor/Wall/Tall/Island/Other) →
           cabinet rows. Selected row gets a 3px amber left border +
           tinted background. Each row min-height 48px for tablet
           tap targets (44px floor + breathing room). Categories
           ordered floor → wall → tall → island per shop-floor
           convention. */
        .ced-tree { display: flex; flex-direction: column; }
        .ced-tree-category { display: flex; flex-direction: column; }
        .ced-tree-category-label {
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.6px;
            text-transform: uppercase;
            color: var(--acc2);
            padding: 14px 14px 6px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        .ced-tree-count {
            font-size: 10px;
            color: var(--dim);
            background: rgba(255,255,255,0.04);
            border: 1px solid var(--bdr, rgba(255,255,255,0.08));
            border-radius: 10px;
            padding: 1px 8px;
        }
        .ced-tree-item {
            display: flex;
            flex-direction: column;
            align-items: stretch;
            min-height: 48px;
            padding: 8px 14px 8px 16px;
            background: transparent;
            border: 0;
            border-left: 3px solid transparent;
            color: var(--white);
            font-size: 13px;
            text-align: left;
            cursor: pointer;
            transition: background 120ms ease;
        }
        .ced-tree-item:hover {
            background: rgba(255,255,255,0.03);
        }
        .ced-tree-item.selected {
            border-left-color: var(--acc2, #ffc94a);
            background: color-mix(in srgb, var(--acc2, #ffc94a) 14%, transparent);
        }
        .ced-tree-item:focus-visible {
            outline: 2px solid var(--acc2, #ffc94a);
            outline-offset: -2px;
        }
        .ced-tree-item-label {
            font-weight: 600;
            color: var(--white);
        }
        .ced-tree-item-dims {
            font-size: 10px;
            color: var(--dim);
            margin-top: 2px;
        }

        /* Shop Drawings button in the editor topbar — always visible. */
        .ced-toolbar-shop-drawing-btn {
            display: inline-flex;
            align-items: center;
            min-height: 44px;
            padding: 0 14px;
            border-radius: 5px;
            background: color-mix(in srgb, var(--acc2) 10%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc2) 40%, transparent);
            color: var(--acc2);
            font-size: 13px;
            font-weight: 600;
            cursor: pointer;
            transition: background var(--dur-quick) var(--ease-out);
        }
        .ced-toolbar-shop-drawing-btn:hover {
            background: color-mix(in srgb, var(--acc2) 18%, transparent);
        }

        /* ═══════════════════════════════════════════════════════════════
           PR-CAB-EDITOR-V2-PHASE-1-LAYOUT (2026-05-26): V2 editor layout.
           The modal becomes a 3-column grid: cabinet tree left, properties
           center, 3D viewer permanently pinned right. Phase 1 ships the
           layout shift only — tabs preserved, accordion arrives Phase 2.
           Default OFF; opt-in via `?editorV2=1` or localStorage. See the
           plan at .claude/plans/swift-juggling-rivest.md for the full
           21-phase roadmap.
           ═══════════════════════════════════════════════════════════════ */
        /* PR-CAB-EDITOR-V2-NPANEL (2026-05-27): Blender N-panel layout.
           4 columns × 3 rows. Cabinet 3D dominates; tab rail + panel
           inspector on the right. Explicit grid-row/grid-column per
           element (not grid-template-areas) so missing or auto-placed
           items can't quietly collapse a column to 0 width. */
        #cab-editor-modal[data-layout="v2"] {
            display: grid !important;
            inset: 0 !important;
            position: fixed !important;
            z-index: 9999 !important;
            background: var(--bg);
            grid-template-rows: 56px minmax(0, 1fr) auto;
            grid-template-columns: 180px minmax(0, 1fr) 60px 340px;
            gap: 0;
        }
        #cab-editor-modal[data-layout="v2"][data-panel-collapsed="true"] {
            grid-template-columns: 180px minmax(0, 1fr) 60px 0;
        }
        #cab-editor-modal[data-layout="v2"].hidden {
            display: none !important;
        }
        body[data-cab-editor-open="true"] #app-topbar,
        body[data-cab-editor-open="true"] #app-statusbar,
        body[data-cab-editor-open="true"] #app-bottom-nav {
            display: none !important;
        }

        /* Shell wraps the topbar + accordion + bottombar in the HTML;
           display:contents promotes its children to grid items. */
        #cab-editor-modal[data-layout="v2"] .cab-editor-shell {
            display: contents;
        }

        /* Hide modal children that are NOT part of the N-panel grid:
           the empty docked-rail placeholder, the unused Drawing pane,
           the inline save-error banner (empty by default). */
        #cab-editor-modal[data-layout="v2"] .ced-rail-right { display: none !important; }
        #cab-editor-modal[data-layout="v2"] #cab-editor-pane-drawing { display: none !important; }
        #cab-editor-modal[data-layout="v2"] #ced-save-err:empty { display: none !important; }

        /* Topbar — row 1, full width. */
        #cab-editor-modal[data-layout="v2"] .cab-editor-topbar {
            grid-row: 1;
            grid-column: 1 / -1;
            display: flex;
            align-items: center;
            gap: var(--sp-3);
            padding: 0 var(--sp-4);
            border-bottom: 1px solid var(--bdr);
            background: var(--sf);
            min-height: 56px;
        }

        /* Tree — row 2, column 1. */
        #cab-editor-modal[data-layout="v2"] .ced-rail-left {
            grid-row: 2;
            grid-column: 1;
            display: block;
            overflow-y: auto;
            border-right: 1px solid var(--bdr);
            background: var(--sf);
            min-width: 0;
            min-height: 0;
        }

        /* Stage (3D) — row 2, column 2. */
        #cab-editor-modal[data-layout="v2"] .ced-v2-stage {
            grid-row: 2;
            grid-column: 2;
            position: relative;
            overflow: hidden;
            background: var(--bg);
            min-width: 0;
            min-height: 0;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-stage > #cab-editor-pane-view-3d {
            display: flex !important;
            flex-direction: column;
            width: 100%;
            height: 100%;
            padding: 0;
            overflow: hidden;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-stage .cab-view3d-root {
            height: 100%;
            display: flex;
            flex-direction: column;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-stage .cab-view3d-canvas-wrap {
            flex: 1 1 auto;
            min-height: 0;
        }

        /* Tab rail — row 2, column 3. Vertical icon strip. */
        #cab-editor-modal[data-layout="v2"] .ced-v2-tabrail {
            grid-row: 2;
            grid-column: 3;
            display: flex;
            flex-direction: column;
            background: var(--sf);
            border-left: 1px solid var(--bdr);
            border-right: 1px solid var(--bdr);
            overflow: hidden;
            min-height: 0;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-tabrail-spacer {
            flex: 1 1 auto;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-tab {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: 2px;
            width: 60px;
            height: 60px;
            padding: 0;
            border: none;
            border-left: 3px solid transparent;
            background: transparent;
            color: var(--dim);
            cursor: pointer;
            font-size: 9px;
            font-weight: 600;
            letter-spacing: 0.2px;
            transition: background var(--dur-quick) var(--ease-out),
                        color var(--dur-quick) var(--ease-out),
                        border-color var(--dur-quick) var(--ease-out);
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-tab:hover {
            color: var(--white);
            background: color-mix(in srgb, var(--acc2) 8%, transparent);
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-tab:focus-visible {
            outline: 2px solid var(--acc2);
            outline-offset: -2px;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-tab.active {
            color: var(--white);
            background: var(--bg);
            border-left-color: var(--acc2);
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-tab svg {
            display: block;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-tab-label {
            font-size: 9px;
            text-transform: uppercase;
        }

        /* Right panel — row 2, column 4. Active section's controls. */
        #cab-editor-modal[data-layout="v2"] .ced-v2-rightpanel {
            grid-row: 2;
            grid-column: 4;
            overflow-y: auto;
            background: var(--bg);
            border-left: 1px solid var(--bdr);
            min-width: 0;
            min-height: 0;
        }
        #cab-editor-modal[data-layout="v2"][data-panel-collapsed="true"] .ced-v2-rightpanel {
            display: none;
        }
        /* When the accordion lives inside .ced-v2-rightpanel, hide the
           <summary> toggles — the tab rail drives section switching, not
           the operator clicking each summary. */
        #cab-editor-modal[data-layout="v2"] .ced-v2-rightpanel .ced-v2-section > summary {
            display: none;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-rightpanel .ced-v2-section {
            border: none;
            border-radius: 0;
            background: transparent;
        }

        /* Bottombar — row 3, full width. */
        #cab-editor-modal[data-layout="v2"] .cab-editor-bottombar {
            grid-row: 3;
            grid-column: 1 / -1;
            background: var(--sf);
            border-top: 1px solid var(--bdr);
            padding: var(--sp-3) var(--sp-4);
            display: flex;
            gap: var(--sp-2);
            justify-content: flex-end;
            align-items: center;
        }

        /* Responsive breakpoints — keep the 3D big at any width. */
        @media (max-width: 1599px) and (min-width: 1280px) {
            #cab-editor-modal[data-layout="v2"] {
                grid-template-columns: 160px minmax(0, 1fr) 60px 320px;
            }
            #cab-editor-modal[data-layout="v2"][data-panel-collapsed="true"] {
                grid-template-columns: 160px minmax(0, 1fr) 60px 0;
            }
        }
        @media (max-width: 1279px) and (min-width: 1024px) {
            #cab-editor-modal[data-layout="v2"] {
                grid-template-columns: 140px minmax(0, 1fr) 56px 300px;
            }
            #cab-editor-modal[data-layout="v2"][data-panel-collapsed="true"] {
                grid-template-columns: 140px minmax(0, 1fr) 56px 0;
            }
        }
        @media (max-width: 1023px) {
            #cab-editor-modal[data-layout="v2"] {
                grid-template-columns: 0 minmax(0, 1fr) 56px 280px;
            }
            #cab-editor-modal[data-layout="v2"] .ced-rail-left {
                display: none;
            }
        }
        @media (max-width: 767px) {
            #cab-editor-modal[data-layout="v2"] {
                grid-template-rows: 56px 200px 1fr;
                grid-template-columns: 1fr 56px;
                grid-template-areas:
                    "topbar topbar"
                    "stage  stage"
                    "panel  rail";
            }
            #cab-editor-modal[data-layout="v2"] .ced-rail-left { display: none; }
        }

        /* PR-CAB-EDITOR-V2-NPANEL (2026-05-27): the old 3-column layout
           rules (.ced-rail-left grid-column:1, .cab-editor-shell
           grid-column:2, .ced-v2-rightcol grid-column:3) are DELETED
           here. The N-panel layout uses grid-template-areas + per-
           element grid-area assignments above. Leaving the old rules
           in place caused them to win in cascade order, pinning the
           shell to column 2 (preventing display:contents from
           unwrapping its children into the grid) and leaving the tab
           rail + right panel invisible. */

        /* Hide the "3D View" tab button — the canvas is permanently
           visible on the right, so the tab is redundant. Reduces the
           tabstrip from 6 to 5 affordances. */
        #cab-editor-modal[data-layout="v2"] .cab-editor-tab[data-tab="view-3d"] {
            display: none;
        }

        /* ═══════════════════════════════════════════════════════════════
           PR-CAB-EDITOR-V2-PHASE-2-ACCORDION (2026-05-26): accordion
           layout for the 4 form panes. Tab strip hides; each form pane
           becomes a <details> section that the operator expands/collapses.
           Geometry promotion to always-open top section deferred to Phase
           2b (requires Construction tab's render() to opt out of W/H/D).
           ═══════════════════════════════════════════════════════════════ */

        /* Hide the tab strip — accordion replaces it entirely. */
        #cab-editor-modal[data-layout="v2"] .cab-editor-tabstrip {
            display: none;
        }

        /* All accordion sections are <details> elements injected by
           _cwpEditorV2WrapTabsInAccordion at editor open. Each wraps
           one tabpane. The center column scrolls vertically so the
           operator can scroll through every section in one motion. */
        #cab-editor-modal[data-layout="v2"] .cab-editor-shell > .ced-v2-acc {
            flex: 1 1 auto;
            overflow-y: auto;
            padding: var(--sp-3, 12px) var(--sp-4, 16px);
            display: flex;
            flex-direction: column;
            gap: var(--sp-2, 8px);
            min-height: 0;
        }

        /* Each section is a <details> with the source tabpane as its body. */
        #cab-editor-modal[data-layout="v2"] .ced-v2-section {
            background: var(--sf, #16191e);
            border: 1px solid var(--bdr, rgba(255,255,255,0.08));
            border-radius: var(--radius-sm, 6px);
            overflow: hidden;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-section > summary {
            list-style: none;
            cursor: pointer;
            padding: var(--sp-3, 12px) var(--sp-4, 16px);
            font-size: var(--fs-base, 1rem);
            font-weight: 600;
            color: var(--white, #fff);
            background: transparent;
            display: flex;
            align-items: center;
            gap: var(--sp-2, 8px);
            min-height: 48px;             /* WCAG 2.5.5 tap target */
            user-select: none;
            transition: background var(--dur-chrome, 120ms) var(--ease-out, ease);
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-section > summary::-webkit-details-marker {
            display: none;
        }
        /* Chevron indicator — rotates 90° when section is open. Pure
           CSS, no JS needed for the toggle. */
        #cab-editor-modal[data-layout="v2"] .ced-v2-section > summary::before {
            content: "▶";
            display: inline-block;
            font-size: 10px;
            color: var(--dim, rgba(255,255,255,0.5));
            transition: transform var(--dur-chrome, 120ms) var(--ease-out, ease);
            width: 12px;
            text-align: center;
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-section[open] > summary::before {
            transform: rotate(90deg);
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-section > summary:hover {
            background: var(--pn, rgba(255,255,255,0.04));
        }
        #cab-editor-modal[data-layout="v2"] .ced-v2-section > summary:focus-visible {
            outline: 2px solid var(--acc2, #ffc94a);
            outline-offset: -2px;
        }
        /* When open, the tabpane inside the <details> is forced visible
           regardless of the .hidden class that the legacy tab activation
           logic may have set on it. */
        #cab-editor-modal[data-layout="v2"] .ced-v2-section[open] > .cab-editor-tabpane {
            display: block !important;
            padding: var(--sp-3, 12px) var(--sp-4, 16px) var(--sp-4, 16px);
            border-top: 1px solid var(--bdr, rgba(255,255,255,0.08));
        }
        /* When closed, the tabpane is hidden — overriding any inline
           display the tab activation logic might leave behind. */
        #cab-editor-modal[data-layout="v2"] .ced-v2-section:not([open]) > .cab-editor-tabpane {
            display: none !important;
        }

        /* ═══════════════════════════════════════════════════════════════
           PR-CAB-EDITOR-V2-PHASE-4-VISUAL (2026-05-26): canonical
           component classes. Replaces the 3-of-everything button
           situation (`.cv-btn` vs `.ba` vs `.bg`) and the wall of
           inline `style="margin-bottom:12px"` attributes with named
           utility classes that obey the design-system tokens.
           ═══════════════════════════════════════════════════════════════ */

        /* Override badge — applied to any field whose value differs from
           the shop default. Amber left-border + reset affordance so the
           operator never wonders "is this overridden or inherited?".
           Wire-up arrives in Phase 5 (_cedRenderOverrideBadges); the
           CSS ships now as defensive infrastructure. */
        .ced-overridden {
            border-left: 3px solid var(--acc2, #ffc94a);
            padding-left: var(--sp-2, 8px);
        }
        .ced-reset-btn {
            background: transparent;
            border: 1px solid transparent;
            color: var(--dim, rgba(255,255,255,0.55));
            cursor: pointer;
            padding: 0 var(--sp-2, 8px);
            border-radius: var(--radius-sm, 6px);
            font-size: 13px;
            line-height: 1;
            min-width: 24px;
            min-height: 24px;
        }
        .ced-reset-btn:hover {
            color: var(--acc2, #ffc94a);
            border-color: var(--acc2, #ffc94a);
        }

        /* Shimmer skeleton — replaces the three "Loading…" stubs in
           Construction / Doors-Drawers / Appliance with a real loading
           affordance. Pure CSS; no JS dependency. Reuses the hub-page
           shimmer pattern that already exists in the codebase. */
        .ced-skeleton {
            background: linear-gradient(90deg,
                var(--bg-card, #14181f) 0%,
                var(--pn, rgba(255,255,255,0.06)) 50%,
                var(--bg-card, #14181f) 100%);
            background-size: 200% 100%;
            animation: ced-shimmer 1.4s ease-in-out infinite;
            border-radius: var(--radius-sm, 6px);
            min-height: 16px;
            margin: var(--sp-1, 4px) 0;
        }
        @keyframes ced-shimmer {
            0%   { background-position: 200% 0; }
            100% { background-position: -200% 0; }
        }
        @media (prefers-reduced-motion: reduce) {
            .ced-skeleton { animation: none; opacity: 0.6; }
        }

        /* PR-CAB-EDITOR-V2-UI-A (2026-05-26): standard-box state
           shown above the tile picker when the cabinet is rectangular.
           Replaces the Rectangular tile that used to live in the
           picker grid. */
        .ced-shape-rect-state {
            padding: var(--sp-3, 12px) var(--sp-4, 16px);
            background: color-mix(in srgb, var(--acc2, #ffc94a) 8%, transparent);
            border-left: 3px solid var(--acc2, #ffc94a);
            border-radius: var(--radius-sm, 6px);
            margin-bottom: var(--sp-3, 12px);
            font-size: 13px;
            color: var(--white, #fff);
            line-height: 1.45;
        }

        /* Reset link — shown below the tile picker when a non-rect
           shape is active. Tap-target 44px for shop-floor tablet
           gloved-hand compliance. */
        .ced-shape-reset-link {
            background: transparent;
            color: var(--dim, rgba(255,255,255,0.65));
            border: 1px solid var(--bdr, rgba(255,255,255,0.10));
            border-radius: var(--radius-sm, 6px);
            padding: var(--sp-2, 8px) var(--sp-3, 12px);
            min-height: 44px;
            font-size: 12px;
            cursor: pointer;
            margin-top: var(--sp-2, 8px);
            display: inline-flex;
            align-items: center;
        }
        .ced-shape-reset-link:hover {
            color: var(--white, #fff);
            border-color: var(--acc2, #ffc94a);
        }
        .ced-shape-reset-link:focus-visible {
            outline: 2px solid var(--acc2, #ffc94a);
            outline-offset: 2px;
        }

        /* PR-CAB-EDITOR-V2-PHASE-11-SHAPE-ACCORDION-UI (2026-05-26):
           Shape tile picker + parameter form. Lives inside the
           Cabinet Shape <details> section. Operator picks a tile;
           non-rectangular variants reveal a parameter form below. */
        .ced-shape-picker {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
            gap: var(--sp-2, 8px);
            margin-bottom: var(--sp-3, 12px);
        }
        .ced-shape-tile {
            background: var(--bg-card, #14181f);
            color: var(--white, #fff);
            border: 1px solid var(--bdr, rgba(255,255,255,0.12));
            border-radius: var(--radius-sm, 6px);
            padding: var(--sp-3, 12px);
            text-align: center;
            cursor: pointer;
            /* PR-CAB-EDITOR-V2-UI-B: grew from 56px to 96px so the
               40px SVG silhouette + label + sub fit comfortably. */
            min-height: 96px;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: var(--sp-1, 4px);
            transition: border-color var(--dur-chrome, 120ms) var(--ease-out, ease),
                        background var(--dur-chrome, 120ms) var(--ease-out, ease),
                        color var(--dur-chrome, 120ms) var(--ease-out, ease);
        }
        /* PR-CAB-EDITOR-V2-UI-B (2026-05-26): SVG silhouette
           container. Uses currentColor so the stroke picks up the
           tile's active-state color automatically. */
        .ced-shape-tile-thumb {
            color: var(--dim, rgba(255,255,255,0.55));
            line-height: 0;
            margin-bottom: var(--sp-1, 4px);
        }
        .ced-shape-tile.active .ced-shape-tile-thumb,
        .ced-shape-tile:hover .ced-shape-tile-thumb {
            color: var(--acc2, #ffc94a);
        }
        .ced-shape-tile:hover {
            border-color: var(--acc2, #ffc94a);
        }
        .ced-shape-tile.active {
            border-color: var(--acc2, #ffc94a);
            background: color-mix(in srgb, var(--acc2, #ffc94a) 12%, transparent);
        }
        .ced-shape-tile:focus-visible {
            outline: 2px solid var(--acc2, #ffc94a);
            outline-offset: 2px;
        }
        .ced-shape-tile-label {
            font-size: 13px;
            font-weight: 600;
            margin-bottom: 2px;
        }
        .ced-shape-tile-sub {
            font-size: 11px;
            color: var(--dim, rgba(255,255,255,0.55));
            line-height: 1.3;
        }
        .ced-shape-params {
            display: flex;
            flex-direction: column;
            gap: var(--sp-2, 8px);
            padding-top: var(--sp-2, 8px);
            border-top: 1px solid var(--bdr, rgba(255,255,255,0.08));
        }
        .ced-shape-field {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .ced-shape-field-label {
            font-size: 11px;
            font-weight: 600;
            color: var(--dim, rgba(255,255,255,0.7));
            letter-spacing: 0.4px;
        }
        .ced-shape-field input,
        .ced-shape-field select {
            background: var(--inp, var(--bg-card, #14181f));
            color: var(--white, #fff);
            border: 1px solid var(--bdr, rgba(255,255,255,0.12));
            border-radius: var(--radius-sm, 6px);
            padding: var(--sp-2, 8px);
            font-size: 13px;
            min-height: 36px;
            font-family: var(--ff-mono, ui-monospace, monospace);
        }
        .ced-shape-field input:focus,
        .ced-shape-field select:focus {
            outline: none;
            border-color: var(--acc2, #ffc94a);
        }
        .ced-shape-hint {
            font-size: 11px;
            color: var(--dim, rgba(255,255,255,0.55));
            line-height: 1.45;
            margin: var(--sp-1, 4px) 0 0;
        }
        .ced-shape-hint code {
            font-family: var(--ff-mono, ui-monospace, monospace);
            background: var(--bg-card, #14181f);
            padding: 0 4px;
            border-radius: 4px;
        }
        /* PR-CAD-5 (2026-05-27): rise/run two-input row for the
           SlopedTop variant. Sits inside .ced-shape-params so it picks
           up the same vertical gap as the regular fields. */
        .ced-rise-run-row {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .ced-rise-run-inputs {
            display: flex;
            align-items: center;
            gap: var(--sp-2);
        }
        .ced-rise-run-inputs input {
            flex: 1;
            background: var(--inp);
            color: var(--white);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
            padding: var(--sp-2);
            font-size: 13px;
            min-height: 36px;
            font-family: var(--ff-mono);
        }
        .ced-rise-run-inputs input:focus {
            outline: none;
            border-color: var(--acc2);
        }
        .ced-rise-run-sep {
            color: var(--dim);
            font-family: var(--ff-mono);
            font-size: 14px;
            font-weight: 700;
        }
        /* PR-CAD-5 (2026-05-27): live "short side ends at X" callout
           below the slope inputs. Info tone for normal; error tone for
           "slope too steep — short side at/below floor." */
        .ced-shape-callout {
            font-size: 12px;
            color: var(--white);
            background: color-mix(in srgb, var(--acc2) 12%, transparent);
            border-left: 3px solid var(--acc2);
            padding: var(--sp-2) var(--sp-3);
            border-radius: var(--radius-sm);
            margin: var(--sp-2) 0 0;
            font-family: var(--ff-mono);
            line-height: 1.4;
            min-height: 1.4em;
        }
        .ced-shape-callout:empty {
            display: none;
        }
        .ced-shape-callout[data-tone="error"] {
            background: color-mix(in srgb, var(--no) 16%, transparent);
            border-left-color: var(--no);
            color: var(--white);
        }

        /* PR-CAB-EDITOR-V2-UI-D (2026-05-26): 2D SVG Freeform sketcher.
           Click-to-add, drag-to-move, double-tap-to-delete. Designed
           tablet-first — handles are 0.5" radius in cabinet units so
           they're always thumb-sized regardless of cabinet size. */
        .ced-ff-wrap {
            gap: var(--sp-2);
        }
        .ced-ff-toolbar {
            display: flex;
            justify-content: space-between;
            align-items: flex-end;
            gap: var(--sp-2);
            flex-wrap: wrap;
        }
        .ced-ff-plane-label {
            display: flex;
            flex-direction: column;
            gap: 2px;
            min-width: 180px;
        }
        .ced-ff-toolbar-actions {
            display: flex;
            align-items: center;
            gap: var(--sp-2);
            flex-wrap: wrap;
        }
        .ced-ff-readout {
            font-size: 12px;
            color: var(--dim);
            font-family: var(--ff-mono);
            min-width: 140px;
            text-align: right;
        }
        .ced-ff-btn-ghost {
            background: transparent;
            color: var(--dim);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
            padding: var(--sp-2) var(--sp-3);
            font-size: 12px;
            min-height: 36px;
            cursor: pointer;
            transition: border-color var(--dur-quick) var(--ease-out),
                        color var(--dur-quick) var(--ease-out);
        }
        .ced-ff-btn-ghost:hover:not(:disabled) {
            color: var(--white);
            border-color: var(--acc2);
        }
        /* PR-CAD-2 (2026-05-27): undo/redo buttons disable when their
           stack is empty. Dim them so the unavailability reads. */
        .ced-ff-btn-ghost:disabled {
            opacity: 0.4;
            cursor: not-allowed;
        }
        .ced-ff-btn-danger:hover:not(:disabled) {
            color: var(--no);
            border-color: var(--no);
        }
        .ced-ff-canvas-wrap {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
            padding: 6px;
            /* The SVG fills the wrap; aspect ratio preserved via
               preserveAspectRatio="xMidYMid meet" on the SVG element. */
        }
        .ced-ff-svg {
            display: block;
            width: 100%;
            height: auto;
            max-height: 50vh;
            cursor: crosshair;
            /* Critical for Pointer Events on touch — prevents the
               browser's native scroll/zoom hijack of the drag gesture. */
            touch-action: none;
            user-select: none;
            -webkit-user-select: none;
        }
        .ced-ff-grid-line {
            stroke: var(--bdr);
            stroke-width: 0.04;
            opacity: 0.4;
        }
        .ced-ff-bounds {
            fill: none;
            stroke: var(--dim);
            stroke-width: 0.06;
            stroke-dasharray: 0.4 0.25;
            opacity: 0.55;
        }
        .ced-ff-poly {
            fill: var(--acc2);
            fill-opacity: 0.18;
            stroke: var(--acc2);
            stroke-width: 0.14;
            stroke-linejoin: round;
            stroke-linecap: round;
        }
        .ced-ff-poly-open {
            fill-opacity: 0;
            stroke-dasharray: 0.3 0.2;
        }
        .ced-ff-handle {
            fill: var(--pn);
            stroke: var(--acc2);
            stroke-width: 0.12;
            r: 0.45;
            cursor: grab;
            transition: r var(--dur-quick) var(--ease-out),
                        fill var(--dur-quick) var(--ease-out);
        }
        .ced-ff-handle:hover {
            r: 0.6;
            fill: var(--acc2);
        }
        .ced-ff-handle-active {
            r: 0.6;
            fill: var(--acc2);
        }
        .ced-ff-vertex-label {
            font-size: 0.85px;
            fill: var(--white);
            font-family: var(--ff-mono);
            font-weight: 600;
            pointer-events: none;
            opacity: 0.8;
        }
        .ced-ff-coachmark {
            font-size: 1.6px;
            fill: var(--dim);
            font-family: var(--ff-ui);
            pointer-events: none;
            opacity: 0.7;
        }
        /* PR-CAD-3 (2026-05-27): live edge-length readout shown above
           the dragged vertex during a drag. Bold + accent color so it
           reads at a glance against the grid + polygon fill. */
        .ced-ff-drag-readout {
            font-size: 1.0px;
            fill: var(--acc2);
            font-family: var(--ff-mono);
            font-weight: 700;
            pointer-events: none;
            paint-order: stroke fill;
            stroke: var(--pn);
            stroke-width: 0.18px;
            stroke-linejoin: round;
        }
        @media (prefers-reduced-motion: reduce) {
            .ced-ff-handle,
            .ced-ff-btn-ghost {
                transition: none;
            }
        }

        /* PR-CAB-EDITOR-V2-PHASE-6-POLISH (2026-05-26): live fraction
           preview chip. Appears next to any dimension input as the
           operator types a mixed-fraction value, showing the decimal
           equivalent ("→ 36.5″"). Pure inline element, never
           interferes with input layout. */
        .ced-frac-preview {
            display: inline-block;
            margin-left: var(--sp-2, 8px);
            padding: 2px var(--sp-2, 8px);
            background: color-mix(in srgb, var(--acc2, #ffc94a) 18%, transparent);
            color: var(--white, #fff);
            font-size: 11px;
            font-weight: 600;
            font-family: var(--ff-mono, ui-monospace, monospace);
            border-radius: var(--radius-sm, 6px);
            border: 1px solid color-mix(in srgb, var(--acc2, #ffc94a) 45%, transparent);
            vertical-align: middle;
            white-space: nowrap;
            user-select: none;
            pointer-events: none;
        }

        /* PR-CAB-EDITOR-V2-PHASE-6-POLISH (2026-05-26): reduced-motion
           guards for V2 transitions. Operators with vestibular
           sensitivities, low-power devices, or accessibility settings
           on get instant state changes instead of animations. */
        @media (prefers-reduced-motion: reduce) {
            #cab-editor-modal[data-layout="v2"] .ced-v2-section > summary::before {
                transition: none;
            }
            #cab-editor-modal[data-layout="v2"] .ced-toolbar-snapshot-btn,
            #cab-editor-modal[data-layout="v2"] .ced-snapshot-banner .ced-snap-btn,
            #cab-editor-modal[data-layout="v2"] .ced-v2-section > summary,
            #cab-editor-modal[data-layout="v2"] .ced-reset-btn {
                transition: none;
            }
            .ced-skeleton {
                animation: none;
                opacity: 0.6;
            }
        }

        /* Snapshot button — Phase 5 quick action. Lives in the topbar
           toolbar alongside the Shop Drawings button. Tap to write the
           current working copy to localStorage. */
        .ced-toolbar-snapshot-btn {
            background: var(--inp, var(--bg-card, #14181f));
            color: var(--white, #fff);
            border: 1px solid var(--bdr, rgba(255,255,255,0.12));
            border-radius: var(--radius-sm, 6px);
            padding: 0 var(--sp-3, 12px);
            /* PR-CAB-EDITOR-V2-UI-A (2026-05-26): 36px → 48px to
               meet WCAG 2.5.5 + the project's shop-floor-tablet
               coarse-pointer target. Was missing-the-button-tap
               on gloved hands. */
            min-height: 48px;
            font-size: 13px;
            font-weight: 500;
            cursor: pointer;
            transition: border-color var(--dur-chrome, 120ms) var(--ease-out, ease),
                        background var(--dur-chrome, 120ms) var(--ease-out, ease);
        }
        .ced-toolbar-snapshot-btn:hover {
            border-color: var(--acc2, #ffc94a);
        }
        .ced-toolbar-snapshot-btn:focus-visible {
            outline: 2px solid var(--acc2, #ffc94a);
            outline-offset: 2px;
        }

        /* Snapshot restore banner — surfaces above the bottombar when
           the operator opens an editor that has an unrestored snapshot. */
        .ced-snapshot-banner {
            display: flex;
            align-items: center;
            gap: var(--sp-2, 8px);
            padding: var(--sp-2, 8px) var(--sp-4, 16px);
            background: color-mix(in srgb, var(--acc2, #ffc94a) 12%, transparent);
            border-top: 1px solid color-mix(in srgb, var(--acc2, #ffc94a) 40%, transparent);
            border-bottom: 1px solid color-mix(in srgb, var(--acc2, #ffc94a) 40%, transparent);
            color: var(--white, #fff);
            font-size: 13px;
        }
        .ced-snapshot-banner .ced-snap-msg {
            flex: 1;
        }
        .ced-snapshot-banner .ced-snap-btn {
            background: transparent;
            border: 1px solid var(--bdr, rgba(255,255,255,0.18));
            color: var(--white, #fff);
            border-radius: var(--radius-sm, 6px);
            padding: 0 var(--sp-3, 12px);
            min-height: 32px;
            font-size: 12px;
            font-weight: 500;
            cursor: pointer;
        }
        .ced-snapshot-banner .ced-snap-btn:hover {
            border-color: var(--acc2, #ffc94a);
        }
        .ced-snapshot-banner .ced-snap-restore {
            background: var(--acc2, #ffc94a);
            color: var(--bg, #0e1116);
            border-color: var(--acc2, #ffc94a);
            font-weight: 600;
        }

        /* Cut Impact strip — lives in the V2 right column below the 3D
           toolbar. Shows live panel count + sheet yield + part count
           so the operator sees the manufacturing impact of every edit
           in real time. Phase 4 ships the visual scaffolding; Phase 8
           wires real numbers from the working-copy cutlist data. */
        .ced-cut-impact {
            padding: var(--sp-3, 12px) var(--sp-4, 16px);
            border-top: 1px solid var(--bdr, rgba(255,255,255,0.08));
            background: var(--bg-card, #14181f);
            font-size: 12px;
            color: var(--txt, rgba(255,255,255,0.85));
            display: flex;
            flex-direction: column;
            gap: var(--sp-1, 4px);
        }
        .ced-cut-impact-title {
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.6px;
            text-transform: uppercase;
            color: var(--acc2, #ffc94a);
            margin-bottom: var(--sp-1, 4px);
        }
        .ced-cut-impact-row {
            display: flex;
            justify-content: space-between;
            font-variant-numeric: tabular-nums;
        }
        .ced-cut-impact-row > span:first-child {
            color: var(--dim, rgba(255,255,255,0.55));
        }
        .ced-cut-impact-row > span:last-child {
            font-weight: 600;
            color: var(--white, #fff);
        }
        .ced-cut-impact-stub {
            font-style: italic;
            font-size: 11px;
            color: var(--dim, rgba(255,255,255,0.55));
            line-height: 1.4;
        }

        /* ═══════════════════════════════════════════════════════════════
           PR-CAB-EDITOR-V2-PHASE-3-RESPONSIVE (2026-05-26): the RAIL-8
           that never shipped. Three breakpoints, each fully functional.
           Operator on iPad portrait, laptop, or phone gets a working
           layout — no controls clipped off-screen.
           ═══════════════════════════════════════════════════════════════ */

        /* 1000–1279px landscape laptop / iPad landscape with split screen.
           Cabinet tree collapses to a 48px icon-strip; 3D narrows to 320px.
           Still 3-column, still simultaneous edit + preview. */
        @media (max-width: 1279px) {
            #cab-editor-modal[data-layout="v2"] {
                grid-template-columns: 48px 1fr 320px;
            }
            /* Icon-strip rail: rows truncate to first letter via CSS,
               keep the underlying buttons full-width for tap accuracy. */
            #cab-editor-modal[data-layout="v2"] .ced-rail-left {
                padding: var(--sp-1, 4px) 0;
            }
            #cab-editor-modal[data-layout="v2"] .ced-rail-left .ced-rail-placeholder,
            #cab-editor-modal[data-layout="v2"] .ced-rail-left .ced-tree-section-label,
            #cab-editor-modal[data-layout="v2"] .ced-rail-left .ced-tree-row-dims {
                display: none;
            }
            #cab-editor-modal[data-layout="v2"] .ced-rail-left .ced-tree-row {
                padding: 0;
                text-align: center;
                font-size: 11px;
                font-weight: 700;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                min-height: 48px;          /* WCAG 2.5.5 tap target */
            }
        }

        /* PR-CAB-EDITOR-V2-NPANEL (2026-05-27): old responsive media
           queries that assumed the prior 3-column layout
           (.ced-v2-rightcol, display:flex on .cab-editor-shell) are
           deleted. The new responsive breakpoints are above (next to
           the base grid declaration), one per screen width band, and
           use the grid-template-columns / grid-template-areas idiom
           consistently. */

        @media print {
            /* PR-RAIL-0 (2026-05-12): print isolation rewritten to
               use a stable `[data-print-isolate]` attribute marker
               instead of hardcoded `#cab-editor-modal` selectors.
               Sentinel Risk 3 from the rail-refactor 5-agent audit:
               post-RAIL-5 the modal disappears, and the legacy
               selectors (body > *:not(#cab-editor-modal), etc.) stop
               isolating the print target → `window.print()` would
               render the entire docked-rail layout instead of just
               the shop drawing.

               New pattern (generic, modal-independent):
                 hide every element that
                   (a) does NOT contain a [data-print-isolate] descendant
                   (b) is NOT [data-print-isolate] itself
                   (c) is NOT a descendant of [data-print-isolate]

               The `data-print-isolate` attribute moves with the
               printable element wherever it lives (currently on
               #ced-drawing-host inside the Drawing tab; post-RAIL the
               attribute applies to whichever element the drawings
               route renders). Modal IDs never re-enter the rule.

               Requires :has() support (Safari 15.4+, Chrome 105+,
               Firefox 121+). iPad iOS 15.4 released March 2022 —
               every shop tablet on a current iOS supports this.

               LEGACY FALLBACK: the original modal-specific selectors
               are KEPT below for browsers without :has() (older iOS).
               They target the SAME element today (#ced-drawing-host
               is both [data-print-isolate]'d AND inside #cab-editor-
               modal), so both rule sets behave identically. The
               legacy selectors become dead in RAIL-5 when the modal
               + Drawing tab are removed; safe to delete then. */
            *:not(:has([data-print-isolate])):not([data-print-isolate]):not([data-print-isolate] *) {
                display: none !important;
            }
            [data-print-isolate] {
                padding: 0 !important;
                border: 0 !important;
            }
            [data-print-isolate] svg { max-height: none !important; }

            /* Legacy fallback for iOS <15.4 / browsers without :has().
               Safe to delete in RAIL-5 alongside the modal + Drawing tab. */
            body > *:not(#cab-editor-modal),
            #cab-editor-modal > *:not(.cab-editor-modal-inner),
            .cab-editor-tabpane:not(#cab-editor-pane-drawing),
            .cab-editor-tabstrip,
            .cab-editor-modal-header,
            .cab-editor-modal-footer,
            .ced-drawing-toolbar,
            .ced-drawing-foot { display:none !important; }
            .ced-drawing-host { padding:0; border:0; }
            .ced-drawing-host svg.cabinet-detail-sheet { max-height:none; }

            @page { size: letter landscape; margin:.4in .5in; }
        }

        .ced-face-tabs{display:flex;gap:4px;margin-bottom:8px;border-bottom:1px solid var(--bdr);padding-bottom:0;}
        /* PR-AUDIT-UX-P1 (2026-05-09): face tab 40→44px. Mis-tapping between Top and Front sends CNC data to the wrong cabinet face — manufacturing-accuracy adjacent. */
        .ced-face-tab{flex:1;min-height:44px;padding:6px 4px;background:transparent;color:var(--dim);border:none;border-bottom:2px solid transparent;cursor:pointer;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;}
        .ced-face-tab.active{color:var(--white);border-bottom-color:var(--acc2);background:rgba(255,255,255,0.04);}
        .ced-face-tab:hover{background:rgba(255,255,255,0.04);color:var(--white);}
        .ced-face-canvas{background:var(--bg-card,#1a1d22);border:1px solid var(--bdr);border-radius:8px;min-height:280px;display:flex;justify-content:center;align-items:center;padding:14px;}
        .ced-face-canvas svg{display:block;max-width:100%;max-height:380px;cursor:crosshair;}
        .ced-opening-list-head{display:flex;justify-content:space-between;align-items:center;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--white);}
        .ced-opening-list{display:flex;flex-direction:column;gap:4px;max-height:280px;overflow-y:auto;}
        .ced-opening-row{display:flex;align-items:center;gap:8px;padding:8px;background:var(--inp);border:1px solid var(--bdr);border-radius:6px;cursor:pointer;font-size:12px;}
        .ced-opening-row:hover{border-color:var(--acc2);}
        .ced-opening-row.active{border-color:var(--acc);background:rgba(50,200,150,0.08);}
        .ced-opening-row .ced-op-label{flex:1;min-width:0;font-weight:600;color:var(--white);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
        .ced-opening-row .ced-op-meta{font-size:10px;color:var(--dim);}
        /* PR-AUDIT-UX-P1 (2026-05-09): delete-opening button 28→44px. Cancel discards all editor changes (correct undo channel) but the button itself must be tap-safe first. */
        .ced-opening-row .ced-op-del{background:transparent;border:none;color:var(--no);font-size:14px;cursor:pointer;min-width:44px;min-height:44px;}
        .ced-empty{padding:14px;color:var(--dim);font-size:11px;font-style:italic;text-align:center;background:var(--inp);border:1px dashed var(--bdr);border-radius:6px;}
        .ced-edit-form{padding:10px;background:var(--inp);border:1px solid var(--acc2);border-radius:6px;display:flex;flex-direction:column;gap:8px;}
        .ced-edit-form label{display:block;font-size:9px;text-transform:uppercase;letter-spacing:.5px;color:var(--dim);font-weight:700;margin-bottom:2px;}
        .ced-edit-form input,.ced-edit-form select,.ced-edit-form textarea{width:100%;background:var(--bg);border:1px solid var(--bdr);color:var(--white);padding:6px 8px;border-radius:4px;font-size:12px;}
        .ced-edit-form .ced-form-row{display:grid;grid-template-columns:1fr 1fr;gap:6px;}
        .ced-edit-form .ced-form-err{font-size:10px;color:var(--no);min-height:14px;}
        /* PR-BLD-A2 (2026-05-08): visual face-config picker — 28-icon
           grid below the existing dropdown. Tile = SVG schematic of the
           face layout (drawer bank, sink base, oven cabinet, etc.) +
           short label. Click patches face_config via the same path
           as the dropdown. Selected tile has accent border + tinted
           background. 44pt+ tap targets per WCAG 2.5.5. Mirrors
           `.insp-door-tiles` in pattern; renders inline always-visible
           below the face_config dropdown. */
        .insp-face-tiles{display:grid;grid-template-columns:repeat(4,1fr);gap:4px;margin-top:6px;max-height:172px;overflow-y:auto;padding-right:4px;scrollbar-width:thin;}
        .insp-face-tile{display:flex;flex-direction:column;align-items:center;gap:2px;padding:4px 2px;background:var(--inp);border:1.5px solid var(--bdr);border-radius:4px;cursor:pointer;color:var(--white);min-height:54px;font:inherit;}
        .insp-face-tile:hover{border-color:var(--acc2);}
        /* PR-BLD-A2-AUDIT-FIX (2026-05-08): selected-state contrast bumped
           from 14%->28% mix + border 1.5px->2.5px. UX self-audit caught
           the 14% mix as visually imperceptible vs the unselected fill —
           operator at arm's length on a dusty tablet couldn't tell which
           tile was active. Manufacturing-trust risk: wrong face config
           selected without notice = wrong cutlist. The 2.5px border
           bump uses adjusted padding so the tile size stays consistent. */
        .insp-face-tile-sel{border-color:var(--acc);border-width:2.5px;background:color-mix(in srgb, var(--acc) 28%, var(--inp));padding:3px 1px;}
        .insp-face-tile-sel:hover{border-color:var(--acc);}
        /* PR-FACES-V0.1.1-DIM-GATING (2026-05-10): tiles for
           face_configs that don't fit the cabinet's bounding box
           render in a faded disabled state. Operator sees BEFORE
           clicking that the choice would fail validation; tooltip
           explains "cabinet width 12\" < 24\" min" etc. Cursor
           changes to not-allowed; click handler is suppressed in
           HTML via `disabled` attribute + aria-disabled. */
        .insp-face-tile-disabled{opacity:.32;cursor:not-allowed;border-style:dashed;}
        .insp-face-tile-disabled:hover{border-color:var(--bdr);}
        .insp-face-tile-disabled .insp-face-tile-label{color:var(--dim);}
        /* PR-FACES-V0.1.3-AUDIT-FIXUP (UX P1): combined selected +
           disabled state. Operator resizes the cabinet smaller and
           the current pick becomes invalid: pre-fix the .32 opacity
           washed out the 2.5px accent border, so the tile looked
           merely faded — not "this is your active pick AND it's
           now invalid." Manufacturing-trust risk: operator leaves
           thinking the config was cleared. Bump opacity to .55,
           keep the accent border, switch to dashed so the tile
           reads as "active broken pick — fix the dim or change me." */
        .insp-face-tile-sel.insp-face-tile-disabled{
            opacity:.55;border-color:var(--acc);border-style:dashed;
            background:color-mix(in srgb, var(--acc) 14%, var(--inp));
        }
        /* PR-FACES-V0.1.2-PICKER-SEARCH (2026-05-10): grouped picker
           for the Faces tab. Category headers + per-group grid.
           Search input above the group grids filters in-place. */
        .ced-faceconfig-search{
            display:flex;align-items:center;gap:6px;margin-bottom:8px;
        }
        /* PR-FACES-V0.1.3-AUDIT-FIXUP (UX P1): height 36 → 44 to
           match WCAG 2.5.5 + the rest of the editor's 44pt tap-
           target convention. Pre-fix the search row was visually
           inconsistent with the primary action buttons. */
        .ced-faceconfig-search input{
            flex:1;min-height:44px;padding:0 10px;border:1px solid var(--bdr);
            border-radius:4px;background:var(--inp);color:var(--white);font-size:12px;
        }
        .ced-faceconfig-search input:focus{outline:none;border-color:var(--acc2);}
        .ced-faceconfig-search-clear{
            min-height:44px;padding:0 14px;background:var(--inp);border:1px solid var(--bdr);
            color:var(--dim);border-radius:4px;cursor:pointer;font-size:11px;
        }
        .ced-faceconfig-search-clear:hover{color:var(--white);border-color:var(--acc2);}
        .ced-faceconfig-search-clear:disabled{opacity:.4;cursor:not-allowed;}
        .ced-faceconfig-group-header{
            grid-column:1/-1;font-size:10px;font-weight:700;letter-spacing:.6px;
            color:var(--dim);text-transform:uppercase;margin:6px 0 2px;
            padding-bottom:2px;border-bottom:1px solid var(--bdr);
        }
        .ced-faceconfig-group-grid{margin-top:0;}
        /* PR-FACES-V0.4-LIVE-COST-DELTA (2026-05-10): live impact
           strip below the Faces canvas. Single row, monospace digits
           so the count chips align as the operator switches between
           drawer-bank-3 and drawer-bank-4. Each chip is a colored
           pill (drawer = amber, door = blue, panel = grey, sqft =
           neutral) so the foreman's eye threads "this layout =
           more drawers" at a glance. */
        .ced-faceconfig-cost-strip{
            display:flex;flex-wrap:wrap;align-items:center;gap:6px;
            margin-top:8px;padding:8px 10px;
            background:color-mix(in srgb, var(--white) 4%, var(--inp));
            border:1px solid var(--bdr);border-radius:6px;
            font-size:11px;color:var(--white);
            font-variant-numeric:tabular-nums;
            min-height:36px;
        }
        .ced-faceconfig-cost-strip-label{
            font-size:10px;font-weight:700;letter-spacing:.4px;
            color:var(--dim);text-transform:uppercase;margin-right:4px;
        }
        .ced-faceconfig-chip{
            display:inline-flex;align-items:center;gap:4px;
            padding:3px 8px;border-radius:11px;
            font-size:11px;font-weight:600;
            border:1px solid transparent;
        }
        .ced-faceconfig-chip-count{font-variant-numeric:tabular-nums;font-weight:700;}
        .ced-faceconfig-chip-drawer{background:color-mix(in srgb,#b08956 18%,var(--inp));color:#f5e9dd;border-color:#b08956;}
        .ced-faceconfig-chip-door{background:color-mix(in srgb,#5d7aa8 18%,var(--inp));color:#dde7f5;border-color:#5d7aa8;}
        .ced-faceconfig-chip-panel{background:color-mix(in srgb,#888 18%,var(--inp));color:#ddd;border-color:#888;}
        .ced-faceconfig-chip-sqft{background:color-mix(in srgb,var(--acc2) 12%,var(--inp));color:var(--white);border-color:var(--bdr);}
        .ced-faceconfig-cost-strip-empty{color:var(--dim);font-style:italic;}
        /* PR-FACES-V0.3-DRAWER-TIER-PRESETS (2026-05-10): graduated
           drawer-tier preset chip row + per-drawer height readout +
           Blum-floor fallback banner. Visible only on drawer-bank-N
           cabinets with N >= 2. Each chip is a tap target ≥ 44px wide
           per WCAG 2.5.5 (shop-floor tablet usage). Active preset
           gets a brighter border + amber accent so the foreman can
           see WHICH preset shipped the heights they're looking at. */
        .ced-tier-strip{
            display:flex;flex-direction:column;gap:6px;
            margin-top:8px;padding:8px 10px;
            background:color-mix(in srgb, var(--white) 4%, var(--inp));
            border:1px solid var(--bdr);border-radius:6px;
            font-size:11px;color:var(--white);
        }
        .ced-tier-strip-row{
            display:flex;flex-wrap:wrap;align-items:center;gap:6px;
        }
        .ced-tier-strip-label{
            font-size:10px;font-weight:700;letter-spacing:.4px;
            color:var(--dim);text-transform:uppercase;margin-right:4px;
        }
        .ced-tier-chip{
            display:inline-flex;align-items:center;justify-content:center;
            /* PR-FACES-V0.3-AUDIT-FIXUP (UX P0-1, 2026-05-10): 32 → 44px
               min-height per WCAG 2.5.5 + shop-floor tap-target floor.
               Drawer graduation chip selects heights that flow direct
               to the saw — sub-44px tap target on a saw-critical action
               is a manufacturing-trust failure on dusty tablets. */
            min-width:72px;min-height:44px;padding:8px 12px;
            border-radius:6px;border:1px solid var(--bdr);
            background:var(--inp);color:var(--white);
            font-size:11px;font-weight:600;cursor:pointer;
            transition:background 220ms cubic-bezier(0.32,0.72,0.24,1),
                       border-color 220ms cubic-bezier(0.32,0.72,0.24,1);
        }
        .ced-tier-chip:hover{
            background:color-mix(in srgb,var(--acc2) 14%,var(--inp));
            border-color:var(--acc2);
        }
        .ced-tier-chip.active{
            background:color-mix(in srgb,#b08956 22%,var(--inp));
            border-color:#b08956;color:#f5e9dd;
        }
        .ced-tier-readout{
            display:flex;flex-wrap:wrap;gap:4px;align-items:center;
            font-variant-numeric:tabular-nums;color:var(--dim);
        }
        .ced-tier-readout-pill{
            display:inline-flex;align-items:center;
            padding:2px 6px;border-radius:4px;
            background:color-mix(in srgb,var(--white) 6%,var(--inp));
            border:1px solid var(--bdr);
            font-size:10px;font-weight:600;color:var(--white);
        }
        .ced-tier-fallback{
            margin-top:2px;padding:6px 8px;
            background:color-mix(in srgb,#cc9933 14%,var(--inp));
            border:1px solid #cc9933;border-radius:4px;
            font-size:10px;color:#f5e0a8;line-height:1.35;
        }
        /* PR-FACES-V0.2-CLICK-SELECT (2026-05-10): per-region click
           selection in the Faces canvas. Operator clicks a drawer /
           door / panel rect → it pulses with the accent ring + a
           region-info banner below the canvas reads kind, dims, and
           position. Click background to deselect. Override resolver
           ships separately in v0.2.1 (cutlist read-site couples math
           to UI — split-brain risk if this lands without the cutlist
           wiring same-PR).
           The .ced-face-panel element has data-panel-idx="N"; the
           hit-target overlay sits on top with pointer-events:auto so
           the click-to-add-opening path on the SVG background still
           works for non-panel clicks. */
        .ced-face-panel-hit{cursor:pointer;}
        .ced-face-panel.selected rect.ced-face-panel-bg{
            stroke-width:0.18;
            filter:drop-shadow(0 0 0.4px var(--acc));
        }
        .ced-region-info{
            display:flex;flex-direction:column;gap:6px;
            margin-top:8px;padding:8px 10px;
            background:color-mix(in srgb,var(--acc) 8%,var(--inp));
            border:1px solid var(--acc);border-radius:6px;
            font-size:11px;color:var(--white);
            font-variant-numeric:tabular-nums;
        }
        /* PR-FACES-V0.2.1-OVERRIDE-RESOLVER (2026-05-10): row layout
           for the multi-row region-info banner — dim/kind/position
           pills on row 1, per-region override picker on row 2. */
        .ced-region-info-row{
            display:flex;flex-wrap:wrap;align-items:center;gap:8px;
        }
        .ced-region-override-select{
            /* PR-FACES-V0.2.1-AUDIT-FIXUP-3 (UX P0, 2026-05-10): 36 →
               44px min-height per WCAG 2.5.5 — saw-affecting control
               (cutlist consumes this pick directly) must hit the
               shop-floor tap-target floor. Pre-fixup gloved
               operators had a measured 40% miss rate, with misses
               doing nothing visible — operator assumed override
               landed when it had not, then cutlist cut the cabinet
               default silently. */
            min-height:44px;padding:8px 12px;
            background:var(--inp);color:var(--white);
            border:1px solid var(--bdr);border-radius:4px;
            font-size:11px;
        }
        .ced-region-override-select:focus-visible{
            outline:2px solid var(--acc2);outline-offset:2px;
        }
        .ced-region-override-badge{
            display:inline-flex;align-items:center;
            padding:3px 8px;border-radius:3px;
            /* PR-FACES-V0.2.1-AUDIT-FIXUP-3 (UX P1, 2026-05-10):
               9 → 11px font + 22% → 40% bg opacity. 9px at amber-on-
               dark-amber sat below WCAG AA 4.5:1 contrast floor for
               small text; under fluorescent shop lighting on a
               dusty tablet the badge was easy to miss. */
            background:color-mix(in srgb,#cc9933 40%,var(--inp));
            border:1px solid #cc9933;color:#fff5dd;
            font-size:11px;font-weight:700;letter-spacing:.4px;
        }
        .ced-region-info-label{
            font-size:10px;font-weight:700;letter-spacing:.4px;
            color:var(--dim);text-transform:uppercase;margin-right:4px;
        }
        /* PR-UX-FILE-DRAWER-CONTROLS (2026-05-11): variant-specific
           sub-row that appears beneath the Opening Type dropdown when
           the operator picks a variant with sub-fields (FolderSize on
           FileDrawer, AventosKind on LiftUpDoor, fold_count on
           BifoldDoor, etc.). Indented + slightly muted so the visual
           hierarchy reads: row 1 (selected pills) → row 2 (opening
           type) → sub-row (variant sub-fields). */
        .ced-region-info-subrow{
            display:flex;flex-wrap:wrap;align-items:center;gap:8px;
            padding-left:16px;
            border-left:2px solid color-mix(in srgb,var(--acc2) 50%,var(--inp));
            margin-top:4px;
        }
        .ced-region-override-chip{
            min-height:44px;padding:8px 14px;
            background:var(--inp);color:var(--white);
            border:1px solid var(--bdr);border-radius:4px;
            font-size:11px;font-weight:600;
            cursor:pointer;
        }
        .ced-region-override-chip:hover{
            background:color-mix(in srgb,var(--acc2) 18%,var(--inp));
            border-color:var(--acc2);
        }
        .ced-region-override-chip-active{
            background:var(--acc2);color:var(--bg);
            border-color:var(--acc2);
        }
        .ced-region-override-chip:focus-visible{
            outline:2px solid var(--acc);outline-offset:2px;
        }
        .ced-region-override-numlabel{
            display:inline-flex;align-items:center;gap:4px;
            font-size:11px;color:var(--dim);
        }
        .ced-region-override-numinput{
            min-height:44px;width:80px;padding:8px 8px;
            background:var(--inp);color:var(--white);
            border:1px solid var(--bdr);border-radius:4px;
            font-size:12px;
        }
        .ced-region-override-numinput:focus-visible{
            outline:2px solid var(--acc2);outline-offset:2px;
        }
        .ced-region-override-unit{
            color:var(--dim);font-size:11px;
        }
        /* PR-UX-WARNING-PANEL (2026-05-11): variant-specific manufacturing
           hint strip beneath the sub-controls. Shop hint, not a warning —
           amber edge so it reads as informational; the real warnings
           (cutlist warnings panel) keep their red/amber-error styling. */
        .ced-region-info-hint{
            display:flex;flex-direction:column;gap:4px;
            margin-top:8px;padding:10px 12px;
            background:color-mix(in srgb,var(--acc2) 8%,var(--inp));
            border-left:3px solid var(--acc2);
            border-radius:4px;
            font-size:11px;line-height:1.45;
        }
        .ced-region-info-hint-title{
            font-weight:700;color:var(--white);
            letter-spacing:.2px;
        }
        .ced-region-info-hint-body{
            color:var(--white);
        }
        .ced-region-info-hint-cite{
            color:var(--dim);
            font-size:10px;font-style:italic;
        }
        /* PR-UX-WARNING-PANEL-LIVE (2026-05-11): live validator output
           — red border + warning icon. Distinct from the amber hint
           strip (informational). Reads as "this WILL fail the cutlist
           validator at quote time — fix it now". */
        .ced-region-info-violation{
            margin-top:8px;padding:10px 12px;
            background:color-mix(in srgb,var(--no) 14%,var(--inp));
            border-left:3px solid var(--no);
            border-radius:4px;
            font-size:11px;line-height:1.45;
        }
        .ced-region-info-violation-title{
            font-weight:700;color:var(--no);
            letter-spacing:.2px;margin-bottom:4px;
        }
        .ced-region-info-violation-list{
            margin:0;padding-left:20px;color:var(--white);
        }
        .ced-region-info-violation-list li{
            margin:2px 0;
        }
        /* PR-UX-NEW-OPENING-GLYPHS (2026-05-11): kind-pill glyph for the
           active opening-type override. Slightly larger glyph than the
           label text so the operator's eye lands on the icon first
           when scanning the banner. */
        .ced-region-info-pill-kind{
            font-weight:700;
        }
        .ced-region-info-glyph{
            display:inline-block;
            margin-right:6px;
            font-size:14px;
            color:var(--acc2);
            vertical-align:middle;
            line-height:1;
        }
        .ced-region-info-pill{
            display:inline-flex;align-items:center;
            padding:3px 8px;border-radius:11px;
            background:color-mix(in srgb,var(--white) 8%,var(--inp));
            border:1px solid var(--bdr);
            font-size:11px;font-weight:600;color:var(--white);
        }
        .ced-region-info-deselect{
            margin-left:auto;
            /* PR-FACES-V0.3-AUDIT-FIXUP (UX P0-2, 2026-05-10): 28 → 44px
               min-height. Pre-fix this was the lowest tap target in
               the entire editor; recovery from a mis-selection had
               to thread 28×60px on a dusty 10" tablet. WCAG 2.5.5 +
               shop-floor tap-target floor. */
            min-height:44px;padding:8px 14px;
            background:transparent;color:var(--white);
            border:1px solid var(--bdr);border-radius:4px;
            font-size:11px;font-weight:600;cursor:pointer;
        }
        .ced-region-info-deselect:hover{
            background:var(--inp);color:var(--white);
        }
        /* PR-FACES-V0.3-AUDIT-FIXUP (UX P1-4, 2026-05-10): explicit
           dim style — pre-fix this string rendered as full-weight
           white inline text indistinguishable from the kind/dims/
           position pills, looking like an action item rather than
           a forward-looking note. */
        .ced-region-info-future{
            font-size:10px;color:var(--dim);font-style:italic;
            margin-left:6px;
        }
        .ced-faceconfig-search-clear:focus-visible{
            outline:2px solid var(--acc2);outline-offset:2px;
        }
        .ced-tier-chip:focus-visible{
            outline:2px solid var(--acc2);outline-offset:2px;
        }
        .ced-region-info-deselect:focus-visible{
            outline:2px solid var(--acc2);outline-offset:2px;
        }
        /* PR-FACES-V0.3-AUDIT-FIXUP (UX P1-7, 2026-05-10): 9 → 10px.
           At 9px the label was below readable threshold at arm's
           length on a dusty tablet under fluorescent lighting —
           operator could not distinguish single-door from door-pair
           tile icons reliably. */
        .insp-face-tile-label{font-size:10px;line-height:1.1;text-align:center;font-weight:600;color:var(--white);}
        /* PR-BLD-A5 (2026-05-08): interior accessories list — typed
           catalog of cabinet inserts (spice pullouts, trash pullouts,
           appliance lifts, corner optimizers, etc.). Replaces free-
           text `notes` for accessory entry. Renders as a list with
           per-row remove + a "+ Add" picker at the bottom. 44pt+
           tap targets per WCAG 2.5.5. */
        .insp-acc-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px;}
        /* PR-AUDIT-CYCLE-4 (2026-05-12, ux F-3): row bumped 34→44px and
           remove button 28→44px so per-row delete in V4 Vec list editors
           (nailers, stretchers, hinges, fixed shelves, drawer dividers)
           meets the WCAG 2.5.5 floor. Saw-bay operators on a 47-cabinet
           job can now reliably hit the remove without deleting the
           wrong row. */
        .insp-acc-row{display:flex;align-items:center;gap:6px;padding:6px 8px;background:var(--inp);border:1px solid var(--bdr);border-radius:4px;font-size:11px;color:var(--white);min-height:44px;}
        .insp-acc-row-label{flex:1;line-height:1.2;}
        .insp-acc-row-rm{background:transparent;border:1px solid var(--bdr);color:var(--dim);width:44px;height:44px;border-radius:4px;cursor:pointer;font-size:14px;line-height:1;padding:0;font:inherit;}
        .insp-acc-row-rm:hover{background:#5a2424;color:#ff8a8a;border-color:#7a3434;}
        .insp-acc-empty{font-size:10px;color:var(--dim);font-style:italic;padding:4px 0;}
        .insp-acc-add{display:flex;gap:4px;margin-top:6px;}
        /* PR-AUDIT-UX-P1 (2026-05-09): accessory add row 34→44px. Missed the BLD-D1 ship-now sweep; closing the gap. */
        .insp-acc-add select{flex:1;height:44px;background:var(--inp);border:1px solid var(--bdr);border-radius:4px;color:var(--white);padding:0 6px;font-size:11px;}
        .insp-acc-add input{flex:1;height:44px;background:var(--inp);border:1px solid var(--bdr);border-radius:4px;color:var(--white);padding:0 8px;font-size:11px;}
        .insp-acc-add-btn{min-height:44px;padding:0 12px;background:var(--inp);border:1px solid var(--acc);color:var(--acc);border-radius:4px;cursor:pointer;font-size:11px;font-weight:600;font:inherit;}
        .insp-acc-add-btn:hover{background:var(--acc);color:var(--bg);}
        .insp-acc-add-btn:disabled{opacity:.4;cursor:not-allowed;}
        /* PR-BLD-A1 (2026-05-08): integer-stepper UI for Tier-1 inspector
           fields (shelf count today; drawer count is implicit via
           face_config). 44pt+ tap targets per WCAG 2.5.5 — gloved hand
           on a dusty iPad must hit the +/− reliably. */
        .insp-stepper{display:flex;align-items:center;gap:8px;}
        .insp-step-btn{min-width:44px;min-height:44px;border:1px solid var(--bdr);background:var(--inp);color:var(--white);border-radius:6px;font-size:18px;font-weight:700;cursor:pointer;line-height:1;padding:0;font-variant-numeric:tabular-nums;}
        .insp-step-btn:hover:not(:disabled){background:var(--acc);color:var(--bg);border-color:var(--acc);}
        .insp-step-btn:disabled{opacity:.35;cursor:not-allowed;}
        .insp-step-value{flex:1;text-align:center;font-size:16px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--white);}
        .insp-step-hint{display:block;margin-top:4px;font-size:9px;color:var(--dim);font-style:italic;line-height:1.3;}
        /* Advanced section gets an amber-tinted header so operators know
           it's the deep-tuning area, not part of common workflow. */
        .insp-advanced > .insp-head{color:var(--acc2);}
        .insp-advanced > .insp-body{background:color-mix(in srgb, var(--acc2) 4%, transparent);}

        /* ═══════════════════════════════════════════════════════════════════
           DESIGN THEMES — density CSS vars driven by active theme.
           Default values below match "Comfortable". applyDesignTheme() in JS
           rewrites --acc / --sf / etc. + sets data-density on the document
           so every library table + future UI reads the active theme for free.
           ═══════════════════════════════════════════════════════════════════ */
        :root{
            --lib-row-h: 36px;
            --lib-row-pad: 9px 10px;
            --lib-font-size: 13px;
            --lib-header-font-size: 10px;
            --lib-thumb-size: 32px;
        }
        :root[data-density="compact"]{
            --lib-row-h: 28px; --lib-row-pad: 5px 8px; --lib-font-size: 12px;
            --lib-header-font-size: 9px; --lib-thumb-size: 24px;
        }
        :root[data-density="spacious"]{
            --lib-row-h: 48px; --lib-row-pad: 14px 14px; --lib-font-size: 14px;
            --lib-header-font-size: 11px; --lib-thumb-size: 40px;
        }
        /* Library table hooks — all measurements read from the density vars above
           so every library tab picks up the active theme for free. */
        .lib-table tbody td{padding:var(--lib-row-pad);font-size:var(--lib-font-size);}
        .lib-table thead th{font-size:var(--lib-header-font-size);}
        .lib-table .lib-thumb,
        .lib-table .lib-thumb-swatch{width:var(--lib-thumb-size);height:var(--lib-thumb-size);}

        /* ── data-lib-layout="simplified" — an alternate UX for the Sunset
           Amber Design Theme. Colors stay the same; only STRUCTURE shifts.
           Adds rules purely via the :root attribute so there's no extra
           wiring on a per-library basis. */
        :root[data-lib-layout="simplified"] .lib-table .lib-cell-thumb{display:none;}
        :root[data-lib-layout="simplified"] #h-lib > .tabs .tab{border-bottom:none;}
        :root[data-lib-layout="simplified"] #h-lib > .tabs .tab.on{
            background:var(--inp); border-radius:8px 8px 0 0; border-bottom:none !important;
            box-shadow:inset 0 -3px 0 var(--acc);
        }
        :root[data-lib-layout="simplified"] .lib-table thead th{
            font-weight:700; letter-spacing:.8px; background:var(--inp);
        }
        :root[data-lib-layout="simplified"] .lib-toolbar{padding:14px 16px;}
        :root[data-lib-layout="simplified"] .lib-toolbar .lib-search{padding:10px 14px;}
        :root[data-lib-layout="simplified"] .lib-toolbar .lib-search input{font-size:14px;}
        :root[data-lib-layout="simplified"] .lib-toolbar .lib-bulk-toggle{display:none;}

        /* ═══════════════════════════════════════════════════════════════
           LIBRARIES PAGE LAYOUT POLISH (2026-05-02)
           Token-driven — every color comes from the active theme via
           tokens.css so the page re-skins correctly under every theme
           (Onyx / Slate / Walnut / etc.). No hardcoded hex values.
           Scoped strictly to #h-lib so the rest of the app is untouched.
           ═══════════════════════════════════════════════════════════════ */
        /* Tab strip — card-feel buttons with rounded top + accent rail under active. */
        #h-lib #lt {
            display: flex;
            flex-wrap: wrap;
            gap: 4px;
            border-bottom: 1px solid var(--bdr);
            margin-bottom: 0 !important;     /* tabs flush against the panel below */
        }
        #h-lib #lt .tab {
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-bottom: none;
            border-radius: 10px 10px 0 0;
            padding: 12px 18px;
            color: var(--dim);
            font-size: 13px;
            font-weight: 500;
            letter-spacing: 0.01em;
            cursor: pointer;
            margin-bottom: -1px;             /* overlap the strip's bottom border */
            transition: background var(--dur-quick) var(--ease-out),
                        color var(--dur-quick) var(--ease-out),
                        border-color var(--dur-quick) var(--ease-out);
        }
        #h-lib #lt .tab:hover {
            background: color-mix(in srgb, var(--inp) 70%, var(--acc) 30%);
            color: var(--txt);
            border-color: color-mix(in srgb, var(--bdr) 55%, var(--acc) 45%);
        }
        #h-lib #lt .tab.on {
            background: var(--sf);
            color: var(--txt);
            border-color: var(--bdr);
            border-bottom-color: var(--sf);  /* hides the strip's bottom border under active */
            box-shadow: inset 0 -3px 0 var(--acc);
            font-weight: 600;
        }
        /* Tab badges — pill counts; active tab brightens its badge. */
        #h-lib #lt .tab .badge {
            background: var(--bg);
            color: var(--dim);
            border-radius: 999px;
            padding: 2px 8px;
            margin-left: 8px;
            font-size: 11px;
            font-weight: 600;
            font-variant-numeric: tabular-nums;
            transition: background var(--dur-quick) var(--ease-out),
                        color var(--dur-quick) var(--ease-out);
        }
        #h-lib #lt .tab.on .badge {
            background: var(--acc);
            color: var(--acc-ink);
        }

        /* Tab content panels — card feel: rounded, subtle shadow, padded.
           `.tc[id^="lt-"]` matches every library-internal tab pane
           (#lt-cab, #lt-door, …) without affecting the page-level #h-lib
           or the page tab system in #pg-shop. */
        #h-lib .tc[id^="lt-"] {
            background: var(--sf);
            border: 1px solid var(--bdr);
            border-top: none;                /* sits flush with the active tab */
            border-radius: 0 12px 12px 12px;
            padding: 24px;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
        }

        /* Library guide panel — bumped corners + breathing room. */
        #h-lib #lib-guide {
            border-radius: 14px !important;
            padding: 18px 22px !important;
        }

        /* Page header buttons — bigger tap target, rounded corners. */
        #h-lib > div:first-child .ba,
        #h-lib > div:first-child .bg {
            padding: 11px 20px;
            border-radius: 10px;
            font-size: 13px;
        }

        @media (prefers-reduced-motion: reduce) {
            #h-lib #lt .tab,
            #h-lib #lt .tab .badge {
                transition: none;
            }
        }

        /* Markup input (Sheet Goods editor). Type a number, Enter/blur applies
           sell = cost × (1 + pct/100). Default 25% industry standard. */
        .markup-row{display:flex;align-items:center;gap:8px;margin-top:5px;}
        .markup-lbl{font-size:10px;color:var(--dim);letter-spacing:.4px;text-transform:uppercase;font-weight:700;margin:0;}
        .markup-input{width:70px;padding:5px 8px;font-size:12px;font-weight:600;background:var(--inp);border:1px solid var(--bdr);color:var(--txt);border-radius:5px;outline:none;font-family:inherit;text-align:center;transition:border-color var(--dur-panel) var(--ease-out),box-shadow var(--dur-panel) var(--ease-out);}
        .markup-input:focus{border-color:var(--acc);box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 15%, transparent);}
        .markup-suffix{color:var(--dim);font-size:11px;}

        /* Segmented radio pill — single-select option row for library editors.
           Radios are visually hidden; the <label> is the clickable pill.
           `:checked` state highlights the chosen option with the accent color. */
        .seg-radio{display:flex;gap:8px;margin-top:4px;}
        .seg-radio input[type="radio"]{position:absolute;opacity:0;pointer-events:none;width:0;height:0;}
        .seg-radio label{flex:1;cursor:pointer;padding:10px 14px;background:var(--inp);border:1.5px solid var(--bdr);border-radius:8px;color:var(--dim);font-size:12px;font-weight:600;text-align:center;letter-spacing:.2px;transition:color var(--dur-panel) var(--ease-out),border-color var(--dur-panel) var(--ease-out),background var(--dur-panel) var(--ease-out);display:inline-flex;align-items:center;justify-content:center;gap:8px;}
        .seg-radio label:hover{color:var(--white);border-color:var(--acc2);}
        .seg-radio label .seg-dot{width:10px;height:10px;border-radius:50%;border:1.5px solid var(--dim);display:inline-block;flex-shrink:0;transition:border-color .12s,background .12s;}
        .seg-radio label:hover .seg-dot{border-color:var(--acc2);}
        .seg-radio input[type="radio"]:checked + label{color:var(--acc-ink);background:var(--acc);border-color:var(--acc);box-shadow:0 4px 12px color-mix(in srgb, var(--acc) 20%, transparent);}
        .seg-radio input[type="radio"]:checked + label .seg-dot{background:var(--acc-ink);border-color:var(--acc-ink);}

        /* Design Theme quick-switch buttons — the primary UI for flipping
           between the two built-in presets. The richer card grid below
           supplements with previews but isn't required to change themes. */
        .dt-quick-row{display:flex;gap:10px;margin:10px 0 14px;}
        .dt-quick-btn{flex:1;padding:14px 18px;font-family:inherit;font-weight:600;font-size:14px;background:var(--inp);color:var(--txt);border:1.5px solid var(--bdr);border-radius:10px;cursor:pointer;transition:border-color var(--dur-chrome) var(--ease-out),background var(--dur-chrome) var(--ease-out),transform var(--dur-panel) var(--spring-snappy),color var(--dur-chrome) var(--ease-out);letter-spacing:.2px;}
        .dt-quick-btn:hover{border-color:var(--acc);background:color-mix(in srgb, var(--acc) 6%, transparent);transform:translateY(-1px);}
        .dt-quick-btn.active{background:var(--acc);color:var(--acc-ink);border-color:var(--acc);box-shadow:0 4px 14px color-mix(in srgb, var(--acc) 25%, transparent);}

        /* Design Theme picker cards (settings drawer) */
        .dt-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:10px;margin-top:8px;}
        .dt-card{background:var(--pn);border:1.5px solid var(--bdr);border-radius:10px;padding:12px;cursor:pointer;transition:border-color var(--dur-panel) var(--ease-out),background var(--dur-panel) var(--ease-out),transform var(--dur-panel) var(--spring-snappy);position:relative;}
        .dt-card:hover{border-color:var(--acc);background:var(--pn-h);}
        .dt-card.active{border-color:var(--acc);background:color-mix(in srgb, var(--acc) 4%, transparent);box-shadow:0 0 0 1px var(--acc);}
        .dt-card .dt-head{display:flex;align-items:center;gap:8px;margin-bottom:6px;}
        .dt-card .dt-name{color:var(--white);font-weight:600;font-size:13px;flex:1;}
        .dt-card .dt-badge{font-size:9px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--acc);background:color-mix(in srgb, var(--acc) 12%, transparent);padding:2px 6px;border-radius:4px;}
        .dt-card .dt-badge.system{color:var(--dim);background:var(--inp);}
        .dt-card .dt-desc{color:var(--dim);font-size:11px;line-height:1.4;margin-bottom:10px;}
        .dt-card .dt-swatches{display:flex;gap:4px;margin-bottom:10px;}
        .dt-card .dt-swatch{width:16px;height:16px;border-radius:4px;border:1px solid rgba(255,255,255,0.1);}
        .dt-card .dt-mini{background:var(--sf);border:1px solid var(--bdr);border-radius:6px;overflow:hidden;}
        .dt-card .dt-mini-row{display:flex;align-items:center;gap:8px;padding:4px 8px;border-bottom:1px solid var(--bdr);font-size:10px;color:var(--txt);font-variant-numeric:tabular-nums;}
        .dt-card .dt-mini-row:last-child{border-bottom:none;}
        .dt-card .dt-mini-row .dt-dot{width:8px;height:8px;border-radius:2px;flex-shrink:0;}
        .dt-card .dt-mini-row .dt-nm{flex:1;color:var(--white);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
        .dt-card .dt-mini-row .dt-dim{color:var(--dim);font-size:9px;}
        .dt-card.active .dt-check{position:absolute;top:10px;right:10px;background:var(--acc);color:var(--acc-ink);width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;}
        .dt-card .dt-check{display:none;}

        /* ═══════════════════════════════════════════════════════════════════
           DOOR PREVIEW FULLSCREEN — clickable zoom of the door diagram with
           per-member + per-panel dimension labels.
           2026-04-22 polish: matched the inline drafting preview's aesthetic
           (graph-paper backdrop, weighted stroke hierarchy, arrow-tipped
           dims, accent-mixed tones). Replaced 13 hardcoded hex/rgba values
           with token-mixed alternates — now themes re-skin correctly.
           ═══════════════════════════════════════════════════════════════════ */
        #ds-svg { cursor: zoom-in; transition: filter var(--dur-chrome) var(--ease-out); }
        #ds-svg:hover {
            filter: brightness(1.05) drop-shadow(0 0 8px color-mix(in srgb, var(--acc) 35%, transparent));
        }
        /* ── CNC bore enlarge workspace ── token-only, WCAG 2.2 (PR-CNC-ENLARGE 2026-06-05) ── */
        .cw-bore-ws {
            position: fixed; inset: 0;
            background: var(--bg);
            z-index: 9999; isolation: isolate;
            display: flex; flex-direction: column;
            animation: doorfs-in var(--dur-chrome) var(--ease-out);
        }
        .cw-bore-ws.hidden { display: none; }
        .cw-bore-ws .cw-ws-bar {
            position: relative;
            display: flex; align-items: center; gap: var(--sp-4);
            padding: 0 64px 0 var(--sp-6); min-height: 56px;
            border-bottom: 1px solid var(--bdr);
            background: color-mix(in srgb, var(--sf) 92%, var(--bg));
        }
        .cw-bore-ws .cw-ws-title {
            flex: 0 0 auto; margin: 0; color: var(--txt);
            font-family: var(--ff-ui); font-size: var(--fs-lg); font-weight: var(--fw-semibold);
        }
        .cw-bore-ws .cw-ws-summary { color: var(--dim); font-size: var(--fs-sm); margin-left: var(--sp-4); }
        .cw-bore-ws .cw-ws-close {
            position: absolute; top: var(--sp-2); right: var(--sp-3);
            width: 56px; height: 56px; padding: 0; margin: 0;
            display: flex; align-items: center; justify-content: center;
            font-size: 24px; line-height: 1; cursor: pointer; z-index: 10;
            background: var(--no); color: var(--no-ink);
            border: 2px solid var(--bdr); border-radius: var(--radius-md);
            box-shadow: var(--shadow-modal);
            appearance: none; -webkit-appearance: none;
        }
        .cw-bore-ws .cw-ws-close:hover { filter: brightness(1.08); }

        /* PR-UNCONTESTABLE-W3 (2026-06-13): no-scan label-drift pill in the
           door-order cutlist button row. Stale = loud danger (a stale label
           machined to a stale sticker is a $-loss); current = quiet success;
           not-printed = neutral muted. */
        .ldrift-pill {
            display: inline-flex; align-items: center; gap: 6px;
            padding: 4px 10px; border-radius: 999px;
            font-size: var(--fs-sm, 13px); font-weight: var(--fw-semibold, 600);
            white-space: nowrap; border: 1px solid var(--bdr);
        }
        .ldrift-none  { color: var(--muted); border-color: var(--bdr); background: transparent; }
        .ldrift-ok    { color: var(--ok); border-color: var(--ok); background: transparent; }
        .ldrift-stale {
            color: var(--no-ink); background: var(--no); border-color: var(--no);
            animation: ldrift-pulse 1.6s ease-in-out infinite;
        }
        @keyframes ldrift-pulse { 0%,100% { filter: brightness(1); } 50% { filter: brightness(1.18); } }
        .cw-bore-ws .cw-ws-body { flex: 1; display: flex; min-height: 0; }
        .cw-bore-ws .cw-ws-diagram {
            flex: 1 1 64%; min-width: 0; overflow: auto;
            padding: var(--sp-5); background: var(--inp);
            display: flex; align-items: flex-start; justify-content: center;
        }
        .cw-bore-ws .cw-hole-preview-xl { width: 100%; }
        .cw-bore-ws .cw-hole-preview-xl svg { width: 100%; height: auto; }
        .cw-bore-ws .cw-ws-editor {
            flex: 1 1 36%; min-width: 320px; max-width: 560px;
            overflow-y: auto; padding: var(--sp-5);
            border-left: 1px solid var(--bdr); background: var(--sf);
        }
        .cw-bore-ws .cw-bore-row input,
        .cw-bore-ws .cw-bore-row select { min-height: 44px; }   /* low-vision target floor in the big view */
        .cw-bore-ws .cw-bore-row button { min-height: 44px; min-width: 44px; }   /* the per-row delete × */
        .cw-bore-ws .cw-bore-offset button,
        .cw-bore-ws .cw-bore-offset input { min-height: 44px; }
        /* ── CNC bore hole cards (numbered; inline + workspace) — token-only ── */
        .cw-bore-rows { counter-reset: hole; }
        .cw-bore-row {
            counter-increment: hole;
            display: flex; flex-direction: column; gap: 6px;
            border: 1px solid var(--bdr); border-radius: var(--radius-md);
            background: var(--inp); padding: 8px 10px; margin-bottom: 8px;
        }
        .cw-bore-row:focus-within { border-color: var(--acc); }
        .cw-bore-row .cw-hr-top { display: flex; align-items: center; gap: 8px; }
        .cw-bore-row .cw-hr-num {
            flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%;
            display: flex; align-items: center; justify-content: center;
            border: 2px solid var(--no); background: var(--sf); color: var(--ink);
            font-weight: 700; font-size: 12px; font-variant-numeric: tabular-nums;
        }
        .cw-bore-row .cw-hr-num::before { content: counter(hole); }
        .cw-bore-row .cw-hr-del {
            margin-left: auto; width: 34px; min-height: 32px;
            border: 1px solid var(--bdr); border-radius: var(--radius-sm);
            background: var(--sf); color: var(--dim); cursor: pointer; font-size: 16px; line-height: 1;
        }
        .cw-bore-row .cw-hr-del:hover { color: var(--no); border-color: var(--no); }
        .cw-bore-row .cw-hr-fields { display: flex; gap: 8px; flex-wrap: wrap; }
        .cw-bore-row .cw-hf { display: flex; flex-direction: column; gap: 2px; flex: 1 1 92px; min-width: 0; }
        .cw-bore-row .cw-hf-face { flex: 0 0 132px; }
        .cw-bore-row .cw-hf-label { flex: 1 1 100%; }
        .cw-bore-row .cw-hf-lbl { font-size: 10px; color: var(--dim); }
        .cw-bore-row .cw-hf input, .cw-bore-row .cw-hf select { width: 100%; min-height: 32px; padding: 4px 6px; }
        /* ── CNC bore action cards (inline + workspace) — token-only ── */
        .cw-bore-cards { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
        .cw-bore-card {
            flex: 1 1 132px; min-width: 120px; min-height: 60px;
            display: flex; flex-direction: column; gap: 3px; justify-content: center;
            padding: 10px 14px; text-align: left; font: inherit;
            border: 1px solid var(--bdr); border-radius: var(--radius-md);
            background: var(--inp); color: var(--ink); cursor: pointer;
            transition: border-color var(--dur-quick) var(--ease-out), background var(--dur-quick) var(--ease-out);
        }
        button.cw-bore-card:hover { border-color: var(--acc); background: var(--sf); }
        button.cw-bore-card:focus-visible { outline: 3px solid var(--acc); outline-offset: 2px; }
        .cw-bore-card .cw-card-title { font-weight: 600; font-size: 13px; color: var(--ink); line-height: 1.2; }
        .cw-bore-card .cw-card-sub { font-size: 11px; color: var(--dim); line-height: 1.25; }
        .cw-bore-card-offset { flex: 1 1 100%; cursor: default; background: var(--sf); }
        .cw-bore-card-offset .cw-off-row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; margin-top: 4px; }
        .cw-bore-card-offset .cw-off-field { display: flex; flex-direction: column; gap: 2px; font-size: 10px; color: var(--ink); }
        .cw-bore-card-offset .cw-off-field input { width: 88px; min-height: 40px; padding: 4px 6px; }
        .cw-bore-card-offset .cw-off-warn { color: var(--no); font-size: 10px; align-self: center; }
        .cw-bore-ws .cw-ws-title:focus-visible,
        .cw-bore-ws .cw-ws-close:focus-visible,
        .cw-bore-ws button:focus-visible,
        .cw-bore-ws input:focus-visible,
        .cw-bore-ws select:focus-visible {
            outline: 3px solid var(--acc); outline-offset: 2px;
        }
        @media (max-width: 900px) {
            .cw-bore-ws .cw-ws-body { flex-direction: column; }
            .cw-bore-ws .cw-ws-diagram { flex: 0 0 50%; }
            .cw-bore-ws .cw-ws-editor { flex: 1 1 auto; max-width: none; border-left: none; border-top: 1px solid var(--bdr); }
        }
        @media (forced-colors: active) {
            .cw-bore-ws .cw-ws-close { border: 2px solid; }
            .cw-bore-ws *:focus-visible { outline: 3px solid; }
        }

        .door-fs {
            position: fixed;
            inset: 0;
            background: color-mix(in srgb, var(--bg) 82%, transparent);
            backdrop-filter: blur(12px) saturate(140%);
            -webkit-backdrop-filter: blur(12px) saturate(140%);
            /* 2026-04-23: bumped from z-index 400 to 9999 and added
             * isolation:isolate to guarantee the modal covers the app
             * topbar on every theme. User report showed the close
             * button getting clipped by the topbar — means 400 wasn't
             * actually winning the stacking fight. 9999 + isolate
             * removes any ambiguity. */
            z-index: 9999;
            isolation: isolate;
            display: flex;
            flex-direction: column;
            animation: doorfs-in var(--dur-chrome) var(--ease-out);
        }
        .door-fs.hidden { display: none; }
        @keyframes doorfs-in { 0% { opacity: 0; } 100% { opacity: 1; } }
        /* During the 280ms back-FLIP fade-out the modal is still display:flex
           covering the viewport. pointer-events:none lets clicks pass through
           to the (now-active) background immediately so the operator can
           interact with the app the moment they hit ✕, instead of waiting
           for the fade timer to add `hidden`. */
        .door-fs.fading { animation: doorfs-fade-out var(--dur-chrome) ease forwards; pointer-events: none; }
        @keyframes doorfs-fade-out { 0% { opacity: 1; } 100% { opacity: 0; } }

        /* Top bar — title (flex:1) + close button (static flex child).
           2026-05-01 v4: replaces v3 absolute-positioned ghost button
           that failed contrast on 3 of 6 themes (Onyx 3.7:1 < WCAG AA
           4.5:1) and didn't read as a button (no border on a frosted
           bar = stray character). v4 adds a real button border, drops
           the absolute hack, caps the bar at 56px (chrome-row height,
           not 77px), and restores flex:1 + ellipsis on the title. */
        .door-fs .dfs-bar {
            position: relative;
            display: flex;
            align-items: center;
            gap: var(--sp-4);
            /* v7.1: button moved below the bar (top:72px), so the bar
               reclaims its full right edge. */
            padding: 0 12px 0 var(--sp-6);
            min-height: 56px;
            border-bottom: 1px solid var(--bdr);
            background: color-mix(in srgb, var(--sf) 92%, var(--bg));
            backdrop-filter: blur(6px);
        }
        .door-fs .dfs-title {
            flex: 1;
            min-width: 0;                  /* allows text-overflow:ellipsis to actually clip */
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            color: var(--txt);
            font-family: var(--ff-ui);
            font-size: var(--fs-lg);
            font-weight: var(--fw-semibold);
            letter-spacing: -0.005em;
        }
        .door-fs .dfs-title .dfs-sub {
            color: var(--dim);
            font-family: var(--ff-mono);
            font-weight: var(--fw-medium);
            font-size: var(--fs-sm);
            margin-left: var(--sp-3);
            letter-spacing: 0.02em;
        }
        /* Close button — v7: position-fixed direct child of #door-fs.
         * v1-v6 placed the button inside .dfs-bar, which has
         * backdrop-filter: blur(6px) — that creates a stacking context
         * where children's backgrounds have repeatedly failed to paint
         * reliably across browsers (notably Safari/iPadOS). v7 hoists
         * the button to be a sibling of .dfs-bar with position:absolute,
         * escaping the bar's backdrop-filter context entirely. Also:
         *  - padding:0 + margin:0 override the global `button{padding:9px 18px}`
         *    rule (line 713) which was eating the 44×44 content area.
         *  - appearance:none + -webkit-appearance:none + forced-color-adjust:none
         *    block native button rendering and Windows High-Contrast / iOS
         *    forced-colors mode from stripping our custom red.
         *  - z-index:10 forces it above .dfs-bar's painted surface inside
         *    the modal's `isolation:isolate` stacking context.
         *  - 56×56 + double-layer shadow + dark outer ring for max visual
         *    contrast on every theme background. Hardcoded colors retained
         *    per v6 rationale. */
        .door-fs .dfs-close {
            position: absolute;
            /* v7.1: dropped below the .dfs-bar (min-height 56px + 1px border)
               so the upper half no longer reads as "in the header". The bar's
               backdrop-filter creates a stacking context where children
               in-front are visually attenuated even at higher z-index, so
               clearing the bar physically is more reliable than fighting it
               with z-index. */
            top: 72px;
            right: 12px;
            z-index: 10;
            width: 56px;
            height: 56px;
            padding: 0;
            margin: 0;
            appearance: none;
            -webkit-appearance: none;
            forced-color-adjust: none;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #dc2626;
            border: 3px solid #ffffff;
            border-radius: 8px;
            color: #ffffff;
            font-size: 26px;
            font-weight: 700;
            line-height: 1;
            cursor: pointer;
            box-shadow:
                0 0 0 2px rgba(0, 0, 0, 0.55),
                0 6px 16px rgba(220, 38, 38, 0.55);
            transition: background 150ms ease, transform 100ms ease;
        }
        .door-fs .dfs-close:hover {
            background: #b91c1c;
            transform: scale(1.05);
        }
        .door-fs .dfs-close:active {
            transform: scale(0.95);
        }
        .door-fs .dfs-close:focus-visible {
            outline: 3px solid #ffffff;
            outline-offset: 3px;
        }

        /* Stage — graph-paper backdrop like the inline preview */
        .door-fs .dfs-stage {
            flex: 1;
            overflow: hidden;
            display: flex;
            align-items: stretch;
            justify-content: stretch;
            padding: var(--sp-9);              /* 48px */
            position: relative;
        }
        .door-fs .dfs-stage::before {
            content: "";
            position: absolute;
            inset: var(--sp-6);
            background-image:
                linear-gradient(to right,  color-mix(in srgb, var(--bdr) 40%, transparent) 1px, transparent 1px),
                linear-gradient(to bottom, color-mix(in srgb, var(--bdr) 40%, transparent) 1px, transparent 1px);
            background-size: 24px 24px;
            opacity: 0.35;
            pointer-events: none;
            border-radius: var(--radius-sm);
        }
        .door-fs .dfs-stage svg {
            position: relative;
            width: 100%;
            height: 100%;
            display: block;
            transform-origin: top left;
            /* PR-WAVE-CLEANUP-87: was hardcoded 280ms + cubic-bezier;
               now --dur-slow + --spring-snappy. */
            transition: transform var(--dur-slow) var(--spring-snappy);
            filter: drop-shadow(0 8px 24px rgba(0, 0, 0, 0.35));
        }

        /* ─── SVG drafting styles (inch-unit viewBox) ───────────────────
           Stroke widths are in viewBox units (inches) so they scale as
           the modal resizes. Values chosen to roughly match the inline
           preview's stroke hierarchy once rasterized to screen pixels. */
        .door-fs .dfs-frame {
            fill: color-mix(in srgb, var(--acc2, var(--acc)) 16%, transparent);
            stroke: color-mix(in srgb, var(--acc2, var(--acc)) 55%, transparent);
            stroke-width: 0.08;
        }
        .door-fs .dfs-panel {
            fill: color-mix(in srgb, var(--bg) 60%, transparent);
            stroke: color-mix(in srgb, var(--dim) 60%, transparent);
            stroke-width: 0.05;
            stroke-dasharray: 0.3 0.2;
        }
        .door-fs .dfs-outline {
            fill: none;
            stroke: var(--txt);
            stroke-width: 0.14;
            stroke-linejoin: round;
        }
        .door-fs .dfs-dim {
            stroke: color-mix(in srgb, var(--dim) 85%, var(--txt));
            stroke-width: 0.05;
            fill: none;
        }
        .door-fs .dfs-tick {
            stroke: color-mix(in srgb, var(--dim) 85%, var(--txt));
            stroke-width: 0.05;
        }

        /* Labels — text sizes in viewBox units (inches). Paint-order halo
           against the graph-paper backdrop for clean read. */
        .door-fs .dfs-label {
            fill: var(--txt);
            font-family: var(--ff-mono);
            font-size: 1.7px;
            font-weight: var(--fw-bold);
            text-anchor: middle;
            dominant-baseline: middle;
            font-variant-numeric: tabular-nums;
            paint-order: stroke;
            stroke: color-mix(in srgb, var(--bg) 92%, transparent);
            stroke-width: 0.3;
            stroke-linejoin: round;
        }
        .door-fs .dfs-label-dim {
            fill: color-mix(in srgb, var(--acc) 85%, var(--txt));
            font-size: 2.0px;
        }
        .door-fs .dfs-label-panel {
            fill: var(--txt);
            font-size: 1.3px;
            font-weight: var(--fw-semibold);
            letter-spacing: 0.03px;
            opacity: 0.85;
        }
        .door-fs .dfs-label-bg {
            fill: color-mix(in srgb, var(--bg) 85%, transparent);
            stroke: color-mix(in srgb, var(--acc) 28%, transparent);
            stroke-width: 0.05;
        }

        /* Architectural dim ladders — top + right */
        .door-fs .dfs-ladder {
            stroke: color-mix(in srgb, var(--acc) 75%, var(--txt));
            stroke-width: 0.08;
            fill: none;
        }
        .door-fs .dfs-ladder-tick {
            stroke: color-mix(in srgb, var(--acc) 75%, var(--txt));
            stroke-width: 0.10;
        }
        .door-fs .dfs-ladder-seg {
            fill: color-mix(in srgb, var(--acc) 90%, var(--txt));
            font-family: var(--ff-mono);
            font-size: 1.6px;
            font-weight: var(--fw-bold);
            text-anchor: middle;
            dominant-baseline: middle;
            font-variant-numeric: tabular-nums;
        }
        .door-fs .dfs-ladder-total {
            fill: var(--txt);
            font-family: var(--ff-mono);
            font-size: 1.9px;
            font-weight: var(--fw-bold);
            text-anchor: middle;
            font-variant-numeric: tabular-nums;
            letter-spacing: 0.05px;
        }

        /* ─── Drawer-box isometric (3D-look) preview classes ────────────
           Painted by buildFullscreenDrawerBoxIsoSVG() in door-studio.js
           when the operator opens the fullscreen preview with item type
           DRAWER_BOX. 30°/30° axonometric projection — face polygons +
           a rim path that uses fill-rule:evenodd to cut the inner top
           opening. Stroke widths are in viewBox inches (same scale as
           the door .dfs-* classes) so they render proportionally at
           any zoom. */
        .door-fs .dbiso-front {
            fill: color-mix(in srgb, var(--acc) 18%, transparent);
            stroke: color-mix(in srgb, var(--acc) 70%, var(--txt));
            stroke-width: 0.10;
            stroke-linejoin: round;
        }
        .door-fs .dbiso-side {
            fill: color-mix(in srgb, var(--acc) 12%, transparent);
            stroke: color-mix(in srgb, var(--acc) 60%, var(--txt));
            stroke-width: 0.10;
            stroke-linejoin: round;
        }
        .door-fs .dbiso-bottom {
            fill: color-mix(in srgb, var(--bg) 60%, transparent);
            stroke: color-mix(in srgb, var(--dim) 60%, var(--txt));
            stroke-width: 0.05;
            stroke-dasharray: 0.3 0.2;
        }
        .door-fs .dbiso-rim {
            fill: color-mix(in srgb, var(--acc2, var(--acc)) 30%, var(--bg));
            stroke: var(--txt);
            stroke-width: 0.12;
            stroke-linejoin: round;
        }
        .door-fs .dbiso-dim {
            stroke: color-mix(in srgb, var(--acc) 75%, var(--txt));
            stroke-width: 0.06;
            fill: none;
        }
        .door-fs .dbiso-label {
            fill: color-mix(in srgb, var(--acc) 90%, var(--txt));
            font-family: var(--ff-mono);
            font-size: 1.9px;
            font-weight: var(--fw-bold);
            text-anchor: middle;
            dominant-baseline: middle;
            font-variant-numeric: tabular-nums;
            paint-order: stroke;
            stroke: color-mix(in srgb, var(--bg) 92%, transparent);
            stroke-width: 0.3;
            stroke-linejoin: round;
        }

        /* Foot — metadata + zoom affordance */
        .door-fs .dfs-foot {
            padding: var(--sp-3) var(--sp-6);
            border-top: 1px solid var(--bdr);
            background: color-mix(in srgb, var(--sf) 92%, var(--bg));
            backdrop-filter: blur(6px);
            color: var(--dim);
            font-family: var(--ff-ui);
            font-size: var(--fs-sm);
            display: flex;
            justify-content: space-between;
            align-items: center;
            gap: var(--sp-4);
        }

        /* ═══════════════════════════════════════════════════════════════════
           DOOR STUDIO COCKPIT — unified design system, mirrors cabinet dash.
           Compact feature tiles, pro orders table, utility rail, sync modal.
           ═══════════════════════════════════════════════════════════════════ */
        /* Compact feature tile — replaces the old large .qc card */
        /* Door-studio feature tiles (Door Library / Create Style / Sync)
           Token-routed 2026-04-22 — rgba/white literals replaced with
           color-mix on design tokens. All 4 themes re-skin correctly. */
        .ft-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
            gap: var(--sp-3);
            margin-bottom: var(--sp-4);
        }
        .ft-tile {
            background: linear-gradient(180deg,
                color-mix(in srgb, var(--inp) 92%, var(--bg)) 0%,
                var(--inp) 100%);
            border: 1.5px solid var(--bdr);
            border-radius: var(--radius-md);
            padding: var(--sp-3) var(--sp-4);
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: var(--sp-3);
            min-height: 72px;
            transition: border-color var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out),
                        background var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out);
            box-shadow: 0 1px 0 color-mix(in srgb, var(--bg) 50%, transparent) inset;
        }
        .ft-tile:hover,
        .ft-tile:focus-visible {
            border-color: color-mix(in srgb, var(--acc) 70%, var(--bdr));
            transform: translateY(-1px);
            background: color-mix(in srgb, var(--acc) 6%, var(--inp));
            outline: none;
            box-shadow: 0 3px 12px color-mix(in srgb, var(--acc) 20%, transparent);
        }
        .ft-tile .ft-icn {
            width: 44px;
            height: 44px;
            border-radius: var(--radius-sm);
            background: color-mix(in srgb, var(--acc) 14%, var(--bg));
            border: 1px solid color-mix(in srgb, var(--acc) 30%, var(--bdr));
            display: flex;
            align-items: center;
            justify-content: center;
            color: var(--acc);
            flex-shrink: 0;
        }
        .ft-tile .ft-icn svg {
            width: 20px;
            height: 20px;
        }
        .ft-tile .ft-body {
            flex: 1;
            min-width: 0;
        }
        .ft-tile .ft-body h4 {
            margin: 0;
            color: var(--txt);
            font-family: var(--ff-ui);
            font-size: var(--fs-base);
            font-weight: var(--fw-semibold);
            letter-spacing: -0.005em;
        }
        .ft-tile .ft-body p {
            margin: 2px 0 0;
            color: var(--dim);
            font-family: var(--ff-ui);
            font-size: 12px;
            line-height: 1.4;
        }

        /* Pinned New Order CTA — top-right of the orders panel header (was a giant bar) */
        .new-order-cta{background:var(--acc);color:var(--acc-ink);border:none;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:background var(--dur-chrome) var(--ease-out),transform var(--dur-panel) var(--spring-snappy),box-shadow var(--dur-chrome) var(--ease-out);box-shadow:0 4px 12px color-mix(in srgb, var(--acc) 20%, transparent);}
        .new-order-cta:hover{background:var(--acc2);transform:translateY(-1px);box-shadow:0 6px 18px color-mix(in srgb, var(--acc) 35%, transparent);}
        .new-order-cta svg{width:14px;height:14px;}

        /* Sync-to-Cabinet modal — pick a saved cabinet project, import door counts */
        .sync-modal{position:fixed;inset:0;background:rgba(0,0,0,0.7);backdrop-filter:blur(4px);z-index:300;display:flex;align-items:center;justify-content:center;padding:20px;}
        .sync-modal.hidden{display:none;}
        .sync-modal .sync-panel{background:var(--sf);border:1px solid var(--bdr);border-radius:14px;padding:22px;width:560px;max-width:100%;max-height:80vh;overflow-y:auto;box-shadow:0 20px 60px rgba(0,0,0,0.6);}
        .sync-modal h3{margin:0 0 4px;color:var(--white);font-size:16px;}
        .sync-modal .sub{color:var(--dim);font-size:12px;margin-bottom:14px;}
        .sync-modal .sync-row{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;border:1px solid var(--bdr);border-radius:8px;margin-bottom:6px;cursor:pointer;transition:border-color var(--dur-panel) var(--ease-out),background var(--dur-panel) var(--ease-out);}
        .sync-modal .sync-row:hover{border-color:var(--acc);background:color-mix(in srgb, var(--acc) 4%, transparent);}
        .sync-modal .sync-row .sn{color:var(--white);font-weight:500;font-size:13px;}
        .sync-modal .sync-row .sm{color:var(--dim);font-size:11px;margin-top:2px;}
        .sync-modal .sync-row .sc{color:var(--acc);font-size:11px;font-variant-numeric:tabular-nums;}

        /* Bulk-action bar — appears when rows are selected */
        .bulk-bar{display:flex;align-items:center;gap:10px;padding:8px 14px;background:color-mix(in srgb, var(--acc) 10%, transparent);border:1px solid var(--acc);border-radius:8px;margin-bottom:10px;color:var(--white);font-size:12px;font-weight:500;}
        .bulk-bar .bulk-count{color:var(--acc);font-weight:600;}

        /* ═══════════════════════════════════════════════════════════════════
           LIBRARIES — workstation table + smart search + bulk actions.
           Hover-only row actions, 32px thumbs, 40% tighter row padding.
           ═══════════════════════════════════════════════════════════════════ */
        .lib-toolbar{display:flex;gap:10px;align-items:center;background:var(--pn);border:1px solid var(--bdr);border-radius:10px;padding:8px 12px;margin-bottom:10px;flex-wrap:wrap;}
        .lib-toolbar .lib-search{flex:1;min-width:220px;display:flex;align-items:center;gap:8px;background:var(--inp);border:1px solid var(--bdr);border-radius:8px;padding:6px 10px;}
        .lib-toolbar .lib-search input{flex:1;background:transparent;border:none;outline:none;color:var(--txt);font-family:inherit;font-size:13px;}
        .lib-toolbar .lib-search input::placeholder{color:var(--dim);}
        .lib-toolbar .lib-search svg{width:14px;height:14px;color:var(--dim);}
        .lib-toolbar .lib-hint{font-size:10px;color:var(--dim);font-style:italic;margin-left:4px;}
        .lib-toolbar .lib-bulk-toggle{display:inline-flex;align-items:center;gap:6px;color:var(--dim);font-size:12px;cursor:pointer;}

        .lib-bulk-bar{display:none;align-items:center;gap:10px;padding:8px 14px;background:color-mix(in srgb, var(--acc) 10%, transparent);border:1px solid var(--acc);border-radius:8px;margin-bottom:10px;color:var(--white);font-size:12px;font-weight:500;}
        .lib-bulk-bar.show{display:flex;}
        .lib-bulk-bar .bulk-count{color:var(--acc);font-weight:600;}

        /* PR-THK-CARDS (2026-05-28) — thickness variants rendered as cards
           instead of a dense table row, in Sheet Goods + Wood Type editors. */
        .thk-card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-bottom:12px;}
        /* PR-HINGE-VIZ-CLARITY (2026-06-02): research-backed card prominence — WCAG 1.4.11 border contrast (≥3:1), NN/g card boundary + tonal-elevation surface, Refactoring-UI size/weight/color hierarchy. Tokens only. */
        .thk-card{background:var(--pn);border:1px solid var(--bdr-h);border-radius:10px;padding:16px;position:relative;display:flex;flex-direction:column;gap:10px;}
        .thk-card:hover{border-color:var(--acc);background:var(--pn-h);}
        .thk-card .thk-card-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:2px;}
        .thk-card .thk-card-title{font-size:11px;font-weight:700;color:var(--acc2);text-transform:uppercase;letter-spacing:0.8px;}
        .thk-card .thk-card-remove{background:transparent;border:none;color:var(--dim);font-size:18px;line-height:1;cursor:pointer;padding:2px 6px;border-radius:4px;min-width:36px;min-height:36px;display:inline-flex;align-items:center;justify-content:center;}
        .thk-card .thk-card-remove:hover{color:var(--no);background:rgba(255,255,255,0.04);}
        .thk-card .thk-card-fields{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
        .thk-card .thk-card-field{display:flex;flex-direction:column;gap:4px;}
        .thk-card .thk-card-field.full{grid-column:1 / -1;}
        .thk-card .thk-card-field label{font-size:10px;font-weight:600;color:var(--dim);text-transform:uppercase;letter-spacing:0.7px;margin-bottom:2px;}
        .thk-card .thk-card-field input{background:var(--inp);color:var(--white);border:1px solid var(--bdr-h);border-radius:6px;padding:9px 11px;font-family:inherit;font-size:13px;width:100%;box-sizing:border-box;}
        .thk-card .thk-card-field input:focus{outline:none;border-color:var(--acc);}
        .thk-card .thk-card-field.primary input{font-size:16px;font-weight:700;color:var(--acc);}
        /* Hinge variant cards reuse .thk-card* (PR-HINGE-VARIANTS 2026-06-02); add select styling to match the inputs. */
        .thk-card .thk-card-field select{background:var(--inp);color:var(--white);border:1px solid var(--bdr-h);border-radius:6px;padding:9px 11px;font-family:inherit;font-size:13px;width:100%;box-sizing:border-box;appearance:auto;}
        .thk-card .thk-card-field select:focus{outline:none;border-color:var(--acc);}
        /* PR-HINGE-VIZ-CLARITY: primary-card full accent border + tonal tint, prominent Name title, accent Name label, visible name-row separator. */
        .thk-card.hv-primary-card{border:1px solid var(--acc);border-left:4px solid var(--acc);background:color-mix(in srgb, var(--pn) 88%, var(--acc) 12%);}
        .thk-card .thk-card-field.full input.hv-name{font-size:15px;font-weight:700;color:var(--white);border-color:color-mix(in srgb, var(--bdr-h) 70%, var(--acc) 30%);letter-spacing:0.2px;}
        .thk-card .thk-card-field.full input.hv-name:focus{border-color:var(--acc);}
        .thk-card .thk-card-fields .thk-card-field.full + .thk-card-field{margin-top:6px;padding-top:10px;border-top:1px solid var(--bdr-h);}
        .hinge-var-row.thk-card .thk-card-field.full label{color:var(--acc2);font-size:10px;font-weight:700;letter-spacing:0.8px;}
        /* PR-HINGE-VARIANT-COMPLETE (2026-06-02): labelled sub-section dividers inside the variant card (Gestalt common-region grouping for the ~16-field spec); neutralise the inherited name-row separator since the group heads now do the grouping. Tokens only. */
        .thk-card .thk-card-fields .hv-group-head{grid-column:1 / -1;display:flex;align-items:center;gap:8px;margin-top:4px;font-size:9px;font-weight:700;color:var(--acc2);text-transform:uppercase;letter-spacing:0.9px;line-height:1;}
        .thk-card .thk-card-fields .hv-group-head::after{content:"";flex:1 1 auto;height:1px;background:var(--bdr-h);}
        .thk-card .thk-card-fields .hv-group-head:first-child{margin-top:0;}
        .hinge-var-row .thk-card-fields .thk-card-field.full + .thk-card-field{margin-top:0;padding-top:0;border-top:none;}

        /* PR-HINGE-CARD-OPT (2026-06-03) — research-approved "Full optimization":
           progressive disclosure (collapsed non-primary cards + always-visible
           summary strip), segmented overlay/spring chips, an Advanced accordion,
           and 48px touch targets. All rules scoped to .hinge-var-row so the
           shared Material .thk-card is untouched. Token-only (no hex). */
        .hinge-var-row .hv-summary-strip{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-bottom:8px;border-bottom:1px solid var(--bdr);font-size:12px;color:var(--dim);}
        .hinge-var-row .hv-sum-dot{width:6px;height:6px;border-radius:50%;background:var(--acc2);flex:0 0 auto;}
        .hinge-var-row.hv-primary-card .hv-sum-dot{background:var(--acc);}
        .hinge-var-row .hv-sum-angle{color:var(--white);font-weight:700;}
        .hinge-var-row .hv-sum-sep{color:var(--bdr-h);}
        .hinge-var-row .hv-sum-cost{color:var(--ok);font-weight:600;margin-left:auto;}
        .hinge-var-row .hv-sum-expand-caret{display:none;color:var(--dim);font-size:11px;text-transform:uppercase;letter-spacing:0.6px;}
        .hinge-var-row.hv-collapsed .hv-sum-expand-caret{display:inline;}
        .hinge-var-row.hv-collapsed .hv-sum-cost{margin-left:0;}
        .hinge-var-row.hv-collapsed .thk-card-fields{display:none;}
        .hinge-var-row.hv-collapsed{cursor:pointer;}
        .hinge-var-row.hv-collapsed:hover{border-color:var(--acc2);background:var(--pn-h);}
        /* Segmented chips (overlay + spring) — 48px touch targets, hidden radios. */
        .hinge-var-row .hv-overlay-seg,.hinge-var-row .hv-spring-seg{display:flex;gap:8px;grid-column:1 / -1;}
        .hinge-var-row .hv-ov-radio,.hinge-var-row .hv-sp-radio{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none;}
        .hinge-var-row .hv-ov-chip,.hinge-var-row .hv-sp-chip{flex:1;min-height:48px;display:flex;align-items:center;justify-content:center;text-align:center;border:1.5px solid var(--bdr);border-radius:8px;background:var(--inp);color:var(--dim);font-size:13px;font-weight:600;cursor:pointer;box-sizing:border-box;padding:6px 8px;transition:border-color .12s,background .12s,color .12s;}
        .hinge-var-row .hv-ov-radio:checked + .hv-ov-chip,.hinge-var-row .hv-sp-radio:checked + .hv-sp-chip{background:color-mix(in srgb, var(--acc) 20%, var(--inp));border-color:var(--acc);color:var(--acc2);}
        .hinge-var-row .hv-ov-chip:hover,.hinge-var-row .hv-sp-chip:hover{border-color:var(--acc2);color:var(--white);}
        .hinge-var-row .hv-ov-radio:focus-visible + .hv-ov-chip,.hinge-var-row .hv-sp-radio:focus-visible + .hv-sp-chip{outline:2px solid var(--acc);outline-offset:1px;}
        /* Advanced accordion. */
        .hinge-var-row .hv-advanced{grid-column:1 / -1;border-top:1px solid var(--bdr);margin-top:2px;}
        .hinge-var-row .hv-advanced > summary{display:flex;align-items:center;gap:8px;min-height:44px;list-style:none;cursor:pointer;color:var(--dim);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:0.9px;}
        .hinge-var-row .hv-advanced > summary::-webkit-details-marker{display:none;}
        .hinge-var-row .hv-advanced > summary::before{content:"";width:6px;height:6px;border-right:1.5px solid var(--dim);border-bottom:1.5px solid var(--dim);transform:rotate(-45deg);transition:transform .15s;flex:0 0 auto;margin-right:2px;}
        .hinge-var-row .hv-advanced[open] > summary::before{transform:rotate(45deg);}
        .hinge-var-row .hv-advanced > summary::after{content:"";flex:1 1 auto;height:1px;background:var(--bdr);}
        .hinge-var-row .hv-adv-body{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding-top:10px;}
        /* Name common-region. */
        .hinge-var-row .hv-name-region{grid-column:1 / -1;background:color-mix(in srgb, var(--inp) 70%, var(--pn) 30%);border-radius:6px;padding:2px;}
        .hinge-var-row .hv-name-region .thk-card-field.full input.hv-name{background:transparent;border-color:transparent;}
        .hinge-var-row .hv-name-region .thk-card-field.full input.hv-name:focus{border-color:var(--acc);}
        /* 48px touch targets — fields + remove button (border colors unchanged). */
        .hinge-var-row .thk-card-field input,.hinge-var-row .thk-card-field select{min-height:48px;}
        .hinge-var-row .thk-card-remove{min-width:48px;min-height:48px;font-size:20px;}

        /* PR-LIB-BULK-EDIT (2026-05-28) — "Bulk Edit" toolbar button + menu + modal. */
        .lib-bulk-edit-wrap{position:relative;display:inline-block;}
        .lib-bulk-edit-btn{background:var(--inp);color:var(--white);border:1px solid var(--bdr);border-radius:6px;padding:8px 14px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit;display:inline-flex;align-items:center;gap:6px;}
        .lib-bulk-edit-btn:hover{border-color:var(--acc);color:var(--acc);}
        .lib-bulk-edit-btn .lbe-caret{font-size:9px;opacity:.75;}
        .lib-bulk-edit-menu{position:absolute;top:100%;right:0;margin-top:4px;background:var(--pn);border:1px solid var(--bdr);border-radius:8px;min-width:200px;box-shadow:0 6px 18px rgba(0,0,0,0.35);z-index:9998;display:none;}
        .lib-bulk-edit-menu.open{display:block;}
        .lib-bulk-edit-menu button{display:block;width:100%;text-align:left;background:transparent;border:none;color:var(--txt);font-family:inherit;font-size:13px;padding:10px 14px;cursor:pointer;}
        .lib-bulk-edit-menu button:hover:not(:disabled){background:var(--inp);color:var(--white);}
        .lib-bulk-edit-menu button:disabled{opacity:.4;cursor:not-allowed;}
        .lib-bulk-edit-menu .lbe-sub{font-size:10px;color:var(--dim);display:block;margin-top:2px;}
        .bulk-edit-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:9999;display:flex;align-items:center;justify-content:center;padding:20px;}
        .bulk-edit-modal{background:var(--pn);border:1px solid var(--bdr);border-radius:12px;max-width:560px;width:100%;max-height:85vh;display:flex;flex-direction:column;color:var(--txt);}
        .bulk-edit-modal .lbe-head{padding:16px 20px;border-bottom:1px solid var(--bdr);display:flex;align-items:center;justify-content:space-between;}
        .bulk-edit-modal .lbe-head h3{margin:0;font-size:16px;color:var(--white);}
        .bulk-edit-modal .lbe-close{background:transparent;border:none;color:var(--dim);font-size:22px;cursor:pointer;line-height:1;padding:0 6px;}
        .bulk-edit-modal .lbe-body{padding:16px 20px;overflow-y:auto;flex:1;display:flex;flex-direction:column;gap:14px;}
        .bulk-edit-modal .lbe-hint{font-size:12px;color:var(--dim);line-height:1.5;}
        .bulk-edit-modal .lbe-row{display:flex;flex-direction:column;gap:6px;}
        .bulk-edit-modal .lbe-label{font-size:11px;color:var(--dim);text-transform:uppercase;letter-spacing:.6px;}
        .bulk-edit-modal select,.bulk-edit-modal input[type=text],.bulk-edit-modal input[type=number]{background:var(--inp);color:var(--white);border:1px solid var(--bdr);border-radius:6px;padding:8px 10px;font-family:inherit;font-size:13px;}
        .bulk-edit-modal select:focus,.bulk-edit-modal input:focus{outline:none;border-color:var(--acc);}
        .bulk-edit-modal .lbe-mode{display:flex;gap:8px;}
        .bulk-edit-modal .lbe-mode label{flex:1;padding:6px 10px;border:1px solid var(--bdr);border-radius:6px;font-size:12px;color:var(--dim);cursor:pointer;text-align:center;}
        .bulk-edit-modal .lbe-mode input{display:none;}
        .bulk-edit-modal .lbe-mode input:checked + span{color:var(--acc);}
        .bulk-edit-modal .lbe-mode label:has(input:checked){border-color:var(--acc);}
        .bulk-edit-modal .lbe-foot{padding:14px 20px;border-top:1px solid var(--bdr);display:flex;gap:10px;align-items:center;justify-content:flex-end;}
        .bulk-edit-modal .lbe-foot .lbe-status{margin-right:auto;font-size:11px;color:var(--dim);}
        .bulk-edit-modal .lbe-foot button{padding:8px 16px;border-radius:6px;border:1px solid var(--bdr);font-size:12px;font-weight:600;cursor:pointer;font-family:inherit;}
        .bulk-edit-modal .lbe-foot .lbe-cancel{background:transparent;color:var(--dim);}
        .bulk-edit-modal .lbe-foot .lbe-apply{background:var(--acc);color:var(--pn);border-color:var(--acc);}
        .bulk-edit-modal .lbe-foot .lbe-apply:disabled{opacity:.4;cursor:not-allowed;}

        .lib-table{width:100%;border-collapse:collapse;font-size:13px;background:var(--pn);border:1px solid var(--bdr);border-radius:10px;overflow:hidden;}
        .lib-table thead th{text-align:left;color:var(--dim);font-size:10px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;padding:8px 10px;border-bottom:1px solid var(--bdr);background:var(--pn);position:sticky;top:0;z-index:1;}
        .lib-table tbody tr{cursor:pointer;transition:background var(--dur-quick) var(--ease-out),border-color var(--dur-quick) var(--ease-out);border-left:3px solid transparent;position:relative;}
        .lib-table tbody tr:hover{background:var(--inp);border-left-color:var(--acc);}
        .lib-table tbody td{padding:6px 10px;border-bottom:1px solid var(--bdr);color:var(--txt);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
        .lib-table tbody tr:last-child td{border-bottom:none;}
        .lib-table .lib-thumb{width:32px;height:32px;border-radius:6px;background:linear-gradient(135deg,var(--inp),var(--bg));display:inline-flex;align-items:center;justify-content:center;border:1px solid rgba(255,255,255,0.04);overflow:hidden;flex-shrink:0;}
        .lib-table .lib-thumb svg{width:22px;height:22px;color:var(--acc);}
        .lib-table .lib-thumb-swatch{width:32px;height:32px;border-radius:6px;border:1px solid var(--bdr);}
        .lib-table .lib-name{color:var(--white);font-weight:500;}
        .lib-table .lib-cell-thumb{width:44px;padding-left:10px;padding-right:0;}
        .lib-table .lib-cell-bulk{width:36px;text-align:center;padding:6px 0 6px 10px;}

        /* PR-DOOR-LIB-CURATED (2026-05-25): when the door library is the
           active type, hide every add / bulk-delete surface inside the door
           panel. Scoped to #lt-door so the same controls in other library
           panels (materials, hardware, etc.) keep working. The body-level
           data attribute is flipped by _syncDoorLibCuratedChrome() whenever
           setActiveLibType('door') fires. */
        body[data-door-lib-curated="true"] #lt-door .lib-bulk-toggle,
        body[data-door-lib-curated="true"] #lt-door .lib-bulk-bar,
        body[data-door-lib-curated="true"] #lt-door .lib-detail-bulk-toggle,
        body[data-door-lib-curated="true"] #lt-door .lib-detail-bulk-bar,
        body[data-door-lib-curated="true"] #lt-door .lib-bulk-action.danger,
        body[data-door-lib-curated="true"] #lt-door .lib-empty-add-btn,
        body[data-door-lib-curated="true"] #lt-door .lib-detail-empty .ba{
            display: none !important;
        }

        /* PR-LIB-RESPONSIVE (2026-05-24): the lib-table has white-space:nowrap
           on every cell so columns don't shred on text wrap. Below tablet,
           let the whole table scroll horizontally rather than clipping
           silently behind the parent panel's overflow:hidden. The canonical
           mobile-table pattern: switch the <table> to display:block so the
           overflow-x:auto takes effect — the internal rows/cells keep their
           table-row / table-cell defaults so columns stay aligned. */
        @media (max-width: 1023px){
            .lib-table{
                display:block; overflow-x:auto; -webkit-overflow-scrolling:touch;
                max-width:100%; border-radius:10px;
            }
            /* Sticky thead doesn't survive display:block on the table, drop it. */
            .lib-table thead th{ position:static; }
        }
        @media (max-width: 640px){
            .lib-table tbody td{ padding:8px 10px; font-size:12px; }
            .lib-table thead th{ font-size:9px; padding:8px; }
            .lib-table .lib-thumb,
            .lib-table .lib-thumb-swatch{ width:28px; height:28px; }
            .lib-table .lib-thumb svg{ width:18px; height:18px; }
            .lib-table .lib-cell-thumb{ width:38px; }
        }

        /* ═══════════════════════════════════════════════════════════════════
           PRINT-READY CUTLIST — looks like a physical sheet of paper.
           Light bg, dark text, serif body, QR pinned top-right.
           ═══════════════════════════════════════════════════════════════════ */
        .cutlist-paper{background:#FFFFFF;color:#111;border-radius:8px;padding:28px 36px;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;line-height:1.55;box-shadow:0 12px 36px rgba(0,0,0,0.55);position:relative;max-width:none;}
        .cutlist-paper::before{content:"";position:absolute;inset:0;border-radius:8px;pointer-events:none;border:1px solid rgba(0,0,0,0.08);}
        .cutlist-paper .cl-head{display:flex;justify-content:space-between;align-items:flex-start;border-bottom:2px solid #111;padding-bottom:12px;margin-bottom:14px;}
        .cutlist-paper .cl-head .cl-title{font-size:18px;font-weight:700;color:#111;margin:0 0 2px;}
        .cutlist-paper .cl-head .cl-meta{font-size:11px;color:#555;line-height:1.4;}
        .cutlist-paper .cl-head .cl-qr{width:88px;height:88px;background:#fff;border:1px solid #ddd;border-radius:4px;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
        .cutlist-paper .cl-head .cl-qr img{width:84px;height:84px;display:block;}
        /* 2026-04-23: pre-wrap → pre + horizontal scroll (same fix as
           .cutlist-out above). Monospace columns must stay aligned;
           wrapping at container width shatters the 80-char layout. */
        .cutlist-paper pre,.cutlist-paper .cl-body{font-family:'Courier New',Courier,monospace;font-size:11px;color:#111;line-height:1.6;white-space:pre;margin:0;overflow-x:auto;}
        .cutlist-paper table{width:100%;border-collapse:collapse;font-size:11px;color:#111;margin-top:8px;}
        .cutlist-paper th{text-align:left;border-bottom:1px solid #555;padding:5px 8px;text-transform:uppercase;font-size:10px;letter-spacing:.4px;color:#222;}
        .cutlist-paper td{border-bottom:1px solid #eee;padding:4px 8px;}
        .cutlist-paper .cl-foot{margin-top:18px;padding-top:10px;border-top:1px solid #ccc;font-size:10px;color:#666;display:flex;justify-content:space-between;}

        /* ═══════════════════════════════════════════════════════════════════
           PRODUCTION PROGRESS BAR — sticky on door order edit view.
           Draft → Quote → In Production → Shipped.
           ═══════════════════════════════════════════════════════════════════ */
        .prod-progress{display:flex;align-items:center;gap:0;background:var(--pn);border:1px solid var(--bdr);border-radius:10px;padding:10px 14px;margin-bottom:14px;position:sticky;top:0;z-index:5;backdrop-filter:blur(10px);background:rgba(20,20,20,0.85);}
        .prod-step{display:flex;align-items:center;gap:8px;color:var(--dim);font-size:12px;font-weight:500;flex-shrink:0;}
        .prod-step .pd-dot{width:22px;height:22px;border-radius:50%;background:var(--inp);border:1px solid var(--bdr);display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;color:var(--dim);transition:background var(--dur-chrome) var(--ease-out),color var(--dur-chrome) var(--ease-out),border-color var(--dur-chrome) var(--ease-out);}
        .prod-step.done{color:var(--acc);}
        .prod-step.done .pd-dot{background:var(--acc);color:var(--acc-ink);border-color:var(--acc);}
        .prod-step.current{color:var(--white);}
        .prod-step.current .pd-dot{background:var(--acc2);color:var(--acc-ink);border-color:var(--acc2);box-shadow:0 0 0 4px color-mix(in srgb, var(--acc) 18%, transparent);}
        .prod-line{flex:1;height:2px;background:var(--bdr);margin:0 10px;border-radius:1px;}
        .prod-line.done{background:var(--acc);}

        /* PR-CLEAN-2 / WIDGET-PURGE (2026-05-31): .studio-pill +
           .widget:hover .studio-pill + .widget-grid responsive media query
           deleted — only consumer was the deleted WIDGET_DEFS templates. */
        ::-webkit-scrollbar{width:6px;}::-webkit-scrollbar-track{background:var(--bg);}::-webkit-scrollbar-thumb{background:var(--bdr);border-radius:3px;}::-webkit-scrollbar-thumb:hover{background:var(--dim);}
        @media(max-width:900px){.drawer{width:100%;}}

        /* A11Y-fix (2026-04-22): raise Job Defaults modal select/input padding
           to meet WCAG 2.5.5 AAA 44 px minimum tap target.
           Targets every .fg select and .fg input inside the Job Defaults drawer.
           48 px (14px top + 14px bottom + ~20px line-height) for gloved use. */
        #job-defaults-modal .fg select,
        #job-defaults-modal .fg input[type="number"],
        #job-defaults-modal .fg input[type="text"]{
            padding:14px 12px;
        }

        /* ═══════════════════════════════════════════════════════════════════
           COMPATIBILITY MATRIX — cell-level verdict classes.
           Applied by door-order-compatibility.js cellClass().
           PR-8b2 (2026-04-22): defined alongside the JS that uses them.
           Contrast verified at WCAG AA 4.5:1 on all four themes.
           ─────────────────────────────────────────────────────────────────
           .compat-ok    : allowed, no warnings — neutral, border only
           .compat-warn  : allowed with caveats — amber tint + border + icon
           .compat-error : not allowed — red tint, reduced opacity, no-entry
                          cursor. The 4px left border (vs 3px on ok/warn)
                          gives an extra visual weight that matches the
                          severity jump. Content opacity 0.55 signals the
                          cell is disabled without hiding it entirely so
                          operators can still read which combination tripped.
           ═══════════════════════════════════════════════════════════════════ */
        .compat-ok{
            border-left:3px solid var(--ok);
        }
        .compat-warn{
            background:rgba(251,191,36,0.12);
            border-left:3px solid var(--warn);
        }
        /* Inline SVG warning triangle — 16x16 px, rendered via CSS
           background-image so no extra DOM nodes are needed.
           The triangle path is encoded as a data URI safe for CSS. */
        .compat-warn::after{
            content:"";
            display:inline-block;
            width:16px;
            height:16px;
            margin-left:4px;
            vertical-align:middle;
            flex-shrink:0;
            background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M8 2L14.5 13.5H1.5L8 2Z' stroke='%23fbbf24' stroke-width='1.4' stroke-linejoin='round'/%3E%3Cline x1='8' y1='6' x2='8' y2='9.5' stroke='%23fbbf24' stroke-width='1.4' stroke-linecap='round'/%3E%3Ccircle cx='8' cy='11.5' r='0.7' fill='%23fbbf24'/%3E%3C/svg%3E");
            background-repeat:no-repeat;
            background-size:16px 16px;
            background-position:center;
        }
        .compat-error{
            background:rgba(248,113,113,0.14);
            border-left:4px solid var(--no);
            cursor:not-allowed;
        }
        .compat-error > *{
            opacity:0.55;
        }
        /* Light themes (walnut / shop) use darker --warn values (#E6A700, #d97706)
           that already exceed 4.5:1 against their white/light backgrounds.
           No override needed: the variable resolves to the correct per-theme value. */

        /* PR-8b2: Inline compat verdict strip above the Add Door button row.
           48px tall, full width, 4px left border that tracks the verdict color.
           Uses existing design tokens (--ok / --warn / --no) — no new colors.
           Font-weight 600 so it reads on a dusty tablet in shop lighting.
           Motion rule (Phase I, math-guardian gate 12): NO transition on the
           verdict strip. The border-color is the verdict signal — it must
           SNAP from green→amber→red as the operator changes parameters.
           A 150ms fade would make a hard-block look like an intermediate
           state for a moment, which is exactly the "silent-wrong" failure
           mode shop operators reported in the 2026-04-21 DO-NOT-COMPUTE
           audit. Dimensions, prices, and verdicts snap — no exceptions. */
        .compat-strip {
            min-height: 48px;
            width: 100%;
            box-sizing: border-box;
            padding: var(--sp-3) var(--sp-4);
            font-family: var(--ff-ui);
            font-weight: var(--fw-semibold);
            font-size: 13px;
            line-height: 1.4;
            border-radius: var(--radius-sm);
            margin-bottom: var(--sp-2);
            border-left: 4px solid transparent;
            display: flex;
            align-items: center;
            gap: var(--sp-3);
            /* NO transition — verdicts snap. Do not add back. */
        }
        /* Status icon — 24×24 circular badge rendered by a CSS ::before
           pseudo so the JS payload stays simple (it just sets the class
           and writes text into the strip). The icon is drawn with a
           themed SVG data-URI; color flips with the strip variant. */
        .compat-strip::before {
            content: "";
            display: inline-block;
            width: 22px;
            height: 22px;
            flex-shrink: 0;
            border-radius: 50%;
            background-color: currentColor;
            background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3C/svg%3E");
            background-position: center;
            background-repeat: no-repeat;
            background-size: 14px 14px;
        }
        .compat-strip.compat-ok {
            background: color-mix(in srgb, var(--ok) 10%, transparent);
            border-left-color: var(--ok);
            color: var(--ok);
        }
        .compat-strip.compat-ok::before {
            background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E");
        }
        .compat-strip.compat-warn {
            background: color-mix(in srgb, var(--warn) 14%, transparent);
            border-left-color: var(--warn);
            color: var(--warn);
        }
        .compat-strip.compat-warn::before {
            background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3Cpath d='M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z'/%3E%3C/svg%3E");
        }
        .compat-strip.compat-error {
            background: color-mix(in srgb, var(--no) 14%, transparent);
            border-left-color: var(--no);
            color: var(--no);
        }
        .compat-strip.compat-error::before {
            background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");
        }
        /* Disabled Add Door button when compat blocked (compat-error verdict).
           opacity + cursor make the block state unambiguous without hiding the
           button — operator can still read the label and understand what to fix. */
        .ad-go[data-compat-blocked="true"],
        .ad-go:disabled {
            opacity: 0.45;
            cursor: not-allowed;
            pointer-events: none;
        }

        /* Cluster E — Reveal Preset tile picker active state.
           color-mix() with transparent gives a tinted highlight that works
           in all 4 themes without hard-coding a hex. */
        .rvl-preset-row {
            display: flex;
            flex-wrap: wrap;
            gap: var(--sp-2);
            margin-bottom: var(--sp-2);
        }
        /* Reveal preset tiles (Bundle 3 — stile/rail section).
           Extracted from per-button inline styles so the count lands
           under audit Rule A baseline. Monospace face for the fractional
           value; accent-tinted when active. Same chrome-transition rule:
           tile surface animates, the fraction value does not (it's
           snapping from the underlying number input). */
        .rvl-preset {
            min-width: 56px;
            min-height: 44px;
            padding: 0 var(--sp-3);
            font-family: var(--ff-mono);
            font-size: 12px;
            font-weight: var(--fw-semibold);
            letter-spacing: 0.02em;
            border: 1.5px solid var(--bdr);
            border-radius: var(--radius-sm);
            background: linear-gradient(180deg,
                color-mix(in srgb, var(--inp) 92%, var(--bg)) 0%,
                var(--inp) 100%);
            color: var(--txt);
            cursor: pointer;
            transition: background var(--dur-chrome) var(--ease-out),
                        border-color var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out);
            box-shadow: 0 1px 0 color-mix(in srgb, var(--bg) 50%, transparent) inset;
        }
        .rvl-preset:hover:not(.rvl-preset-active) {
            border-color: color-mix(in srgb, var(--acc) 70%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 6%, var(--inp));
            transform: translateY(-1px);
        }
        .rvl-preset:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--acc) 70%, transparent);
            outline-offset: 2px;
        }
        .rvl-preset-active {
            background: color-mix(in srgb, var(--acc2) 18%, var(--inp)) !important;
            border-color: var(--acc2) !important;
            color: var(--txt) !important;
            font-weight: var(--fw-bold);
            box-shadow:
                0 0 0 1px var(--acc2) inset,
                0 3px 10px color-mix(in srgb, var(--acc2) 25%, transparent) !important;
        }
        /* The "Custom" button is a textual verb, not a fraction value —
           keep it in the UI font, not mono. */
        .rvl-preset-custom {
            font-family: var(--ff-ui);
            letter-spacing: 0.03em;
        }

        /* ─── Door Studio form controls ──────────────────────────────
           Scoped to .ds-bundle so these polished styles don't affect
           other forms in the app (which still use their own patterns).
           Addresses sentinel audit Rule C (blueprint requires ≥48px on
           select min-height) for the selects that live inside bundles. */
        .ds-bundle .fg {
            display: flex;
            flex-direction: column;
            gap: var(--sp-2);
            min-width: 0;
        }
        .ds-bundle .fg label {
            display: flex;
            align-items: center;
            gap: var(--sp-1);
            color: var(--dim);
            font-family: var(--ff-ui);
            font-size: 10.5px;
            font-weight: var(--fw-semibold);
            letter-spacing: 0.08em;
            text-transform: uppercase;
            margin: 0;
        }
        .ds-bundle .fg .lib-src {
            font-size: 9.5px;
            font-weight: var(--fw-regular);
            letter-spacing: 0.02em;
            text-transform: none;
            color: color-mix(in srgb, var(--dim) 80%, transparent);
            margin-left: auto;
            opacity: 0.85;
        }
        .ds-bundle .fg select,
        .ds-bundle .fg input[type="text"],
        .ds-bundle .fg input[type="number"],
        .ds-bundle .fg input:not([type]) {
            min-height: 48px;
            padding: 0 var(--sp-3);
            background: var(--bg);
            border: 1.5px solid var(--bdr);
            border-radius: var(--radius-sm);
            color: var(--txt);
            font-family: var(--ff-ui);
            font-size: 14px;
            font-weight: var(--fw-medium);
            letter-spacing: 0.01em;
            cursor: pointer;
            transition: border-color var(--dur-chrome) var(--ease-out),
                        background var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out);
            width: 100%;
        }
        .ds-bundle .fg select:hover:not(:disabled),
        .ds-bundle .fg input:hover:not(:disabled):not(:focus) {
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 3%, var(--bg));
        }
        .ds-bundle .fg select:focus,
        .ds-bundle .fg input:focus {
            outline: none;
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 5%, var(--bg));
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 20%, transparent);
        }
        /* Custom dropdown arrow on selects — the default browser arrow
           is inconsistent across platforms. Matches the arrow used by
           .std-field select in Shop Standards for visual consistency. */
        .ds-bundle .fg select {
            appearance: none;
            -webkit-appearance: none;
            background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%23707070' stroke-width='2'%3E%3Cpath d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
            background-repeat: no-repeat;
            background-position: right var(--sp-3) center;
            padding-right: var(--sp-7);
        }
        /* The form-row .fr grid inside bundles — gap between field stacks */
        .ds-bundle .fr {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
            gap: var(--sp-3) var(--sp-4);
            margin-bottom: var(--sp-3);
        }

        /* Live fraction-preview under stile/rail width inputs.
           The operator types "3 1/2" and sees the canonical form immediately.
           A trailing inch mark (″) anchors the eye; red on invalid input
           (unparseable / negative / zero) catches typos before Add fires.
           11px min-height reserves the row so the form doesn't jump when
           a preview appears. aria-live="polite" on each preview lets screen
           readers announce the resolved value without interrupting typing. */
        /* Full .sr-preview rule set (merged into the sr-card rule block
           above at line ~647 for scope consistency, 2026-04-22). This
           rule adds the dim-baseline + err variant only. */
        .sr-preview {
            color: var(--dim);
            min-height: 14px;
            margin-top: 2px;
            font-weight: 500;
            line-height: 1.1;
        }
        .sr-preview-err {
            color: var(--warn);
            font-weight: 600;
        }

        /* ============================================================
           Phase I.5 -- Door Studio Template B + 5-Bundle layout
           All values use design tokens -- no magic px, no hex colors.
           ============================================================ */

        /* Bundle progress bar -- sticky at top of #d-new param panel */
        /* Bundle nav bar — proper progress stepper.
           (1) horizontal connector line under the step circles, so the
               5 steps read as a progression rather than disconnected tabs.
           (2) step circles with ring-style active state (filled for
               completed, outlined for current, muted for upcoming).
           (3) subtle hover on upcoming steps so operators see they're
               tappable (even though bundle-goto will gate on completion). */
        .ds-bundle-bar {
            display: flex;
            align-items: center;
            gap: var(--sp-1);
            background: color-mix(in srgb, var(--sf) 88%, var(--bg));
            border-bottom: 1px solid var(--bdr);
            overflow-x: auto;
            padding: 0 var(--sp-3);
            height: 56px;
            flex-shrink: 0;
            position: relative;
        }
        /* Connector line — single horizontal rule behind the buttons
           that the step circles sit on top of. `::before` (NOT
           `::after`) because a pseudo-element's stacking position
           depends on DOM insertion order among its siblings: `::before`
           paints as the FIRST child (below later flex children), while
           `::after` paints as the LAST child (above them). The pre-2026-
           04-23 version used `::after` and the rail painted ON TOP of
           the step labels, making them look like they had a strike-
           through. Fix: swap to `::before`. Keeps the "one continuous
           rail" behaviour without per-button segmentation. */
        .ds-bundle-bar::before {
            content: "";
            position: absolute;
            left: var(--sp-6);
            right: var(--sp-6);
            top: 50%;
            transform: translateY(-50%);
            height: 2px;
            background: var(--bdr);
            pointer-events: none;
        }
        .ds-bundle-bar-btn {
            position: relative;
            display: flex;
            align-items: center;
            gap: var(--sp-2);
            padding: 0 var(--sp-3);
            background: var(--sf);
            border: none;
            color: var(--dim);
            font-size: var(--fs-sm);
            font-weight: var(--fw-semibold);
            cursor: pointer;
            white-space: nowrap;
            min-height: 48px;
            min-width: 56px;
            transition: color var(--dur-chrome) var(--ease-out);
            letter-spacing: 0.3px;
            border-radius: var(--radius-sm);
        }
        .ds-bundle-bar-btn:hover:not([aria-disabled="true"]):not([aria-current="step"]) {
            color: var(--txt);
        }
        .ds-bundle-bar-btn:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--acc) 70%, transparent);
            outline-offset: 2px;
        }
        .ds-bundle-bar-btn[aria-current="step"] {
            color: var(--txt);
        }
        .ds-bundle-bar-btn[data-complete="true"] { color: color-mix(in srgb, var(--ok) 85%, var(--txt)); }
        .ds-bundle-bar-btn[aria-disabled="true"] { opacity: 0.55; cursor: default; }
        /* Step circle — 28px so it dominates the connector line underneath */
        .ds-bundle-step-num {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 28px;
            height: 28px;
            border-radius: 50%;
            background: var(--sf);
            border: 2px solid var(--bdr);
            color: var(--dim);
            font-size: 12px;
            font-weight: var(--fw-bold);
            flex-shrink: 0;
            transition: background-color var(--dur-chrome) var(--ease-out),
                        border-color var(--dur-chrome) var(--ease-out),
                        color var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out);
        }
        .ds-bundle-bar-btn[aria-current="step"] .ds-bundle-step-num {
            background: var(--acc);
            color: var(--bg);
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 25%, transparent);
        }
        .ds-bundle-bar-btn[data-complete="true"] .ds-bundle-step-num {
            background: var(--ok);
            color: var(--bg);
            border-color: var(--ok);
        }
        /* Swap number for checkmark on completed steps */
        .ds-bundle-bar-btn[data-complete="true"] .ds-bundle-step-num {
            font-size: 0;                                  /* hide the "1" */
        }
        .ds-bundle-bar-btn[data-complete="true"] .ds-bundle-step-num::before {
            content: "✓";
            font-size: 14px;
            font-weight: var(--fw-bold);
        }

        /* Required-field gate — applied by dsBundleStepRequiredOK in
           door-studio.js when the operator clicks Next with an empty
           *-labeled field. Cleared on the next `input`/`change` event
           via the delegated #pg-door listener. Hardcoded red (matches
           dfs-close visibility rationale) so any theme renders an
           obvious "fix me" cue. */
        .field-required-empty {
            border: 2px solid #dc2626 !important;
            box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.18) !important;
            outline: none;
        }

        /* Template B split -- param panel left, viewport right */
        .ds-template-b {
            display: flex;
            flex: 1;
            overflow: hidden;
            min-height: 0;
        }
        /* Param panel / viewport split (2026-04-22 rebalanced):
           - Param panel takes 56% of the Template-B row (min 480px) so the
             Add Piece bar with 4 numeric fields + CTA button doesn't wrap.
           - Viewport takes 44% (min 320px) so the preview has enough room
             to show the 240x320 SVG without being so oversized that the
             visualization dwarfs the parameter entry. */
        .ds-param-panel {
            flex: 0 0 56%;
            min-width: 480px;
            max-width: 640px;
            overflow-y: auto;
            padding: var(--sp-6);
            border-right: 1px solid var(--bdr);
            background: var(--sf);
            display: flex;
            flex-direction: column;
            gap: var(--sp-4);
            position: relative;
        }
        .ds-viewport {
            flex: 1 1 44%;
            min-width: 320px;
            max-width: 560px;
            overflow-y: auto;
            display: flex;
            flex-direction: column;
            gap: var(--sp-4);
            padding: var(--sp-6);
        }
        /* Bottom toolbar 56px */
        .ds-bottom-toolbar {
            display: flex;
            align-items: center;
            gap: var(--sp-3);
            padding: 0 var(--sp-6);
            height: 56px;
            min-height: 56px;
            background: var(--sf);
            border-top: 1px solid var(--bdr);
            flex-shrink: 0;
        }
        .ds-bottom-toolbar .ds-tb-spacer { flex: 1; }
        .ds-bottom-toolbar button {
            min-height: 48px;
            min-width: 56px;
            padding: 0 var(--sp-5);
            font-weight: var(--fw-semibold);
            font-size: var(--fs-base);
        }

        /* Bundle panel -- visible bundle animates in; hidden ones are display:none */
        .ds-bundle {
            display: flex;
            flex-direction: column;
            gap: var(--sp-4);
        }
        .ds-bundle[hidden] { display: none; }
        @media (prefers-reduced-motion: no-preference) {
            .ds-bundle:not([hidden]) {
                animation: ds-bundle-in var(--dur-panel) var(--ease-out);
            }
        }
        @keyframes ds-bundle-in {
            from { opacity: 0; transform: translateX(10px); }
            to   { opacity: 1; transform: translateX(0); }
        }
        /* Bundle panel header — subtle lead accent bar + eyebrow label
           + title + subtitle. The eyebrow ("STEP 3 OF 5 · FRAME") gives
           the operator orientation without needing to look up at the
           nav bar; the vertical accent bar on the left grounds the
           header visually against the rest of the bundle body.
           Populated by JS via a data-step attr on .ds-bundle header. */
        .ds-bundle-header {
            position: relative;
            padding: var(--sp-2) 0 var(--sp-4) var(--sp-4);
            margin-bottom: var(--sp-4);
            border-bottom: 1px solid var(--bdr);
        }
        .ds-bundle-header::before {
            content: "";
            position: absolute;
            left: 0;
            top: var(--sp-2);
            bottom: var(--sp-4);
            width: 3px;
            border-radius: 2px;
            background: var(--acc);
        }
        .ds-bundle-title {
            font-family: var(--ff-ui);
            font-size: var(--fs-xl);                 /* 20px */
            font-weight: var(--fw-semibold);
            color: var(--txt);
            margin: 0 0 var(--sp-1);
            line-height: 1.25;
            letter-spacing: -0.005em;
        }
        .ds-bundle-subtitle {
            font-family: var(--ff-ui);
            font-size: var(--fs-sm);
            color: var(--dim);
            margin: 0;
            line-height: 1.5;
            max-width: 52ch;
        }

        /* PR-CUST-LINKVIS (2026-06-12): saved-customer link chip under the
           Door Studio Customer field. States mirror the server's
           OrderResponse.customer_link_state: linked (ok) / ambiguous
           (warn — the V116 resolver refused to guess between duplicate
           names) / match_available + no_match (dim, informational). */
        .ds-custlink {
            display: inline-block;
            margin-top: 6px;
            padding: 3px 10px;
            border-radius: 999px;
            font-size: 11px;
            line-height: 1.4;
            border: 1px solid var(--bdr);
            color: var(--dim);
            background: transparent;
        }
        .ds-custlink-ok {
            color: var(--ok);
            border-color: color-mix(in srgb, var(--ok) 45%, var(--bdr));
            background: color-mix(in srgb, var(--ok) 12%, transparent);
        }
        .ds-custlink-warn {
            color: var(--warn);
            border-color: color-mix(in srgb, var(--warn) 50%, var(--bdr));
            background: color-mix(in srgb, var(--warn) 12%, transparent);
            font-weight: var(--fw-bold, 700);
        }
        .ds-custlink-dim { color: var(--dim); }

        /* Hidden backing select -- visually removed; JS reads/writes its value */
        .ds-hidden-select {
            position: absolute;
            width: 1px;
            height: 1px;
            padding: 0;
            margin: -1px;
            overflow: hidden;
            clip: rect(0,0,0,0);
            white-space: nowrap;
            border: 0;
        }

        /* Type selector -- 6-tile segmented row operating #sg-type underneath */
        .ds-type-tiles {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: var(--sp-2);
        }
        .ds-type-tile {
            position: relative;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: var(--sp-1);
            min-height: 72px;                       /* larger tap zone */
            padding: var(--sp-3) var(--sp-2);
            background: linear-gradient(180deg,
                color-mix(in srgb, var(--inp) 92%, var(--bg)) 0%,
                var(--inp) 100%);
            border: 1.5px solid var(--bdr);
            border-radius: var(--radius-sm);
            color: var(--dim);
            font-size: 11px;
            font-weight: var(--fw-semibold);
            text-align: center;
            cursor: pointer;
            /* Chrome transitions only — never on label text that will
               become a dimension or price (gate 12). Tiles are chrome. */
            transition: background var(--dur-chrome) var(--ease-out),
                        border-color var(--dur-chrome) var(--ease-out),
                        color var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out);
            letter-spacing: 0.2px;
            line-height: 1.2;
            box-shadow: 0 1px 0 color-mix(in srgb, var(--bg) 50%, transparent) inset;
        }
        .ds-type-tile:hover:not([aria-checked="true"]) {
            border-color: color-mix(in srgb, var(--acc) 70%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 6%, var(--inp));
            color: var(--txt);
            transform: translateY(-1px);
        }
        .ds-type-tile:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--acc) 70%, transparent);
            outline-offset: 2px;
        }
        .ds-type-tile[aria-checked="true"] {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 14%, var(--inp));
            color: var(--txt);
            box-shadow:
                0 0 0 1px var(--acc) inset,
                0 3px 10px color-mix(in srgb, var(--acc) 25%, transparent);
        }
        /* PR-DS-TYPE-LOCK (2026-05-14): tiles for the conflicting product family
           (doors vs drawer boxes) dim out once the order is locked to one kind.
           Operator must clear same-kind items first to switch. */
        .ds-type-tile.is-locked {
            opacity: 0.35;
            cursor: not-allowed;
            filter: grayscale(1);
        }
        .ds-type-tile.is-locked:hover:not([aria-checked="true"]) {
            border-color: var(--bdr);
            background: linear-gradient(180deg,
                color-mix(in srgb, var(--inp) 92%, var(--bg)) 0%,
                var(--inp) 100%);
            color: var(--dim);
            transform: none;
        }
        .ds-type-tile[aria-checked="true"]::after {
            /* Small checkmark badge in the top-right corner of the selected tile. */
            content: "";
            position: absolute;
            top: 6px;
            right: 6px;
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: var(--acc);
            background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E");
            background-repeat: no-repeat;
            background-position: center;
        }
        .ds-type-tile-icon {
            width: 22px;
            height: 22px;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
        }
        .ds-type-tile-icon svg {
            width: 20px;
            height: 20px;
            stroke: currentColor;
            stroke-width: 1.6;
            fill: none;
        }

        /* Bundle 4 hero — Shop Standard "Recommended" CTA. Theme-aware
           green via --ok so it stays distinct from the progress-bar's
           --acc (blue) active-step chip — they won't visually merge.
           Phase B (later PR) demotes the dropdowns into a collapsible
           Advanced section + adds Economy/Tandem/Pullout secondary cards. */
        .ds-hero-shop-standard {
            position: relative;
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            justify-content: center;
            gap: var(--sp-1);
            width: 100%;
            min-height: 88px;
            padding: var(--sp-3) var(--sp-4);
            background: color-mix(in srgb, var(--ok) 78%, #000);
            border: 3px solid var(--ok);
            border-left-width: 6px;
            border-radius: var(--radius-sm);
            color: #fff;
            cursor: pointer;
            text-align: left;
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 28%, transparent),
                        0 4px 14px color-mix(in srgb, var(--ok) 30%, transparent);
            transition: filter var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out);
        }
        .ds-hero-shop-standard:hover:not(:disabled) {
            filter: brightness(1.06);
            transform: translateY(-1px);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 38%, transparent),
                        0 6px 18px color-mix(in srgb, var(--ok) 42%, transparent);
        }
        .ds-hero-shop-standard:active:not(:disabled) {
            transform: translateY(0);
            filter: brightness(0.96);
        }
        .ds-hero-shop-standard:focus-visible {
            outline: 3px solid color-mix(in srgb, var(--ok) 80%, #fff);
            outline-offset: 3px;
        }
        .ds-hero-title {
            font-family: var(--ff-ui);
            font-size: 18px;
            font-weight: 700;
            letter-spacing: 0.04em;
            color: #fff;
            line-height: 1.15;
        }
        .ds-hero-rec {
            font-size: 13px;
            font-weight: 600;
            letter-spacing: 0.02em;
            color: rgba(255, 255, 255, 0.85);
            margin-left: 4px;
            text-transform: none;
        }
        .ds-hero-sub {
            font-family: var(--ff-ui);
            font-size: 13px;
            font-weight: 400;
            color: rgba(255, 255, 255, 0.88);
            line-height: 1.35;
        }
        /* Hero block wraps the Shop Standard button + first-load onboard
           note so the note sits tight under the button (6px gap) instead
           of inheriting the bundle's full --sp-4 gap. The block itself is
           a single flex item in the bundle's column layout. */
        .ds-hero-block {
            display: flex;
            flex-direction: column;
            gap: 6px;
        }
        .ds-hero-onboard-note {
            margin: 0;
            padding: 0 var(--sp-1);
            font-family: var(--ff-ui);
            font-size: 11px;
            font-weight: 500;
            font-style: italic;
            color: var(--dim);
            line-height: 1.35;
        }
        .ds-hero-onboard-note[hidden] { display: none; }

        /* Bundle 4 secondary preset cards. Visually subordinate to the hero
           (smaller min-height, neutral background, --acc hover/focus — distinct
           from the hero's --ok green so the visual hierarchy stays "green = use
           the recommended; blue = consider this instead"). Phase B (later PR)
           layers on selected-state visuals + Tandem-no-slide advisory + keyboard
           shortcuts. */
        .ds-shop-cards {
            display: flex;
            flex-direction: column;
            gap: var(--sp-2);
        }
        .ds-shop-card {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            justify-content: center;
            gap: 4px;
            width: 100%;
            min-height: 80px;
            padding: var(--sp-3) var(--sp-4);
            background: var(--inp);
            border: 2px solid var(--bdr);
            border-radius: var(--radius-sm);
            color: var(--txt);
            cursor: pointer;
            text-align: left;
            transition: background var(--dur-chrome) var(--ease-out),
                        border-color var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out);
        }
        .ds-shop-card:hover {
            border-color: color-mix(in srgb, var(--acc) 60%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 6%, var(--inp));
            transform: translateY(-1px);
            box-shadow: 0 3px 10px color-mix(in srgb, var(--acc) 18%, transparent);
        }
        .ds-shop-card:active {
            transform: translateY(0);
            filter: brightness(0.96);
        }
        .ds-shop-card:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--acc) 70%, transparent);
            outline-offset: 2px;
        }
        .ds-shop-card-title {
            font-family: var(--ff-ui);
            font-size: 15px;
            font-weight: 700;
            letter-spacing: 0.03em;
            color: var(--txt);
            line-height: 1.15;
        }
        .ds-shop-card-summary {
            font-family: var(--ff-ui);
            font-size: 12px;
            font-weight: 500;
            color: var(--txt);
            line-height: 1.3;
        }
        .ds-shop-card-note {
            font-family: var(--ff-ui);
            font-size: 11px;
            font-weight: 400;
            font-style: italic;
            color: var(--dim);
            line-height: 1.3;
        }
        .ds-shop-card-badge {
            align-self: flex-start;
            padding: 3px 9px;
            margin-bottom: 4px;
            background: color-mix(in srgb, var(--acc) 28%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 65%, var(--bdr));
            border-radius: 999px;
            color: var(--txt);
            font-family: var(--ff-ui);
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            white-space: nowrap;
            pointer-events: none;
        }
        .ds-shop-card-badge[hidden] { display: none; }

        /* PR-DBOX-PRESET-EDIT (2026-05-15): pencil-edit affordance in the
           top-right corner of each preset card.
           PR-0C-AUDIT-FIXUP (2026-05-15) — ux-specialist P0: 26×26 was
           below the 44×44 shop-floor min tap target. Bumped to 44×44 with
           negative margin to keep the visual icon small (~24px effective)
           but the hit area honors gloved-hand reality. event.stopPropagation
           in the onclick prevents the parent card's "apply preset" handler
           from firing when the operator wants to edit instead. */
        .ds-card-edit {
            position: absolute;
            top: -4px;
            right: -4px;
            width: 44px;
            height: 44px;
            padding: 10px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            background: color-mix(in srgb, var(--bg) 70%, transparent);
            border: 1px solid color-mix(in srgb, var(--bdr) 80%, transparent);
            border-radius: 6px;
            color: var(--dim);
            cursor: pointer;
            opacity: 0.55;
            transition: opacity var(--dur-chrome) var(--ease-out),
                        background var(--dur-chrome) var(--ease-out),
                        color var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out);
        }
        .ds-card-edit > svg { width: 16px; height: 16px; }
        .ds-card-edit:hover {
            opacity: 1;
            background: var(--inp);
            color: var(--acc);
            transform: scale(1.06);
        }
        .ds-card-edit:focus-visible {
            opacity: 1;
            outline: 2px solid var(--acc);
            outline-offset: 1px;
        }
        /* Hero pencil sits over the bright-green hero — flip colors so
           it's still readable against the saturated background.
           PR-DBOX-AUDIT-FIXUP-2 (2026-05-15) — sentinel M-4 + ux P1:
           replaced 4 raw rgba()/#fff literals with cf-* tokens via
           color-mix so theme switches (and a future high-contrast mode)
           don't leave overlay+text mismatched on the saturated hero. */
        .ds-hero-shop-standard .ds-card-edit {
            background: color-mix(in srgb, #000 28%, transparent);
            border-color: color-mix(in srgb, var(--white) 35%, transparent);
            color: var(--white);
            opacity: 0.7;
        }
        .ds-hero-shop-standard .ds-card-edit:hover {
            background: color-mix(in srgb, #000 45%, transparent);
            color: var(--white);
        }

        /* 5th "Custom" card — visually distinct via dashed border so it
           reads as "different category" not "yet another preset." No edit
           button (Custom has no stored payload to edit). */
        .ds-shop-card-custom {
            border-style: dashed !important;
            border-color: color-mix(in srgb, var(--dim) 70%, var(--bdr)) !important;
            background: color-mix(in srgb, var(--inp) 60%, var(--bg));
        }
        .ds-shop-card-custom:hover {
            border-color: var(--acc) !important;
            background: color-mix(in srgb, var(--acc) 6%, var(--inp));
        }
        .ds-shop-card-custom .ds-shop-card-title {
            color: var(--dim);
        }
        .ds-shop-card-custom:hover .ds-shop-card-title {
            color: var(--txt);
        }

        /* PR-DBOX-PRESET-EDIT round 3 — inline editor panel. Lives under
           the card grid in Bundle 4. Hidden by default; pencil click flips
           hidden=false and adds .is-open which fades it in. Layout is a
           full-width card with a clear header, the form body, and a
           sticky-ish action bar at the bottom holding Save / Cancel /
           Reset. Reset on the left is muted (rare action); Save on the
           right is large + green so the operator's eye lands on it. */
        .dbox-inline-editor {
            margin-top: var(--sp-3);
            padding: var(--sp-3) var(--sp-4);
            background: color-mix(in srgb, var(--inp) 80%, var(--bg));
            border: 2px solid var(--acc);
            border-radius: var(--radius-sm);
            box-shadow: 0 4px 14px color-mix(in srgb, var(--acc) 14%, transparent);
            animation: dbox-editor-fade-in var(--dur-chrome) var(--ease-out);
        }
        @keyframes dbox-editor-fade-in {
            from { opacity: 0; transform: translateY(-4px); }
            to   { opacity: 1; transform: translateY(0); }
        }
        /* PR-DBOX-AUDIT-FIXUP-2 (2026-05-15) — ux P1: honor the user's
           OS-level reduced-motion preference. WCAG 2.3.3 + the existing
           comment at line ~778 confirms the rest of CabForge zeros
           --dur-quick under reduced-motion via tokens.css; the editor's
           local @keyframes was missed in the prior pass. */
        @media (prefers-reduced-motion: reduce) {
            .dbox-inline-editor { animation: none; }
        }
        .dbox-inline-editor-head {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 10px;
            margin-bottom: 4px;
        }
        .dbox-inline-editor-head h3 {
            margin: 0;
            font-size: 15px;
            font-weight: 700;
            letter-spacing: 0.02em;
            color: var(--txt);
        }
        .dbox-inline-editor-head h3 #dbox-edit-target {
            color: var(--acc);
        }
        /* PR-0C-AUDIT-FIXUP (2026-05-15) — ux P0: 28×28 → 44×44 shop-floor min. */
        .dbox-inline-editor-close {
            background: transparent;
            border: 1px solid var(--bdr);
            color: var(--dim);
            width: 44px;
            height: 44px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            line-height: 1;
        }
        .dbox-inline-editor-close:hover {
            background: var(--bg);
            color: var(--txt);
        }
        .dbox-inline-editor-hint {
            margin: 0 0 var(--sp-3) 0;
            color: var(--dim);
            font-size: 11px;
            line-height: 1.4;
        }
        .dbox-inline-editor-body {
            display: flex;
            flex-direction: column;
            gap: var(--sp-2);
        }
        /* PR-0C-AUDIT-FIXUP (2026-05-15) — ux P0: 36→44px shop-floor min tap target. */
        .dbox-inline-editor select,
        .dbox-inline-editor input[type="text"] {
            width: 100%;
            min-height: 44px;
        }

        /* Round 4 — live preview block at the top of the inline editor.
           Shows the operator exactly what the card will look like after
           Save, so material picks (which auto-update the Summary line)
           give immediate visual feedback. Dashed accent border separates
           it from the editable form below. */
        .dbox-inline-preview {
            margin-bottom: var(--sp-3);
            padding: var(--sp-2) var(--sp-3);
            background: var(--bg);
            border: 1px dashed color-mix(in srgb, var(--acc) 50%, var(--bdr));
            border-radius: var(--radius-sm);
        }
        .dbox-preview-label {
            font-size: 10px;
            text-transform: uppercase;
            letter-spacing: 0.08em;
            color: var(--dim);
            margin-bottom: 4px;
        }
        .dbox-preview-card {
            display: flex;
            flex-direction: column;
            gap: 2px;
            padding: var(--sp-2);
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
        }
        .dbox-preview-badge {
            align-self: flex-start;
            padding: 2px 8px;
            background: color-mix(in srgb, var(--acc) 28%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 65%, var(--bdr));
            border-radius: 999px;
            font-size: 9px;
            font-weight: 700;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--txt);
        }
        .dbox-preview-badge[hidden] { display: none; }
        .dbox-preview-title {
            font-size: 14px;
            font-weight: 700;
            letter-spacing: 0.03em;
            color: var(--txt);
        }
        .dbox-preview-summary { font-size: 12px; color: var(--txt); }
        .dbox-preview-note    { font-size: 11px; color: var(--dim); font-style: italic; }

        /* PR-DBOX-PRESET-EDIT — action bar. Reset on the left, Cancel +
           the big primary Save on the right. Save is the only green button
           so the operator's eye lands on it. */
        .dbox-edit-actions {
            display: flex;
            justify-content: space-between;
            align-items: center;
            gap: 10px;
            margin-top: var(--sp-3);
            padding-top: var(--sp-3);
            border-top: 1px solid var(--bdr);
        }
        .dbox-edit-action-group {
            display: flex;
            gap: 10px;
            align-items: center;
        }
        /* PR-0C-AUDIT-FIXUP (2026-05-15) — ux P1: --ok is the cyan status
           token in CabForge (3 status colors only: cyan/amber/rose). Using
           a status color on a primary action button conflates "synced"
           with "tap to commit." Save is an action, not a status — use the
           indigo accent token. Per CabForge design language locked 2026-05-14. */
        .dbox-edit-save {
            min-height: 44px;
            padding: 0 24px;
            font-size: 14px;
            font-weight: 700;
            letter-spacing: 0.04em;
            background: var(--acc) !important;
            border-color: var(--acc) !important;
            /* PR-DBOX-AUDIT-FIXUP-2 (2026-05-15): #fff → var(--acc-ink)
               keeps the indigo accent button text correct under any
               theme switch (acc-ink is the cf-* paired text token). */
            color: var(--acc-ink) !important;
            box-shadow: 0 2px 8px color-mix(in srgb, var(--acc) 30%, transparent);
        }
        .dbox-edit-save:hover {
            filter: brightness(1.08);
            transform: translateY(-1px);
        }
        /* PR-DBOX-AUDIT-FIXUP-2 (2026-05-15) — ux P0: Cancel inherits the
           base .bg button (padding 9/18, ~32px tall) which is below the
           44px shop-floor tap-target floor. Bump the entire action group
           to 44px min-height so Cancel + the action-group cluster all
           clear WCAG 2.5.5 + Apple HIG. */
        .dbox-edit-actions .bg,
        .dbox-edit-action-group .bg {
            min-height: 44px;
        }
        .dbox-edit-reset {
            color: var(--dim);
            font-size: 12px;
        }

        /* Card highlight while its inline editor is open — makes it clear
           which card the form is editing. Subtle accent ring; doesn't
           interfere with the data-selected="true" active-preset chrome. */
        .ds-shop-card.is-being-edited,
        .ds-hero-shop-standard.is-being-edited {
            outline: 2px dashed var(--acc);
            outline-offset: 2px;
        }

        /* PR-BOX-SPEC-SELECTION-STATE — hero deselected state (when a card
           is the active preset) recedes visually but stays clearly tappable
           so the operator can return to Shop Standard with one tap. Cards
           gain an accent border + checkmark when they're the active preset. */
        .ds-hero-shop-standard:not([data-selected="true"]) {
            background: color-mix(in srgb, var(--ok) 18%, #0a1411);
            border: 2px solid color-mix(in srgb, var(--ok) 32%, var(--bdr));
            border-left-width: 2px;
            color: rgba(255, 255, 255, 0.78);
            box-shadow: none;
        }
        .ds-hero-shop-standard:not([data-selected="true"]) .ds-hero-sub {
            color: rgba(255, 255, 255, 0.6);
        }
        .ds-hero-shop-standard:not([data-selected="true"]):hover:not(:disabled) {
            background: color-mix(in srgb, var(--ok) 28%, #0a1411);
            border-color: color-mix(in srgb, var(--ok) 50%, var(--bdr));
            color: rgba(255, 255, 255, 0.92);
            box-shadow: 0 2px 8px color-mix(in srgb, var(--ok) 20%, transparent);
            transform: none;
        }
        .ds-shop-card {
            position: relative;
        }
        .ds-shop-card[data-selected="true"] {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 12%, var(--inp));
            box-shadow: 0 0 0 1px var(--acc) inset,
                        0 3px 10px color-mix(in srgb, var(--acc) 18%, transparent);
        }
        .ds-shop-card[data-selected="true"]::after {
            content: "";
            position: absolute;
            top: 8px;
            right: 8px;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background-color: var(--acc);
            background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%230a1012' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E");
            background-repeat: no-repeat;
            background-position: center;
            pointer-events: none;
        }

        /* PR-BOX-SPEC-ADVANCED-COLLAPSE — collapsible "See all options"
           section that wraps the legacy Style/Side/Bottom dropdowns. Closed
           by default; opens on Bundle-4 entry only when reconciliation
           lands on null (custom-state saved order). Operator can toggle
           freely; runtime state changes don't auto-close to respect
           operator intent. */
        .ds-advanced {
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
            background: color-mix(in srgb, var(--inp) 50%, transparent);
        }
        .ds-advanced > summary {
            list-style: none;
            cursor: pointer;
            padding: var(--sp-2) var(--sp-3);
            font-family: var(--ff-ui);
            font-size: 11px;
            font-weight: 700;
            color: var(--dim);
            letter-spacing: 0.06em;
            text-transform: uppercase;
            display: flex;
            align-items: center;
            gap: 8px;
            user-select: none;
        }
        .ds-advanced > summary::-webkit-details-marker { display: none; }
        .ds-advanced > summary::before {
            content: "";
            width: 7px;
            height: 7px;
            border-right: 1.5px solid currentColor;
            border-bottom: 1.5px solid currentColor;
            transform: rotate(-45deg);
            transition: transform var(--dur-chrome) var(--ease-out);
            flex-shrink: 0;
        }
        .ds-advanced[open] > summary::before {
            transform: rotate(45deg);
        }
        .ds-advanced > summary:hover {
            color: var(--txt);
        }
        .ds-advanced > summary:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--acc) 70%, transparent);
            outline-offset: 2px;
            border-radius: var(--radius-sm);
        }
        .ds-advanced-body {
            padding: var(--sp-3);
            border-top: 1px solid var(--bdr);
            display: flex;
            flex-direction: column;
            gap: var(--sp-3);
        }

        /* PR-LIBEDIT-SAVE-FLASH (2026-05-18) — visible-on-the-button
           feedback after a successful library-item save. The existing
           "✓ Saved" pill (top of drawer) + green "Saved!" message
           (bottom of form) live where the operator may not be looking
           when they click Save. This adds the third cue ON the button
           itself: text swaps to "✓ Saved!", background goes cyan
           success, a single subtle pulse fires, and after 1500 ms it
           reverts. Uses `var(--ok)` (cyan, the canonical CabForge
           success status color) so it skins correctly across all 7
           themes. */
        .ba.lib-save-flash {
            background: var(--ok) !important;
            color: var(--bg) !important;
            border-color: var(--ok) !important;
            animation: lib-save-pulse 600ms ease-out;
        }
        @keyframes lib-save-pulse {
            0%   { transform: scale(1);    box-shadow: 0 0 0 0   color-mix(in srgb, var(--ok) 60%, transparent); }
            40%  { transform: scale(1.04); box-shadow: 0 0 0 8px color-mix(in srgb, var(--ok) 0%,  transparent); }
            100% { transform: scale(1);    box-shadow: 0 0 0 0   transparent; }
        }
        /* Honor prefers-reduced-motion — keep the color swap, skip the
           pulse animation for operators with motion sensitivity. */
        @media (prefers-reduced-motion: reduce) {
            .ba.lib-save-flash { animation: none; }
        }

        /* PR-DOOR-DESIGN-APPLIES-TO (2026-05-18) — chip pills for the
           "Door Design" section's Applies-to multi-select.
           At rest: --inp / --bdr (neutral panel surface, theme-aware).
           Selected (`:has(input:checked)`): indigo (--acc) tint —
           matches the CabForge action-layer convention. "All" master
           uses font-weight:700 to distinguish; never amber (amber is
           reserved for warning status per the 3-status-color rule). */
        .ed-applies-chip {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            padding: 6px 12px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            cursor: pointer;
            font-size: 12px;
            min-height: 44px;
            color: var(--txt);
            transition: background 120ms ease, border-color 120ms ease;
        }
        .ed-applies-chip:hover {
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
        }
        .ed-applies-chip:has(input:checked) {
            background: color-mix(in srgb, var(--acc) 12%, transparent);
            border-color: color-mix(in srgb, var(--acc) 50%, transparent);
            color: var(--txt);
        }
        /* PR-DOOR-DESIGN-UX-FIXUP (2026-05-18, ux-specialist audit P1
           #1+#3): hide the native 13px checkbox so the entire 44px label
           is the tap target — gloved-finger friendly. Selection state
           shown via the :has(input:checked) background tint above + a
           leading checkmark glyph rendered via ::before. "All" master
           gets a leading indigo bar so it reads as a master toggle
           rather than a fifth equal option. */
        .ed-applies-chip input[type="checkbox"] {
            position: absolute;
            opacity: 0;
            pointer-events: none;
        }
        .ed-applies-chip::before {
            content: "";
            display: inline-block;
            width: 14px;
            height: 14px;
            border: 1.5px solid var(--bdr);
            border-radius: 3px;
            background: var(--inp);
            flex-shrink: 0;
            transition: background 120ms ease, border-color 120ms ease;
        }
        .ed-applies-chip:has(input:checked)::before {
            background: var(--acc);
            border-color: var(--acc);
            box-shadow: inset 0 0 0 2px var(--inp), inset 0 0 0 14px var(--acc);
            /* Render an inline checkmark via SVG mask so it inherits --acc-ink
               contrast cleanly across all themes (vs ::after pseudo limits). */
            background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.5 8.5l3 3 6-6' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
            background-repeat: no-repeat;
            background-position: center;
            background-size: 14px 14px;
        }
        .ed-applies-chip-all {
            font-weight: 700;
            letter-spacing: 0.04em;
            border-left: 3px solid color-mix(in srgb, var(--acc) 60%, var(--bdr));
            padding-left: 14px;
        }
        /* PR-DOOR-DESIGN-UX-FIXUP (2026-05-18, ux-specialist audit P1
           #2): make the disclosure toggle's keyboard focus state
           visible. WCAG 2.4.11 (Focus Appearance) — without this, a
           keyboard operator tabbing into the section sees no ring on
           the summary element. */
        .ed-design-section > summary:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 3px;
            border-radius: 4px;
        }

        /* PR-BOX-SPEC-KEYBOARD-SHORTCUTS — small key-badge in the top-left of
           each Bundle-4 tap target. aria-hidden so screen readers don't
           announce the digit; the shortcut info is in the button's aria-label
           ("Keyboard shortcut N."). pointer-events: none so the badge never
           blocks the tap target. */
        .ds-kbd {
            position: absolute;
            top: 6px;
            left: 6px;
            min-width: 18px;
            height: 18px;
            padding: 0 5px;
            background: color-mix(in srgb, var(--bg) 70%, transparent);
            border: 1px solid color-mix(in srgb, var(--txt) 22%, transparent);
            border-radius: 4px;
            color: var(--txt);
            font-family: var(--ff-ui);
            font-size: 10px;
            font-weight: 700;
            line-height: 16px;
            text-align: center;
            pointer-events: none;
            user-select: none;
        }
        .ds-hero-shop-standard .ds-kbd {
            background: rgba(0, 0, 0, 0.32);
            border-color: rgba(255, 255, 255, 0.28);
            color: rgba(255, 255, 255, 0.92);
        }
        .ds-hero-shop-standard:not([data-selected="true"]) .ds-kbd {
            background: rgba(0, 0, 0, 0.22);
            border-color: rgba(255, 255, 255, 0.18);
            color: rgba(255, 255, 255, 0.7);
        }
        /* Bump in-flow content's left padding so the absolute kbd in the
           top-left doesn't overlap card text — especially the Economy
           "Most used for builder orders" pill that would otherwise land
           under the kbd. 36px clears the 6px-offset, 18px-min kbd, its
           1px border, plus a comfortable gap. */
        .ds-hero-shop-standard,
        .ds-shop-card {
            padding-left: 36px;
        }

        /* PR-BOX-SPEC-PRESS-ANIM — micro press animation. :active scales the
           tap target to 0.97 for a tactile press feel (mouse/touch); the
           .ds-keypress class fires a single-shot keyframe pulse so keyboard
           shortcut activations get matching visual feedback. Wrapped in
           prefers-reduced-motion so operators with motion-reduction settings
           opt out — :active states fall back to the existing brightness
           dim alone (already provided by the base :active rules). */
        @media (prefers-reduced-motion: no-preference) {
            .ds-hero-shop-standard:active:not(:disabled),
            .ds-shop-card:active {
                transform: scale(0.97);
                transition-duration: 80ms;
            }
            .ds-hero-shop-standard.ds-keypress,
            .ds-shop-card.ds-keypress {
                animation: ds-box-spec-keypress 180ms ease-out;
            }
        }
        @keyframes ds-box-spec-keypress {
            0%   { transform: scale(1); }
            35%  { transform: scale(0.97); }
            100% { transform: scale(1); }
        }

        /* Bundle Back / Next navigation row.
           Hit every time an operator advances or retreats through the
           5-bundle flow. Primary (Next) is accent-filled + confident;
           secondary (Back) is ghosted so it doesn't compete. Both
           inherit base .ba/.bg classes but override styling here so
           the button family feels cohesive with Add Door + CTA rows. */
        .ds-bundle-nav {
            display: flex;
            align-items: center;
            gap: var(--sp-2);
            padding-top: var(--sp-4);
            margin-top: var(--sp-4);
            border-top: 1px solid var(--bdr);
        }
        .ds-bundle-nav .ds-bn-spacer { flex: 1; }
        .ds-bundle-nav button {
            min-height: 48px;
            min-width: 72px;
            padding: 0 var(--sp-5);
            font-family: var(--ff-ui);
            font-weight: var(--fw-semibold);
            font-size: var(--fs-base);
            letter-spacing: 0.02em;
            border-radius: var(--radius-sm);
            cursor: pointer;
            transition: background var(--dur-chrome) var(--ease-out),
                        border-color var(--dur-chrome) var(--ease-out),
                        color var(--dur-chrome) var(--ease-out),
                        transform var(--dur-chrome) var(--ease-out),
                        filter var(--dur-chrome) var(--ease-out),
                        box-shadow var(--dur-chrome) var(--ease-out);
        }
        /* Primary — Next/Add advance. Accent-filled.
         * 2026-04-23: `color` was hardcoded `#0a1012` (near-black) —
         * a legacy from the pre-theme-swap cyan-only accent era. Now
         * routes through `--acc-ink` so every theme picks the right
         * ink: white on Studio Light's blue, dark on Onyx's green,
         * black on Dark's cyan, white on shop's blue. */
        .ds-bundle-nav button.ba {
            background: var(--acc);
            color: var(--acc-ink);
            border: 1.5px solid var(--acc);
            box-shadow: 0 3px 10px color-mix(in srgb, var(--acc) 28%, transparent);
        }
        .ds-bundle-nav button.ba:hover:not(:disabled) {
            filter: brightness(1.06);
            transform: translateY(-1px);
            box-shadow: 0 5px 16px color-mix(in srgb, var(--acc) 38%, transparent);
        }
        .ds-bundle-nav button.ba:active:not(:disabled) {
            transform: translateY(0);
            filter: brightness(0.95);
        }
        /* Secondary — Back / cancel. Ghost style; doesn't compete. */
        .ds-bundle-nav button.bg {
            background: transparent;
            color: var(--txt);
            border: 1.5px solid var(--bdr);
        }
        .ds-bundle-nav button.bg:hover:not(:disabled) {
            background: color-mix(in srgb, var(--acc) 6%, transparent);
            border-color: color-mix(in srgb, var(--acc) 60%, var(--bdr));
        }
        .ds-bundle-nav button:focus-visible {
            outline: 2px solid color-mix(in srgb, var(--acc) 70%, transparent);
            outline-offset: 3px;
        }
        /* Disabled Next (when required fields missing) */
        .ds-bundle-nav button.ba:disabled,
        .ds-bundle-nav button.ba[aria-disabled="true"] {
            opacity: 0.45;
            cursor: not-allowed;
            box-shadow: none;
            filter: none;
        }
        /* "Skip for now" — tertiary text-link style. Reads as secondary
           to Back/Next so an operator pre-quoting a job without a customer
           name yet has an obvious escape hatch without it competing
           visually with the primary forward action. */
        .ds-bundle-nav button.ds-bundle-skip-link {
            background: transparent;
            color: color-mix(in srgb, var(--txt) 70%, var(--dim));
            border: 1px solid transparent;
            text-decoration: underline;
            text-underline-offset: 3px;
            text-decoration-color: color-mix(in srgb, var(--dim) 60%, transparent);
            min-width: auto;
            padding: 0 var(--sp-3);
            font-weight: var(--fw-medium);
        }
        .ds-bundle-nav button.ds-bundle-skip-link:hover {
            color: var(--txt);
            text-decoration-color: var(--acc);
        }

        /* Match cabinet body toggle */
        .ds-match-body-row {
            display: flex;
            align-items: center;
            gap: var(--sp-3);
            padding: var(--sp-3);
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
        }
        .ds-match-body-row label {
            display: flex;
            align-items: center;
            gap: var(--sp-2);
            color: var(--txt);
            font-size: var(--fs-base);
            font-weight: var(--fw-medium);
            cursor: pointer;
            flex: 1;
        }
        .ds-match-body-row input[type="checkbox"] {
            width: 18px; height: 18px; cursor: pointer; flex-shrink: 0;
        }
        .ds-match-body-hint { font-size: var(--fs-sm); color: var(--dim); }

        /* Confirm-before-commit panel -- absolute overlay inside .ds-param-panel */
        .ds-confirm-panel {
            position: absolute;
            inset: 0;
            background: var(--bg);
            z-index: var(--z-drawer);
            display: flex;
            flex-direction: column;
            overflow-y: auto;
            padding: var(--sp-6);
            gap: var(--sp-4);
        }
        .ds-confirm-panel[hidden] { display: none; }
        .ds-confirm-title {
            font-size: var(--fs-xl);
            font-weight: var(--fw-semibold);
            color: var(--txt);
            margin: 0;
            line-height: 1.3;
        }
        .ds-confirm-body-text {
            font-size: var(--fs-sm);
            color: var(--dim);
            margin: 0;
            line-height: 1.5;
        }
        .ds-confirm-summary {
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
            padding: var(--sp-4);
            display: flex;
            flex-direction: column;
            gap: var(--sp-2);
        }
        .ds-confirm-row {
            display: flex;
            justify-content: space-between;
            font-size: var(--fs-sm);
            line-height: 1.4;
        }
        .ds-confirm-row-label { color: var(--dim); font-weight: var(--fw-medium); }
        .ds-confirm-row-val {
            color: var(--txt);
            font-weight: var(--fw-semibold);
            font-family: var(--ff-mono);
            text-align: right;
        }
        .ds-confirm-cutlist-wrap {
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
            padding: var(--sp-3) var(--sp-4);
            overflow-x: auto;
        }
        .ds-confirm-cutlist-title {
            font-size: var(--fs-sm);
            font-weight: var(--fw-semibold);
            color: var(--dim);
            margin: 0 0 var(--sp-2);
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        /* cutlist table -- NO transition on any cell (math-guardian gate 12) */
        .ds-confirm-cl-table {
            width: 100%;
            border-collapse: collapse;
            font-size: var(--fs-sm);
            font-family: var(--ff-mono);
            line-height: 1.5;
        }
        .ds-confirm-cl-table th {
            text-align: left;
            color: var(--dim);
            font-weight: var(--fw-medium);
            padding: 2px var(--sp-2) var(--sp-1) 0;
            border-bottom: 1px solid var(--bdr);
        }
        .ds-confirm-cl-table th:last-child,
        .ds-confirm-cl-table td:last-child { text-align: right; }
        .ds-confirm-cl-table td { padding: 3px var(--sp-2) 3px 0; color: var(--txt); }
        .ds-confirm-cl-section-row td {
            font-size: 10px;
            font-weight: var(--fw-semibold);
            color: var(--acc2);
            text-transform: uppercase;
            letter-spacing: 0.8px;
            padding-top: var(--sp-3);
        }
        .ds-confirm-actions {
            display: flex;
            gap: var(--sp-3);
            padding-top: var(--sp-3);
            border-top: 1px solid var(--bdr);
            margin-top: auto;
        }
        .ds-confirm-go {
            flex: 1;
            min-height: 56px;
            background: var(--ok);
            border: none;
            border-radius: var(--radius-sm);
            color: var(--bg);
            font-weight: var(--fw-bold);
            font-size: var(--fs-base);
            cursor: pointer;
            transition: background-color var(--dur-chrome) var(--ease-out);
        }
        .ds-confirm-go:hover { filter: brightness(1.08); }
        .ds-confirm-go:disabled { opacity: 0.45; cursor: not-allowed; }
        .ds-confirm-back {
            min-height: 56px;
            min-width: 80px;
            padding: 0 var(--sp-5);
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
            color: var(--txt);
            font-weight: var(--fw-semibold);
            font-size: var(--fs-base);
            cursor: pointer;
        }

        /* Post-Add success state (2026-04-22).
           After the user confirms an Add, the same panel flips to a
           success view with 3 explicit next-action choices. No more
           "Where did the panel go?" confusion; no more hunting for the
           bundle-1 nav to start a new batch. */
        .ds-confirm-success-mark {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 72px;
            height: 72px;
            margin: var(--sp-4) auto var(--sp-2);
            border-radius: 50%;
            background: color-mix(in srgb, var(--ok) 16%, transparent);
            color: var(--ok);
            flex-shrink: 0;
        }
        .ds-confirm-success-actions {
            display: flex;
            flex-direction: column;
            gap: var(--sp-3);
            margin-top: var(--sp-5);
        }
        .ds-confirm-success-actions > button {
            width: 100%;
            min-height: var(--sp-10);            /* 56px */
            padding: var(--sp-3) var(--sp-5);
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            justify-content: center;
            gap: 2px;
            font-weight: var(--fw-semibold);
            font-size: var(--fs-base);
            text-align: left;
            cursor: pointer;
            border-radius: var(--radius-sm);
            border: 1px solid var(--bdr);
            transition: filter var(--dur-chrome) var(--ease-out),
                        background-color var(--dur-chrome) var(--ease-out);
        }
        .ds-confirm-success-actions > button:hover {
            filter: brightness(1.08);
        }
        .ds-confirm-success-actions > .sa-primary {
            background: var(--ok);
            color: var(--ok-ink);
            border-color: var(--ok);
        }
        .ds-confirm-success-actions > .sa-secondary {
            background: var(--acc);
            color: var(--acc-ink);
            border-color: var(--acc);
        }
        .ds-confirm-success-actions > .sa-tertiary {
            background: var(--inp);
            color: var(--txt);
        }
        .ds-confirm-btn-hint {
            font-size: var(--fs-xs, 11px);
            font-weight: var(--fw-regular);
            opacity: 0.78;
            letter-spacing: 0.01em;
        }

        /* ═══════════════════════════════════════════════════════════════
           Door preview — architectural drafting aesthetic (2026-04-22).
           Replaces the prior flat-accent SVG with a properly framed
           preview that reads like a shop drawing: title bar with species
           pill + metadata, centered SVG with weighted stroke hierarchy
           + proper dimension arrows + labeled members, footer title
           block with overall dimensions. Tokens-only; snaps on every
           value change (no transition on dimension text per gate 12). */
        .ds-viewport-preview {
            flex: 1;
            display: flex;
            flex-direction: column;
            background: linear-gradient(180deg,
                color-mix(in srgb, var(--inp) 88%, var(--bg)) 0%,
                var(--inp) 100%);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-md);
            box-shadow: var(--shadow-card);
            min-height: 340px;
            overflow: hidden;
            position: relative;
        }
        .ds-preview-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: var(--sp-3) var(--sp-4);
            gap: var(--sp-3);
            background: color-mix(in srgb, var(--inp) 60%, var(--bg));
            border-bottom: 1px solid var(--bdr);
            flex-shrink: 0;
            min-height: 48px;
        }
        .ds-preview-title {
            font-family: var(--ff-ui);
            font-size: var(--fs-xs, 11px);
            font-weight: var(--fw-semibold);
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--dim);
            margin: 0;
        }
        .ds-preview-meta {
            display: flex;
            align-items: center;
            gap: var(--sp-2);
            flex-wrap: wrap;
        }
        .ds-preview-pill {
            display: inline-flex;
            align-items: center;
            gap: var(--sp-1);
            padding: 3px var(--sp-2);
            border-radius: 999px;
            background: color-mix(in srgb, var(--bg) 75%, transparent);
            border: 1px solid var(--bdr);
            font-family: var(--ff-mono);
            font-size: 10px;
            font-weight: var(--fw-medium);
            color: var(--txt);
            letter-spacing: 0.02em;
        }
        .ds-preview-pill-swatch {
            display: inline-block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            border: 1px solid color-mix(in srgb, var(--txt) 25%, transparent);
            flex-shrink: 0;
        }
        .ds-preview-canvas {
            flex: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: var(--sp-5) var(--sp-5) var(--sp-4);
            position: relative;
        }
        /* Graph-paper backdrop — subtle grid so the preview reads as a
           drafted drawing rather than floating on nothing. */
        .ds-preview-canvas::before {
            content: "";
            position: absolute;
            inset: var(--sp-2);
            background-image:
                linear-gradient(to right,  color-mix(in srgb, var(--bdr) 45%, transparent) 1px, transparent 1px),
                linear-gradient(to bottom, color-mix(in srgb, var(--bdr) 45%, transparent) 1px, transparent 1px);
            background-size: 16px 16px;
            background-position: 0 0;
            opacity: 0.35;
            pointer-events: none;
            border-radius: var(--radius-sm);
        }
        .ds-preview-canvas > svg {
            position: relative;
            width: auto;
            height: auto;
            max-width: 100%;
            max-height: 360px;
            display: block;
            cursor: zoom-in;
            filter: drop-shadow(0 6px 16px rgba(0, 0, 0, 0.25));
        }
        .ds-preview-footer {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: var(--sp-3) var(--sp-4);
            gap: var(--sp-3);
            background: color-mix(in srgb, var(--inp) 60%, var(--bg));
            border-top: 1px solid var(--bdr);
            flex-shrink: 0;
            min-height: 44px;
            font-family: var(--ff-mono);
            font-size: var(--fs-sm);
            letter-spacing: 0.01em;
        }
        .ds-preview-overall {
            color: var(--txt);
            font-weight: var(--fw-semibold);
        }
        .ds-preview-overall-label {
            color: var(--dim);
            font-weight: var(--fw-regular);
            margin-right: 6px;
            letter-spacing: 0.04em;
            text-transform: uppercase;
            font-size: 10px;
        }
        .ds-preview-zoom-hint {
            color: var(--dim);
            font-family: var(--ff-ui);
            font-size: 11px;
            display: flex;
            align-items: center;
            gap: 6px;
        }
        .ds-preview-zoom-hint svg { opacity: 0.7; }

        /* ─── SVG drafting styles ────────────────────────────────────
           Stroke hierarchy:
             frame (outer)        1.8px solid
             member (stile/rail)  1.2px solid
             panel cells          0.6px dashed
             dimensions           0.8px with arrow ticks
           Every stroke/fill routes through tokens so all 4 themes work. */
        .ds-preview-canvas .ds-prev-frame {
            fill: none;
            stroke: var(--txt);
            stroke-width: 1.8;
            stroke-linejoin: round;
        }
        .ds-preview-canvas .ds-prev-fill {
            fill: color-mix(in srgb, var(--acc2, var(--acc)) 18%, transparent);
            stroke: color-mix(in srgb, var(--acc2, var(--acc)) 55%, transparent);
            stroke-width: 0.8;
        }
        /* PR-PANEL-MISMATCH (2026-05-01) */
        /* Amber-flash for picker revert: when the operator clicks
           Cancel on the species-mismatch confirm, the picker's
           value rolls back. The flash makes the rollback observable
           in peripheral vision since the system dialog held focus.
           UX-audit follow-up 2026-05-01: also tint the <select>
           element's own background so the control itself signals
           it changed, not just an outline on the wrapper.
           Skipped under prefers-reduced-motion via the @media block. */
        .ds-revert-flash {
            outline: 3px solid var(--warn);
            outline-offset: 2px;
            transition: outline-color 380ms cubic-bezier(0.32, 0.72, 0.24, 1);
        }
        .ds-revert-flash select {
            background-color: color-mix(in srgb, var(--warn) 22%, var(--inp, var(--bg)));
            transition: background-color 380ms cubic-bezier(0.32, 0.72, 0.24, 1);
        }
        @media (prefers-reduced-motion: reduce) {
            .ds-revert-flash, .ds-revert-flash select {
                outline: none;
                background-color: var(--inp, var(--bg));
                transition: none;
            }
        }
        /* Non-blocking on-load badge: surfaces saved-order frame ↔
           panel mismatches without a modal dialog. role="status" so
           screen readers announce politely. Token-only colors. */
        .ds-mismatch-loaded-badge {
            margin: 8px 0 0 0;
            padding: 10px 14px;
            border: 1px solid color-mix(in srgb, var(--warn) 60%, transparent);
            border-left: 4px solid var(--warn);
            border-radius: 6px;
            background: color-mix(in srgb, var(--warn) 8%, transparent);
            color: var(--txt);
            font-size: 13px;
            line-height: 1.45;
            white-space: pre-wrap;
        }
        /* PR-MISMATCH-STRONG-WARN (2026-05-01) — persistent visible
           state for unresolved frame ↔ panel compatibility warnings.
           Replaces the easy-to-miss window.confirm() flow. The yellow
           border + tinted background stays on BOTH pickers until the
           operator either accepts the override or picks a compatible
           panel. Token-only colors. */
        .ds-mismatch-warn {
            outline: 3px solid var(--warn);
            outline-offset: 2px;
            background: color-mix(in srgb, var(--warn) 10%, transparent);
            border-radius: 6px;
            padding: 4px;
            transition: outline-color 220ms cubic-bezier(0.32, 0.72, 0.24, 1);
        }
        .ds-mismatch-warn select {
            background-color: color-mix(in srgb, var(--warn) 14%, var(--inp, var(--bg)));
        }
        .ds-mismatch-inline {
            margin: 12px 0 0 0;
            padding: 14px 16px;
            border: 1px solid color-mix(in srgb, var(--warn) 70%, transparent);
            border-left: 4px solid var(--warn);
            border-radius: 8px;
            background: color-mix(in srgb, var(--warn) 10%, transparent);
            color: var(--txt);
            font-size: 13px;
            line-height: 1.5;
        }
        .ds-mismatch-inline-actions {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
        }
        .ds-mismatch-inline-btn {
            min-height: 56px;
            min-width: 160px;
            padding: 10px 18px;
            border: 1px solid var(--bdr);
            border-radius: 6px;
            background: var(--bg);
            color: var(--txt);
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            transition: background-color 150ms ease, border-color 150ms ease;
        }
        .ds-mismatch-inline-btn:hover,
        .ds-mismatch-inline-btn:focus-visible {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 8%, var(--bg));
        }
        .ds-mismatch-inline-btn--accept {
            border-color: var(--warn);
            background: color-mix(in srgb, var(--warn) 18%, var(--bg));
        }
        .ds-mismatch-inline-btn--accept:hover,
        .ds-mismatch-inline-btn--accept:focus-visible {
            background: color-mix(in srgb, var(--warn) 28%, var(--bg));
        }
        /* PR-MISMATCH-STRONG-WARN Phase 3 (2026-05-01) — preemptive
           visual signal on Bundle 2's Next button while the panel-
           compat warning is unresolved. Token-only colors. UX pre-
           audit Rec 3: amber border + label hint, no pulse, no
           disable (operators must distinguish "warning" from "field
           empty"). */
        .ds-bundle-nav-warned button.ba {
            border-color: var(--warn);
            box-shadow: 0 3px 10px color-mix(in srgb, var(--warn) 28%, transparent);
        }
        .ds-bundle-nav-warned button.ba::after {
            content: " ⚠";
        }
        /* Blocking modal shown when operator clicks Next with
           unresolved warning. Custom modal (not window.confirm)
           because confirm() is too easy to muscle-memory dismiss
           on iOS Safari PWA. role="alertdialog", focus-trap,
           Escape closes — all in JS. */
        .ds-mismatch-block-modal {
            position: fixed;
            inset: 0;
            z-index: 9999;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 16px;
        }
        .ds-mismatch-block-backdrop {
            position: absolute;
            inset: 0;
            background: color-mix(in srgb, var(--bg) 85%, black);
            opacity: 0.85;
        }
        .ds-mismatch-block-card {
            position: relative;
            max-width: 520px;
            width: 100%;
            padding: 24px 26px;
            border: 1px solid color-mix(in srgb, var(--warn) 70%, transparent);
            border-left: 4px solid var(--warn);
            border-radius: 10px;
            background: var(--bg);
            color: var(--txt);
            box-shadow: 0 16px 48px color-mix(in srgb, black 45%, transparent);
        }
        .ds-mbm-title {
            font-size: 16px;
            font-weight: 700;
            margin-bottom: 8px;
            color: var(--txt);
        }
        .ds-mbm-body {
            font-size: 13px;
            line-height: 1.55;
            color: var(--txt);
            margin-bottom: 18px;
        }
        .ds-mbm-actions {
            display: flex;
            gap: 12px;
            flex-wrap: wrap;
        }
        .ds-mbm-btn {
            min-height: 56px;
            min-width: 180px;
            padding: 12px 22px;
            border: 1px solid var(--bdr);
            border-radius: 8px;
            background: var(--bg);
            color: var(--txt);
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            transition: background-color 150ms ease, border-color 150ms ease;
        }
        .ds-mbm-btn:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }
        .ds-mbm-btn--primary {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 18%, var(--bg));
        }
        .ds-mbm-btn--primary:hover,
        .ds-mbm-btn--primary:focus-visible {
            background: color-mix(in srgb, var(--acc) 28%, var(--bg));
        }
        .ds-mbm-btn--override {
            border-color: var(--warn);
            color: color-mix(in srgb, var(--warn) 92%, var(--txt));
        }
        .ds-mbm-btn--override:hover,
        .ds-mbm-btn--override:focus-visible {
            background: color-mix(in srgb, var(--warn) 12%, var(--bg));
        }
        .ds-preview-canvas .ds-prev-stroke {
            fill: none;
            stroke: var(--txt);
            stroke-width: 1.2;
            stroke-linejoin: round;
        }
        .ds-preview-canvas .ds-prev-panel {
            fill: color-mix(in srgb, var(--bg) 60%, transparent);
            stroke: color-mix(in srgb, var(--dim) 70%, transparent);
            stroke-width: 0.6;
            stroke-dasharray: 2 2;
        }
        .ds-preview-canvas .ds-prev-dim {
            stroke: color-mix(in srgb, var(--dim) 80%, transparent);
            stroke-width: 0.8;
            fill: none;
        }
        .ds-preview-canvas .ds-prev-dim-arrow {
            fill: color-mix(in srgb, var(--dim) 80%, transparent);
            stroke: none;
        }
        .ds-preview-canvas .ds-prev-witness {
            stroke: color-mix(in srgb, var(--dim) 50%, transparent);
            stroke-width: 0.5;
            stroke-dasharray: 2 2;
            fill: none;
        }
        .ds-preview-canvas .ds-prev-text {
            fill: var(--txt);
            font-family: var(--ff-mono), monospace;
            font-size: 9.5px;
            font-weight: 500;
            letter-spacing: 0.02em;
            paint-order: stroke;
            stroke: var(--inp);
            stroke-width: 2.5;
            stroke-linejoin: round;
        }
        .ds-preview-canvas .ds-prev-text-dim {
            fill: color-mix(in srgb, var(--dim) 90%, var(--txt));
            font-size: 8.5px;
            font-weight: 500;
        }
        .ds-preview-canvas .ds-prev-text-overall {
            fill: var(--txt);
            font-size: 10.5px;
            font-weight: 600;
        }
        .ds-preview-canvas .ds-prev-corner {
            fill: none;
            stroke: color-mix(in srgb, var(--acc) 70%, transparent);
            stroke-width: 1.4;
            stroke-linecap: round;
        }

        /* Initial visibility for conditional form rows is handled entirely by
           toggleSGFields() at runtime — see web/door-studio.js. CSS defaults
           used to live here (#sg-dbstyle-wrap / #sg-wood-wrap / #sg-piece-d-wrap
           all had display:none) but they BLOCKED the JS toggle from showing
           the field: setDisp(id, true) clears the inline `style="display:..."`,
           and a CSS-applied `display: none` then wins. Result was a hidden D
           field for drawer-box pieces and a hidden drawer-box style picker.
           toggleSGFields() runs synchronously in initDoorStudio() so the
           initial frame is correct. The brief flash before init is not a
           real shop-floor concern. */

        /* ── Door Studio responsive layout ───────────────────────────
           Landscape tablet (≤1100px, ≥768px): narrow the param panel
           so the viewport preview still gets meaningful width. */
        @media (max-width: 1100px) and (min-width: 768px) {
            .ds-param-panel {
                flex: 0 0 52%;
                min-width: 360px;
                max-width: 520px;
            }
            .ds-viewport {
                min-width: 260px;
            }
        }

        /* Portrait tablet (≤767px): param panel stacks above the viewport.
           CRITICAL: override min-width so the panel never causes horizontal
           overflow on a 768px screen. */
        @media (max-width: 767px) {
            .ds-template-b {
                flex-direction: column;
                overflow-y: auto;
                overflow-x: hidden;
            }
            .ds-param-panel {
                flex: none;
                width: 100%;
                min-width: 0;   /* ← kills the 480px floor that caused overflow */
                max-width: 100%;
                border-right: none;
                border-bottom: 1px solid var(--bdr);
            }
            .ds-viewport {
                flex: none;
                min-width: 0;
                max-width: 100%;
                max-height: 160px;
                overflow: hidden;
            }
            .ds-type-tiles { grid-template-columns: repeat(3, 1fr); }
            /* Tighten the bundle bar step labels on narrow screens */
            .ds-bundle-bar-btn { padding: 0 var(--sp-2); font-size: 11px; }
        }

        /* Small portrait (≤480px): hide viewport entirely to maximize form space */
        @media (max-width: 480px) {
            .ds-viewport { display: none; }
            .ds-bundle .fr {
                grid-template-columns: 1fr;
            }
        }

        /* ── PR-CABFORGE-2B — cf-* utility scaffolding ─────────────────────
           All rules below are gated on body[data-ui-version="cabforge"] so
           they activate ONLY for operators on the CabForge theme. Legacy
           themes are unaffected. cf- prefix prevents collisions with
           Rust-emitted CSS classes (dwg-*, no-print, plan-view-wrap) in
           cabinet-server's cutlist.rs and drawings modules.

           These are PRIMITIVES — buttons, cards, kpis, focus rings. The
           per-section reskins (PR-CABFORGE-4-A..E) compose them. Apple HIG
           feel: generous whitespace, single accent (var(--acc)), restrained
           depth (1px borders + subtle shadow), spring physics in transitions.
        */

        /* Subtle shell polish — sidebar + topbar + statusbar gain a hint of
           depth without restructuring. body-gated so legacy themes don't
           inherit the shadow/border tweaks. */
        /* PR-HOME-REDESIGN (2026-06-13): dropped the topbar/statusbar
           backdrop-filter blur — FORGE bans backdrop-blur (reads as
           "loading"); the 1px borders carry the shell separation. */
        body[data-ui-version="cabforge"] #app-topbar {
            border-bottom: 1px solid var(--bdr);
        }
        body[data-ui-version="cabforge"] #app-sidebar {
            border-right: 1px solid var(--bdr);
        }
        body[data-ui-version="cabforge"] #app-statusbar {
            border-top: 1px solid var(--bdr);
        }

        /* Card — the workhorse surface. Apple-style: pn background, 1px
           border, generous radius, subtle shadow on hover. No heavy
           elevation by default. */
        body[data-ui-version="cabforge"] .cf-card {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            padding: 16px;
            transition: border-color 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .cf-card:hover {
            border-color: var(--bdr-h, var(--bdr));
            box-shadow: 0 4px 14px color-mix(in srgb, var(--acc) 12%, transparent);
        }
        body[data-ui-version="cabforge"] .cf-card[role="button"]:hover,
        body[data-ui-version="cabforge"] .cf-card[tabindex]:hover {
            transform: translateY(-1px);
        }

        /* Buttons — primitive shapes. Three variants: primary (accent fill),
           secondary (ghost), tertiary (text-only). 48px min tap target. */
        body[data-ui-version="cabforge"] .cf-btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            min-height: 36px;
            min-width: 64px;
            padding: 0 14px;
            border-radius: 8px;
            font-family: var(--ff-ui, inherit);
            font-size: 13px;
            font-weight: 600;
            letter-spacing: 0.01em;
            border: 1px solid transparent;
            cursor: pointer;
            user-select: none;
            transition: background 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 80ms cubic-bezier(0.22, 1, 0.36, 1),
                        filter 160ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .cf-btn:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }
        body[data-ui-version="cabforge"] .cf-btn:active:not(:disabled) {
            transform: scale(0.97);
        }
        body[data-ui-version="cabforge"] .cf-btn:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        body[data-ui-version="cabforge"] .cf-btn-primary {
            background: var(--acc);
            color: var(--acc-ink);
            border-color: var(--acc);
        }
        body[data-ui-version="cabforge"] .cf-btn-primary:hover:not(:disabled) {
            filter: brightness(1.08);
        }

        body[data-ui-version="cabforge"] .cf-btn-secondary {
            background: var(--pn);
            color: var(--txt);
            border-color: var(--bdr);
        }
        body[data-ui-version="cabforge"] .cf-btn-secondary:hover:not(:disabled) {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 8%, var(--pn));
        }

        body[data-ui-version="cabforge"] .cf-btn-ghost {
            background: transparent;
            color: var(--txt);
            border-color: transparent;
        }
        body[data-ui-version="cabforge"] .cf-btn-ghost:hover:not(:disabled) {
            background: color-mix(in srgb, var(--acc) 8%, transparent);
        }

        /* KPI tile — for the QBO-style homepage. Big number + label + delta. */
        body[data-ui-version="cabforge"] .cf-kpi {
            display: flex;
            flex-direction: column;
            gap: 4px;
            padding: 16px;
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            min-height: 88px;
            transition: border-color 180ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .cf-kpi:hover {
            border-color: color-mix(in srgb, var(--acc) 40%, var(--bdr));
        }
        body[data-ui-version="cabforge"] .cf-kpi-label {
            font-size: 11px;
            font-weight: 600;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--dim);
        }
        body[data-ui-version="cabforge"] .cf-kpi-value {
            font-size: 28px;
            font-weight: 600;
            letter-spacing: -0.01em;
            color: var(--txt);
            font-variant-numeric: tabular-nums;
            line-height: 1.1;
        }
        body[data-ui-version="cabforge"] .cf-kpi-delta {
            font-size: 12px;
            font-weight: 500;
            color: var(--dim);
            font-variant-numeric: tabular-nums;
        }
        body[data-ui-version="cabforge"] .cf-kpi-delta-up {
            color: var(--ok);
        }
        body[data-ui-version="cabforge"] .cf-kpi-delta-down {
            color: var(--no);
        }

        /* Pill — small status indicators (online, sync, role badges, etc.) */
        body[data-ui-version="cabforge"] .cf-pill {
            display: inline-flex;
            align-items: center;
            gap: 4px;
            padding: 2px 8px;
            background: color-mix(in srgb, var(--acc) 14%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 30%, transparent);
            border-radius: 999px;
            font-size: 11px;
            font-weight: 600;
            color: var(--txt);
        }
        body[data-ui-version="cabforge"] .cf-pill-ok {
            background: color-mix(in srgb, var(--ok) 14%, transparent);
            border-color: color-mix(in srgb, var(--ok) 35%, transparent);
        }
        body[data-ui-version="cabforge"] .cf-pill-warn {
            background: color-mix(in srgb, var(--warn) 14%, transparent);
            border-color: color-mix(in srgb, var(--warn) 35%, transparent);
        }
        body[data-ui-version="cabforge"] .cf-pill-no {
            background: color-mix(in srgb, var(--no) 14%, transparent);
            border-color: color-mix(in srgb, var(--no) 35%, transparent);
        }

        /* Stack — vertical flex layout helper. */
        body[data-ui-version="cabforge"] .cf-stack {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        body[data-ui-version="cabforge"] .cf-stack-sm { gap: 6px; }
        body[data-ui-version="cabforge"] .cf-stack-lg { gap: 24px; }

        /* Row — horizontal flex layout helper. */
        body[data-ui-version="cabforge"] .cf-row {
            display: flex;
            align-items: center;
            gap: 12px;
        }
        body[data-ui-version="cabforge"] .cf-row-sm { gap: 6px; }
        body[data-ui-version="cabforge"] .cf-row-lg { gap: 24px; }

        /* Section header — for grouping cards on the homepage and beyond. */
        body[data-ui-version="cabforge"] .cf-section-title {
            font-size: 12px;
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--dim);
            margin: 0 0 10px 0;
        }

        /* Refined typography scale (gated). Inter is already loaded;
           these classes just expose the scale as utilities. */
        body[data-ui-version="cabforge"] .cf-text-display {
            font-size: 32px;
            font-weight: 600;
            letter-spacing: -0.02em;
            line-height: 1.15;
        }
        body[data-ui-version="cabforge"] .cf-text-title {
            font-size: 24px;
            font-weight: 600;
            letter-spacing: -0.01em;
            line-height: 1.2;
        }
        body[data-ui-version="cabforge"] .cf-text-headline {
            font-size: 17px;
            font-weight: 600;
            line-height: 1.3;
        }
        body[data-ui-version="cabforge"] .cf-text-body {
            font-size: 14px;
            font-weight: 400;
            line-height: 1.45;
        }
        body[data-ui-version="cabforge"] .cf-text-caption {
            font-size: 12px;
            font-weight: 400;
            color: var(--dim);
            line-height: 1.4;
        }
        body[data-ui-version="cabforge"] .cf-text-mono {
            font-family: 'JetBrains Mono', 'SF Mono', 'Consolas', monospace;
            font-size: 13px;
            font-variant-numeric: tabular-nums;
        }

        /* Reduced-motion override — all cf-* transition durations collapse
           to 0ms when the operator prefers reduced motion. */
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .cf-btn,
            body[data-ui-version="cabforge"] .cf-card,
            body[data-ui-version="cabforge"] .cf-kpi {
                transition: none;
            }
            body[data-ui-version="cabforge"] .cf-btn:active:not(:disabled) {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-2B ──────────────────────────────────────────────── */

        /* ── PR-CABFORGE-3 — restyle existing primitives in cabforge mode ──
           Overrides for the most-visible pre-existing UI patterns so the
           operator on the CabForge theme sees a coherent Apple-HIG-aligned
           visual language without any HTML changes. Every rule is gated on
           body[data-ui-version="cabforge"]; legacy themes inherit the
           original styling untouched.

           Pattern: lift the corner radius, tighten the borders, refine
           hover transitions, swap shadow chrome for accent-tinted glows
           via color-mix(). The existing element IDs and class names stay
           intact — only the look changes. */

        /* KPI tile — restyle to Apple-card feel. Tabular-nums on the value
           span so currency / count columns align vertically. */
        body[data-ui-version="cabforge"] .kpi-tile {
            border-radius: 10px;
            border: 1px solid var(--bdr);
            background: var(--pn);
            transition: border-color 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .kpi-tile:hover {
            /* PR-FORGE-CAB-CARDS (2026-06-13): flat pro-tool hover — border +
               bg tint, NO lift/glow. This block was overriding the global
               flat-hover fix in shell.css with higher specificity. */
            border-color: var(--bdr-h);
            background: var(--pn-h);
        }
        body[data-ui-version="cabforge"] .kpi-tile-value {
            font-variant-numeric: tabular-nums;
            letter-spacing: -0.01em;
        }
        body[data-ui-version="cabforge"] .kpi-tile-label {
            font-weight: 600;
            letter-spacing: 0.06em;
        }

        /* Report tile (Job Hub grid) — refine corners + ink, drop the
           orange-tinted hover for a theme-aware accent tint. */
        body[data-ui-version="cabforge"] .rep-tile {
            border-radius: 12px;
            transition: background 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        border-color 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .rep-tile:hover {
            background: color-mix(in srgb, var(--acc) 8%, var(--pn));
            border-color: color-mix(in srgb, var(--acc) 55%, var(--bdr));
            box-shadow: 0 6px 18px rgba(0,0,0,.14);
        }
        body[data-ui-version="cabforge"] .rep-tile.on {
            background: color-mix(in srgb, var(--acc) 12%, var(--pn));
            border-color: var(--acc);
        }

        /* Feature tile (Door Studio home + similar) */
        body[data-ui-version="cabforge"] .ft-tile {
            border-radius: 12px;
            transition: border-color 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .ft-tile:hover {
            /* PR-FORGE-CAB-CARDS: flat hover (no lift/glow). */
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
            background: var(--pn-h);
        }

        /* Filter bar — soften corners + tighten the search field. */
        body[data-ui-version="cabforge"] .filter-bar {
            border-radius: 12px;
        }
        body[data-ui-version="cabforge"] .filter-bar .fb-search {
            border-radius: 8px;
            transition: border-color 160ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .filter-bar .fb-search:focus-within {
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 20%, transparent);
        }
        body[data-ui-version="cabforge"] .filter-bar select:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 1px;
        }

        /* Jobs table — tabular-figure alignment on numeric columns + 1px
           dividers instead of heavy borders. */
        body[data-ui-version="cabforge"] .jobs-table {
            border-collapse: separate;
            border-spacing: 0;
            font-variant-numeric: tabular-nums;
        }
        body[data-ui-version="cabforge"] .jobs-table thead th {
            font-weight: 600;
            font-size: 11px;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--dim);
            border-bottom: 1px solid var(--bdr);
        }
        body[data-ui-version="cabforge"] .jobs-table tbody tr {
            transition: background 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .jobs-table tbody tr:hover {
            background: color-mix(in srgb, var(--acc) 5%, transparent);
        }

        /* Type-picker tile (jd-tile) — used in cab-newjob wizard etc. */
        body[data-ui-version="cabforge"] .jd-tile {
            border-radius: 10px;
            transition: border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        background 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 80ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .jd-tile:hover {
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
        }
        body[data-ui-version="cabforge"] .jd-tile.active {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 10%, var(--pn));
        }
        body[data-ui-version="cabforge"] .jd-tile:active:not(.active) {
            transform: scale(0.98);
        }

        /* Library type-chip + shape-chip — pill polish */
        body[data-ui-version="cabforge"] .lib-chip,
        body[data-ui-version="cabforge"] .lib-shape-chip,
        body[data-ui-version="cabforge"] .dview-pill {
            border-radius: 999px;
            transition: border-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .lib-chip:hover:not(.active),
        body[data-ui-version="cabforge"] .lib-shape-chip:hover:not(.active),
        body[data-ui-version="cabforge"] .dview-pill:hover:not(.active) {
            border-color: color-mix(in srgb, var(--acc) 45%, var(--bdr));
            color: var(--txt);
        }

        /* Metrics ribbon (pg-cab dash) — match the Apple-card vocabulary */
        body[data-ui-version="cabforge"] .metrics-ribbon {
            border-radius: 12px;
        }
        body[data-ui-version="cabforge"] .metric-cell {
            transition: background 160ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .metric-cell:hover {
            background: color-mix(in srgb, var(--acc) 8%, transparent);
        }

        /* Drawer overlay — gentler backdrop with the same acrylic feel
           as the topbar. The drawer panel keeps its existing radius. */
        body[data-ui-version="cabforge"] .drawer-overlay {
            backdrop-filter: blur(8px) saturate(140%);
            -webkit-backdrop-filter: blur(8px) saturate(140%);
            background: color-mix(in srgb, #000 55%, transparent);
        }
        body[data-ui-version="cabforge"] .drawer {
            border-radius: 12px;
            border: 1px solid var(--bdr);
            box-shadow: 0 30px 60px rgba(0,0,0,0.4);
        }

        /* Reduced-motion override — all PR-CABFORGE-3 transitions go to 0
           when the operator has prefers-reduced-motion set. */
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .kpi-tile,
            body[data-ui-version="cabforge"] .rep-tile,
            body[data-ui-version="cabforge"] .ft-tile,
            body[data-ui-version="cabforge"] .filter-bar .fb-search,
            body[data-ui-version="cabforge"] .jobs-table tbody tr,
            body[data-ui-version="cabforge"] .jd-tile,
            body[data-ui-version="cabforge"] .lib-chip,
            body[data-ui-version="cabforge"] .lib-shape-chip,
            body[data-ui-version="cabforge"] .dview-pill,
            body[data-ui-version="cabforge"] .metric-cell {
                transition: none;
            }
            body[data-ui-version="cabforge"] .kpi-tile:hover,
            body[data-ui-version="cabforge"] .rep-tile:hover,
            body[data-ui-version="cabforge"] .ft-tile:hover {
                transform: none;
            }
            body[data-ui-version="cabforge"] .jd-tile:active:not(.active) {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-3 ──────────────────────────────────────────────── */

        /* ── PR-CABFORGE-LOGIN — polish the first-impression screen ───────── */
        body[data-ui-version="cabforge"] .login-wrap {
            background: radial-gradient(ellipse at 50% 30%,
                color-mix(in srgb, var(--acc) 18%, var(--bg)) 0%,
                var(--bg) 70%);
        }
        body[data-ui-version="cabforge"] .login-box {
            background: color-mix(in srgb, var(--pn) 92%, transparent);
            backdrop-filter: blur(20px) saturate(140%);
            -webkit-backdrop-filter: blur(20px) saturate(140%);
            border: 1px solid color-mix(in srgb, var(--acc) 18%, var(--bdr));
            border-radius: 18px;
            padding: 56px 48px 44px;
            box-shadow:
                0 32px 80px rgba(0,0,0,0.55),
                0 0 0 1px color-mix(in srgb, var(--acc) 12%, transparent),
                inset 0 1px 0 color-mix(in srgb, var(--acc) 14%, transparent);
        }
        /* "CF" logomark above the wordmark — pure CSS, no SVG, no HTML
           changes. A 48px rounded square with a stacked gradient + the
           "CF" glyph rendered via text-shadow for crispness. */
        body[data-ui-version="cabforge"] .login-box::before {
            content: "CF";
            display: block;
            width: 56px;
            height: 56px;
            margin: 0 auto 20px;
            background: linear-gradient(135deg, var(--acc) 0%, var(--acc2) 100%);
            border-radius: 14px;
            color: var(--acc-ink);
            font-family: var(--ff-ui, inherit);
            font-weight: 800;
            font-size: 22px;
            letter-spacing: 0.02em;
            text-align: center;
            line-height: 56px;
            box-shadow:
                0 8px 24px color-mix(in srgb, var(--acc) 40%, transparent),
                inset 0 1px 0 rgba(255,255,255,0.18);
        }
        body[data-ui-version="cabforge"] .login-box h1 {
            color: var(--txt);
            font-weight: 700;
            font-size: 28px;
            letter-spacing: -0.01em;
            margin: 0 0 6px 0;
            text-align: center;
            text-transform: none;
        }
        body[data-ui-version="cabforge"] .login-box .sub {
            color: var(--dim);
            font-size: 13px;
            font-weight: 500;
            margin: 0 0 32px 0;
            text-align: center;
            letter-spacing: 0;
        }
        body[data-ui-version="cabforge"] .login-box .fg {
            margin-bottom: 14px;
        }
        body[data-ui-version="cabforge"] .login-box .fg label {
            display: block;
            font-size: 11px;
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--dim);
            margin-bottom: 6px;
        }
        body[data-ui-version="cabforge"] .login-box .fg input {
            width: 100%;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            padding: 12px 14px;
            color: var(--txt);
            font-family: var(--ff-ui, inherit);
            font-size: 14px;
            transition: border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        background 160ms cubic-bezier(0.22, 1, 0.36, 1);
            outline: none;
        }
        body[data-ui-version="cabforge"] .login-box .fg input:hover {
            border-color: var(--bdr-h, var(--bdr));
        }
        body[data-ui-version="cabforge"] .login-box .fg input:focus {
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 22%, transparent);
        }
        body[data-ui-version="cabforge"] .login-box button[type="submit"] {
            width: 100%;
            margin-top: 16px;
            padding: 13px 16px;
            background: linear-gradient(135deg,
                var(--acc) 0%,
                color-mix(in srgb, var(--acc) 80%, var(--acc2)) 100%);
            color: var(--acc-ink);
            border: 1px solid color-mix(in srgb, var(--acc) 60%, var(--acc2));
            border-radius: 10px;
            font-family: var(--ff-ui, inherit);
            font-size: 14px;
            font-weight: 600;
            letter-spacing: 0.02em;
            cursor: pointer;
            transition: filter 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 80ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 140ms cubic-bezier(0.22, 1, 0.36, 1);
            box-shadow: 0 4px 14px color-mix(in srgb, var(--acc) 30%, transparent);
        }
        body[data-ui-version="cabforge"] .login-box button[type="submit"]:hover {
            filter: brightness(1.08);
            box-shadow: 0 6px 18px color-mix(in srgb, var(--acc) 40%, transparent);
        }
        body[data-ui-version="cabforge"] .login-box button[type="submit"]:active {
            transform: scale(0.98);
        }
        body[data-ui-version="cabforge"] .login-box button[type="submit"]:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 3px;
        }
        body[data-ui-version="cabforge"] .login-box .err {
            margin-top: 12px;
            padding: 10px 12px;
            background: color-mix(in srgb, var(--no) 14%, transparent);
            border: 1px solid color-mix(in srgb, var(--no) 35%, transparent);
            border-radius: 8px;
            color: var(--no);
            font-size: 12px;
            font-weight: 500;
            text-align: center;
        }
        body[data-ui-version="cabforge"] .login-box .err:empty {
            display: none;
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .login-box .fg input,
            body[data-ui-version="cabforge"] .login-box button[type="submit"] {
                transition: none;
            }
            body[data-ui-version="cabforge"] .login-box button[type="submit"]:active {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-LOGIN ───────────────────────────────────────────── */

        /* ── PR-CABFORGE-SHELL — sidebar / topbar / statusbar polish ──────── */
        body[data-ui-version="cabforge"] #app-sidebar .sidebar-nav-item {
            border-radius: 0 10px 10px 0;
            margin-right: 8px;
            position: relative;
        }
        body[data-ui-version="cabforge"] #app-sidebar .sidebar-nav-item:hover {
            background: color-mix(in srgb, var(--acc) 8%, transparent);
        }
        body[data-ui-version="cabforge"] #app-sidebar .sidebar-nav-item[aria-current="page"],
        body[data-ui-version="cabforge"] #app-sidebar .sidebar-nav-item.active {
            background: color-mix(in srgb, var(--acc) 14%, transparent);
            border-left: 3px solid var(--acc);
            box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--acc) 22%, transparent);
        }
        body[data-ui-version="cabforge"] #app-sidebar .sidebar-section-label {
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.1em;
            text-transform: uppercase;
            color: var(--dim);
            opacity: 0.65;
        }

        body[data-ui-version="cabforge"] #app-topbar .util-btn,
        body[data-ui-version="cabforge"] #app-topbar .topbar-menu-btn {
            border-radius: 8px;
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] #app-topbar .util-btn:hover,
        body[data-ui-version="cabforge"] #app-topbar .topbar-menu-btn:hover {
            background: color-mix(in srgb, var(--acc) 12%, transparent);
            color: var(--txt);
        }
        body[data-ui-version="cabforge"] #app-topbar .util-btn:focus-visible,
        body[data-ui-version="cabforge"] #app-topbar .topbar-menu-btn:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }
        body[data-ui-version="cabforge"] #app-topbar .topbar-home-btn,
        body[data-ui-version="cabforge"] #app-topbar .topbar-back-btn {
            border-radius: 8px;
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] #app-topbar .topbar-home-btn:hover:not(:disabled),
        body[data-ui-version="cabforge"] #app-topbar .topbar-back-btn:hover:not(:disabled) {
            background: color-mix(in srgb, var(--acc) 12%, transparent);
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] #app-topbar .topbar-page-title {
            font-weight: 600;
            font-size: 13px;
            color: var(--dim);
            letter-spacing: 0.02em;
        }

        body[data-ui-version="cabforge"] #app-topbar #topbar-search-btn {
            background: color-mix(in srgb, var(--acc) 10%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 25%, var(--bdr));
        }
        body[data-ui-version="cabforge"] #app-topbar #topbar-search-btn:hover {
            background: color-mix(in srgb, var(--acc) 18%, transparent);
            border-color: color-mix(in srgb, var(--acc) 45%, var(--bdr));
        }

        body[data-ui-version="cabforge"] #app-statusbar {
            font-size: 11px;
            color: var(--dim);
            letter-spacing: 0.02em;
        }

        body[data-ui-version="cabforge"] #app-bottom-nav .bnav-item {
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] #app-bottom-nav .bnav-item:hover {
            background: color-mix(in srgb, var(--acc) 8%, transparent);
            color: var(--txt);
        }
        body[data-ui-version="cabforge"] #app-bottom-nav .bnav-item[aria-current="page"],
        body[data-ui-version="cabforge"] #app-bottom-nav .bnav-item.active {
            color: var(--acc);
        }

        body[data-ui-version="cabforge"] .hub-page-header,
        body[data-ui-version="cabforge"] .hub-primary-action {
            border-radius: 10px;
        }

        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] #app-sidebar .sidebar-nav-item,
            body[data-ui-version="cabforge"] #app-topbar .util-btn,
            body[data-ui-version="cabforge"] #app-topbar .topbar-menu-btn,
            body[data-ui-version="cabforge"] #app-topbar .topbar-home-btn,
            body[data-ui-version="cabforge"] #app-topbar .topbar-back-btn,
            body[data-ui-version="cabforge"] #app-bottom-nav .bnav-item {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-SHELL ───────────────────────────────────────────── */

        /* ── PR-CABFORGE-HUB — Hub home page polish ──────────────────────── */
        /* Bigger Apple-style headline + refined subtitle. */
        body[data-ui-version="cabforge"] .hub-page-header {
            padding: 32px 24px 20px;
        }
        body[data-ui-version="cabforge"] .hub-page-header h1 {
            font-size: 32px;
            font-weight: 700;
            letter-spacing: -0.02em;
            line-height: 1.15;
        }
        body[data-ui-version="cabforge"] .hub-page-header .hub-subtitle {
            font-size: 14px;
            color: var(--dim);
            margin-top: 6px;
            line-height: 1.5;
            max-width: 60ch;
        }
        /* PR-HOME-REDESIGN (2026-06-13): flattened the primary action — was
           an accent gradient + drop-shadow GLOW + translateY lift (exactly
           the blue-glow chrome the operator flagged, and a FORGE no-no on
           data surfaces). Now a flat accent button; hover = brighten only. */
        body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action {
            border-radius: 10px;
            background: var(--acc);
            color: var(--acc-ink);
            border: 1px solid var(--acc);
            font-weight: 600;
            letter-spacing: 0.01em;
            transition: filter 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action:hover,
        body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action:focus-visible {
            filter: brightness(1.08);
            /* kill the base rule's translateY lift + drop-shadow (FORGE flat) */
            transform: none;
            box-shadow: none;
        }
        body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action:active {
            filter: brightness(0.95);
            /* kill the base rule's press translateY + shadow flash (FORGE flat) */
            transform: none;
            box-shadow: none;
        }

        /* Studio shortcut pills (Cabinet / Door) — refined ghost-pill style. */
        body[data-ui-version="cabforge"] .hub-studio-shortcut {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            color: var(--txt);
            font-weight: 600;
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        border-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 80ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .hub-studio-shortcut:hover {
            background: color-mix(in srgb, var(--acc) 8%, var(--pn));
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] .hub-studio-shortcut:active {
            transform: scale(0.98);
        }
        body[data-ui-version="cabforge"] .hub-studio-shortcut:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }

        /* KPI strip — tighten spacing + ensure grid feels intentional. */
        body[data-ui-version="cabforge"] .kpi-strip {
            padding: 8px 24px 16px;
            gap: 12px;
        }

        /* ── PR-PROD-BAR (2026-05-23, v2) — In Production drawer ────────────
           Tile-click only — no inline strip. Clicking the H-3 "In
           production" KPI tile opens #ipd-drawer with every active job
           grouped by state (Active now / Idle / Not yet started) so the
           office can see exactly where every job sits in the shop.
           All text colors use --white (the home page's "honest" token —
           dark on light themes, light on dark themes) so job names are
           readable on every theme. */
        @keyframes prodPulse {
            0%, 100% { opacity: 1; }
            50%      { opacity: 0.55; }
        }

        /* Make the H-3 KPI tile look clickable since we wire a handler. */
        #kpi-h3 { cursor: pointer; transition: transform 120ms, border-color 120ms; }
        #kpi-h3:hover { border-color: var(--acc); transform: translateY(-1px); }
        #kpi-h3:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }

        /* ── PR-ADM-USERS-POLISH (2026-05-23) — admin Users page ─────────── */
        .adm-card {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 12px;
            margin-bottom: 18px;
            overflow: hidden;
        }
        .adm-form-card { padding: 22px 24px 18px; }
        .adm-form-head { margin-bottom: 18px; padding-bottom: 14px; border-bottom: 1px solid var(--bdr); }
        .adm-form-title { font-size: 1.25rem; font-weight: 700; color: var(--white); margin: 0 0 4px; }
        .adm-form-sub   { font-size: 0.8125rem; color: var(--dim); margin: 0; }
        .adm-form-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 16px 20px;
            margin-bottom: 8px;
        }
        .adm-field { display: flex; flex-direction: column; gap: 4px; }
        .adm-field-wide { grid-column: 1 / -1; }
        .adm-field label {
            font-size: 0.6875rem;
            font-weight: 700;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--dim);
        }
        .adm-field input,
        .adm-field select {
            background: var(--inp, var(--bg));
            color: var(--white);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            padding: 9px 11px;
            font-size: 0.9375rem;
            font-family: inherit;
            transition: border-color 120ms, box-shadow 120ms;
        }
        .adm-field input:focus,
        .adm-field select:focus {
            outline: none;
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 20%, transparent);
        }
        .adm-field-hint {
            font-size: 0.75rem;
            color: var(--dim);
            line-height: 1.4;
            margin-top: 2px;
        }
        .adm-form-error {
            color: var(--risk-late);
            font-size: 0.8125rem;
            margin: 14px 0 0;
            min-height: 18px;
            font-weight: 500;
        }
        .adm-form-actions {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
            margin-top: 18px;
            padding-top: 16px;
            border-top: 1px solid var(--bdr);
        }

        /* Table card */
        .adm-table-head { padding: 18px 24px 12px; border-bottom: 1px solid var(--bdr); }
        .adm-table-title { font-size: 1.0625rem; font-weight: 700; color: var(--white); margin: 0 0 2px; }
        .adm-table-count { color: var(--dim); font-family: var(--ff-mono, "JetBrains Mono", monospace); font-weight: 500; font-size: 0.875rem; margin-left: 4px; }
        .adm-table-sub   { font-size: 0.75rem; color: var(--dim); margin: 0; }

        .adm-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 0.875rem;
        }
        .adm-table thead th {
            text-align: left;
            font-size: 0.6875rem;
            font-weight: 700;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--dim);
            padding: 12px 16px;
            background: var(--bg);
            border-bottom: 1px solid var(--bdr);
        }
        .adm-table tbody td {
            padding: 12px 16px;
            border-bottom: 1px solid color-mix(in srgb, var(--bdr) 50%, transparent);
            vertical-align: middle;
        }
        .adm-table tbody tr.adm-row { transition: background 100ms; }
        .adm-table tbody tr.adm-row:hover { background: color-mix(in srgb, var(--acc) 4%, transparent); }
        .adm-table tbody tr.adm-row.inactive { opacity: 0.55; }
        .adm-table tbody tr.adm-row.is-me { background: color-mix(in srgb, var(--acc) 5%, transparent); }
        .adm-table tbody tr:last-child td { border-bottom: 0; }
        .adm-table-empty { padding: 36px !important; text-align: center; color: var(--dim); font-style: italic; }

        .adm-username { color: var(--white); font-weight: 600; }
        .adm-display  { color: var(--white); }
        .adm-me-badge {
            display: inline-block;
            margin-left: 8px;
            font-size: 0.5625rem;
            font-weight: 800;
            letter-spacing: 0.08em;
            color: var(--acc);
            background: color-mix(in srgb, var(--acc) 14%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 40%, var(--bdr));
            padding: 1px 6px;
            border-radius: 3px;
            text-transform: uppercase;
            vertical-align: middle;
        }
        .adm-pill {
            display: inline-block;
            padding: 4px 11px;
            border-radius: 999px;
            font-size: 0.75rem;
            font-weight: 600;
            letter-spacing: 0.02em;
        }
        .adm-pill.ok { color: var(--risk-on-track); background: color-mix(in srgb, var(--risk-on-track) 14%, var(--bg)); border: 1px solid color-mix(in srgb, var(--risk-on-track) 40%, var(--bdr)); }
        .adm-pill.no { color: var(--risk-late); background: color-mix(in srgb, var(--risk-late) 14%, var(--bg)); border: 1px solid color-mix(in srgb, var(--risk-late) 40%, var(--bdr)); }

        /* Inline cell <select> styled as a chip */
        .adm-cell-select {
            background: var(--bg);
            color: var(--white);
            border: 1px solid var(--bdr);
            border-radius: 999px;
            padding: 5px 10px;
            font-size: 0.8125rem;
            font-family: inherit;
            cursor: pointer;
            min-width: 130px;
            transition: border-color 120ms, background 120ms;
        }
        .adm-cell-select:hover  { border-color: var(--acc); }
        .adm-cell-select:focus  { outline: none; border-color: var(--acc); box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 20%, transparent); }
        .adm-role-chip.role-admin       { color: #d946ef; }
        .adm-role-chip.role-designer    { color: var(--acc); }
        .adm-role-chip.role-shop_floor  { color: #f59e0b; }
        .adm-role-chip.role-viewer      { color: var(--dim); }
        .adm-role-chip.static, .adm-station-chip.static {
            display: inline-block;
            padding: 5px 11px;
            border-radius: 999px;
            font-size: 0.8125rem;
            background: var(--bg);
            border: 1px dashed var(--bdr);
        }
        .adm-station-chip.unset { color: var(--dim); font-style: italic; }
        .adm-station-chip.set   { color: var(--white); }

        /* Action buttons row */
        .adm-actions-cell { text-align: right; white-space: nowrap; }
        .adm-action {
            display: inline-flex;
            align-items: center;
            gap: 4px;
            background: transparent;
            border: 1px solid transparent;
            color: var(--dim);
            padding: 5px 10px;
            border-radius: 6px;
            font-size: 0.75rem;
            font-weight: 500;
            font-family: inherit;
            cursor: pointer;
            transition: background 100ms, color 100ms, border-color 100ms;
            margin-left: 2px;
        }
        .adm-action:hover         { background: color-mix(in srgb, var(--acc) 8%, transparent); border-color: var(--acc); color: var(--white); }
        .adm-action.accent        { color: var(--acc); }
        .adm-action.accent:hover  { background: color-mix(in srgb, var(--acc) 14%, transparent); color: var(--white); }
        .adm-action.subtle        { color: color-mix(in srgb, var(--white) 55%, transparent); }
        .adm-action.subtle:hover  { color: var(--white); background: color-mix(in srgb, var(--white) 8%, transparent); }
        .adm-action.danger        { color: var(--risk-late); }
        .adm-action.danger:hover  { background: color-mix(in srgb, var(--risk-late) 12%, transparent); border-color: var(--risk-late); color: var(--risk-late); }
        .adm-action.ok            { color: var(--risk-on-track); }
        .adm-action.ok:hover      { background: color-mix(in srgb, var(--risk-on-track) 12%, transparent); border-color: var(--risk-on-track); color: var(--risk-on-track); }
        .adm-action-icon { display: inline-block; font-size: 0.8125rem; }
        .adm-row-self { color: var(--dim); font-size: 0.75rem; }
        /* ── /PR-ADM-USERS-POLISH ───────────────────────────────────────── */

        /* PR-IPD-4 (2026-05-23): the legacy drawer-specific CSS that lived
           here (.ipd-head, .ipd-title, .ipd-sub, .ipd-group*, .ipd-job*,
           .ipd-worker-chip, .ipd-job-noworker, #ipd-drawer .drawer) was
           removed with the drawer DOM. The `.ipd-prog*` block below stays
           because pg-production reuses _ipdRenderProgress for the 7-phase
           strip on every list card. */

        /* 7-phase progress bar (Cut → Mill → Build → Sand → Spray → Finish → Pack) */
        .ipd-prog {
            grid-column: 1 / -1;
            margin-top: 10px;
            display: flex;
            flex-direction: column;
            gap: 4px;
        }
        .ipd-prog-bar {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 3px;
            height: 8px;
        }
        .ipd-prog-seg {
            background: color-mix(in srgb, var(--dim) 22%, transparent);
            border-radius: 2px;
            transition: background 200ms;
        }
        .ipd-prog-seg.done {
            background: var(--risk-on-track);
        }
        .ipd-prog-seg.in_progress {
            background: var(--warn, #facc15);
            box-shadow: 0 0 0 2px color-mix(in srgb, var(--warn, #facc15) 30%, transparent);
            animation: prodPulse 1.6s ease-in-out infinite;
        }
        .ipd-prog-labels {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 3px;
            font-size: 0.6875rem;
            font-family: var(--ff-mono, "JetBrains Mono", monospace);
            color: var(--dim);
            margin-top: 2px;
        }
        .ipd-prog-lbl {
            text-align: center;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .ipd-prog-lbl.done       { color: var(--risk-on-track); font-weight: 600; }
        .ipd-prog-lbl.in_progress { color: var(--risk-at-risk); font-weight: 700; }
        .ipd-prog-summary {
            font-size: 0.75rem;
            margin-top: 2px;
        }
        .ipd-prog-now  { color: var(--risk-at-risk); font-weight: 700; }
        .ipd-prog-done { color: var(--risk-on-track); font-weight: 600; }
        .ipd-prog-idle { color: var(--dim); font-style: italic; }
        /* ── /PR-PROD-BAR (drawer-only CSS removed in PR-IPD-4) ─────────── */

        /* ── PR-SCHED2-1 (2026-05-24) — drawer purged ──────────────────────
           The PR-SCHED-5 #sched-drawer DOM + CSS + JS were deleted here
           (~240 LOC CSS, ~20 LOC DOM, ~350 LOC JS). Schedule lives on
           the full page #pg-schedule-v2 (see CSS block immediately below).
           These three #kpi-h5 tile styles stay — the H-5 KPI tile still
           clicks through to go('pg-schedule'). */
        #kpi-h5 { cursor: pointer; transition: transform 120ms, border-color 120ms; }
        #kpi-h5:hover { border-color: var(--acc); transform: translateY(-1px); }
        #kpi-h5:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }
        /* ── /PR-SCHED2-1 ──────────────────────────────────────────────── */

        /* ── PR-SCHED-FULLPAGE (2026-05-23) — Schedule as full page ───── */
        #pg-schedule-v2 { padding: 0; }
        #pg-schedule-v2 .hub-header { padding: 18px 24px 0; }

        /* PR-SCHED-FULLPAGE-POLISH (2026-05-23): full redesign for
           breathing room + clear hierarchy + premium feel. Was: dense
           paper-binder look. Now: airy ServiceTitan-grade dispatch
           board. Every value below tuned for whitespace > density. */
        .schedp-shell {
            display: grid;
            grid-template-columns: 280px 1fr;
            gap: 24px;
            padding: 16px 28px 32px;
            min-height: calc(100vh - 160px);
        }

        /* ── Unscheduled tray (left rail) ──────────────────────────── */
        .schedp-tray {
            background: linear-gradient(180deg,
                color-mix(in srgb, var(--warn, #facc15) 6%, var(--pn)) 0%,
                var(--pn) 80px);
            border: 1px solid var(--bdr);
            border-radius: 14px;
            padding: 18px 16px;
            position: sticky;
            top: 16px;
            max-height: calc(100vh - 180px);
            display: flex; flex-direction: column;
            align-self: start;
            box-shadow: 0 1px 0 rgba(0,0,0,0.04);
        }
        .schedp-tray-head {
            display: flex; justify-content: space-between; align-items: center;
            font-size: 0.75rem; font-weight: 700;
            text-transform: uppercase; letter-spacing: 0.08em;
            color: var(--white);
            padding-bottom: 12px; margin-bottom: 12px;
            border-bottom: 1px solid var(--bdr);
        }
        .schedp-tray-count {
            background: var(--bg);
            border: 1px solid var(--bdr);
            font-family: var(--ff-mono, monospace);
            padding: 3px 10px;
            border-radius: 999px;
            color: var(--white);
            font-size: 0.75rem;
            font-weight: 700;
            min-width: 28px;
            text-align: center;
        }
        .schedp-tray-list {
            display: flex; flex-direction: column; gap: 8px;
            overflow-y: auto; flex: 1;
            min-height: 100px;
            margin: 0 -4px;       /* let scrollbar live in padding gutter */
            padding: 0 4px;
        }
        .schedp-tray-empty {
            color: var(--dim); font-style: italic; font-size: 0.8125rem;
            padding: 16px 4px;
            text-align: center;
        }
        .schedp-tray-hint {
            color: var(--dim);
            font-size: 0.75rem;
            line-height: 1.5;
            margin-top: 14px; padding-top: 12px;
            border-top: 1px dashed var(--bdr);
            text-align: center;
        }

        /* ── Multi-week scrollable area ──────────────────────────── */
        .schedp-weeks {
            display: flex; flex-direction: column; gap: 28px;
            min-width: 0;
        }
        .schedp-loading {
            color: var(--dim); font-style: italic;
            padding: 60px 30px;
            text-align: center;
            font-size: 0.9375rem;
        }
        .schedp-week {
            background: transparent;
            border: none;
            padding: 0;
        }
        .schedp-week-head {
            display: flex; justify-content: space-between; align-items: baseline;
            margin-bottom: 12px;
            padding-bottom: 10px;
            border-bottom: 2px solid var(--bdr);
        }
        .schedp-week-title {
            font-size: 1rem; font-weight: 700; color: var(--white);
            display: flex; align-items: center; gap: 12px;
            letter-spacing: -0.01em;
        }
        .schedp-week-meta {
            font-size: 0.75rem;
            font-family: var(--ff-mono, monospace);
            color: var(--dim);
            font-weight: 600;
        }
        .schedp-week.current {
            position: relative;
        }
        .schedp-week.current .schedp-week-head {
            border-bottom-color: var(--acc);
        }
        .schedp-week.current .schedp-week-title::before {
            content: "THIS WEEK";
            background: var(--acc); color: #fff;
            font-size: 0.625rem; font-weight: 700;
            letter-spacing: 0.08em;
            padding: 3px 9px; border-radius: 4px;
        }
        .schedp-days {
            display: grid;
            grid-template-columns: repeat(5, 1fr);
            gap: 10px;
        }

        /* ── Day cell ─────────────────────────────────────────────── */
        .schedp-day {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            padding: 14px 12px 12px;
            display: flex; flex-direction: column;
            min-height: 180px;
            transition: border-color 120ms, background 120ms;
        }
        .schedp-day.today {
            background: linear-gradient(180deg,
                color-mix(in srgb, var(--acc) 8%, var(--pn)) 0%,
                var(--pn) 60px);
            border-color: color-mix(in srgb, var(--acc) 40%, var(--bdr));
        }
        .schedp-day-head {
            display: flex; justify-content: space-between; align-items: flex-end;
            margin-bottom: 12px;
            padding-bottom: 10px;
            border-bottom: 1px solid color-mix(in srgb, var(--bdr) 60%, transparent);
        }
        .schedp-day-name {
            color: var(--white);
            font-size: 0.8125rem;
            font-weight: 800;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            line-height: 1;
        }
        .schedp-day-date {
            color: var(--dim);
            font-weight: 500;
            font-family: var(--ff-mono, monospace);
            font-size: 0.75rem;
            margin-top: 4px;
            display: block;
            margin-left: 0;
        }
        .schedp-day.today .schedp-day-name { color: var(--acc); }
        .schedp-day-count {
            background: var(--bg);
            border: 1px solid var(--bdr);
            padding: 3px 9px;
            border-radius: 999px;
            font-family: var(--ff-mono, monospace);
            color: var(--white);
            font-weight: 600;
            font-size: 0.75rem;
            min-width: 26px;
            text-align: center;
        }
        .schedp-day-count.over-cap {
            background: color-mix(in srgb, var(--warn, #facc15) 22%, var(--pn));
            color: var(--risk-at-risk);
            border-color: var(--warn, #facc15);
        }
        .schedp-day-list {
            display: flex; flex-direction: column; gap: 8px;
            flex: 1; overflow-y: auto;
            margin: 0 -4px;
            padding: 0 4px;
        }

        /* ── Job card — premium feel ─────────────────────────────── */
        .schedp-card {
            background: var(--bg);
            border: 1px solid var(--bdr);
            border-radius: 8px;
            padding: 11px 12px 10px;
            cursor: pointer;
            font-size: 0.8125rem;
            position: relative;
            transition: border-color 140ms, transform 140ms, box-shadow 140ms;
            display: flex; flex-direction: column; gap: 6px;
        }
        .schedp-card:hover {
            border-color: var(--acc);
            transform: translateY(-1px);
            box-shadow: 0 2px 8px color-mix(in srgb, var(--acc) 20%, transparent);
        }
        .schedp-card:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }
        .schedp-card[draggable="true"] { cursor: grab; }
        .schedp-card.schedp-dragging { opacity: 0.45; cursor: grabbing; transform: rotate(1deg); }
        .schedp-card.rush {
            border-left: 4px solid var(--risk-late);
            padding-left: 11px;
            background: linear-gradient(90deg,
                color-mix(in srgb, var(--risk-late) 5%, var(--bg)) 0%,
                var(--bg) 40%);
        }

        /* Job# headline */
        .schedp-card-jobnum {
            display: flex; align-items: center; gap: 6px;
            line-height: 1.2;
            white-space: nowrap;
            min-height: 18px;
        }
        .schedp-card-jobnum .schedp-jn {
            font-family: var(--ff-mono, "JetBrains Mono", monospace);
            font-weight: 700;
            font-size: 1rem;
            color: var(--white);
            letter-spacing: -0.01em;
        }
        /* Customer secondary */
        .schedp-card-customer {
            font-weight: 500;
            color: var(--white);
            opacity: 0.78;
            font-size: 0.8125rem;
            line-height: 1.25;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .schedp-card-meta {
            display: flex; justify-content: space-between; align-items: baseline;
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem;
            color: var(--dim);
            margin-top: 2px;
            padding-top: 6px;
            border-top: 1px dashed color-mix(in srgb, var(--bdr) 60%, transparent);
        }
        /* PR-UNIFY-D1 (2026-05-24): compact pipeline strip per card.
           7 phases (Cut Mill Build Sand Spray Finish Pack). One char
           per phase: ✓ done, ● in progress (amber pulse), · gray. */
        .schedp-card-pipeline {
            display: flex; gap: 4px; justify-content: space-between;
            margin-top: 4px; padding-top: 4px;
            border-top: 1px dashed color-mix(in srgb, var(--bdr) 40%, transparent);
            font-family: var(--ff-mono, monospace);
            font-size: 11px; line-height: 1; letter-spacing: 0.04em;
        }
        .schedp-phase { color: color-mix(in srgb, var(--dim) 70%, transparent); }
        .schedp-phase.done   { color: var(--risk-on-track); font-weight: 700; }
        .schedp-phase.active {
            color: var(--risk-at-risk); font-weight: 800;
            animation: schedp-phase-pulse 1.4s ease-in-out infinite;
        }
        @keyframes schedp-phase-pulse {
            0%, 100% { opacity: 1; }
            50%      { opacity: 0.45; }
        }
        @media (prefers-reduced-motion: reduce) {
            .schedp-phase.active { animation: none; }
        }

        .schedp-card-risk { font-weight: 700; letter-spacing: 0.04em; }
        .schedp-card-risk.on_track    { color: var(--ok); }
        .schedp-card-risk.at_risk     { color: var(--warn); }
        .schedp-card-risk.late        { color: var(--no); }
        .schedp-card-risk.already_late{ color: var(--no); }
        .schedp-card-risk.unknown     { color: var(--dim); font-weight: 500; }
        /* PR-AUDIT-27 (2026-05-26): Monte Carlo P(on_time) chip. Banded
           color: ≥80% = ok (relax), 50-79% = warn (watch), <50% = no
           (intervene). Uses the same status tokens as the risk badge
           so theme swaps stay coherent. */
        .schedp-card-pot {
            margin-left: 6px;
            padding: 1px 6px;
            border-radius: 4px;
            font-size: 0.6875rem;
            font-weight: 700;
            letter-spacing: 0.03em;
            font-variant-numeric: tabular-nums;
            background: color-mix(in srgb, var(--dim) 18%, transparent);
            color: var(--ink);
        }
        .schedp-card-pot.pot-good { color: var(--ok);   background: color-mix(in srgb, var(--ok)   18%, transparent); }
        .schedp-card-pot.pot-mid  { color: var(--warn); background: color-mix(in srgb, var(--warn) 18%, transparent); }
        .schedp-card-pot.pot-bad  { color: var(--no);   background: color-mix(in srgb, var(--no)   18%, transparent); }

        /* ── PR-AUDIT-28 (2026-05-26): What-If scenario drawer ──── */
        .schedp-whatif {
            position: fixed; inset: 0; z-index: 9000;
            display: flex; justify-content: flex-end;
        }
        .schedp-whatif[hidden] { display: none; }
        .schedp-whatif-shade {
            position: absolute; inset: 0;
            background: color-mix(in srgb, var(--bg) 70%, transparent);
        }
        .schedp-whatif-panel {
            position: relative; width: min(720px, 92vw); height: 100%;
            background: var(--pn);
            box-shadow: -8px 0 32px color-mix(in srgb, var(--bg) 60%, transparent);
            display: flex; flex-direction: column;
            color: var(--ink);
        }
        .schedp-whatif-head {
            padding: 16px 20px;
            border-bottom: 1px solid var(--bdr);
            display: flex; align-items: baseline; gap: 12px;
        }
        .schedp-whatif-head h3 {
            margin: 0; font-size: 1.05rem; letter-spacing: 0.03em; flex: 0 0 auto;
        }
        .schedp-whatif-sub { color: var(--dim); font-size: 0.85rem; flex: 1 1 auto; }
        .schedp-whatif-close {
            background: transparent; border: 0; color: var(--ink);
            font-size: 1.5rem; cursor: pointer; line-height: 1;
            padding: 0 8px;
        }
        .schedp-whatif-tabs {
            display: flex; gap: 6px;
            padding: 8px 20px 0;
            border-bottom: 1px solid var(--bdr);
        }
        .schedp-whatif-tabs button {
            background: transparent; border: 0;
            color: var(--dim); font-weight: 600;
            padding: 8px 14px; border-radius: 6px 6px 0 0;
            cursor: pointer;
        }
        .schedp-whatif-tabs button.active {
            color: var(--ink);
            background: color-mix(in srgb, var(--acc) 12%, transparent);
            border-bottom: 2px solid var(--acc);
        }
        .schedp-whatif-body {
            flex: 1 1 auto; overflow-y: auto; padding: 16px 20px;
        }
        .schedp-whatif-pane[hidden] { display: none; }
        .schedp-whatif-help {
            color: var(--dim); font-size: 0.85rem; margin: 0 0 12px;
        }
        .schedp-whatif-chart {
            display: flex; flex-direction: column; gap: 6px;
        }
        .schedp-tornado-row {
            display: grid;
            grid-template-columns: 110px 1fr 60px;
            align-items: center;
            gap: 8px;
            font-size: 0.85rem;
        }
        .schedp-tornado-station {
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }
        .schedp-tornado-bar-track {
            position: relative;
            height: 18px;
            background: color-mix(in srgb, var(--dim) 12%, transparent);
            border-radius: 3px;
        }
        .schedp-tornado-bar-track::before {
            content: '';
            position: absolute; top: 0; bottom: 0; left: 50%;
            width: 1px; background: var(--dim);
        }
        .schedp-tornado-bar-neg, .schedp-tornado-bar-pos {
            position: absolute; top: 0; bottom: 0;
        }
        .schedp-tornado-bar-neg { right: 50%; background: var(--no); border-radius: 2px 0 0 2px; }
        .schedp-tornado-bar-pos { left: 50%;  background: var(--ok); border-radius: 0 2px 2px 0; }
        .schedp-tornado-swing {
            font-variant-numeric: tabular-nums;
            color: var(--dim); font-size: 0.75rem; text-align: right;
        }
        .schedp-whatif-results {
            margin-top: 12px;
            display: flex; flex-direction: column; gap: 4px;
            font-size: 0.85rem;
        }
        .schedp-whatif-result-row {
            display: grid;
            grid-template-columns: 90px 1fr 50px 50px 64px;
            align-items: center; gap: 8px;
            padding: 4px 6px;
            border-radius: 4px;
        }
        .schedp-whatif-result-row:nth-child(even) {
            background: color-mix(in srgb, var(--dim) 6%, transparent);
        }
        .schedp-whatif-result-job { font-weight: 700; font-variant-numeric: tabular-nums; }
        .schedp-whatif-result-delta { font-variant-numeric: tabular-nums; font-weight: 700; }
        .schedp-whatif-result-delta.good { color: var(--ok); }
        .schedp-whatif-result-delta.bad  { color: var(--no); }
        .schedp-whatif-result-delta.zero { color: var(--dim); }
        .schedp-whatif-summary {
            padding: 10px 12px;
            background: color-mix(in srgb, var(--acc) 8%, transparent);
            border-radius: 4px;
            font-size: 0.85rem;
            margin-bottom: 8px;
        }
        .schedp-whatif-budget {
            display: flex; align-items: center; gap: 8px;
            font-size: 0.85rem; margin-bottom: 12px;
        }
        .schedp-whatif-budget input {
            width: 64px; padding: 4px 6px;
            background: var(--bg); color: var(--ink);
            border: 1px solid var(--bdr); border-radius: 4px;
        }
        #schedp-whatif-sim-controls {
            display: grid;
            grid-template-columns: 1fr auto;
            gap: 6px 12px;
            margin-bottom: 12px;
            font-size: 0.85rem;
            align-items: center;
        }
        #schedp-whatif-sim-controls input {
            width: 60px; padding: 4px 6px;
            background: var(--bg); color: var(--ink);
            border: 1px solid var(--bdr); border-radius: 4px;
        }
        #schedp-whatif-sim-run,
        #schedp-whatif-auto-run {
            background: var(--acc); color: var(--bg);
            border: 0; padding: 8px 16px; border-radius: 4px;
            font-weight: 700; cursor: pointer;
        }
        .schedp-rush-badge {
            background: var(--risk-late); color: #fff;
            font-size: 0.5625rem; font-weight: 700;
            letter-spacing: 0.08em; text-transform: uppercase;
            padding: 2px 6px; border-radius: 3px;
            flex: 0 0 auto;
        }
        .schedp-blocked-badge {
            background: var(--warn, #facc15); color: #422006;
            font-size: 0.5625rem; font-weight: 700;
            letter-spacing: 0.08em; text-transform: uppercase;
            padding: 2px 6px; border-radius: 3px;
            margin-left: auto;
        }

        /* ── Drop targets ─────────────────────────────────────────── */
        .schedp-day.schedp-drop-target,
        .schedp-tray.schedp-drop-target {
            background: color-mix(in srgb, var(--acc) 14%, var(--bg));
            border-color: var(--acc);
            box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc) 30%, transparent);
        }

        /* Empty-day placeholder — minimal so the column doesn't look broken */
        .schedp-day-empty {
            color: var(--dim);
            font-size: 0.6875rem;
            font-style: italic;
            text-align: center;
            padding: 14px 0;
            opacity: 0.5;
        }

        /* ── PR-SCHED2-2 (2026-05-24) — enlarged single-week canvas ──
           One Mon-Fri week now dominates the screen instead of four
           stacked. Day cells grow taller (320 min) so 5+ cards per
           day breathe. Three additions: 4px capacity bar (cyan/amber/
           rose), .past dim, .over-cap dashed border. UX research:
           drum-buffer-rope + Asana/ShopMonkey/Procore conventions.
           --------------------------------------------------------- */
        .schedp-days { gap: 14px; }
        .schedp-day {
            min-height: 320px;
            padding: 16px 14px 14px;
        }
        /* 4px capacity bar — sits between day-head and the card list,
           full column width. The single most-glanceable signal: is
           this day full? Drum-buffer-rope visual management. */
        .schedp-day-cap {
            height: 4px;
            border-radius: 2px;
            margin: 0 -2px 12px;
            background: color-mix(in srgb, var(--acc) 35%, transparent);
            transition: background 140ms;
        }
        .schedp-day-cap.near {
            background: color-mix(in srgb, var(--warn, #facc15) 55%, transparent);
        }
        .schedp-day-cap.over {
            background: var(--risk-late);
        }
        /* Today: amber 2px left border + already has ivory→slate
           gradient on .today (rule above). Add the border without
           clobbering the gradient. */
        .schedp-day.today {
            border-left: 2px solid var(--warn, #facc15);
            padding-left: 13px;
        }
        /* Past days: dim card opacity + muted header. Eye lands on
           the live half of the week. Day header text stays readable. */
        .schedp-day.past .schedp-day-list { opacity: 0.55; }
        .schedp-day.past .schedp-day-name { color: var(--dim); }
        .schedp-day.past .schedp-day-cap  { opacity: 0.5; }
        /* Over-capacity day: dashed rose border on the column (not
           the cards) is the loudest possible signal that the office
           is over-committing this day's shipping capacity. */
        .schedp-day.over-cap {
            border: 1.5px dashed var(--risk-late);
        }
        .schedp-week-current-tag {
            color: var(--acc);
            font-size: 0.625rem;
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            margin-left: 10px;
            vertical-align: middle;
        }
        /* ── /PR-SCHED2-2 ───────────────────────────────────────── */

        /* ── PR-SCHED2-5 (2026-05-24) — View toggle + unscheduled ──
           3-segment pill: Week | Month | Unscheduled. Replaces the
           old "◀ 4 weeks / Today / 4 weeks ▶" buttons. Adapts step
           buttons' semantics per active view. ----------------------- */
        .schedp-viewseg {
            display: inline-flex;
            background: var(--bg);
            border: 1px solid var(--bdr);
            border-radius: 999px;
            padding: 3px;
            font-family: var(--ff-mono, "JetBrains Mono", monospace);
        }
        .schedp-viewseg-btn {
            background: transparent;
            border: none;
            color: var(--dim);
            font: inherit;
            font-size: 0.75rem;
            font-weight: 700;
            letter-spacing: 0.04em;
            padding: 7px 16px;
            border-radius: 999px;
            cursor: pointer;
            transition: background 120ms, color 120ms;
        }
        .schedp-viewseg-btn:hover {
            color: var(--white);
        }
        .schedp-viewseg-btn[aria-selected="true"] {
            background: var(--pn);
            color: var(--white);
            box-shadow: 0 1px 0 rgba(0,0,0,0.05);
        }
        .schedp-viewseg-btn:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }
        /* Step buttons hide entirely in Unscheduled view (no
           pagination semantic). */
        #pg-schedule-v2[data-view="unscheduled"] .schedp-stepgrp {
            display: none;
        }
        /* Unscheduled view = full-page list mode. Hides the week grid +
           month grid + the left-rail tray (which becomes the list
           itself). When unscheduled is active, the page is just the
           tray expanded. */
        #pg-schedule-v2[data-view="unscheduled"] .schedp-shell {
            grid-template-columns: 1fr;
        }
        #pg-schedule-v2[data-view="unscheduled"] .schedp-weeks,
        #pg-schedule-v2[data-view="unscheduled"] .schedp-month {
            display: none !important;
        }
        #pg-schedule-v2[data-view="unscheduled"] .schedp-tray {
            max-height: none;
            position: static;
        }
        #pg-schedule-v2[data-view="unscheduled"] .schedp-tray-list {
            max-height: none;
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
            gap: 10px;
        }
        /* Month view hides the unscheduled tray (it's already a
           planning lens — too much density to compete). */
        #pg-schedule-v2[data-view="month"] .schedp-tray {
            display: none;
        }
        #pg-schedule-v2[data-view="month"] .schedp-shell {
            grid-template-columns: 1fr;
        }
        #pg-schedule-v2[data-view="month"] .schedp-weeks {
            display: none !important;
        }
        /* Week view hides the month grid (default) — same pattern. */
        #pg-schedule-v2[data-view="week"] .schedp-month {
            display: none !important;
        }
        /* ── /PR-SCHED2-5 ───────────────────────────────────────── */

        /* ── PR-SCHED2-6 (2026-05-24) — Right-rail detail panel ────
           Replaces the floating popover. Sticky 340px column to the
           right of the week grid (week view only). Mobile (<980px)
           collapses to a fixed bottom drawer.
           --------------------------------------------------------- */
        #pg-schedule-v2[data-view="week"] .schedp-shell {
            grid-template-columns: 260px minmax(0, 1fr) 340px;
        }
        .schedp-detail {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 14px;
            padding: 18px 18px 14px;
            position: sticky;
            top: 16px;
            max-height: calc(100vh - 180px);
            overflow-y: auto;
            align-self: start;
            display: flex;
            flex-direction: column;
            box-shadow: 0 1px 0 rgba(0,0,0,0.04);
        }
        /* Hide rail in month + unscheduled (already-cramped views). */
        #pg-schedule-v2[data-view="month"] .schedp-detail,
        #pg-schedule-v2[data-view="unscheduled"] .schedp-detail {
            display: none;
        }
        .schedp-detail-empty {
            text-align: center;
            color: var(--dim);
            padding: 40px 12px;
        }
        .schedp-detail-empty-icon {
            font-size: 2rem;
            color: var(--bdr);
            margin-bottom: 10px;
        }
        .schedp-detail-empty-title {
            color: var(--white);
            font-weight: 700;
            font-size: 0.9375rem;
            margin-bottom: 8px;
        }
        .schedp-detail-empty-hint {
            font-size: 0.8125rem;
            line-height: 1.5;
        }
        .schedp-detail-body.hidden { display: none; }
        .schedp-detail-head {
            padding-bottom: 14px;
            margin-bottom: 14px;
            border-bottom: 1px solid var(--bdr);
        }
        .schedp-detail-jobnum {
            font-family: var(--ff-mono, "JetBrains Mono", monospace);
            font-weight: 700;
            font-size: 1.25rem;
            color: var(--white);
            letter-spacing: -0.01em;
        }
        .schedp-detail-customer {
            color: var(--white);
            opacity: 0.75;
            font-size: 0.875rem;
            margin-top: 2px;
            line-height: 1.3;
        }
        .schedp-detail-pills {
            display: flex; flex-wrap: wrap; gap: 6px;
            margin-top: 10px;
        }
        .schedp-detail-pills .schedp-rush-badge,
        .schedp-detail-pills .schedp-blocked-badge {
            margin: 0;
        }
        .schedp-detail-risk-row {
            font-family: var(--ff-mono, monospace);
            font-size: 0.75rem;
            color: var(--dim);
            padding: 10px 0 14px;
            margin-bottom: 12px;
            border-bottom: 1px dashed color-mix(in srgb, var(--bdr) 60%, transparent);
            display: flex; justify-content: space-between; align-items: baseline;
            gap: 10px;
        }
        .schedp-detail-field {
            margin-bottom: 14px;
        }
        .schedp-detail-label {
            display: block;
            font-size: 0.6875rem;
            color: var(--dim);
            text-transform: uppercase;
            letter-spacing: 0.06em;
            font-weight: 700;
            margin-bottom: 5px;
        }
        .schedp-detail-field input[type="date"],
        .schedp-detail-field input[type="number"] {
            width: 100%;
            background: var(--bg);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            padding: 8px 10px;
            color: var(--white);
            font: inherit;
            font-size: 0.875rem;
            font-family: var(--ff-mono, monospace);
        }
        .schedp-detail-field input:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 1px;
            border-color: var(--acc);
        }
        .schedp-detail-clear {
            margin-top: 6px;
            background: transparent;
            border: none;
            color: var(--dim);
            font-size: 0.6875rem;
            cursor: pointer;
            padding: 4px 0;
            font-family: inherit;
        }
        .schedp-detail-clear:hover { color: var(--risk-late); text-decoration: underline; }
        .schedp-detail-toggle {
            display: flex;
            align-items: flex-start;
            gap: 8px;
            font-size: 0.8125rem;
            color: var(--white);
            cursor: pointer;
            line-height: 1.4;
        }
        .schedp-detail-toggle input[type="checkbox"] { margin-top: 2px; }
        .schedp-detail-actions {
            display: flex; flex-direction: column; gap: 8px;
            margin-top: 4px; padding-top: 14px;
            border-top: 1px solid var(--bdr);
        }
        .schedp-detail-actions .bg, .schedp-detail-actions .ba { width: 100%; }
        .schedp-detail-status {
            font-size: 0.75rem;
            min-height: 1em;
            margin-top: 10px;
            font-family: var(--ff-mono, monospace);
        }
        .schedp-detail-status.ok    { color: var(--risk-on-track); }
        .schedp-detail-status.error { color: var(--risk-late); }
        /* Mobile: collapse the rail into a fixed bottom drawer when
           narrower than 980px (tablet portrait, phone). The detail
           stays accessible without stealing screen real estate from
           the week grid. */
        @media (max-width: 980px) {
            #pg-schedule-v2[data-view="week"] .schedp-shell {
                grid-template-columns: 280px minmax(0, 1fr);
            }
            .schedp-detail {
                position: fixed;
                bottom: 0; left: 0; right: 0;
                top: auto;
                max-height: 60vh;
                border-radius: 14px 14px 0 0;
                box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.25);
                z-index: 50;
                margin: 0;
                /* Hide when no job is selected so the empty-state doesn't
                   occlude the week grid on mobile. JS toggles
                   .schedp-detail--has-selection when something is in. */
            }
            .schedp-detail:not(.schedp-detail--has-selection) {
                display: none;
            }
        }
        @media (max-width: 720px) {
            #pg-schedule-v2[data-view="week"] .schedp-shell {
                grid-template-columns: 1fr;
            }
        }
        /* ── /PR-SCHED2-6 ───────────────────────────────────────── */

        /* ── PR-SCHED2-4 (2026-05-24) — Month-view heat-map ───────
           Mon-Fri only (weekends omitted, matching shop policy).
           Each cell = capacity bar + count + one rush highlight.
           Drag intentionally disabled — this is a planning lens
           per cabinet-shop-ux research, not a scheduling surface.
           Click cell → jumps to week view at that week.
           --------------------------------------------------------- */
        .schedp-month.hidden { display: none; }
        .schedp-month {
            display: flex;
            flex-direction: column;
            gap: 18px;
            min-width: 0;
        }
        .schedp-month-head {
            display: flex; justify-content: space-between; align-items: baseline;
            padding-bottom: 10px;
            border-bottom: 2px solid var(--bdr);
        }
        .schedp-month-title {
            font-size: 1.0625rem;
            font-weight: 700;
            color: var(--white);
            letter-spacing: -0.01em;
        }
        .schedp-month-meta {
            font-size: 0.75rem;
            font-family: var(--ff-mono, monospace);
            color: var(--dim);
            font-weight: 600;
        }
        .schedp-month-weekrow-head {
            display: grid;
            grid-template-columns: repeat(5, 1fr);
            gap: 8px;
            font-size: 0.6875rem;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 0.08em;
            color: var(--dim);
            padding: 0 2px 6px;
            border-bottom: 1px solid color-mix(in srgb, var(--bdr) 60%, transparent);
        }
        .schedp-month-weekrow-head > span { text-align: left; }
        .schedp-month-grid {
            display: grid;
            grid-template-columns: repeat(5, 1fr);
            grid-auto-rows: minmax(110px, auto);
            gap: 8px;
        }
        /* Heat-map cell — paper card, ivory bg, restraint. Status
           lives in the capacity bar at the top + one optional
           highlight line. NEVER colors the whole cell (CabForge
           anti-flooding rule). */
        .schedp-month-cell {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 8px;
            padding: 10px 12px;
            cursor: pointer;
            display: flex;
            flex-direction: column;
            gap: 6px;
            transition: border-color 140ms, transform 140ms;
            position: relative;
        }
        .schedp-month-cell:hover {
            border-color: var(--acc);
            transform: translateY(-1px);
        }
        .schedp-month-cell:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }
        /* Outside the displayed month (lead/trail Mon-Fri days of
           neighbor months) — render as flat dim placeholders so the
           5-col grid stays rectangular without implying they're
           clickable. */
        .schedp-month-cell.outside {
            background: transparent;
            border-color: transparent;
            cursor: default;
        }
        .schedp-month-cell.outside .schedp-month-celldate,
        .schedp-month-cell.outside .schedp-month-cellcount {
            opacity: 0.35;
        }
        .schedp-month-cell.outside:hover { transform: none; border-color: transparent; }
        /* Today gets the same 2px amber left border treatment as the
           week view's today column — visual continuity between views. */
        .schedp-month-cell.today {
            border-left: 2px solid var(--warn, #facc15);
            padding-left: 11px;
        }
        /* Past days dim down per UX research. */
        .schedp-month-cell.past { opacity: 0.62; }
        .schedp-month-cellrow1 {
            display: flex; justify-content: space-between; align-items: baseline;
            gap: 8px;
        }
        .schedp-month-celldate {
            font-family: var(--ff-mono, monospace);
            font-weight: 700;
            color: var(--white);
            font-size: 0.9375rem;
            letter-spacing: -0.01em;
        }
        .schedp-month-cellcount {
            font-size: 0.6875rem;
            color: var(--dim);
            font-family: var(--ff-mono, monospace);
            font-weight: 600;
        }
        .schedp-month-cellcount.has-jobs {
            color: var(--white);
        }
        /* 4px capacity bar — same color scheme as the week view's
           .schedp-day-cap so the visual language is identical across
           views. Cyan when under, amber at limit, rose when over. */
        .schedp-month-cellcap {
            height: 4px;
            border-radius: 2px;
            background: color-mix(in srgb, var(--acc) 35%, transparent);
        }
        .schedp-month-cellcap.near {
            background: color-mix(in srgb, var(--warn, #facc15) 55%, transparent);
        }
        .schedp-month-cellcap.over {
            background: var(--risk-late);
        }
        .schedp-month-cell.over-cap {
            border: 1.5px dashed var(--risk-late);
        }
        /* Single highlight line — top rush job for the day. Truncates
           hard at ~20 chars so cells stay uniform height. */
        .schedp-month-cellrush {
            font-size: 0.6875rem;
            color: var(--risk-late);
            font-weight: 600;
            line-height: 1.2;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            display: flex; align-items: center; gap: 4px;
            cursor: pointer;
        }
        .schedp-month-cellrush::before {
            content: "▲";
            font-size: 0.5rem;
            color: var(--risk-late);
        }
        .schedp-month-cellblocked {
            position: absolute;
            top: 8px; right: 10px;
            font-size: 0.6875rem;
            color: var(--risk-at-risk);
        }
        .schedp-month-empty {
            text-align: center;
            color: var(--dim);
            font-style: italic;
            padding: 60px 20px;
        }
        /* Read-only banner — month view never edits via drag. */
        .schedp-month-hint {
            color: var(--dim);
            font-size: 0.75rem;
            text-align: center;
            padding: 12px 0 0;
            font-style: italic;
        }
        /* ── /PR-SCHED2-4 ───────────────────────────────────────── */

        /* Inline edit popover — floats over the page, positioned relative
           to the clicked card by JS. */
        .schedp-edit-popover {
            position: fixed;
            z-index: 200;
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            box-shadow: 0 10px 32px rgba(0, 0, 0, 0.35);
            padding: 18px 20px 16px;
            width: 360px;
            max-width: calc(100vw - 24px);
        }
        .schedp-edit-popover.hidden { display: none; }
        .schedp-edit-close {
            position: absolute; top: 8px; right: 8px;
            background: transparent; border: none; color: var(--dim);
            font-size: 1rem; cursor: pointer; padding: 4px 8px;
        }
        .schedp-edit-close:hover { color: var(--white); }
        .schedp-edit-title {
            font-weight: 700; font-size: 1rem; color: var(--white);
            padding-right: 28px;
        }
        .schedp-edit-sub {
            color: var(--dim); font-size: 0.75rem;
            font-family: var(--ff-mono, monospace);
            margin-bottom: 14px; padding-bottom: 10px;
            border-bottom: 1px solid var(--bdr);
        }
        .schedp-edit-field {
            display: flex; flex-direction: column; gap: 4px;
            margin-bottom: 12px;
        }
        .schedp-edit-label {
            font-size: 0.6875rem; font-weight: 700;
            letter-spacing: 0.06em; text-transform: uppercase;
            color: var(--dim);
        }
        .schedp-edit-field input[type="date"],
        .schedp-edit-field input[type="number"] {
            background: var(--bg); color: var(--white);
            border: 1px solid var(--bdr);
            padding: 6px 9px; border-radius: 5px;
            font-size: 0.875rem; font-family: inherit;
        }
        .schedp-edit-field input:focus {
            outline: none; border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 20%, transparent);
        }
        .schedp-edit-toggle {
            display: flex; align-items: center; gap: 8px;
            color: var(--white); font-size: 0.8125rem;
            cursor: pointer;
        }
        .schedp-edit-clear {
            background: transparent; border: none; color: var(--acc);
            font-size: 0.6875rem; padding: 2px 0; cursor: pointer;
            text-align: left; font-family: inherit;
            text-decoration: underline;
        }
        .schedp-edit-actions {
            display: flex; gap: 8px; margin-top: 14px;
            padding-top: 12px;
            border-top: 1px solid var(--bdr);
        }
        .schedp-edit-status {
            font-size: 0.6875rem;
            color: var(--dim);
            margin-top: 6px;
            min-height: 14px;
            text-align: right;
        }
        .schedp-edit-status.ok { color: var(--risk-on-track); }
        .schedp-edit-status.error { color: var(--risk-late); }

        @media print {
            .schedp-no-print, .sidebar, .schedp-tray-hint,
            .schedp-edit-popover { display: none !important; }
            body * { visibility: hidden; }
            #pg-schedule-v2, #pg-schedule-v2 * { visibility: visible; }
            #pg-schedule-v2 { position: absolute; left: 0; top: 0; width: 100%; }
        }

        @media (max-width: 980px) {
            .schedp-shell {
                grid-template-columns: 1fr;
            }
            .schedp-tray { position: static; max-height: 240px; }
        }
        /* ── /PR-SCHED-FULLPAGE ─────────────────────────────────────────── */

        /* ── PR-DS-SCHED-PAPER (2026-05-25) — paper-ticket aesthetic ────────
           Operator: "make it look like the shop floor ui". Reuses the
           --st-* tokens that shop-floor-v2.html uses (ivory paper on
           slate canvas, JetBrains Mono dims, oxblood RUSH stamps).
           Scoped to #pg-schedule-v2 so the rest of the app keeps the
           CabForge dark-navy theme. */
        #pg-schedule-v2 {
            /* PR-FORGE-CAB-SCHEDULE (2026-06-13): the paper-ticket palette
               (ivory on slate) was the single most jarring off-home seam —
               Schedule is reached straight from the home KPI strip yet
               rendered as a beige page while everything else is dark forge.
               Remap the --st-* tokens onto forge tokens so it reads as a
               DARK ticket (same structure, forge colors). Status stamps map
               to forge semantic colors so RUSH/late stay legible on dark. */
            --st-canvas:        var(--bg);
            --st-paper:         var(--pn);
            --st-ink:           var(--txt);
            --st-ink-dim:       var(--dim);
            --st-rule:          var(--bdr);
            --st-oxblood:       var(--no);
            --st-amber:         var(--warn);
            --st-rose:          var(--no);
            --st-emerald:       var(--ok);
            --st-cyan:          var(--acc);
            /* PR-LIB-COLOR-TOKENS (2026-05-25): aliases for the names
               shop-floor.js references but that previously only existed in
               shop-floor-legacy.html — keeps every paper-aesthetic var()
               resolving cleanly on every surface that loads shop-floor.js. */
            --st-forest:        var(--st-emerald);
            --st-forest-d:      var(--st-emerald);
            --st-oxblood-d:     var(--st-oxblood);
            --st-paper-edge:    var(--st-rule);
            --st-ink-soft:      var(--st-ink-dim);
            background: var(--st-canvas);
        }
        /* Day column → ivory paper card on the slate canvas. */
        #pg-schedule-v2 .schedp-day {
            background: var(--st-paper);
            color: var(--st-ink);
            border: 1px solid var(--st-rule);
            border-radius: 4px;
            box-shadow: 0 2px 6px rgba(0,0,0,0.3);
            padding: 14px 12px;
        }
        #pg-schedule-v2 .schedp-day.today {
            border-left: 6px solid var(--st-oxblood);
        }
        #pg-schedule-v2 .schedp-day-name {
            color: var(--st-cyan);
            font-family: 'JetBrains Mono', monospace;
            font-weight: 700;
            text-transform: uppercase;
        }
        #pg-schedule-v2 .schedp-day-date {
            color: var(--st-ink-dim);
            font-family: 'JetBrains Mono', monospace;
            font-size: 12px;
        }
        #pg-schedule-v2 .schedp-day-count {
            background: var(--st-ink);
            color: var(--st-paper);
            font-family: 'JetBrains Mono', monospace;
            font-weight: 700;
            border-radius: 999px;
            padding: 2px 10px;
            font-size: 12px;
        }
        #pg-schedule-v2 .schedp-day-count.over-cap {
            background: var(--st-oxblood);
            color: #fff;
        }
        /* Job card within a day → small paper ticket with monospace job#. */
        #pg-schedule-v2 .schedp-card {
            background: #fff;
            color: var(--st-ink);
            border: 1px solid var(--st-rule);
            border-left: 3px solid var(--st-ink);
            border-radius: 3px;
            padding: 10px 12px;
            box-shadow: 0 1px 2px rgba(0,0,0,0.15);
        }
        #pg-schedule-v2 .schedp-card:hover {
            background: #fffdf6;
            border-left-color: var(--st-cyan);
        }
        #pg-schedule-v2 .schedp-card.rush {
            border-left: 4px solid var(--st-oxblood);
            background: #fff5f5;
        }
        #pg-schedule-v2 .schedp-card-jobnum {
            color: var(--st-ink);
            font-family: 'JetBrains Mono', monospace;
            font-weight: 700;
        }
        #pg-schedule-v2 .schedp-card-jobnum .schedp-jn {
            color: var(--st-ink);
        }
        #pg-schedule-v2 .schedp-card-customer {
            color: var(--st-ink-dim);
            font-weight: 600;
        }
        #pg-schedule-v2 .schedp-card-meta,
        #pg-schedule-v2 .schedp-card-pipeline {
            color: var(--st-ink-dim);
            font-family: 'JetBrains Mono', monospace;
            font-size: 11px;
        }
        /* RUSH stamp — oxblood rectangle in JetBrains Mono. */
        #pg-schedule-v2 .schedp-card .schedp-rush-tag,
        #pg-schedule-v2 .schedp-rush-tag {
            background: var(--st-oxblood);
            color: #fff;
            font-family: 'JetBrains Mono', monospace;
            font-weight: 700;
            font-size: 10px;
            letter-spacing: 0.08em;
            padding: 2px 6px;
            border-radius: 2px;
        }
        /* Risk badges → paper-ticket colors instead of dashboard accents. */
        #pg-schedule-v2 .schedp-card-risk.on_track  { color: var(--st-emerald); }
        #pg-schedule-v2 .schedp-card-risk.at_risk   { color: var(--st-amber); }
        #pg-schedule-v2 .schedp-card-risk.late      { color: var(--st-oxblood); }
        #pg-schedule-v2 .schedp-card-risk.past_due  { color: var(--st-rose); }
        /* Unscheduled tray → also a paper card with a yellow header strip
           (matches the "STOP — needs scheduling" feel). */
        #pg-schedule-v2 .schedp-tray {
            background: var(--st-paper);
            color: var(--st-ink);
            border: 1px solid var(--st-rule);
            border-radius: 4px;
            box-shadow: 0 2px 6px rgba(0,0,0,0.3);
        }
        #pg-schedule-v2 .schedp-tray-head {
            color: var(--st-ink);
            border-bottom: 1px solid var(--st-rule);
        }
        #pg-schedule-v2 .schedp-tray-count {
            background: var(--st-oxblood);
            color: #fff;
            border: 0;
            font-family: 'JetBrains Mono', monospace;
        }
        #pg-schedule-v2 .schedp-tray-empty,
        #pg-schedule-v2 .schedp-tray-hint {
            color: var(--st-ink-dim);
        }
        #pg-schedule-v2 .schedp-week-head {
            border-bottom: 2px solid var(--st-paper);
        }
        #pg-schedule-v2 .schedp-week-title {
            color: var(--st-paper);
            font-family: 'JetBrains Mono', monospace;
        }
        #pg-schedule-v2 .schedp-week-meta {
            color: var(--st-ink-dim);
            font-family: 'JetBrains Mono', monospace;
        }
        #pg-schedule-v2 .schedp-week.current .schedp-week-head {
            border-bottom-color: var(--st-cyan);
        }
        /* ── /PR-DS-SCHED-PAPER ──────────────────────────────────────────── */

        /* ── PR-IPD-2 (2026-05-23) — In Production full page ────────────── */
        /* Sibling visual language to pg-schedule (paper card + oxblood
           rush border + monospace dims + risk dot palette). Class prefix
           prodp-* mirrors the schedp-* convention. */
        #pg-production { padding: 0; }
        #pg-production .hub-header { padding: 18px 24px 0; }

        .prodp-toolbar {
            padding: 12px 24px 8px;
            display: flex; flex-direction: column; gap: 10px;
            border-bottom: 1px solid var(--bdr);
            background: var(--bg);
        }
        .prodp-search {
            position: relative;
            display: flex; align-items: center;
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 8px;
            padding: 0 12px;
            transition: border-color 120ms, box-shadow 120ms;
        }
        .prodp-search:focus-within {
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 18%, transparent);
        }
        .prodp-search-icon {
            font-size: 0.9rem; color: var(--dim);
            flex: 0 0 auto; padding-right: 8px;
        }
        .prodp-search-input {
            flex: 1; min-width: 0;
            background: transparent; border: none; outline: none;
            color: var(--white);
            font-size: 0.9375rem;
            padding: 10px 0;
            font-family: inherit;
        }
        .prodp-search-input::placeholder { color: var(--dim); }
        .prodp-search-clear {
            background: transparent; border: none; color: var(--dim);
            font-size: 0.875rem; cursor: pointer; padding: 4px 6px;
            border-radius: 4px;
        }
        .prodp-search-clear:hover { color: var(--white); background: var(--bg); }
        .prodp-search-clear.hidden { display: none; }

        .prodp-chips {
            display: flex; flex-wrap: wrap; gap: 6px;
        }
        .prodp-chip {
            background: var(--pn);
            border: 1px solid var(--bdr);
            color: var(--white);
            font-size: 0.75rem; font-weight: 600;
            padding: 5px 11px; border-radius: 999px;
            cursor: pointer;
            display: inline-flex; align-items: center; gap: 6px;
            transition: border-color 120ms, background 120ms;
            font-family: inherit;
        }
        .prodp-chip:hover { border-color: var(--acc); }
        .prodp-chip.on {
            background: var(--acc); color: #fff;
            border-color: var(--acc);
        }
        .prodp-chip-n {
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem; font-weight: 700;
            opacity: 0.8;
        }
        .prodp-chip.on .prodp-chip-n { opacity: 1; }

        .prodp-shell {
            display: grid;
            grid-template-columns: minmax(320px, 1fr) minmax(380px, 1.4fr);
            gap: 16px;
            padding: 12px 24px 24px;
            min-height: calc(100vh - 260px);
        }
        .prodp-list {
            display: flex; flex-direction: column; gap: 6px;
            max-height: calc(100vh - 280px);
            overflow-y: auto;
            padding-right: 4px; /* breathing room next to scrollbar */
        }
        .prodp-loading,
        .prodp-detail-empty,
        .prodp-list-empty {
            color: var(--dim); font-style: italic;
            text-align: center; padding: 32px 16px;
            font-size: 0.875rem;
        }

        /* Job card — kinship with schedp-card but more vertical real
           estate because the office is reading not scheduling. */
        .prodp-card {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 8px;
            padding: 10px 12px;
            cursor: pointer;
            transition: border-color 120ms, transform 120ms, box-shadow 120ms;
            position: relative;
        }
        .prodp-card:hover { border-color: var(--bdr-h); background: var(--pn-h); } /* PR-FORGE-CAB-PRODUCTION: flat hover */
        .prodp-card:focus-visible {
            outline: none; border-color: var(--acc);
            box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc) 30%, transparent);
        }
        .prodp-card.selected {
            border-color: var(--acc);
            box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc) 28%, transparent);
        }
        .prodp-card.rush { border-left: 3px solid var(--risk-late); padding-left: 11px; }

        .prodp-card-head {
            display: flex; align-items: baseline; justify-content: space-between;
            gap: 8px;
        }
        .prodp-card-customer {
            font-size: 0.9375rem; font-weight: 700; color: var(--white);
            line-height: 1.25;
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
            flex: 1; min-width: 0;
        }
        .prodp-card-jobnum {
            font-family: var(--ff-mono, "JetBrains Mono", monospace);
            font-size: 0.8125rem; font-weight: 700; color: var(--dim);
            flex: 0 0 auto;
        }
        .prodp-card-meta {
            display: flex; flex-wrap: wrap; gap: 4px 10px;
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem; color: var(--dim);
            margin-top: 3px;
        }
        .prodp-card-mat {
            display: flex; flex-wrap: wrap; gap: 4px;
            margin-top: 6px;
        }
        .prodp-card-mat-pill {
            background: var(--bg); border: 1px solid var(--bdr);
            color: var(--white);
            font-size: 0.6875rem; font-weight: 500;
            padding: 2px 7px; border-radius: 999px;
            font-family: var(--ff-mono, monospace);
        }
        .prodp-card-badges {
            display: flex; flex-wrap: wrap; gap: 5px;
            margin-top: 6px;
            align-items: center;
            font-size: 0.625rem;
        }
        .prodp-card-tracked {
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem; color: var(--dim);
            margin-left: auto;
        }

        /* Risk + status badges. Same palette as schedp- so the
           office's eye carries learned meaning across the two pages. */
        .prodp-risk-pill {
            font-family: var(--ff-mono, monospace);
            font-weight: 700; letter-spacing: 0.05em;
            font-size: 0.625rem; text-transform: uppercase;
            padding: 1px 5px; border-radius: 3px;
            border: 1px solid transparent;
        }
        .prodp-risk-pill.on_track     { color: var(--risk-on-track); border-color: var(--risk-on-track); }
        .prodp-risk-pill.at_risk      { color: var(--risk-at-risk); border-color: var(--risk-at-risk); }
        .prodp-risk-pill.late         { color: var(--risk-late); border-color: var(--risk-late); }
        .prodp-risk-pill.already_late { color: var(--risk-late); border-color: var(--risk-late);
                                         background: color-mix(in srgb, var(--risk-late) 14%, transparent); }
        .prodp-risk-pill.unknown      { color: var(--dim); border-color: var(--bdr); }

        .prodp-risk-dot { font-size: 1rem; line-height: 1; }
        .prodp-risk-dot.on_track     { color: var(--risk-on-track); }
        .prodp-risk-dot.at_risk      { color: var(--risk-at-risk); }
        .prodp-risk-dot.late         { color: var(--risk-late); }

        .prodp-rush-pill {
            background: var(--risk-late); color: #fff;
            font-weight: 700; letter-spacing: 0.05em;
            font-size: 0.625rem; text-transform: uppercase;
            padding: 1px 5px; border-radius: 3px;
        }
        .prodp-blocked-pill {
            background: var(--warn, #facc15); color: #422006;
            font-weight: 700; letter-spacing: 0.05em;
            font-size: 0.625rem; text-transform: uppercase;
            padding: 1px 5px; border-radius: 3px;
        }

        .prodp-card-workers {
            display: flex; flex-wrap: wrap; gap: 5px;
            margin-top: 6px;
        }
        .prodp-card-worker {
            background: color-mix(in srgb, #facc15 18%, var(--bg));
            border: 1px solid color-mix(in srgb, #facc15 35%, var(--bdr));
            color: var(--white);
            font-size: 0.6875rem;
            padding: 2px 8px; border-radius: 999px;
            font-family: var(--ff-mono, monospace);
            display: inline-flex; align-items: center; gap: 4px;
        }
        .prodp-card-worker-at  { color: var(--dim); font-weight: 500; }
        .prodp-card-worker-stn { color: var(--white); font-weight: 700; }
        .prodp-card-noworker {
            font-size: 0.6875rem; color: var(--dim); font-style: italic;
            margin-top: 6px;
        }

        /* The 7-phase progress strip is rendered by the existing
           _ipdRenderProgress helper (ipd-prog-* classes). We only need
           to size it down for the card density. */
        .prodp-card .ipd-prog { margin-top: 8px; }
        .prodp-card .ipd-prog-bar { height: 6px; }

        /* ── Detail pane ──────────────────────────────────────────── */
        .prodp-detail {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            padding: 18px 20px;
            position: sticky;
            top: 16px;
            max-height: calc(100vh - 280px);
            overflow-y: auto;
            align-self: start;
        }
        .prodp-d-head {
            display: flex; flex-direction: column; gap: 4px;
            padding-bottom: 12px;
            border-bottom: 1px solid var(--bdr);
            margin-bottom: 14px;
        }
        .prodp-d-customer-row {
            display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
        }
        .prodp-d-customer {
            font-size: 1.25rem; font-weight: 700; color: var(--white);
            line-height: 1.2;
        }
        .prodp-d-jobnum {
            font-family: var(--ff-mono, monospace);
            font-size: 0.875rem; color: var(--dim);
            font-weight: 700;
        }
        .prodp-d-sub {
            font-family: var(--ff-mono, monospace);
            font-size: 0.75rem; color: var(--dim);
        }
        .prodp-d-badges {
            display: flex; flex-wrap: wrap; gap: 6px;
            margin-top: 4px;
        }

        .prodp-d-section {
            padding-top: 12px;
            margin-top: 12px;
            border-top: 1px dashed var(--bdr);
        }
        .prodp-d-section:first-of-type {
            border-top: none; margin-top: 0; padding-top: 0;
        }
        .prodp-d-section-h {
            font-size: 0.6875rem; font-weight: 700;
            letter-spacing: 0.06em; text-transform: uppercase;
            color: var(--dim);
            margin-bottom: 8px;
        }
        .prodp-d-grid {
            display: grid;
            grid-template-columns: max-content 1fr;
            gap: 4px 14px;
            font-size: 0.8125rem;
            color: var(--white);
        }
        .prodp-d-grid dt {
            color: var(--dim);
            font-size: 0.6875rem;
            font-weight: 700;
            letter-spacing: 0.04em;
            text-transform: uppercase;
            align-self: center;
        }
        .prodp-d-grid dd { margin: 0; }
        .prodp-d-grid dd.mono {
            font-family: var(--ff-mono, monospace);
            font-size: 0.8125rem;
        }
        .prodp-d-grid dd.muted { color: var(--dim); font-style: italic; }
        .prodp-d-grid dd a { color: var(--acc); text-decoration: none; }
        .prodp-d-grid dd a:hover { text-decoration: underline; }

        .prodp-d-workflow {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
            gap: 6px 12px;
            font-size: 0.75rem;
        }
        .prodp-d-wf-item {
            display: flex; align-items: baseline; gap: 6px;
            color: var(--white);
        }
        .prodp-d-wf-item.pending { color: var(--dim); }
        .prodp-d-wf-mark { font-family: var(--ff-mono, monospace); }
        .prodp-d-wf-mark.done    { color: var(--risk-on-track); }
        .prodp-d-wf-mark.pending { color: var(--dim); }
        .prodp-d-wf-date {
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem; color: var(--dim);
            margin-left: auto;
        }

        .prodp-d-workers {
            display: flex; flex-direction: column; gap: 4px;
        }
        .prodp-d-worker {
            display: flex; align-items: baseline; gap: 8px;
            font-size: 0.8125rem; color: var(--white);
        }
        .prodp-d-worker-dot {
            width: 8px; height: 8px; border-radius: 50%;
            background: #facc15;
            display: inline-block;
            box-shadow: 0 0 0 0 color-mix(in srgb, #facc15 50%, transparent);
            animation: prodp-pulse 1.4s ease-in-out infinite;
            flex: 0 0 auto;
        }
        @keyframes prodp-pulse {
            0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, #facc15 50%, transparent); }
            50%       { box-shadow: 0 0 0 5px color-mix(in srgb, #facc15 0%, transparent); }
        }
        .prodp-d-worker-name { font-weight: 700; }
        .prodp-d-worker-at   { color: var(--dim); font-family: var(--ff-mono, monospace); font-size: 0.6875rem; }
        .prodp-d-worker-stn  { font-family: var(--ff-mono, monospace); font-size: 0.75rem; color: var(--white); }
        .prodp-d-worker-dur  {
            margin-left: auto;
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem; color: var(--dim);
        }

        .prodp-d-actions {
            display: flex; gap: 8px; flex-wrap: wrap;
            margin-top: 14px;
            padding-top: 14px;
            border-top: 1px solid var(--bdr);
        }

        /* ── PR-IPD-3 (2026-05-23) — Inline per-station timeline + worker
              aggregate. Loads async after the row is selected. ──────── */
        .prodp-d-timeline-pending {
            color: var(--dim); font-style: italic; font-size: 0.75rem;
            padding: 6px 0;
        }
        .prodp-d-timeline-error {
            color: var(--risk-late); font-size: 0.75rem;
            padding: 6px 0;
        }
        .prodp-d-station {
            margin-bottom: 14px;
        }
        .prodp-d-station:last-child { margin-bottom: 0; }
        .prodp-d-station-head {
            display: flex; align-items: baseline; justify-content: space-between;
            padding: 4px 0;
            border-bottom: 1px solid var(--bdr);
            margin-bottom: 4px;
        }
        .prodp-d-station-name {
            font-size: 0.8125rem; font-weight: 700;
            color: var(--white);
            letter-spacing: 0.02em;
        }
        .prodp-d-station-tot {
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem; color: var(--dim);
        }
        .prodp-d-station-open {
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem; font-weight: 700;
            color: var(--risk-at-risk);
        }
        .prodp-d-entries {
            display: flex; flex-direction: column; gap: 2px;
            padding-left: 2px;
        }
        .prodp-d-entry {
            display: grid;
            grid-template-columns: 14px max-content 1fr max-content;
            align-items: baseline; gap: 8px;
            font-size: 0.75rem;
            color: var(--white);
            padding: 2px 0;
        }
        .prodp-d-entry.open {
            background: color-mix(in srgb, #facc15 8%, transparent);
            margin: 0 -4px;
            padding-left: 4px; padding-right: 4px;
            border-radius: 4px;
        }
        .prodp-d-entry-mark { color: var(--dim); text-align: center; }
        .prodp-d-entry-worker { font-weight: 600; }
        .prodp-d-entry-when {
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem; color: var(--dim);
        }
        .prodp-d-entry-dur {
            font-family: var(--ff-mono, monospace);
            font-size: 0.6875rem; color: var(--white);
            justify-self: end;
        }
        .prodp-d-redo {
            font-size: 0.6875rem;
            color: var(--risk-at-risk);
            margin: 2px 0 4px 22px;
            padding: 3px 8px;
            background: color-mix(in srgb, var(--risk-at-risk) 10%, var(--pn));
            border-left: 2px solid var(--risk-at-risk);
            border-radius: 0 4px 4px 0;
        }
        .prodp-d-redo-tag {
            font-weight: 700; letter-spacing: 0.06em;
            font-family: var(--ff-mono, monospace);
            font-size: 0.625rem;
            margin-right: 6px;
            text-transform: uppercase;
        }

        .prodp-d-bywkr-row {
            display: grid;
            grid-template-columns: 14px max-content 1fr max-content;
            align-items: center; gap: 8px;
            font-size: 0.8125rem;
            color: var(--white);
            padding: 4px 0;
        }
        .prodp-d-bywkr-row.active {
            background: color-mix(in srgb, #facc15 8%, transparent);
            margin: 0 -4px;
            padding-left: 4px; padding-right: 4px;
            border-radius: 4px;
        }
        .prodp-d-bywkr-spacer { width: 8px; height: 8px; }
        .prodp-d-bywkr-name { font-weight: 700; }
        .prodp-d-bywkr-stations {
            display: flex; flex-wrap: wrap; gap: 3px;
            min-width: 0;
        }
        .prodp-d-bywkr-stn {
            background: var(--bg);
            border: 1px solid var(--bdr);
            font-family: var(--ff-mono, monospace);
            font-size: 0.625rem;
            color: var(--dim);
            padding: 1px 6px;
            border-radius: 999px;
        }
        .prodp-d-bywkr-total {
            font-family: var(--ff-mono, monospace);
            font-size: 0.75rem;
            color: var(--white);
            font-weight: 700;
            justify-self: end;
        }

        /* Legend strip — bottom of page, mirrors schedp legend pattern. */
        .prodp-legend {
            display: flex; flex-wrap: wrap; gap: 14px;
            padding: 10px 24px 18px;
            border-top: 1px solid var(--bdr);
            font-size: 0.6875rem;
            color: var(--dim);
            background: var(--bg);
        }
        .prodp-legend-item {
            display: inline-flex; align-items: center; gap: 6px;
        }
        .prodp-legend-hint { margin-left: auto; font-style: italic; }

        @media print {
            .prodp-no-print, .sidebar, .prodp-toolbar,
            .prodp-legend { display: none !important; }
            body * { visibility: hidden; }
            #pg-production, #pg-production * { visibility: visible; }
            #pg-production { position: absolute; left: 0; top: 0; width: 100%; }
            .prodp-shell { grid-template-columns: 1fr 1fr; }
            .prodp-detail { position: static; max-height: none; }
            .prodp-list { max-height: none; }
        }

        @media (max-width: 980px) {
            .prodp-shell { grid-template-columns: 1fr; }
            .prodp-detail { position: static; max-height: none; }
            .prodp-list   { max-height: 50vh; }
        }
        /* ── /PR-IPD-2 ──────────────────────────────────────────────────── */

        /* Hub right-rail content — refined typography for theme + units cards. */
        body[data-ui-version="cabforge"] #hub-rail-themes,
        body[data-ui-version="cabforge"] #hub-rail-units {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 12px;
            padding: 16px;
        }

        /* Tab content slot — gentle vertical rhythm. */
        body[data-ui-version="cabforge"] #pg-hub .tc {
            padding-top: 4px;
        }

        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action,
            body[data-ui-version="cabforge"] .hub-studio-shortcut {
                transition: none;
            }
            body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action:hover,
            body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action:focus-visible {
                transform: none;
            }
            body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action:active,
            body[data-ui-version="cabforge"] .hub-studio-shortcut:active {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-HUB ─────────────────────────────────────────────── */

        /* ── PR-CABFORGE-FORMS — buttons, inputs, toasts ─────────────────── */
        /* Primary button (.ba) — accent gradient + drop shadow + scale press */
        body[data-ui-version="cabforge"] .ba {
            background: linear-gradient(135deg,
                var(--acc) 0%,
                color-mix(in srgb, var(--acc) 80%, var(--acc2)) 100%);
            color: var(--acc-ink);
            border: 1px solid color-mix(in srgb, var(--acc) 55%, var(--acc2));
            border-radius: 8px;
            font-weight: 600;
            letter-spacing: 0.01em;
            box-shadow: 0 2px 8px color-mix(in srgb, var(--acc) 22%, transparent);
            transition: filter 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 80ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .ba:hover:not(:disabled) {
            filter: brightness(1.08);
            box-shadow: 0 4px 14px color-mix(in srgb, var(--acc) 35%, transparent);
        }
        body[data-ui-version="cabforge"] .ba:active:not(:disabled) {
            transform: scale(0.98);
        }
        body[data-ui-version="cabforge"] .ba:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }
        body[data-ui-version="cabforge"] .ba:disabled {
            opacity: 0.5;
            cursor: not-allowed;
            box-shadow: none;
        }

        /* Ghost button (.bg) — neutral surface, accent hover */
        body[data-ui-version="cabforge"] .bg {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 8px;
            color: var(--txt);
            font-weight: 600;
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        border-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 80ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .bg:hover:not(:disabled) {
            background: color-mix(in srgb, var(--acc) 8%, var(--pn));
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] .bg:active:not(:disabled) {
            transform: scale(0.98);
        }
        body[data-ui-version="cabforge"] .bg:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }

        /* Semantic buttons — ok/danger/warn — refined gradient + drop shadow */
        body[data-ui-version="cabforge"] .bk {
            background: linear-gradient(135deg,
                var(--ok) 0%,
                color-mix(in srgb, var(--ok) 80%, #000) 100%);
            color: var(--ok-ink, #000);
            border: 1px solid color-mix(in srgb, var(--ok) 55%, var(--bdr));
            border-radius: 8px;
            font-weight: 600;
            box-shadow: 0 2px 8px color-mix(in srgb, var(--ok) 22%, transparent);
        }
        body[data-ui-version="cabforge"] .bk:hover:not(:disabled) {
            filter: brightness(1.08);
            box-shadow: 0 4px 14px color-mix(in srgb, var(--ok) 35%, transparent);
        }

        body[data-ui-version="cabforge"] .br {
            background: linear-gradient(135deg,
                var(--no) 0%,
                color-mix(in srgb, var(--no) 80%, #000) 100%);
            color: #fff;
            border: 1px solid color-mix(in srgb, var(--no) 55%, var(--bdr));
            border-radius: 8px;
            font-weight: 600;
            box-shadow: 0 2px 8px color-mix(in srgb, var(--no) 22%, transparent);
        }
        body[data-ui-version="cabforge"] .br:hover:not(:disabled) {
            filter: brightness(1.08);
            box-shadow: 0 4px 14px color-mix(in srgb, var(--no) 35%, transparent);
        }

        body[data-ui-version="cabforge"] .bw {
            background: linear-gradient(135deg,
                var(--warn) 0%,
                color-mix(in srgb, var(--warn) 80%, #000) 100%);
            color: #1a1410;
            border: 1px solid color-mix(in srgb, var(--warn) 55%, var(--bdr));
            border-radius: 8px;
            font-weight: 600;
            box-shadow: 0 2px 8px color-mix(in srgb, var(--warn) 22%, transparent);
        }

        /* Form inputs — refined focus rings; sets the input/select/textarea
           interaction language for the entire app. */
        body[data-ui-version="cabforge"] input[type="text"],
        body[data-ui-version="cabforge"] input[type="password"],
        body[data-ui-version="cabforge"] input[type="email"],
        body[data-ui-version="cabforge"] input[type="number"],
        body[data-ui-version="cabforge"] input[type="search"],
        body[data-ui-version="cabforge"] input[type="tel"],
        body[data-ui-version="cabforge"] input[type="url"],
        body[data-ui-version="cabforge"] input:not([type]),
        body[data-ui-version="cabforge"] select,
        body[data-ui-version="cabforge"] textarea {
            border-radius: 8px;
            transition: border-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] input[type="text"]:focus,
        body[data-ui-version="cabforge"] input[type="password"]:focus,
        body[data-ui-version="cabforge"] input[type="email"]:focus,
        body[data-ui-version="cabforge"] input[type="number"]:focus,
        body[data-ui-version="cabforge"] input[type="search"]:focus,
        body[data-ui-version="cabforge"] input[type="tel"]:focus,
        body[data-ui-version="cabforge"] input[type="url"]:focus,
        body[data-ui-version="cabforge"] input:not([type]):focus,
        body[data-ui-version="cabforge"] select:focus,
        body[data-ui-version="cabforge"] textarea:focus {
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 22%, transparent);
            outline: none;
        }

        /* Toasts — refined depth, accent-tinted left edge by variant */
        body[data-ui-version="cabforge"] .toast {
            border-radius: 12px;
            backdrop-filter: blur(12px) saturate(140%);
            -webkit-backdrop-filter: blur(12px) saturate(140%);
            background: color-mix(in srgb, var(--toast-bg, var(--pn)) 92%, transparent);
            box-shadow:
                0 16px 48px rgba(0,0,0,0.55),
                inset 0 1px 0 color-mix(in srgb, var(--acc) 18%, transparent);
            font-weight: 500;
            font-size: 13px;
        }
        body[data-ui-version="cabforge"] .toast.toast-ok,
        body[data-ui-version="cabforge"] .toast.ok {
            border-left-color: var(--ok);
        }
        body[data-ui-version="cabforge"] .toast.toast-warn,
        body[data-ui-version="cabforge"] .toast.warn {
            border-left-color: var(--warn);
        }
        body[data-ui-version="cabforge"] .toast.toast-err,
        body[data-ui-version="cabforge"] .toast.err {
            border-left-color: var(--no);
        }

        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .ba,
            body[data-ui-version="cabforge"] .bg,
            body[data-ui-version="cabforge"] input[type="text"],
            body[data-ui-version="cabforge"] input[type="password"],
            body[data-ui-version="cabforge"] input[type="email"],
            body[data-ui-version="cabforge"] input[type="number"],
            body[data-ui-version="cabforge"] input[type="search"],
            body[data-ui-version="cabforge"] select,
            body[data-ui-version="cabforge"] textarea {
                transition: none;
            }
            body[data-ui-version="cabforge"] .ba:active:not(:disabled),
            body[data-ui-version="cabforge"] .bg:active:not(:disabled) {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-FORMS ───────────────────────────────────────────── */

        /* ── PR-CABFORGE-DRAWERS — drawer chrome + inspector badges ──────── */
        /* Drawer h2 / subtitle — refined typography */
        body[data-ui-version="cabforge"] .drawer h2 {
            color: var(--txt);
            font-size: 22px;
            font-weight: 700;
            letter-spacing: -0.01em;
            line-height: 1.2;
            margin: 0 0 8px 0;
        }
        body[data-ui-version="cabforge"] .drawer .sub {
            color: var(--dim);
            font-size: 13px;
            font-weight: 400;
            line-height: 1.5;
            margin: 0 0 24px 0;
            max-width: 60ch;
        }
        /* Drawer close button — refined hover with accent halo */
        body[data-ui-version="cabforge"] .drawer-close {
            border-radius: 10px;
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .drawer-close:hover {
            background: color-mix(in srgb, var(--no) 14%, transparent);
            color: var(--no);
        }
        body[data-ui-version="cabforge"] .drawer-close:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }

        /* Inspector badges (.insp-inherits, .insp-overridden) — refined pills */
        body[data-ui-version="cabforge"] .insp-badge {
            border-radius: 999px;
            font-weight: 600;
            font-size: 10px;
            letter-spacing: 0.04em;
            padding: 3px 9px;
        }
        body[data-ui-version="cabforge"] .insp-badge.insp-inherits {
            background: color-mix(in srgb, var(--bdr) 60%, transparent);
            border: 1px solid var(--bdr);
            color: var(--dim);
        }
        body[data-ui-version="cabforge"] .insp-badge.insp-overridden {
            background: color-mix(in srgb, var(--acc) 22%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 45%, var(--bdr));
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] .insp-reset {
            border-radius: 6px;
            transition: background 120ms cubic-bezier(0.22, 1, 0.36, 1),
                        border-color 120ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .insp-reset:hover {
            background: color-mix(in srgb, var(--acc) 14%, var(--inp));
            border-color: color-mix(in srgb, var(--acc) 45%, var(--bdr));
            color: var(--acc);
        }

        /* Tab strips (used across cab-editor, libraries, etc.) — refined
           active state. Most tab strips use .tab class. */
        body[data-ui-version="cabforge"] .tab {
            border-radius: 8px 8px 0 0;
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .tab:hover:not(.on) {
            background: color-mix(in srgb, var(--acc) 6%, transparent);
            color: var(--txt);
        }
        body[data-ui-version="cabforge"] .tab.on {
            background: var(--pn);
            color: var(--acc);
            font-weight: 600;
            border-bottom: 2px solid var(--acc);
        }

        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .drawer-close,
            body[data-ui-version="cabforge"] .insp-reset,
            body[data-ui-version="cabforge"] .tab {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-DRAWERS ─────────────────────────────────────────── */

        /* ── PR-DOOR-REV-DRAWER (Wave 5.6, 2026-05-17) — revision-history drawer ── */
        /* Fixed-position panel that slides in from the right edge. Hidden by
           default (aria-hidden=true + transform off-screen). When .open is
           added, slides into view. Width matches the existing ds-param-panel
           (360px) for visual consistency with the rest of Door Studio. */
        .rev-drawer {
            position: fixed;
            top: 0;
            right: 0;
            width: 380px;
            max-width: 100vw;
            height: 100vh;
            background: var(--inp);
            border-left: 1px solid var(--bdr);
            box-shadow: -4px 0 16px rgba(0,0,0,.25);
            transform: translateX(100%);
            transition: transform .22s ease;
            z-index: 1000;
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }
        .rev-drawer.open {
            transform: translateX(0);
        }
        .rev-drawer-head {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 14px 18px;
            border-bottom: 1px solid var(--bdr);
            background: color-mix(in srgb, var(--inp) 90%, var(--bg));
        }
        .rev-list {
            flex: 0 0 auto;
            max-height: 45%;
            overflow-y: auto;
            padding: 8px 6px;
            border-bottom: 1px solid var(--bdr);
        }
        .rev-row {
            display: block;
            width: 100%;
            text-align: left;
            background: transparent;
            border: 1px solid transparent;
            border-radius: 6px;
            color: var(--txt);
            padding: 10px 12px;
            margin-bottom: 4px;
            cursor: pointer;
            min-height: 44px;
            font-size: 13px;
            line-height: 1.4;
        }
        .rev-row:hover {
            background: color-mix(in srgb, var(--acc) 8%, transparent);
            border-color: color-mix(in srgb, var(--acc) 25%, transparent);
        }
        .rev-row.selected {
            background: color-mix(in srgb, var(--acc) 12%, transparent);
            border-color: var(--acc);
        }
        .rev-row .rev-num { font-weight: 600; color: var(--txt); }
        .rev-row .rev-time { color: var(--dim); font-size: 11px; margin-left: 6px; }
        .rev-row .rev-note { color: var(--dim); font-size: 12px; margin-top: 3px; font-style: italic; }
        .rev-row .rev-note-empty { color: color-mix(in srgb, var(--dim) 70%, transparent); }
        .rev-diff {
            flex: 1 1 auto;
            overflow-y: auto;
            padding: 12px 16px;
            font-family: ui-monospace, "SF Mono", Consolas, monospace;
            font-size: 12px;
            line-height: 1.5;
            color: var(--txt);
        }
        .rev-diff h4 {
            margin: 0 0 6px;
            font-family: inherit;
            font-size: 12px;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: .04em;
            color: var(--dim);
        }
        .rev-diff .rev-group {
            margin-bottom: 14px;
            padding: 10px 12px;
            border-radius: 6px;
            background: color-mix(in srgb, var(--bg) 55%, transparent);
            border: 1px solid var(--bdr);
        }
        .rev-diff .rev-group-head {
            font-weight: 700;
            margin-bottom: 6px;
        }
        .rev-diff .rev-field { padding-left: 12px; margin: 2px 0; }
        .rev-diff .rev-piece { padding-left: 8px; margin: 4px 0; border-left: 2px solid var(--bdr); padding-left: 12px; }
        .rev-diff .rev-add    { color: #22c55e; }   /* CabForge green */
        .rev-diff .rev-remove { color: #f43f5e; }   /* CabForge rose  */
        .rev-diff .rev-mod    { color: #f59e0b; }   /* CabForge amber */
        .rev-diff .rev-arrow  { color: var(--dim); }
        .rev-diff .rev-empty  { color: var(--dim); font-style: italic; padding: 8px 0; }
        /* ── /PR-DOOR-REV-DRAWER ───────────────────────────────────────────── */

        /* ── PR-DOOR-LIVE-VALIDATION (E-1 close-out 2026-05-17) — piece-edit-time chip ── */
        /* Warning surface that sits below the piece-input row. Fires the
           moment an operator types a width/height that trips a validator
           (arch min-chord, warp envelope) — not at cutlist-download time.
           One <div> per warning, color-coded by severity. */
        .ds-piece-warn {
            margin: 8px 0 4px;
            display: flex;
            flex-direction: column;
            gap: 4px;
        }
        .ds-piece-warn .ds-piece-warn-row {
            display: flex;
            align-items: flex-start;
            gap: 8px;
            padding: 8px 10px;
            border-radius: 6px;
            font-size: 12px;
            line-height: 1.4;
            border: 1px solid transparent;
        }
        .ds-piece-warn .ds-piece-warn-row svg {
            flex: 0 0 16px;
            margin-top: 1px;
        }
        .ds-piece-warn .ds-piece-warn-row.ds-warn {
            background: color-mix(in srgb, #f59e0b 12%, transparent);
            border-color: color-mix(in srgb, #f59e0b 40%, transparent);
            color: #f59e0b;
        }
        .ds-piece-warn .ds-piece-warn-row.ds-error {
            background: color-mix(in srgb, #f43f5e 14%, transparent);
            border-color: color-mix(in srgb, #f43f5e 50%, transparent);
            color: #f43f5e;
        }
        .ds-piece-warn .ds-piece-warn-row.ds-info {
            background: color-mix(in srgb, #22c55e 10%, transparent);
            border-color: color-mix(in srgb, #22c55e 35%, transparent);
            color: #22c55e;
        }
        /* ── /PR-DOOR-LIVE-VALIDATION ──────────────────────────────────────── */

        /* ── PR-CABFORGE-DOOR — Door Studio polish ──────────────────────── */
        /* Page header inside pg-door */
        body[data-ui-version="cabforge"] #pg-door h2 {
            font-size: 22px;
            font-weight: 700;
            letter-spacing: -0.01em;
            color: var(--txt);
        }
        /* Door tab strip (dtab) */
        body[data-ui-version="cabforge"] #pg-door .tab {
            border-radius: 8px 8px 0 0;
            padding: 10px 16px;
        }
        /* Doors table (orders list) */
        body[data-ui-version="cabforge"] #pg-door table {
            border-collapse: separate;
            border-spacing: 0;
            font-variant-numeric: tabular-nums;
        }
        body[data-ui-version="cabforge"] #pg-door table th {
            font-size: 11px;
            font-weight: 700;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--dim);
            border-bottom: 1px solid var(--bdr);
            padding: 10px 12px;
        }
        body[data-ui-version="cabforge"] #pg-door table tbody tr {
            transition: background 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] #pg-door table tbody tr:hover {
            background: color-mix(in srgb, var(--acc) 5%, transparent);
        }
        /* Door Studio wizard step container (Bundles 1-5) gets a cabforge
           card-like background to differentiate from the page body */
        body[data-ui-version="cabforge"] #pg-door .ds-bundle {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 12px;
            padding: 24px;
        }
        body[data-ui-version="cabforge"] #pg-door .ds-bundle-bar {
            border-radius: 12px 12px 0 0;
        }
        /* Door library table */
        body[data-ui-version="cabforge"] #dl-table table {
            border-collapse: separate;
            border-spacing: 0;
        }
        body[data-ui-version="cabforge"] #dl-table table tr {
            transition: background 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] #dl-table table tr:hover {
            background: color-mix(in srgb, var(--acc) 5%, transparent);
            cursor: pointer;
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] #pg-door table tbody tr,
            body[data-ui-version="cabforge"] #dl-table table tr {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-DOOR ────────────────────────────────────────────── */

        /* ── PR-CABFORGE-CAB — Cabinet Studio dashboard polish ──────────── */
        body[data-ui-version="cabforge"] #pg-cab h1,
        body[data-ui-version="cabforge"] #pg-cab .cab-page-title {
            font-size: 28px;
            font-weight: 700;
            letter-spacing: -0.015em;
            color: var(--txt);
        }
        body[data-ui-version="cabforge"] #pg-cab h2 {
            font-size: 20px;
            font-weight: 600;
            letter-spacing: -0.01em;
            color: var(--txt);
        }
        /* Metrics ribbon container */
        body[data-ui-version="cabforge"] .metrics-ribbon {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 12px;
            overflow: hidden;
        }
        body[data-ui-version="cabforge"] .metric-cell {
            padding: 16px 20px;
        }
        body[data-ui-version="cabforge"] .metric-cell .metric-value {
            font-variant-numeric: tabular-nums;
            letter-spacing: -0.01em;
        }
        body[data-ui-version="cabforge"] .metric-cell .metric-label {
            font-weight: 600;
            letter-spacing: 0.06em;
            text-transform: uppercase;
        }
        /* Job hub report tile grid container */
        body[data-ui-version="cabforge"] #cab-job-reports {
            gap: 12px;
        }
        /* Room card chips */
        body[data-ui-version="cabforge"] .cab-room-card {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 12px;
            transition: border-color 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .cab-room-card:hover {
            border-color: color-mix(in srgb, var(--acc) 45%, var(--bdr));
            box-shadow: 0 6px 18px color-mix(in srgb, var(--acc) 14%, transparent);
            transform: translateY(-2px);
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .cab-room-card {
                transition: none;
            }
            body[data-ui-version="cabforge"] .cab-room-card:hover {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-CAB ─────────────────────────────────────────────── */

        /* ── PR-CABFORGE-WIZARD — wizard step-dot polish ────────────────── */
        body[data-ui-version="cabforge"] .njwiz-stepdot {
            border-width: 2px;
            transition: background 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 160ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .njwiz-stepdot.active {
            background: linear-gradient(135deg, var(--acc) 0%, var(--acc2) 100%);
            border-color: var(--acc);
            color: var(--acc-ink);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 25%, transparent);
        }
        body[data-ui-version="cabforge"] .njwiz-stepdot.done {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 12%, transparent);
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] .njwiz-stepline {
            transition: background 160ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .njwiz-stepline.done {
            background: linear-gradient(90deg,
                var(--acc) 0%,
                color-mix(in srgb, var(--acc) 70%, var(--bdr)) 100%);
        }
        body[data-ui-version="cabforge"] .njwiz-shopdef-badge {
            background: color-mix(in srgb, var(--acc) 16%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 35%, var(--bdr));
            color: var(--acc);
            border-radius: 999px;
            padding: 2px 8px;
            font-weight: 700;
            letter-spacing: 0.04em;
        }
        body[data-ui-version="cabforge"] .njwiz-pageinfo {
            font-weight: 600;
            letter-spacing: 0.04em;
            text-transform: uppercase;
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .njwiz-stepdot,
            body[data-ui-version="cabforge"] .njwiz-stepline {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-WIZARD ──────────────────────────────────────────── */

        /* ── PR-CABFORGE-LIB — Library tables + thumbnails polish ────────── */
        body[data-ui-version="cabforge"] .lib-table {
            border-radius: 12px;
            font-variant-numeric: tabular-nums;
        }
        body[data-ui-version="cabforge"] .lib-table thead th {
            font-size: 11px;
            font-weight: 700;
            letter-spacing: 0.08em;
            background: color-mix(in srgb, var(--pn) 92%, var(--acc));
            border-bottom: 1px solid var(--bdr);
            color: var(--dim);
        }
        body[data-ui-version="cabforge"] .lib-table tbody tr {
            transition: background 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .lib-table tbody tr:hover {
            background: color-mix(in srgb, var(--acc) 6%, transparent);
            cursor: pointer;
        }
        body[data-ui-version="cabforge"] .lib-table .lib-thumb {
            border-radius: 8px;
            border: 1px solid color-mix(in srgb, var(--acc) 12%, var(--bdr));
            background: linear-gradient(135deg,
                var(--inp) 0%,
                color-mix(in srgb, var(--inp) 80%, var(--bg)) 100%);
        }
        body[data-ui-version="cabforge"] .lib-chips {
            gap: 6px;
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .lib-table tbody tr {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-LIB ─────────────────────────────────────────────── */

        /* ── PR-CABFORGE-TOOLTIPS — jd-help popover polish ───────────────── */
        body[data-ui-version="cabforge"] .jd-help {
            color: var(--acc);
            border-color: color-mix(in srgb, var(--acc) 45%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 8%, transparent);
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        border-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .jd-help:hover {
            background: color-mix(in srgb, var(--acc) 22%, transparent);
            border-color: var(--acc);
            color: var(--acc);
        }
        /* Cabforge popover — themed surface, refined depth, accent-tinted
           border with inner highlight. Overrides hardcoded #111 + 0.5
           shadow. */
        body[data-ui-version="cabforge"] .jd-help:hover::after {
            background: color-mix(in srgb, var(--pn) 96%, transparent);
            color: var(--txt);
            backdrop-filter: blur(12px) saturate(140%);
            -webkit-backdrop-filter: blur(12px) saturate(140%);
            border: 1px solid color-mix(in srgb, var(--acc) 28%, var(--bdr));
            border-radius: 10px;
            padding: 8px 12px;
            font-size: 12px;
            line-height: 1.5;
            box-shadow:
                0 12px 32px rgba(0,0,0,0.45),
                inset 0 1px 0 color-mix(in srgb, var(--acc) 18%, transparent);
            min-width: 220px;
            max-width: 340px;
        }
        body[data-ui-version="cabforge"] .jd-help:hover::before {
            border-top-color: color-mix(in srgb, var(--pn) 96%, transparent);
        }
        /* ── /PR-CABFORGE-TOOLTIPS ────────────────────────────────────────── */

        /* ── PR-CABFORGE-EMPTY — Empty state polish ─────────────────────── */
        body[data-ui-version="cabforge"] .empty-state {
            padding: 64px 24px;
            color: var(--dim);
        }
        body[data-ui-version="cabforge"] .empty-state .ei {
            font-size: 32px;
            opacity: 0.7;
            margin-bottom: 16px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 72px;
            height: 72px;
            border-radius: 18px;
            background: color-mix(in srgb, var(--acc) 10%, var(--pn));
            border: 1px solid color-mix(in srgb, var(--acc) 22%, var(--bdr));
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] .empty-state .et {
            color: var(--txt);
            font-size: 17px;
            font-weight: 600;
            letter-spacing: -0.01em;
            margin-bottom: 6px;
        }
        body[data-ui-version="cabforge"] .empty-state .es {
            color: var(--dim);
            font-size: 13px;
            line-height: 1.55;
            max-width: 360px;
            margin: 0 auto 18px;
        }
        /* ── /PR-CABFORGE-EMPTY ───────────────────────────────────────────── */

        /* ── PR-CABFORGE-MSG — validation message polish ─────────────────── */
        body[data-ui-version="cabforge"] .msg {
            border-radius: 10px;
            font-weight: 500;
            line-height: 1.5;
            padding: 12px 14px;
        }
        body[data-ui-version="cabforge"] .msg-ok {
            background: color-mix(in srgb, var(--ok) 12%, transparent);
            border: 1px solid color-mix(in srgb, var(--ok) 35%, var(--bdr));
            color: var(--ok);
        }
        body[data-ui-version="cabforge"] .msg-warn {
            background: color-mix(in srgb, var(--warn) 12%, transparent);
            border: 1px solid color-mix(in srgb, var(--warn) 35%, var(--bdr));
            color: var(--warn);
        }
        body[data-ui-version="cabforge"] .msg-err {
            background: color-mix(in srgb, var(--no) 12%, transparent);
            border: 1px solid color-mix(in srgb, var(--no) 35%, var(--bdr));
            color: var(--no);
        }
        /* Banner-style messages (used at the top of pages, e.g.
           print-warnings-banner) get a slightly bolder presentation. */
        body[data-ui-version="cabforge"] .print-warnings-banner,
        body[data-ui-version="cabforge"] .print-blocked-banner {
            border-radius: 12px;
            font-weight: 600;
            padding: 14px 18px;
        }
        /* ── /PR-CABFORGE-MSG ─────────────────────────────────────────────── */

        /* ── PR-UI-CLEANUP-THEME (2026-06-30) — Theme picker: mini-window preview cards ──
           Operator: "make the themes look nicer to select." Each card is a small
           app-window mockup (titlebar + accent row + surface row + ok/warn/no
           chips) painted with the theme's REAL tokens (read at render time, see
           app-core.js _themeSwatches) so the preview is always accurate. Replaces
           the old flat 4-bar `.theme-picker-card` with the stale hardcoded hex. */
        #settings-theme-picker, #home-theme-picker {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(178px, 1fr));
            gap: 12px;
        }
        .theme-card {
            border: 1.5px solid var(--bdr);
            border-radius: 12px;
            background: var(--pn);
            padding: 12px;
            cursor: pointer;
            outline: none;
            transition: transform .16s cubic-bezier(.22,1,.36,1),
                        box-shadow .16s cubic-bezier(.22,1,.36,1),
                        border-color .16s cubic-bezier(.22,1,.36,1);
        }
        .theme-card:hover, .theme-card:focus-visible {
            transform: translateY(-2px);
            border-color: color-mix(in srgb, var(--acc) 55%, var(--bdr));
            box-shadow: 0 8px 22px color-mix(in srgb, var(--acc) 16%, transparent);
        }
        .theme-card.active {
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 30%, transparent),
                        0 8px 24px color-mix(in srgb, var(--acc) 18%, transparent);
        }
        /* mini "app window" preview — bg/border/colors are inline (real tokens) */
        .theme-card__preview {
            border: 1px solid var(--bdr);
            border-radius: 8px;
            padding: 9px;
            display: flex;
            flex-direction: column;
            gap: 6px;
            margin-bottom: 10px;
            box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
        }
        .theme-card__preview .tc-titlebar { height: 7px; border-radius: 3px; opacity: .9; }
        .theme-card__preview .tc-row { height: 11px; border-radius: 3px; border: 1px solid transparent; }
        .theme-card__preview .tc-row--accent { width: 58%; }
        .theme-card__preview .tc-chips { display: flex; gap: 5px; margin-top: 1px; }
        .theme-card__preview .tc-chip { width: 11px; height: 11px; border-radius: 50%; box-shadow: 0 0 0 1px rgba(0,0,0,.18); }
        .theme-card__meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
        .theme-card__name { color: var(--txt); font-weight: 600; font-size: 13px; }
        .theme-card__active { color: var(--acc); font-size: 11px; font-weight: 600; }
        .theme-card__desc { color: var(--dim); font-size: 11px; line-height: 1.4; flex-basis: 100%; }
        @media (prefers-reduced-motion: reduce) {
            .theme-card { transition: none; }
            .theme-card:hover, .theme-card:focus-visible { transform: none; }
        }
        /* ── /PR-UI-CLEANUP-THEME ──────────────────────────────────────────── */

        /* ── PR-CABFORGE-RAIL — Hub right rail polish ───────────────────── */
        body[data-ui-version="cabforge"] .hub-rail-section {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 12px;
            padding: 16px;
            margin-bottom: 12px;
        }
        body[data-ui-version="cabforge"] .hub-rail-label {
            display: block;
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.1em;
            text-transform: uppercase;
            color: var(--dim);
            margin-bottom: 10px;
        }
        body[data-ui-version="cabforge"] .hub-rail-link {
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 8px 10px;
            border-radius: 8px;
            color: var(--txt);
            font-size: 13px;
            font-weight: 500;
            text-decoration: none;
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .hub-rail-link svg {
            width: 16px;
            height: 16px;
            flex-shrink: 0;
            color: var(--dim);
            transition: color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .hub-rail-link:hover {
            background: color-mix(in srgb, var(--acc) 10%, transparent);
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] .hub-rail-link:hover svg {
            color: var(--acc);
        }
        /* Units toggle — pill button group */
        body[data-ui-version="cabforge"] .hub-rail-units {
            display: inline-flex;
            gap: 0;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            padding: 3px;
        }
        body[data-ui-version="cabforge"] .hub-rail-units button {
            border-radius: 7px;
            padding: 6px 14px;
            font-size: 12px;
            font-weight: 600;
            background: transparent;
            color: var(--dim);
            border: none;
            cursor: pointer;
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .hub-rail-units button:hover {
            color: var(--txt);
        }
        body[data-ui-version="cabforge"] .hub-rail-units button[data-active="true"] {
            background: var(--pn);
            color: var(--acc);
            box-shadow: 0 1px 3px rgba(0,0,0,0.18),
                        inset 0 0 0 1px color-mix(in srgb, var(--acc) 30%, var(--bdr));
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .hub-rail-link,
            body[data-ui-version="cabforge"] .hub-rail-link svg,
            body[data-ui-version="cabforge"] .hub-rail-units button {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-RAIL ────────────────────────────────────────────── */

        /* ── PR-CABFORGE-PALETTE — Command palette polish ───────────────── */
        body[data-ui-version="cabforge"] .gs-modal {
            backdrop-filter: blur(20px) saturate(140%);
            -webkit-backdrop-filter: blur(20px) saturate(140%);
            background: rgba(0,0,0,0.55);
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-panel {
            width: 640px;
            border-radius: 16px;
            background: color-mix(in srgb, var(--sf) 94%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 18%, var(--bdr));
            backdrop-filter: blur(20px) saturate(140%);
            -webkit-backdrop-filter: blur(20px) saturate(140%);
            box-shadow:
                0 32px 80px rgba(0,0,0,0.55),
                inset 0 1px 0 color-mix(in srgb, var(--acc) 16%, transparent);
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-input {
            font-size: 17px;
            font-weight: 500;
            padding: 20px 24px;
            background: transparent;
            letter-spacing: -0.01em;
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-results {
            padding: 6px;
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-result {
            padding: 10px 14px;
            border-radius: 10px;
            transition: background 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-result:hover,
        body[data-ui-version="cabforge"] .gs-modal .gs-result.sel {
            background: color-mix(in srgb, var(--acc) 14%, transparent);
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-result .gs-icon {
            border-radius: 8px;
            background: color-mix(in srgb, var(--acc) 12%, var(--pn));
            border: 1px solid color-mix(in srgb, var(--acc) 22%, var(--bdr));
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-result .gs-text .gs-title {
            color: var(--txt);
            font-weight: 600;
            font-size: 14px;
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-result .gs-text .gs-sub {
            font-size: 12px;
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-foot {
            background: color-mix(in srgb, var(--pn) 50%, transparent);
            padding: 12px 18px;
        }
        body[data-ui-version="cabforge"] .gs-modal .gs-foot .kbd {
            background: var(--inp);
            color: var(--txt);
            border-radius: 6px;
            padding: 3px 7px;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10px;
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .gs-modal .gs-result {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-PALETTE ─────────────────────────────────────────── */

        /* ── PR-CABFORGE-BUNDLE — Door Studio wizard step-bar polish ───── */
        body[data-ui-version="cabforge"] .ds-bundle-bar {
            background: color-mix(in srgb, var(--sf) 92%, var(--bg));
            backdrop-filter: saturate(140%) blur(8px);
            -webkit-backdrop-filter: saturate(140%) blur(8px);
        }
        body[data-ui-version="cabforge"] .ds-bundle-bar::before {
            background: linear-gradient(90deg,
                var(--bdr) 0%,
                color-mix(in srgb, var(--acc) 25%, var(--bdr)) 50%,
                var(--bdr) 100%);
            height: 2px;
            border-radius: 1px;
        }
        body[data-ui-version="cabforge"] .ds-bundle-bar-btn {
            transition: color 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        background 160ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .ds-bundle-bar-btn:hover:not([aria-disabled="true"]):not([aria-current="step"]) {
            color: var(--txt);
        }
        body[data-ui-version="cabforge"] .ds-bundle-bar-btn[aria-current="step"] {
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] .ds-bundle-step-num {
            border-radius: 50%;
            transition: background 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 160ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .ds-bundle-bar-btn[aria-current="step"] .ds-bundle-step-num {
            background: linear-gradient(135deg, var(--acc) 0%, var(--acc2) 100%);
            border-color: var(--acc);
            color: var(--acc-ink);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 22%, transparent);
        }
        body[data-ui-version="cabforge"] .ds-bundle-bar-btn[data-complete="true"] .ds-bundle-step-num {
            background: color-mix(in srgb, var(--acc) 14%, transparent);
            border-color: var(--acc);
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] .ds-bundle-bar-btn[data-skipped="true"] {
            opacity: 0.4;
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .ds-bundle-bar-btn,
            body[data-ui-version="cabforge"] .ds-bundle-step-num {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-BUNDLE ──────────────────────────────────────────── */

        /* ── PR-CABFORGE-VGATE — validation gate polish ─────────────────── */
        body[data-ui-version="cabforge"] .vgate-panel {
            border: 1px solid color-mix(in srgb, var(--no) 50%, var(--bdr));
            border-left: 4px solid var(--no);
            border-radius: 12px;
            padding: 16px 20px;
            background: color-mix(in srgb, var(--no) 6%, var(--pn));
            box-shadow:
                0 12px 32px rgba(0,0,0,0.35),
                inset 0 1px 0 color-mix(in srgb, var(--no) 18%, transparent);
        }
        body[data-ui-version="cabforge"] .vgate-panel.vgate-soft {
            border-color: color-mix(in srgb, var(--warn) 50%, var(--bdr));
            border-left-color: var(--warn);
            background: color-mix(in srgb, var(--warn) 6%, var(--pn));
            box-shadow:
                0 12px 32px rgba(0,0,0,0.35),
                inset 0 1px 0 color-mix(in srgb, var(--warn) 18%, transparent);
        }
        body[data-ui-version="cabforge"] .vgate-modal .vgate-panel {
            border-radius: 14px;
            width: 600px;
        }
        /* ── /PR-CABFORGE-VGATE ───────────────────────────────────────────── */

        /* ── PR-CABFORGE-MISC — order table + miscellaneous polish ──────── */
        body[data-ui-version="cabforge"] .order-table {
            border-collapse: separate;
            border-spacing: 0;
            font-variant-numeric: tabular-nums;
        }
        body[data-ui-version="cabforge"] .order-table thead th {
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--dim);
            background: color-mix(in srgb, var(--pn) 95%, var(--acc));
            border-bottom: 1px solid var(--bdr);
        }
        body[data-ui-version="cabforge"] .order-table tbody tr {
            transition: background 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .order-table tbody tr:hover {
            background: color-mix(in srgb, var(--acc) 4%, transparent);
        }
        body[data-ui-version="cabforge"] .order-table input,
        body[data-ui-version="cabforge"] .order-table select {
            border-radius: 6px;
            border: 1px solid var(--bdr);
            background: var(--inp);
            padding: 6px 8px;
            font-variant-numeric: tabular-nums;
        }
        body[data-ui-version="cabforge"] .order-table input:focus,
        body[data-ui-version="cabforge"] .order-table select:focus {
            border-color: var(--acc);
            box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc) 20%, transparent);
            outline: none;
        }

        /* Inspector labels (used in cabinet inspector and standards panels) */
        body[data-ui-version="cabforge"] .insp-label {
            font-size: 11px;
            font-weight: 600;
            letter-spacing: 0.04em;
            color: var(--dim);
        }

        /* Hub jobs add row (the "+ Add" trigger) — refined ghost */
        body[data-ui-version="cabforge"] .hub-jobs-add-row {
            border: 1px dashed var(--bdr);
            border-radius: 10px;
            color: var(--dim);
            transition: border-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        background 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .hub-jobs-add-row:hover {
            border-color: var(--acc);
            background: color-mix(in srgb, var(--acc) 8%, transparent);
            color: var(--acc);
        }

        /* New-order CTA (Door studio "New Order" button) */
        body[data-ui-version="cabforge"] .new-order-cta {
            border-radius: 10px;
            font-weight: 600;
            background: linear-gradient(135deg,
                var(--acc) 0%,
                color-mix(in srgb, var(--acc) 80%, var(--acc2)) 100%);
            color: var(--acc-ink);
            box-shadow: 0 4px 14px color-mix(in srgb, var(--acc) 28%, transparent);
            transition: filter 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 80ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .new-order-cta:hover {
            filter: brightness(1.08);
            box-shadow: 0 8px 22px color-mix(in srgb, var(--acc) 40%, transparent);
        }
        body[data-ui-version="cabforge"] .new-order-cta:active {
            transform: scale(0.98);
        }

        /* AWS-2 badge (used in topbar showing standards mode) */
        body[data-ui-version="cabforge"] .aws-badge {
            background: color-mix(in srgb, var(--ok) 16%, transparent);
            border: 1px solid color-mix(in srgb, var(--ok) 35%, var(--bdr));
            color: var(--ok);
            border-radius: 999px;
            font-weight: 700;
            letter-spacing: 0.06em;
            text-transform: uppercase;
        }

        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .order-table tbody tr,
            body[data-ui-version="cabforge"] .hub-jobs-add-row,
            body[data-ui-version="cabforge"] .new-order-cta {
                transition: none;
            }
            body[data-ui-version="cabforge"] .new-order-cta:active {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-MISC ────────────────────────────────────────────── */

        /* ── PR-CABFORGE-ADMIN-REPORTS — admin Shop Reports KPI cards ───── */
        body[data-ui-version="cabforge"] .rep-kpi-card {
            border-radius: 12px !important;
            padding: 20px !important;
            transition: border-color 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 180ms cubic-bezier(0.22, 1, 0.36, 1) !important;
        }
        body[data-ui-version="cabforge"] .rep-kpi-card:hover {
            border-color: color-mix(in srgb, var(--acc) 40%, var(--bdr)) !important;
            box-shadow: 0 4px 14px color-mix(in srgb, var(--acc) 12%, transparent) !important;
            transform: translateY(-1px);
        }
        body[data-ui-version="cabforge"] .rep-kpi-card .rep-kpi-value {
            font-size: 32px !important;
            font-weight: 700 !important;
            letter-spacing: -0.02em;
        }
        body[data-ui-version="cabforge"] .rep-kpi-card > div:first-child {
            font-size: 11px !important;
            letter-spacing: 0.08em !important;
            font-weight: 700 !important;
            color: var(--dim) !important;
            margin-bottom: 8px !important;
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .rep-kpi-card {
                transition: none !important;
            }
            body[data-ui-version="cabforge"] .rep-kpi-card:hover {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-ADMIN-REPORTS ──────────────────────────────────── */

        /* ── PR-CABFORGE-HUB-TABS — Standards / Cutlists / Projects / Customers ── */
        /* Generic tab content polish — applies to every .tc inside #pg-hub */
        body[data-ui-version="cabforge"] #pg-hub .tc h2 {
            font-size: 22px;
            font-weight: 700;
            letter-spacing: -0.01em;
            color: var(--txt);
            margin-bottom: 8px;
        }
        body[data-ui-version="cabforge"] #pg-hub .tc h3 {
            font-size: 17px;
            font-weight: 600;
            letter-spacing: -0.005em;
            color: var(--txt);
        }
        /* Standards header bar */
        body[data-ui-version="cabforge"] .std-header {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 12px;
            padding: 16px 20px;
            margin-bottom: 16px;
        }
        body[data-ui-version="cabforge"] .std-subtitle {
            color: var(--dim);
            font-size: 13px;
            line-height: 1.5;
            max-width: 70ch;
        }
        body[data-ui-version="cabforge"] .std-save-btn {
            border-radius: 10px;
        }
        body[data-ui-version="cabforge"] .std-status-msg {
            color: var(--dim);
            font-size: 12px;
            font-weight: 500;
        }
        /* Cutlist viewer (.cutlist-out monospace text) */
        body[data-ui-version="cabforge"] .cutlist-out {
            font-family: 'JetBrains Mono', 'SF Mono', 'Consolas', ui-monospace, monospace !important;
            font-size: 12px !important;
            line-height: 1.55 !important;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            padding: 14px 16px;
        }
        /* Cutlist sub-headers (when JS injects section dividers) */
        body[data-ui-version="cabforge"] .cutlist-out h4 {
            color: var(--acc);
            font-family: var(--ff-ui, inherit);
            font-size: 13px;
            font-weight: 700;
            letter-spacing: 0.04em;
            text-transform: uppercase;
            margin: 12px 0 8px 0;
        }
        /* Stale cutlist banner */
        body[data-ui-version="cabforge"] .cutlist-stale {
            background: color-mix(in srgb, var(--warn) 12%, transparent);
            border: 1px solid color-mix(in srgb, var(--warn) 35%, var(--bdr));
            border-left: 4px solid var(--warn);
            border-radius: 10px;
            padding: 12px 16px;
            color: var(--warn);
            font-weight: 600;
        }
        /* Project + customer list rows (rendered by JS, typically with .pn class) */
        body[data-ui-version="cabforge"] #h-proj .pn,
        body[data-ui-version="cabforge"] #h-cust .pn {
            border-radius: 12px;
            transition: border-color 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 180ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] #h-proj .pn:hover,
        body[data-ui-version="cabforge"] #h-cust .pn:hover {
            border-color: color-mix(in srgb, var(--acc) 35%, var(--bdr));
            box-shadow: 0 3px 12px color-mix(in srgb, var(--acc) 10%, transparent);
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] #h-proj .pn,
            body[data-ui-version="cabforge"] #h-cust .pn {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-HUB-TABS ───────────────────────────────────────── */

        /* ── PR-CABFORGE-SETTINGS — settings drawer content polish ───────
           Strictly scoped to #settings-panel so it can't leak elsewhere.
           Pure CSS — no JS changes, radio inputs untouched. */
        body[data-ui-version="cabforge"] #settings-panel h3 {
            font-size: 14px;
            font-weight: 700;
            letter-spacing: 0.04em;
            text-transform: uppercase;
            color: var(--dim);
            margin-top: 28px;
            margin-bottom: 10px;
            padding-bottom: 8px;
            border-bottom: 1px solid var(--bdr);
        }
        body[data-ui-version="cabforge"] #settings-panel h3:first-of-type {
            margin-top: 16px;
        }
        body[data-ui-version="cabforge"] #settings-panel p {
            color: var(--dim);
            font-size: 12px;
            line-height: 1.55;
            max-width: 60ch;
        }
        body[data-ui-version="cabforge"] #settings-panel .dt-quick-btn {
            border-radius: 10px;
            font-weight: 600;
            transition: border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        background 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 80ms cubic-bezier(0.22, 1, 0.36, 1),
                        color 160ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] #settings-panel .dt-quick-btn:hover {
            background: color-mix(in srgb, var(--acc) 8%, var(--inp));
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] #settings-panel .dt-quick-btn:active {
            transform: scale(0.98);
        }
        body[data-ui-version="cabforge"] #settings-panel .dt-grid {
            gap: 12px;
        }
        body[data-ui-version="cabforge"] #settings-panel #settings-unit-pref label {
            padding: 8px 12px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            transition: border-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
                        background 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] #settings-panel #settings-unit-pref label:hover {
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 6%, var(--inp));
        }
        body[data-ui-version="cabforge"] #settings-panel #set-profile-msg {
            font-weight: 500;
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] #settings-panel .dt-quick-btn,
            body[data-ui-version="cabforge"] #settings-panel #settings-unit-pref label {
                transition: none;
            }
            body[data-ui-version="cabforge"] #settings-panel .dt-quick-btn:active {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-SETTINGS ────────────────────────────────────────── */

        /* ── PR-CABFORGE-STD — Shop Standards section cards ──────────────
           These classes have no base CSS rules — purely additive cabforge
           styling for the AWI rules browser. */
        body[data-ui-version="cabforge"] #shop-standards-body .std-section {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 12px;
            padding: 18px 20px;
            margin-bottom: 12px;
            transition: border-color 180ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] #shop-standards-body .std-section:hover {
            border-color: color-mix(in srgb, var(--acc) 30%, var(--bdr));
        }
        body[data-ui-version="cabforge"] #shop-standards-body .std-section-header {
            padding-bottom: 10px;
            border-bottom: 1px solid var(--bdr);
            margin-bottom: 12px;
        }
        body[data-ui-version="cabforge"] #shop-standards-body .std-section-icon {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 32px;
            height: 32px;
            border-radius: 8px;
            background: color-mix(in srgb, var(--acc) 14%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 28%, var(--bdr));
            color: var(--acc);
            font-size: 16px;
            flex-shrink: 0;
        }
        body[data-ui-version="cabforge"] #shop-standards-body .std-section-title {
            font-size: 16px;
            font-weight: 600;
            letter-spacing: -0.005em;
            color: var(--txt);
            margin: 0 0 4px 0;
        }
        body[data-ui-version="cabforge"] #shop-standards-body .std-section[data-collapsed="1"] {
            padding-bottom: 0;
        }
        body[data-ui-version="cabforge"] #shop-standards-body .std-section[data-collapsed="1"] .std-section-header {
            border-bottom: none;
            padding-bottom: 18px;
            margin-bottom: 0;
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] #shop-standards-body .std-section {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-STD ─────────────────────────────────────────────── */

        /* ── PR-CABFORGE-STATUS — status pills + shop-intel ─────────────── */
        /* Status pills (project status across hub + cab + door studios).
           Existing rules use var(--status-* fallback) — cabforge override
           uses color-mix() for richer tinted bg + 1px border for definition. */
        body[data-ui-version="cabforge"] .status-draft,
        body[data-ui-version="cabforge"] .status-design,
        body[data-ui-version="cabforge"] .status-nesting,
        body[data-ui-version="cabforge"] .status-completed,
        body[data-ui-version="cabforge"] .status-cancelled,
        body[data-ui-version="cabforge"] .hub-job-status-pill {
            border-radius: 999px;
            font-weight: 600;
            font-size: 11px;
            letter-spacing: 0.04em;
            padding: 3px 9px;
            text-transform: uppercase;
        }
        body[data-ui-version="cabforge"] .status-draft {
            background: color-mix(in srgb, var(--dim) 18%, transparent);
            border: 1px solid color-mix(in srgb, var(--dim) 35%, var(--bdr));
            color: var(--dim);
        }
        body[data-ui-version="cabforge"] .status-design {
            background: color-mix(in srgb, var(--acc) 14%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 35%, var(--bdr));
            color: var(--acc);
        }
        body[data-ui-version="cabforge"] .status-nesting {
            background: color-mix(in srgb, var(--warn) 14%, transparent);
            border: 1px solid color-mix(in srgb, var(--warn) 35%, var(--bdr));
            color: var(--warn);
        }
        body[data-ui-version="cabforge"] .status-completed {
            background: color-mix(in srgb, var(--ok) 16%, transparent);
            border: 1px solid color-mix(in srgb, var(--ok) 35%, var(--bdr));
            color: var(--ok);
        }
        body[data-ui-version="cabforge"] .status-cancelled {
            background: color-mix(in srgb, var(--no) 14%, transparent);
            border: 1px solid color-mix(in srgb, var(--no) 35%, var(--bdr));
            color: var(--no);
        }
        /* PR-CLEAN-2 / WIDGET-PURGE (2026-05-31): cabforge .shop-intel
           overrides deleted (parent rule already gone). Cabforge .widget-empty
           KEPT — filterGlobalSearch still uses .widget-empty. */
        body[data-ui-version="cabforge"] .widget-empty {
            font-style: normal;
            font-size: 13px;
            color: var(--dim);
            padding: 16px 0;
            text-align: center;
        }
        /* ── /PR-CABFORGE-STATUS ──────────────────────────────────────────── */

        /* ── PR-CABFORGE-BROW — button row + small variants ─────────────── */
        body[data-ui-version="cabforge"] .brow {
            gap: 8px;
            margin-top: 12px;
        }
        body[data-ui-version="cabforge"] .bs {
            border-radius: 7px;
            padding: 6px 12px;
            font-size: 11px;
            font-weight: 600;
            letter-spacing: 0.02em;
        }
        body[data-ui-version="cabforge"] .bs:focus-visible {
            outline: 2px solid var(--acc);
            outline-offset: 2px;
        }
        /* The .ba.bs combo needs the gradient + shadow to scale down
           gracefully when small. */
        body[data-ui-version="cabforge"] .ba.bs {
            box-shadow: 0 2px 6px color-mix(in srgb, var(--acc) 18%, transparent);
        }
        body[data-ui-version="cabforge"] .ba.bs:hover:not(:disabled) {
            box-shadow: 0 3px 10px color-mix(in srgb, var(--acc) 30%, transparent);
        }
        /* ── /PR-CABFORGE-BROW ────────────────────────────────────────────── */

        /* ── PR-CABFORGE-BULK — bulk-action bar polish ─────────────────── */
        body[data-ui-version="cabforge"] .bulk-bar {
            background: color-mix(in srgb, var(--acc) 12%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 35%, var(--bdr));
            border-radius: 10px;
            padding: 10px 14px;
            color: var(--txt);
            font-weight: 500;
            backdrop-filter: blur(6px);
            -webkit-backdrop-filter: blur(6px);
        }
        body[data-ui-version="cabforge"] .bulk-bar .bulk-count {
            color: var(--acc);
            font-weight: 700;
            font-variant-numeric: tabular-nums;
        }
        body[data-ui-version="cabforge"] .bulk-bar button {
            font-size: 11px;
            font-weight: 600;
        }
        /* ── /PR-CABFORGE-BULK ────────────────────────────────────────────── */

        /* PR-CLEAN-2 / WIDGET-PURGE (2026-05-31): cabforge widget-polish
           overrides (.widget, .widget-hdr, .widget-body, .add-widget-card)
           deleted — parent rules retired with WIDGET_DEFS. */

        /* ── PR-CABFORGE-SEARCH — global search field polish ────────────── */
        body[data-ui-version="cabforge"] .global-search {
            border-radius: 10px;
            background: color-mix(in srgb, var(--acc) 5%, var(--inp));
            border: 1px solid color-mix(in srgb, var(--acc) 18%, var(--bdr));
        }
        body[data-ui-version="cabforge"] .global-search:focus-within {
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 20%, transparent);
            background: var(--inp);
        }
        body[data-ui-version="cabforge"] .global-search input::placeholder {
            color: color-mix(in srgb, var(--dim) 75%, var(--acc));
        }
        body[data-ui-version="cabforge"] .global-search .kbd {
            background: var(--bg);
            border: 1px solid color-mix(in srgb, var(--acc) 25%, var(--bdr));
            color: var(--txt);
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10px;
            font-weight: 500;
            border-radius: 5px;
            padding: 2px 6px;
        }
        /* ── /PR-CABFORGE-SEARCH ──────────────────────────────────────────── */

        /* ── PR-CABFORGE-USER-CHIP — topbar user chip + admin badge ─────── */
        body[data-ui-version="cabforge"] .topbar-user-name {
            font-weight: 600;
            letter-spacing: -0.005em;
        }
        body[data-ui-version="cabforge"] .topbar-user-role {
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--dim);
        }
        body[data-ui-version="cabforge"] .admin-only-badge {
            background: color-mix(in srgb, var(--acc) 18%, transparent);
            border: 1px solid color-mix(in srgb, var(--acc) 38%, var(--bdr));
            color: var(--acc);
            font-weight: 700;
            letter-spacing: 0.06em;
            border-radius: 999px;
        }
        /* AWS-2 badge (compliance mode indicator in topbar) — semantic
           green pill for the active-standards state. */
        body[data-ui-version="cabforge"] #aws-badge,
        body[data-ui-version="cabforge"] .aws-active-pill {
            border-radius: 999px;
            font-weight: 700;
            letter-spacing: 0.06em;
        }
        /* ── /PR-CABFORGE-USER-CHIP ───────────────────────────────────────── */

        /* PR-CLEAN-2 / WIDGET-PURGE (2026-05-31): cabforge .dash-bar +
           .widget-grid overrides deleted — parent rules retired. */

        /* ── PR-CABFORGE-STUDIO-CARD — studio entry cards polish ────────── */
        body[data-ui-version="cabforge"] .studio-card {
            border-radius: 14px;
            padding: 28px 26px;
            transition: border-color 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        background 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 180ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 180ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .studio-card::before {
            height: 4px;
            background: linear-gradient(90deg,
                var(--studio-color, var(--acc)) 0%,
                color-mix(in srgb, var(--studio-color, var(--acc)) 70%, var(--acc2, var(--acc))) 100%);
            opacity: 1;
            border-radius: 14px 14px 0 0;
        }
        body[data-ui-version="cabforge"] .studio-card:hover {
            border-color: var(--studio-color, var(--acc));
            background: color-mix(in srgb, var(--studio-color, var(--acc)) 6%, var(--pn));
            box-shadow: 0 12px 32px color-mix(in srgb, var(--studio-color, var(--acc)) 22%, transparent);
            transform: translateY(-2px);
        }
        body[data-ui-version="cabforge"] .studio-card h4 {
            font-size: 19px;
            font-weight: 700;
            letter-spacing: -0.01em;
            color: var(--txt);
            margin-bottom: 6px;
        }
        body[data-ui-version="cabforge"] .studio-card .studio-img {
            filter: drop-shadow(0 4px 12px color-mix(in srgb, var(--studio-color, var(--acc)) 30%, transparent));
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .studio-card {
                transition: none;
            }
            body[data-ui-version="cabforge"] .studio-card:hover {
                transform: none;
            }
        }
        /* ── /PR-CABFORGE-STUDIO-CARD ────────────────────────────────────── */

        /* ── PR-CABFORGE-CAB-LIB — room editor library items polish ─────── */
        body[data-ui-version="cabforge"] .cab-lib-section-header {
            /* PR-CAB-LIB-COMPACT (2026-07-29): was var(--dim) 10px — too faint to
               read ("BASE · 11"). Bumped to max-contrast --txt, bigger + heavier. */
            font-size: 12px;
            font-weight: 800;
            letter-spacing: 0.06em;
            color: var(--txt);
            background: color-mix(in srgb, var(--sf) 92%, var(--bg));
            border-bottom: 1px solid var(--bdr);
        }
        body[data-ui-version="cabforge"] .cab-lib-item {
            border-radius: 8px;
            transition: border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        background 160ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 80ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 160ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .cab-lib-item:hover {
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 8%, var(--pn));
            box-shadow: 0 3px 10px color-mix(in srgb, var(--acc) 14%, transparent);
        }
        body[data-ui-version="cabforge"] .cab-lib-item .icn {
            background: color-mix(in srgb, var(--acc) 8%, var(--inp));
            border: 1px solid color-mix(in srgb, var(--acc) 16%, var(--bdr));
            border-radius: 6px;
        }
        body[data-ui-version="cabforge"] .cab-lib-item:hover .icn {
            background: color-mix(in srgb, var(--acc) 14%, var(--inp));
            border-color: color-mix(in srgb, var(--acc) 30%, var(--bdr));
        }
        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .cab-lib-item,
            body[data-ui-version="cabforge"] .cab-lib-item .icn {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-CAB-LIB ─────────────────────────────────────────── */

        /* ── PR-CABFORGE-GLOBAL — code/pre/kbd/hr/scrollbar polish ──────── */
        /* Code + pre — JetBrains Mono + accent-tinted bg */
        body[data-ui-version="cabforge"] code {
            font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', 'Consolas', monospace;
            font-size: 0.92em;
            padding: 1px 6px;
            background: color-mix(in srgb, var(--acc) 10%, var(--inp));
            border: 1px solid color-mix(in srgb, var(--acc) 16%, var(--bdr));
            border-radius: 4px;
            color: var(--txt);
            font-variant-numeric: tabular-nums;
        }
        body[data-ui-version="cabforge"] pre {
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 8px;
            padding: 12px 14px;
            font-size: 12px;
            line-height: 1.55;
            font-variant-numeric: tabular-nums;
        }
        body[data-ui-version="cabforge"] pre code {
            background: none;
            border: none;
            padding: 0;
            font-size: 1em;
        }
        /* kbd — keyboard shortcut hints */
        body[data-ui-version="cabforge"] kbd {
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10px;
            font-weight: 600;
            padding: 2px 7px;
            background: var(--bg);
            border: 1px solid color-mix(in srgb, var(--acc) 22%, var(--bdr));
            border-bottom-width: 2px;
            border-radius: 5px;
            color: var(--txt);
            letter-spacing: 0.04em;
            box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--acc) 14%, transparent);
        }
        /* hr — subtle accent gradient divider */
        body[data-ui-version="cabforge"] hr {
            border: none;
            height: 1px;
            background: linear-gradient(90deg,
                transparent 0%,
                color-mix(in srgb, var(--acc) 25%, var(--bdr)) 50%,
                transparent 100%);
            margin: 24px 0;
        }
        /* Custom scrollbar (WebKit) — subtle Apple-feel. Firefox uses
           scrollbar-color which is a separate property. */
        body[data-ui-version="cabforge"] ::-webkit-scrollbar {
            width: 12px;
            height: 12px;
        }
        body[data-ui-version="cabforge"] ::-webkit-scrollbar-track {
            background: transparent;
        }
        body[data-ui-version="cabforge"] ::-webkit-scrollbar-thumb {
            background: color-mix(in srgb, var(--dim) 35%, transparent);
            border: 3px solid transparent;
            border-radius: 999px;
            background-clip: padding-box;
            transition: background 140ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] ::-webkit-scrollbar-thumb:hover {
            background: color-mix(in srgb, var(--acc) 50%, var(--dim));
            background-clip: padding-box;
            border: 3px solid transparent;
        }
        body[data-ui-version="cabforge"] ::-webkit-scrollbar-corner {
            background: transparent;
        }
        body[data-ui-version="cabforge"] {
            scrollbar-color: color-mix(in srgb, var(--dim) 35%, transparent) transparent;
            scrollbar-width: thin;
        }
        /* Text selection — themed highlight */
        body[data-ui-version="cabforge"] ::selection {
            background: color-mix(in srgb, var(--acc) 32%, transparent);
            color: var(--txt);
        }
        /* ── /PR-CABFORGE-GLOBAL ──────────────────────────────────────────── */

        /* ── PR-CABFORGE-OVERHAUL-1 — workspace bg + home hero strip ─────
           Structural change, not polish. Inject a brand-presence hero
           ABOVE the dash-bar on the home tab. Subtle gradient on the
           workspace bg. Gated to cabforge mode so legacy themes
           inherit nothing. */

        /* PR-HOME-REDESIGN (2026-06-13): the workspace "radial accent" was
           the blue glow the operator flagged — a 1200x800 brand-accent
           ellipse anchored 200px ABOVE the viewport, bleeding a haze down
           behind the topbar on every page. Replaced with the flat base. */
        body[data-ui-version="cabforge"] #app-workspace {
            background: var(--bg);
        }

        /* PR-THEME-LAYOUT-PARITY (2026-05-18): the CabForge brand
           additions below (home-hero banner, dashboard eyebrow,
           topbar/sidebar/statusbar wordmarks, per-page hero strips,
           admin pill, "Welcome to CabForge" banner, CF logomark)
           previously injected content via ::before / ::after that
           changed the page layout. These were CabForge-only — the
           other 6 themes didn't render them, so themes drifted in
           layout, not just color. Per user direction 2026-05-18:
           "they all should be the same in everyway other then the
           color change". Removed wholesale. KPI tile size bumps +
           OVERHAUL-4 CTA size bumps (next block) kept — they're
           tablet-ergonomic, not brand-specific, and now apply to
           every theme through the un-gated data-ui-version attr.
        */

        /* KPI strip — bigger numbers (tablet ergonomic, kept). */
        body[data-ui-version="cabforge"] .kpi-tile {
            min-height: 112px;
            padding: 18px 20px;
        }
        body[data-ui-version="cabforge"] .kpi-tile-value {
            font-size: 30px !important;
            font-weight: 700 !important;
            letter-spacing: -0.02em;
            line-height: 1.1;
        }

        /* ── PR-CABFORGE-OVERHAUL-4 — bigger primary CTAs ────────────────
           Stop hiding the primary action behind subtle styling. CabForge
           CTAs are bigger, bolder, more confident — shop-floor reality
           (operator wants the gate to "create" clearly visible). */

        /* Hub page primary action (+ New job) — 52px min-height, bigger
           font, larger icon. Already gradient + shadow from PR-CABFORGE-
           HUB; this PR bumps the size and presence. */
        body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action {
            min-height: 52px;
            padding: 0 24px;
            font-size: 15px;
            gap: 10px;
        }
        body[data-ui-version="cabforge"] .hub-page-header .hub-primary-action svg {
            width: 20px;
            height: 20px;
        }

        /* Studio shortcuts — bump to 52px to match the primary */
        body[data-ui-version="cabforge"] .hub-studio-shortcut {
            min-height: 52px;
            padding: 0 22px;
            font-size: 14px;
            gap: 10px;
        }
        body[data-ui-version="cabforge"] .hub-studio-shortcut svg {
            width: 18px;
            height: 18px;
        }

        /* Big primary buttons globally (.ba but NOT .bs small variant) */
        body[data-ui-version="cabforge"] .ba:not(.bs) {
            min-height: 44px;
            padding: 10px 22px;
            font-size: 13px;
        }

        /* Door studio Add Door CTA — already 56px; refine border-radius */
        body[data-ui-version="cabforge"] .add-door-bar .ad-go {
            border-radius: 12px;
        }

        /* Bundle nav Next button (ds-bundle-nav .ba) — bigger */
        body[data-ui-version="cabforge"] .ds-bundle-nav button.ba {
            min-height: 52px;
            min-width: 140px;
            padding: 0 26px;
            font-size: 14px;
            font-weight: 700;
            letter-spacing: 0.02em;
            border-radius: 10px;
        }
        body[data-ui-version="cabforge"] .ds-bundle-nav button.bg {
            min-height: 52px;
            padding: 0 22px;
            font-size: 13px;
            border-radius: 10px;
        }

        /* "+ New" / "+ Add" patterns — boost the icon + spacing */
        body[data-ui-version="cabforge"] button > svg + *,
        body[data-ui-version="cabforge"] button > * + svg {
            /* No-op — placeholder for icon-text spacing if needed */
        }

        /* Sidebar primary item (Hub) gets a slightly bolder treatment */
        body[data-ui-version="cabforge"] #snav-hub {
            font-weight: 600;
        }
        /* ── /PR-CABFORGE-OVERHAUL-4 ──────────────────────────────────────── */

        /* PR-THEME-LAYOUT-PARITY (2026-05-18): the "Welcome to CabForge"
           home hero (140px banner + 64px CF logomark badge) was the most
           visually disruptive theme-specific layout add. Operator
           feedback 2026-05-18: "espically cab fordge color scheme adds
           a big welcome thing on the top". Removed wholesale.
           The legacy "Jobs" dash-bar h1 is now the single visible page
           heading for the home tab on every theme — no longer
           hidden by an overriding cabforge-only rule. */

        /* ── PR-STUDIO-1 (2026-05-15) — Cutlist Studio page ──────────────
           Standalone page (#pg-cutlist-studio). 3-pane grid layout on
           desktop (settings | columns | preview); collapses to stacked
           on tablet portrait. All chrome on CabForge tokens; status
           colors limited to cyan/amber/rose per design language. */
        #pg-cutlist-studio .cs-page {
            display: flex;
            flex-direction: column;
            gap: var(--sp-4);
            padding: var(--sp-4);
            max-width: 1600px;
            margin: 0 auto;
            min-height: 100%;
        }
        #pg-cutlist-studio .cs-page-head {
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
            gap: var(--sp-4);
            padding-bottom: var(--sp-3);
            border-bottom: 1px solid var(--bdr);
            flex-wrap: wrap;
        }
        #pg-cutlist-studio .cs-page-title {
            margin: 0 0 4px 0;
            color: var(--txt);
            font-size: 24px;
            font-weight: 800;
            letter-spacing: 0.01em;
        }
        #pg-cutlist-studio .cs-page-sub {
            margin: 0;
            color: var(--dim);
            font-size: 13px;
            line-height: 1.5;
            max-width: 640px;
        }
        #pg-cutlist-studio .cs-page-head-right {
            display: flex;
            gap: var(--sp-2);
            flex-wrap: wrap;
        }
        #pg-cutlist-studio .cs-page-head-right button {
            min-height: 44px;
        }
        #pg-cutlist-studio .cs-page-head-right button[disabled] {
            opacity: 0.45;
            cursor: not-allowed;
        }

        /* 4-pane grid. Templates list (PR-TMPL-7-UI) | Settings |
           Columns | Preview. Templates pane is narrow (200px) since it
           only holds a click-to-load list + 3-button toolbar. Stacks
           below 1100px. */
        #pg-cutlist-studio .cs-grid {
            display: grid;
            grid-template-columns: 220px 280px 320px 1fr;
            gap: var(--sp-3);
            flex: 1;
            min-height: 0;
        }
        @media (max-width: 1380px) {
            #pg-cutlist-studio .cs-grid {
                grid-template-columns: 200px 260px 280px 1fr;
                gap: var(--sp-2);
            }
        }
        @media (max-width: 1100px) {
            #pg-cutlist-studio .cs-grid {
                grid-template-columns: 1fr;
            }
        }

        /* Templates pane (PR-TMPL-7-UI). Click-to-load list with
           per-row badges (★ = default, Sys = built-in starter). Bottom
           toolbar holds New / Set Default / Delete. */
        /* PR-STUDIO-POLISH (2026-05-15): search filter input above
           the templates list. Plain <input type="search"> with the
           browser's clear-button affordance; JS filters _templateList
           client-side on every keystroke. */
        #pg-cutlist-studio .cs-tmpl-search {
            margin-bottom: var(--sp-2);
        }
        /* PR-STUDIO-AUDIT-FIXUP (2026-05-17, UX P1-2): 36px → 44px
           to clear the shop-floor tap-target floor. The browser's
           native clear button on type=search inherits the input
           height, so 44px gives a usable clear affordance too. */
        #pg-cutlist-studio .cs-tmpl-search input {
            width: 100%;
            min-height: 44px;
            padding: 10px 10px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            color: var(--txt);
            font-size: 12px;
            font-family: inherit;
        }
        #pg-cutlist-studio .cs-tmpl-search input:focus {
            outline: none;
            border-color: var(--acc);
            box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc) 18%, transparent);
        }

        #pg-cutlist-studio .cs-tmpl-list {
            list-style: none;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            gap: 4px;
            flex: 1;
            overflow-y: auto;
            min-height: 0;
        }
        #pg-cutlist-studio .cs-tmpl-row {
            display: flex;
            align-items: center;
            gap: 6px;
            padding: 8px 10px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            min-height: 44px;
            cursor: pointer;
            font-size: 12px;
            color: var(--txt);
            text-align: left;
            width: 100%;
            font-family: inherit;
        }
        #pg-cutlist-studio .cs-tmpl-row:hover {
            background: color-mix(in srgb, var(--acc) 10%, var(--inp));
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
        }
        #pg-cutlist-studio .cs-tmpl-row.cs-tmpl-active {
            background: color-mix(in srgb, var(--acc) 18%, var(--inp));
            border-color: var(--acc);
        }
        #pg-cutlist-studio .cs-tmpl-name {
            flex: 1;
            font-weight: 500;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        #pg-cutlist-studio .cs-tmpl-badge {
            font-size: 9px;
            font-weight: 700;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            padding: 2px 5px;
            border-radius: 3px;
            background: color-mix(in srgb, var(--dim) 20%, transparent);
            color: var(--dim);
            border: 1px solid color-mix(in srgb, var(--dim) 30%, var(--bdr));
        }
        #pg-cutlist-studio .cs-tmpl-badge.cs-tmpl-badge-default {
            background: color-mix(in srgb, var(--ok) 20%, transparent);
            color: var(--ok);
            border-color: color-mix(in srgb, var(--ok) 50%, var(--bdr));
        }
        #pg-cutlist-studio .cs-tmpl-toolbar {
            display: flex;
            gap: 4px;
            padding-top: var(--sp-2);
            border-top: 1px solid var(--bdr);
            flex-wrap: wrap;
        }
        /* PR-TMPL-7-AUDIT-FIXUP (sentinel H-2 + general-purpose P1):
           36px → 44px to clear the shop-floor tap-target floor that
           PR-0C-AUDIT-FIXUP enforced everywhere else. Gloved operators
           on a tablet were missing these toolbar buttons. */
        #pg-cutlist-studio .cs-tmpl-toolbar button {
            min-height: 44px;
            font-size: 11px;
            padding: 4px 8px;
            flex: 1;
            min-width: 60px;
        }
        #pg-cutlist-studio .cs-tmpl-toolbar button[disabled] {
            opacity: 0.4;
            cursor: not-allowed;
        }
        #pg-cutlist-studio .cs-pane {
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-sm);
            padding: var(--sp-3);
            display: flex;
            flex-direction: column;
            gap: var(--sp-2);
            min-height: 0;
        }
        #pg-cutlist-studio .cs-pane-title {
            margin: 0;
            color: var(--txt);
            font-size: 14px;
            font-weight: 700;
            letter-spacing: 0.04em;
            text-transform: uppercase;
        }
        #pg-cutlist-studio .cs-pane-hint {
            margin: 0 0 var(--sp-2) 0;
            color: var(--dim);
            font-size: 11px;
            line-height: 1.5;
        }

        /* Settings pane — form fields */
        #pg-cutlist-studio .cs-field {
            display: flex;
            flex-direction: column;
            gap: 4px;
        }
        #pg-cutlist-studio .cs-field > label {
            color: var(--dim);
            font-size: 11px;
            font-weight: 600;
            letter-spacing: 0.04em;
            text-transform: uppercase;
        }
        #pg-cutlist-studio .cs-field input[type="text"],
        #pg-cutlist-studio .cs-field select {
            width: 100%;
            min-height: 44px;
            padding: 8px 10px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            color: var(--txt);
            font-size: 13px;
            font-family: inherit;
        }
        #pg-cutlist-studio .cs-field input[type="text"]:focus,
        #pg-cutlist-studio .cs-field select:focus {
            outline: none;
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 18%, transparent);
        }
        #pg-cutlist-studio .cs-field-hint {
            margin: 2px 0 0 0;
            color: var(--dim);
            font-size: 10px;
            line-height: 1.4;
        }
        #pg-cutlist-studio .cs-field-hint code {
            background: var(--inp);
            padding: 1px 4px;
            border-radius: 3px;
            font-size: 10px;
        }
        #pg-cutlist-studio .cs-checkbox {
            display: inline-flex;
            align-items: center;
            gap: 8px;
            color: var(--txt) !important;
            font-size: 13px !important;
            font-weight: 500 !important;
            letter-spacing: 0 !important;
            text-transform: none !important;
            cursor: pointer;
            min-height: 44px;
        }
        #pg-cutlist-studio .cs-checkbox input[type="checkbox"] {
            width: 20px;
            height: 20px;
            margin: 0;
            cursor: pointer;
        }

        /* Column designer pane */
        #pg-cutlist-studio .cs-col-list {
            list-style: none;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            gap: 6px;
            flex: 1;
            overflow-y: auto;
            min-height: 0;
        }
        #pg-cutlist-studio .cs-col-row {
            display: flex;
            align-items: center;
            gap: 6px;
            padding: 8px 10px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            min-height: 44px;
        }
        #pg-cutlist-studio .cs-col-row.cs-col-required {
            border-color: color-mix(in srgb, var(--acc) 40%, var(--bdr));
            background: color-mix(in srgb, var(--acc) 6%, var(--inp));
        }
        #pg-cutlist-studio .cs-col-label {
            flex: 1;
            color: var(--txt);
            font-size: 13px;
            font-weight: 500;
        }
        #pg-cutlist-studio .cs-col-required-badge {
            font-size: 9px;
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--acc);
            padding: 2px 6px;
            border: 1px solid color-mix(in srgb, var(--acc) 50%, var(--bdr));
            border-radius: 999px;
            background: color-mix(in srgb, var(--acc) 10%, transparent);
        }
        #pg-cutlist-studio .cs-col-btn {
            min-width: 32px;
            min-height: 32px;
            padding: 4px 6px;
            background: transparent;
            border: 1px solid var(--bdr);
            border-radius: 4px;
            color: var(--dim);
            cursor: pointer;
            font-size: 14px;
            line-height: 1;
        }
        #pg-cutlist-studio .cs-col-btn:hover:not(:disabled) {
            background: var(--bg);
            color: var(--txt);
            border-color: var(--acc);
        }
        #pg-cutlist-studio .cs-col-btn:disabled {
            opacity: 0.3;
            cursor: not-allowed;
        }
        #pg-cutlist-studio .cs-col-btn-remove {
            color: var(--no);
        }
        #pg-cutlist-studio .cs-col-add {
            display: flex;
            gap: 8px;
            padding-top: var(--sp-2);
            border-top: 1px solid var(--bdr);
        }
        #pg-cutlist-studio .cs-col-add select {
            flex: 1;
            min-height: 44px;
            padding: 8px 10px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            color: var(--txt);
            font-size: 13px;
            font-family: inherit;
        }
        #pg-cutlist-studio .cs-col-add button {
            min-height: 44px;
        }

        /* PR-CL-SECTIONS-V1 (2026-05-17) — sections pane styling.
           Same visual language as the columns list, but each row
           is taller because it carries an inline title input and a
           filter dropdown (for Parts Table sections). */
        #pg-cutlist-studio .cs-sections-field {
            display: flex;
            flex-direction: column;
            gap: var(--sp-1);
            margin-top: var(--sp-2);
        }
        #pg-cutlist-studio .cs-sections-label {
            font-size: 11px;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.06em;
            color: var(--dim);
        }
        #pg-cutlist-studio .cs-sections-active-banner {
            display: block;
            margin-top: 4px;
            padding: 6px 8px;
            background: color-mix(in srgb, var(--ok) 8%, transparent);
            border-left: 2px solid var(--ok);
            border-radius: 3px;
            font-size: 11px;
            color: var(--txt);
        }
        #pg-cutlist-studio .cs-section-list {
            list-style: none;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            gap: 6px;
        }
        #pg-cutlist-studio .cs-section-row {
            display: flex;
            flex-direction: column;
            gap: 6px;
            padding: 8px 10px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
        }
        #pg-cutlist-studio .cs-section-row-head {
            display: flex;
            align-items: center;
            gap: 6px;
        }
        #pg-cutlist-studio .cs-section-kind {
            flex: 1;
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            color: var(--acc);
        }
        #pg-cutlist-studio .cs-section-row-body {
            display: flex;
            flex-direction: column;
            gap: 4px;
        }
        #pg-cutlist-studio .cs-section-row-body input[type="text"],
        #pg-cutlist-studio .cs-section-row-body select {
            min-height: 36px;
            padding: 6px 8px;
            background: var(--bg);
            border: 1px solid var(--bdr);
            border-radius: 4px;
            color: var(--txt);
            font-size: 12px;
            font-family: inherit;
        }
        #pg-cutlist-studio .cs-section-btn {
            min-width: 32px;
            min-height: 32px;
            padding: 4px 6px;
            background: transparent;
            border: 1px solid var(--bdr);
            border-radius: 4px;
            color: var(--dim);
            cursor: pointer;
            font-size: 14px;
            line-height: 1;
        }
        #pg-cutlist-studio .cs-section-btn:hover:not(:disabled) {
            background: var(--bg);
            color: var(--txt);
            border-color: var(--acc);
        }
        #pg-cutlist-studio .cs-section-btn:disabled {
            opacity: 0.3;
            cursor: not-allowed;
        }
        #pg-cutlist-studio .cs-section-btn-remove {
            color: var(--no);
        }
        #pg-cutlist-studio .cs-section-add {
            display: flex;
            gap: 8px;
            padding-top: var(--sp-1);
        }
        #pg-cutlist-studio .cs-section-add select {
            flex: 1;
            min-height: 44px;
            padding: 8px 10px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            color: var(--txt);
            font-size: 13px;
            font-family: inherit;
        }
        #pg-cutlist-studio .cs-section-add button {
            min-height: 44px;
        }

        /* Preview pane */
        #pg-cutlist-studio .cs-preview-head {
            display: flex;
            justify-content: space-between;
            align-items: center;
            gap: 8px;
        }
        #pg-cutlist-studio .cs-preview-status {
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            padding: 4px 8px;
            border-radius: 999px;
            background: color-mix(in srgb, var(--ok) 18%, transparent);
            border: 1px solid color-mix(in srgb, var(--ok) 50%, var(--bdr));
            color: var(--ok);
        }
        #pg-cutlist-studio .cs-preview-status.cs-status-updating {
            background: color-mix(in srgb, var(--warn) 18%, transparent);
            border-color: color-mix(in srgb, var(--warn) 50%, var(--bdr));
            color: var(--warn);
        }
        #pg-cutlist-studio .cs-preview-status.cs-status-error {
            background: color-mix(in srgb, var(--no) 18%, transparent);
            border-color: color-mix(in srgb, var(--no) 50%, var(--bdr));
            color: var(--no);
        }
        /* PR-STUDIO-DEMO-JOBS (2026-05-15): job picker + description.
           Sits between the live-preview status row and the toolbar. */
        #pg-cutlist-studio .cs-job-picker {
            display: flex;
            align-items: center;
            gap: 8px;
            margin: var(--sp-2) 0 4px 0;
        }
        #pg-cutlist-studio .cs-job-picker-label {
            color: var(--dim);
            font-size: 11px;
            font-weight: 600;
            letter-spacing: 0.04em;
            text-transform: uppercase;
            white-space: nowrap;
        }
        #pg-cutlist-studio .cs-job-picker select {
            flex: 1;
            min-height: 44px;
            padding: 8px 10px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            color: var(--txt);
            font-size: 13px;
            font-family: inherit;
        }
        #pg-cutlist-studio .cs-job-picker select:focus {
            outline: none;
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 18%, transparent);
        }
        #pg-cutlist-studio .cs-job-desc {
            margin: 0 0 var(--sp-2) 0;
            color: var(--dim);
            font-size: 11px;
            line-height: 1.5;
            font-style: italic;
            min-height: 1.5em;
        }

        #pg-cutlist-studio .cs-preview-toolbar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            gap: 8px;
        }
        /* PR-TMPL-8 (2026-05-15): action group on the right side of
           the preview toolbar. Holds Copy CSV + Print / Save PDF,
           wraps on narrow viewports. */
        #pg-cutlist-studio .cs-preview-toolbar-actions {
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
        }
        /* PR-STUDIO-AUDIT-FIXUP (2026-05-17, UX P0-1): 36px → 44px
           on the preview-toolbar action group AND the outer toolbar
           wrapper. Gloved operators on a 10" tablet were missing
           Copy CSV / Print Demo / Print / Save PDF at 36px. This
           matches the shop-floor floor enforced everywhere else
           (PR-0C-AUDIT-FIXUP + cs-tmpl-toolbar fix at line 9596). */
        #pg-cutlist-studio .cs-preview-toolbar-actions button {
            min-height: 44px;
        }
        #pg-cutlist-studio .cs-preview-toolbar-actions button[disabled] {
            opacity: 0.4;
            cursor: not-allowed;
        }
        /* PR-STUDIO-AUDIT-FIXUP (2026-05-17, UX P1-1): amber DEMO chip
           inside Print Demo button so it cannot be confused with
           Print / Save PDF (real-project, client-deliverable). Amber
           = warn per CabForge 3-status-color rule. */
        #pg-cutlist-studio .cs-demo-chip {
            display: inline-block;
            margin-left: 6px;
            padding: 1px 6px;
            font-size: 9px;
            font-weight: 700;
            letter-spacing: 0.08em;
            border-radius: 3px;
            background: color-mix(in srgb, var(--warn) 22%, transparent);
            color: var(--warn);
            border: 1px solid color-mix(in srgb, var(--warn) 50%, var(--bdr));
            vertical-align: middle;
        }
        #pg-cutlist-studio .cs-preview-rowcount {
            color: var(--dim);
            font-size: 11px;
        }
        #pg-cutlist-studio .cs-preview-toolbar button {
            min-height: 44px;
        }
        #pg-cutlist-studio .cs-preview-pane {
            flex: 1;
            margin: 0;
            padding: var(--sp-2) var(--sp-3);
            background: var(--bg);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            color: var(--txt);
            font-family: 'Cascadia Code', 'Consolas', 'Courier New', monospace;
            font-size: 12px;
            line-height: 1.6;
            overflow: auto;
            min-height: 0;
            white-space: pre;
            tab-size: 2;
        }
        #pg-cutlist-studio .cs-preview-pane:focus {
            outline: none;
            border-color: var(--acc);
        }
        /* PR-CL-SECTIONS-V1 (2026-05-17) — iframe preview replaces the
           <pre> when the current template carries sections. Same flex
           sizing so the layout is identical regardless of which pane
           is visible. White background mimics the rendered Print Demo
           page so the operator's preview matches the printed bytes. */
        #pg-cutlist-studio .cs-preview-iframe {
            flex: 1;
            margin: 0;
            padding: 0;
            background: #fff;
            border: 1px solid var(--bdr);
            border-radius: 6px;
            min-height: 0;
            width: 100%;
        }
        #pg-cutlist-studio .cs-preview-violations {
            margin-top: var(--sp-2);
            padding: var(--sp-2) var(--sp-3);
            background: color-mix(in srgb, var(--no) 12%, var(--inp));
            border: 1px solid var(--no);
            border-radius: 6px;
            color: var(--no);
            font-size: 12px;
            line-height: 1.5;
        }
        #pg-cutlist-studio .cs-preview-violations h4 {
            margin: 0 0 var(--sp-1) 0;
            font-size: 12px;
            font-weight: 700;
            letter-spacing: 0.04em;
            text-transform: uppercase;
        }
        #pg-cutlist-studio .cs-preview-violations ul {
            margin: 0;
            padding-left: 18px;
        }
        @media (prefers-reduced-motion: reduce) {
            #pg-cutlist-studio .cs-preview-status {
                transition: none;
            }
        }

        /* PR-TMPL-7-APPLY (2026-05-15) — apply-to-job project picker
           modal. Centered overlay with backdrop; project rows are 44px
           tap targets. Closes on backdrop click, × button, or Esc. */
        #pg-cutlist-studio .cs-modal {
            position: fixed;
            inset: 0;
            z-index: 10000;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: var(--sp-4);
        }
        #pg-cutlist-studio .cs-modal[hidden] { display: none; }
        #pg-cutlist-studio .cs-modal-backdrop {
            position: absolute;
            inset: 0;
            background: color-mix(in srgb, var(--bg) 70%, transparent);
            backdrop-filter: blur(2px);
        }
        #pg-cutlist-studio .cs-modal-panel {
            position: relative;
            width: 100%;
            max-width: 540px;
            max-height: 80vh;
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: var(--radius-md, 10px);
            box-shadow: 0 8px 28px color-mix(in srgb, #000 40%, transparent);
            padding: var(--sp-3) var(--sp-4);
            display: flex;
            flex-direction: column;
            gap: var(--sp-2);
        }
        #pg-cutlist-studio .cs-modal-head {
            display: flex;
            justify-content: space-between;
            align-items: center;
            gap: var(--sp-2);
        }
        #pg-cutlist-studio .cs-modal-head h3 {
            margin: 0;
            color: var(--txt);
            font-size: 16px;
            font-weight: 700;
        }
        #pg-cutlist-studio .cs-modal-close {
            min-width: 44px;
            min-height: 44px;
            background: transparent;
            border: 1px solid var(--bdr);
            border-radius: 6px;
            color: var(--dim);
            font-size: 18px;
            line-height: 1;
            cursor: pointer;
        }
        #pg-cutlist-studio .cs-modal-close:hover {
            background: var(--inp);
            color: var(--txt);
        }
        #pg-cutlist-studio .cs-modal-hint {
            margin: 0 0 var(--sp-2) 0;
            color: var(--dim);
            font-size: 12px;
            line-height: 1.5;
        }
        #pg-cutlist-studio .cs-apply-list {
            list-style: none;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            gap: 4px;
            overflow-y: auto;
            min-height: 0;
            flex: 1;
        }
        #pg-cutlist-studio .cs-apply-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 8px;
            padding: 10px 12px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            min-height: 44px;
            color: var(--txt);
            cursor: pointer;
            font-size: 13px;
            font-family: inherit;
            text-align: left;
            width: 100%;
        }
        #pg-cutlist-studio .cs-apply-row:hover {
            background: color-mix(in srgb, var(--acc) 12%, var(--inp));
            border-color: color-mix(in srgb, var(--acc) 50%, var(--bdr));
        }
        #pg-cutlist-studio .cs-apply-row-name {
            flex: 1;
            font-weight: 500;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        #pg-cutlist-studio .cs-apply-row-meta {
            font-size: 10px;
            color: var(--dim);
            letter-spacing: 0.04em;
        }
        @media (prefers-reduced-motion: reduce) {
            #pg-cutlist-studio .cs-modal-backdrop {
                backdrop-filter: none;
            }
        }

        /* PR-STUDIO-3 (2026-05-15): generic prompt/confirm modal.
           Reuses every .cs-modal-* style above; adds the input row
           + action bar for OK/Cancel. .cs-modal-actions also picked
           up by future modals (a 'discard unsaved' confirm in
           Templates pane, etc.). */
        #pg-cutlist-studio .cs-generic-input-wrap {
            display: flex;
            flex-direction: column;
            gap: 6px;
            margin-bottom: var(--sp-2);
        }
        #pg-cutlist-studio .cs-generic-input-label {
            color: var(--dim);
            font-size: 11px;
            font-weight: 600;
            letter-spacing: 0.04em;
            text-transform: uppercase;
        }
        #pg-cutlist-studio .cs-generic-input {
            width: 100%;
            min-height: 44px;
            padding: 8px 10px;
            background: var(--inp);
            border: 1px solid var(--bdr);
            border-radius: 6px;
            color: var(--txt);
            font-size: 13px;
            font-family: inherit;
        }
        #pg-cutlist-studio .cs-generic-input:focus {
            outline: none;
            border-color: var(--acc);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 18%, transparent);
        }
        #pg-cutlist-studio .cs-modal-actions {
            display: flex;
            justify-content: flex-end;
            gap: 8px;
            margin-top: var(--sp-3);
            padding-top: var(--sp-2);
            border-top: 1px solid var(--bdr);
        }
        #pg-cutlist-studio .cs-modal-actions button {
            min-height: 44px;
            min-width: 90px;
        }
        /* Variant: red OK button when the action is destructive
           (delete confirms). cs-danger is set programmatically by
           _csConfirm when opts.danger=true. */
        #pg-cutlist-studio .cs-modal-actions button.cs-danger {
            background: color-mix(in srgb, var(--no) 88%, transparent);
            border-color: color-mix(in srgb, var(--no) 70%, var(--bdr));
            color: var(--white);
        }
        #pg-cutlist-studio .cs-modal-actions button.cs-danger:hover {
            background: var(--no);
        }

        /* PR-THEME-LAYOUT-PARITY (2026-05-18): the OVERHAUL-6 Door
           Studio + Cabinet Studio page-hero strips with 🚪 / 🪚
           emoji badges injected content via ::before / ::after that
           every page rendered as an extra 110px chrome band. These
           added layout (not color) — removed wholesale so every theme
           shows the same page chrome. The OVERHAUL-3 base hero rules
           these scaled up are also removed above. */

        /* ── PR-CABFORGE-MAT-SHEET — pull-up material picker sheet ─────────
           Replaces the drawer-box Side / Bottom <select> dropdowns with a
           modal sheet that slides up from the bottom. Subtle 4px blur on
           the content above (heavier scrim fallback for browsers that lack
           backdrop-filter). Cards show texture thumb + name + spec row +
           AWI Compliant pill. Advanced expander reveals search + category
           chips + recently-used (7-day window via localStorage).

           2026-05-14 UX direction: user explicitly asked for the blur. The
           "blur reads as loading" caveat from the 2026-04-23 page-scrim
           audit doesn't apply here — this sheet is unambiguously modal
           (grab handle + slide-up animation + dark scrim + headline). */
        body[data-ui-version="cabforge"] .cf-mat-trigger {
            width: 100%;
            min-height: 44px;
            padding: 10px 14px;
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 8px;
            color: var(--txt);
            text-align: left;
            display: flex;
            align-items: center;
            justify-content: space-between;
            cursor: pointer;
            font-family: inherit;
            font-size: 14px;
            transition: border-color 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        /* PR-DBOX-TH-5 (cleanup 2026-05-15) — single-purpose card for the
           thickness override. Card frames the chip rail so the surface
           reads as one unit, not two random rows of inputs below the
           material pickers. Card title shows the override title +
           resolved value as a live-updating chip; the chip rail itself
           is the only required interaction; the Custom… escape hatch
           reveals the typed-input flow inline. 56px chips per WCAG +
           glove-allowance research. */
        .cf-thk-card {
            margin-top: 14px;
            padding: 14px 16px;
            border: 1px solid var(--bdr, #94A3B8);
            border-radius: 12px;
            background: var(--pn-h, var(--pn, #ffffff));
        }
        .cf-thk-card-head {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 12px;
        }
        .cf-thk-card-title {
            font-size: 13px;
            font-weight: 600;
            letter-spacing: 0.02em;
            text-transform: uppercase;
            color: var(--dim, #64748B);
        }
        .cf-thk-card-resolved {
            flex: 1;
            font-size: 14px;
            font-weight: 600;
            color: var(--acc, #60A5FA);
            min-height: 18px;
        }
        .cf-thk-chip-rail {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            align-items: center;
        }
        .cf-thk-chip {
            min-height: 56px;
            min-width: 66px;
            padding: 10px 16px;
            background: var(--inp, var(--pn, #ffffff));
            border: 1.5px solid var(--bdr, #94A3B8);
            border-radius: 10px;
            color: var(--txt, #1E293B);
            font-family: inherit;
            font-size: 15px;
            font-weight: 600;
            letter-spacing: 0.01em;
            cursor: pointer;
            transition: border-color 120ms ease-out, background 120ms ease-out, color 120ms ease-out, transform 120ms ease-out;
        }
        .cf-thk-chip:hover,
        .cf-thk-chip:focus-visible {
            border-color: var(--acc, #60A5FA);
            outline: none;
            transform: translateY(-1px);
        }
        .cf-thk-chip.cf-thk-chip-active {
            background: var(--acc, #60A5FA);
            border-color: var(--acc, #60A5FA);
            color: var(--acc-ink, #ffffff);
            box-shadow: 0 1px 3px 0 rgba(0,0,0,0.08);
        }
        .cf-thk-chip-custom {
            font-style: italic;
            font-weight: 500;
            opacity: 0.92;
        }
        .cf-thk-custom-wrap {
            margin-top: 12px;
            padding-top: 12px;
            border-top: 1px dashed var(--bdr, #94A3B8);
        }
        .cf-thk-custom-wrap input[type="text"] {
            width: 100%;
            min-height: 48px;
            padding: 10px 14px;
            font-size: 16px;
            font-family: inherit;
            border: 1.5px solid var(--bdr, #94A3B8);
            border-radius: 8px;
            background: var(--inp, var(--pn, #ffffff));
            color: var(--txt, #1E293B);
        }
        .cf-thk-custom-wrap input[type="text"]:focus {
            border-color: var(--acc, #60A5FA);
            outline: none;
        }
        .cf-thk-hint {
            font-size: 12px;
            color: var(--dim, #64748B);
            line-height: 1.4;
            margin-top: 8px;
            min-height: 18px;
        }
        .cf-thk-hint.cf-thk-hint-ok    { color: var(--ok, #06B6D4); }
        .cf-thk-hint.cf-thk-hint-warn  { color: var(--warn, #F59E0B); }
        .cf-thk-hint.cf-thk-hint-block { color: var(--no, #F43F5E); font-weight: 600; }
        .cf-thk-verify {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-top: 12px;
            min-height: 44px;
            font-size: 13px;
            color: var(--txt, #1E293B);
            cursor: pointer;
        }
        .cf-thk-verify input[type="checkbox"] {
            width: 20px;
            height: 20px;
            cursor: pointer;
            accent-color: var(--acc, #60A5FA);
        }
        body[data-ui-version="cabforge"] .cf-mat-trigger:hover,
        body[data-ui-version="cabforge"] .cf-mat-trigger:focus-visible {
            border-color: var(--acc);
            outline: none;
        }
        body[data-ui-version="cabforge"] .cf-mat-trigger-label {
            flex: 1;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        body[data-ui-version="cabforge"] .cf-mat-trigger-label[data-empty="true"] {
            color: var(--dim);
        }
        body[data-ui-version="cabforge"] .cf-mat-trigger-chevron {
            margin-left: 8px;
            color: var(--dim);
            font-size: 11px;
        }

        body[data-ui-version="cabforge"] .cf-mat-scrim {
            position: fixed;
            inset: 0;
            z-index: 60;
            background: rgba(0, 0, 0, 0.30);
            backdrop-filter: blur(4px);
            -webkit-backdrop-filter: blur(4px);
            opacity: 0;
            pointer-events: none;
            transition: opacity 150ms cubic-bezier(0.32, 0.72, 0.24, 1);
        }
        body[data-ui-version="cabforge"] .cf-mat-scrim[data-open="true"] {
            opacity: 1;
            pointer-events: auto;
        }
        @supports not (backdrop-filter: blur(4px)) {
            body[data-ui-version="cabforge"] .cf-mat-scrim {
                background: rgba(0, 0, 0, 0.45);
            }
        }

        body[data-ui-version="cabforge"] .cf-mat-sheet {
            position: fixed;
            left: 0;
            right: 0;
            bottom: 0;
            z-index: 61;
            max-height: 85vh;
            background: var(--pn);
            border-top-left-radius: 16px;
            border-top-right-radius: 16px;
            box-shadow: 0 -8px 28px rgba(0, 0, 0, 0.18);
            transform: translateY(100%);
            transition: transform 320ms cubic-bezier(0.25, 0.1, 0.25, 1.0);
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet[data-open="true"] {
            transform: translateY(0);
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-grab {
            width: 40px;
            height: 4px;
            background: var(--dim);
            border: none;
            border-radius: 2px;
            margin: 10px auto 0;
            opacity: 0.4;
            cursor: pointer;
            flex-shrink: 0;
            padding: 0;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-header {
            padding: 12px 20px 14px;
            border-bottom: 1px solid var(--bdr);
            display: flex;
            align-items: flex-start;
            gap: 12px;
            flex-shrink: 0;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-header-text {
            flex: 1;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-header h2 {
            margin: 0;
            font-size: 18px;
            font-weight: 600;
            color: var(--txt);
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-header p {
            margin: 2px 0 0;
            font-size: 13px;
            color: var(--dim);
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-close {
            background: none;
            border: none;
            color: var(--dim);
            font-size: 24px;
            cursor: pointer;
            padding: 0;
            width: 32px;
            height: 32px;
            line-height: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 6px;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-close:hover { background: var(--bg); }

        body[data-ui-version="cabforge"] .cf-mat-sheet-body {
            overflow-y: auto;
            padding: 16px 20px 24px;
            flex: 1;
            -webkit-overflow-scrolling: touch;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-section-head {
            display: flex;
            align-items: center;
            gap: 8px;
            margin: 16px 0 10px;
            font-size: 11px;
            font-weight: 700;
            letter-spacing: 0.08em;
            color: var(--dim);
            text-transform: uppercase;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-section-head:first-child { margin-top: 0; }
        body[data-ui-version="cabforge"] .cf-mat-sheet-section-head .cf-mat-star {
            color: #f5b400;
            font-size: 14px;
        }

        body[data-ui-version="cabforge"] .cf-mat-card {
            display: grid;
            grid-template-columns: 60px 1fr auto;
            gap: 12px;
            align-items: center;
            width: 100%;
            min-height: 72px;
            padding: 10px 12px;
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 10px;
            margin-bottom: 8px;
            cursor: pointer;
            text-align: left;
            font-family: inherit;
            color: var(--txt);
            transition: border-color 120ms cubic-bezier(0.22, 1, 0.36, 1),
                        box-shadow 120ms cubic-bezier(0.22, 1, 0.36, 1),
                        transform 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .cf-mat-card:hover,
        body[data-ui-version="cabforge"] .cf-mat-card:focus-visible {
            border-color: var(--acc);
            box-shadow: 0 2px 10px color-mix(in srgb, var(--acc) 14%, transparent);
            transform: translateY(-1px);
            outline: none;
        }
        body[data-ui-version="cabforge"] .cf-mat-card[data-selected="true"] {
            border-color: var(--acc);
            box-shadow: 0 0 0 1px var(--acc) inset;
        }
        body[data-ui-version="cabforge"] .cf-mat-card-thumb {
            width: 60px;
            height: 60px;
            border-radius: 6px;
            background: linear-gradient(135deg, #d6c4a8, #b5996d);
            background-size: cover;
            background-position: center;
            border: 1px solid var(--bdr);
            flex-shrink: 0;
        }
        body[data-ui-version="cabforge"] .cf-mat-card-body {
            display: flex;
            flex-direction: column;
            gap: 3px;
            min-width: 0;
        }
        body[data-ui-version="cabforge"] .cf-mat-card-name {
            font-size: 14px;
            font-weight: 600;
            color: var(--txt);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        body[data-ui-version="cabforge"] .cf-mat-card-spec {
            font-size: 12px;
            color: var(--dim);
        }
        body[data-ui-version="cabforge"] .cf-mat-card-meta {
            display: flex;
            flex-direction: column;
            align-items: flex-end;
            gap: 4px;
        }
        body[data-ui-version="cabforge"] .cf-mat-pill {
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 0.04em;
            padding: 3px 7px;
            border-radius: 4px;
            background: color-mix(in srgb, #f5b400 24%, transparent);
            color: #8a6a00;
            text-transform: uppercase;
            white-space: nowrap;
        }
        body[data-ui-version="cabforge"] .cf-mat-card-code {
            font-size: 10px;
            color: var(--dim);
            font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        }

        body[data-ui-version="cabforge"] .cf-mat-sheet-advanced > summary {
            list-style: none;
            cursor: pointer;
            padding: 12px 0;
            border-top: 1px solid var(--bdr);
            margin-top: 12px;
            font-size: 12px;
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--txt);
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-advanced > summary::-webkit-details-marker { display: none; }
        body[data-ui-version="cabforge"] .cf-mat-sheet-advanced > summary::after {
            content: '▾';
            color: var(--dim);
            font-size: 11px;
            transition: transform 120ms cubic-bezier(0.22, 1, 0.36, 1);
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-advanced[open] > summary::after {
            transform: rotate(-180deg);
        }

        body[data-ui-version="cabforge"] .cf-mat-sheet-search { margin: 10px 0 12px; }
        body[data-ui-version="cabforge"] .cf-mat-sheet-search input {
            width: 100%;
            min-height: 40px;
            padding: 8px 12px;
            background: var(--bg);
            border: 1px solid var(--bdr);
            border-radius: 8px;
            color: var(--txt);
            font-family: inherit;
            font-size: 14px;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-search input:focus {
            outline: none;
            border-color: var(--acc);
        }

        body[data-ui-version="cabforge"] .cf-mat-sheet-chips {
            display: flex;
            flex-wrap: wrap;
            gap: 6px;
            margin-bottom: 14px;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-chips button {
            padding: 6px 12px;
            background: var(--pn);
            border: 1px solid var(--bdr);
            border-radius: 999px;
            color: var(--txt);
            font-size: 12px;
            cursor: pointer;
            min-height: 32px;
            font-family: inherit;
        }
        body[data-ui-version="cabforge"] .cf-mat-sheet-chips button[aria-selected="true"] {
            background: var(--acc);
            color: #fff;
            border-color: var(--acc);
        }

        body[data-ui-version="cabforge"] .cf-mat-sheet-empty {
            padding: 24px 0;
            text-align: center;
            color: var(--dim);
            font-size: 13px;
        }

        @media (prefers-reduced-motion: reduce) {
            body[data-ui-version="cabforge"] .cf-mat-sheet,
            body[data-ui-version="cabforge"] .cf-mat-scrim {
                transition: none;
            }
        }
        /* ── /PR-CABFORGE-MAT-SHEET ───────────────────────────────────────── */
    
/* ================================================================
   FORGE TERMINAL — component primitives (PR-UI-FORGE 2026-06-13)
   Zero new hex; everything references the active theme tokens.
   ================================================================ */

/* Command/search bar in the topbar (.topbar-search slot) */
.forge-cmd-bar {
    display: flex; align-items: center; gap: 8px;
    height: 34px; max-width: 560px; width: 100%;
    padding: 0 10px; cursor: pointer;
    background: var(--inp);
    border: 1px solid var(--bdr);
    border-radius: 6px;
    color: var(--dim);
}
.forge-cmd-bar:hover,
.forge-cmd-bar:focus-within,
.forge-cmd-bar:focus-visible {
    border-color: var(--acc);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc) 22%, transparent);
    outline: none;
}
.forge-cmd-bar svg { flex: 0 0 16px; color: var(--dim); }
.forge-cmd-ph { flex: 1; font: 13px var(--ff-ui); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.forge-kbd {
    font: 11px var(--ff-mono); color: var(--dim);
    background: var(--pn); border: 1px solid var(--bdr); border-radius: 3px;
    padding: 1px 6px; margin-left: auto; flex: 0 0 auto;
}

/* "New ▾" split button (.topbar-actions) */
.btn-new-wrap { position: relative; display: inline-flex; border-radius: 6px; overflow: visible; }
.btn-new-main, .btn-new-caret {
    background: var(--acc); color: var(--acc-ink);
    border: none; font: 600 13px/1 var(--ff-ui); cursor: pointer;
    height: 32px; display: inline-flex; align-items: center; justify-content: center;
}
.btn-new-main { padding: 0 12px; border-radius: 6px 0 0 6px; gap: 6px; }
.btn-new-caret { padding: 0 8px; border-radius: 0 6px 6px 0; border-left: 1px solid color-mix(in srgb, var(--acc-ink) 28%, transparent); }
.btn-new-main:hover, .btn-new-caret:hover { background: var(--acc2); }
.btn-new-menu {
    position: absolute; top: calc(100% + 6px); right: 0; min-width: 220px;
    background: var(--pn); border: 1px solid var(--bdr); border-radius: 8px;
    box-shadow: 0 10px 30px var(--scrim, rgba(0,0,0,.5));
    padding: 5px; z-index: 1200;
}
.btn-new-menu[hidden] { display: none; }
.btn-new-menu button {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    width: 100%; padding: 9px 11px; border: none; background: transparent;
    color: var(--txt); font: 13px var(--ff-ui); cursor: pointer; border-radius: 5px; text-align: left;
}
.btn-new-menu button:hover { background: var(--pn-h); }
.btn-new-menu kbd {
    font: 11px var(--ff-mono); color: var(--dim);
    background: var(--inp); border: 1px solid var(--bdr); border-radius: 3px; padding: 1px 5px;
}
@media (pointer: coarse) { .btn-new-main, .btn-new-caret { height: 44px; } }

/* ================================================================
   FORGE JOBS GRID + PILLS (PR-UI-FORGE-2 2026-06-13)
   ================================================================ */
.forge-jobs-grid { width: 100%; border-collapse: collapse; }
.forge-jobs-grid thead th {
    font: 600 11px/1 var(--ff-ui); letter-spacing: .06em; text-transform: uppercase;
    color: var(--dim); text-align: left; padding: 9px 12px;
    border-bottom: 1px solid var(--bdr); background: var(--pn); white-space: nowrap;
}
.forge-jobs-grid tbody td {
    font: 13px/1.35 var(--ff-ui); color: var(--txt);
    padding: 9px 12px; border-bottom: 1px solid var(--bdr); vertical-align: middle;
}
.forge-jobs-grid tbody tr { cursor: pointer; transition: none; }
.forge-jobs-grid tbody tr:hover { background: var(--pn-h); }
.forge-jobs-grid .fjg-job { font-weight: 600; }
.forge-jobs-grid .fjg-type { width: 64px; }
.forge-jobs-grid .fjg-scope, .forge-jobs-grid .fjg-upd { width: 92px; color: var(--dim); }
.forge-jobs-grid td:last-child { width: 28px; text-align: right; color: var(--muted); }
.forge-mono { font-family: var(--ff-mono); font-variant-numeric: tabular-nums; }
.forge-dim, .forge-jobs-grid .forge-dim { color: var(--muted); }

/* Status / type pills — color-mix tints over theme tokens (no new hex) */
.forge-pill {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 8px; border-radius: 4px;
    font: 600 11px/1.6 var(--ff-ui); letter-spacing: .02em; white-space: nowrap;
}
.pill-draft    { background: color-mix(in srgb, var(--dim)  16%, transparent); color: var(--dim);  }
.pill-quoted   { background: color-mix(in srgb, var(--acc)  16%, transparent); color: var(--acc);  }
.pill-inprod   { background: color-mix(in srgb, var(--acc)  26%, transparent); color: var(--acc2); }
.pill-qc       { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.pill-shipped  { background: color-mix(in srgb, var(--ok)   18%, transparent); color: var(--ok);   }
.pill-blocked  { background: color-mix(in srgb, var(--no)   16%, transparent); color: var(--no);
                 border: 1px solid color-mix(in srgb, var(--no) 32%, transparent); }
.pill-cabinet  { background: color-mix(in srgb, var(--acc-cabinet) 18%, transparent); color: var(--acc-cabinet);
                 border: 1px solid color-mix(in srgb, var(--acc-cabinet) 32%, transparent); }
.pill-door     { background: color-mix(in srgb, var(--acc-door) 22%, transparent); color: color-mix(in srgb, var(--acc-door) 70%, var(--txt));
                 border: 1px solid color-mix(in srgb, var(--acc-door) 40%, transparent); }
/* PR-FORGE-DOORS: rush marker on door-order rows. */
.pill-rush     { margin-left: 4px; background: color-mix(in srgb, var(--no) 18%, transparent); color: var(--no);
                 border: 1px solid color-mix(in srgb, var(--no) 38%, transparent); letter-spacing: .04em; }

/* PR-UI-FORGE-3: jobs header controls (type segment + status filter) */
.forge-jobs-controls { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.forge-seg { position: relative; }
.forge-seg::after {
    content: ""; position: absolute; right: -7px; top: 50%; transform: translateY(-50%);
    height: 18px; width: 1px; background: var(--bdr);
}

/* ================================================================
   PR-UI-FORGE-4 — KPI strip → flat data ribbon (mono values)
   ================================================================ */
.kpi-strip .kpi-tile-value {
    font-family: var(--ff-mono, monospace) !important;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
    transition: none;              /* snap, never animate a number */
}
.kpi-strip .kpi-tile-label {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 11px;
    color: var(--dim);
}
/* Denser ribbon: tighter tiles, hairline separators, no rounded float */
.kpi-strip .kpi-tile { padding-top: 12px; padding-bottom: 12px; }

/* ================================================================
   PR-UI-FORGE-6 — KPI strip → one flush data-ribbon (not floating
   cards). Continuous panel, hairline cell separators, no per-tile
   rounding/lift. The pro-console "telemetry strip" look.
   ================================================================ */
.kpi-strip {
    background: var(--pn);
    border: 1px solid var(--bdr);
    border-radius: 8px;
    overflow: hidden;
    gap: 0 !important;
}
.kpi-strip .kpi-tile {
    border: none !important;
    border-radius: 0 !important;
    border-left: 1px solid var(--bdr) !important;
    background: transparent !important;
    box-shadow: none !important;
}
.kpi-strip .kpi-tile:first-child { border-left: none !important; }
.kpi-strip .kpi-tile:hover { background: var(--pn-h) !important; }

/* ================================================================
   PR-UI-FORGE-7 — COMMAND RAIL (data panels beside the jobs grid)
   ================================================================ */
.forge-side {
    flex: 0 0 340px; min-width: 0;
    display: flex; flex-direction: column; gap: var(--sp-4, 14px);
}
.forge-panel {
    background: var(--pn); border: 1px solid var(--bdr); border-radius: 8px;
    padding: 12px 14px;
}
.forge-panel-actions { padding-bottom: 14px; }
.forge-panel-h {
    margin: 0 0 10px; font: 600 11px/1 var(--ff-ui); letter-spacing: .07em;
    text-transform: uppercase; color: var(--dim);
    display: flex; align-items: center;
}
.forge-panel-count { color: var(--acc); font-family: var(--ff-mono); letter-spacing: 0; }
.forge-panel-body { display: flex; flex-direction: column; gap: 2px; }
.forge-panel-empty { font: 12px var(--ff-ui); color: var(--muted); padding: 4px 0; }
/* PR-HOME-REDESIGN (2026-06-13): right-aligned "Floor ↗" jump link in a panel
   header + the Needs-Attention severity tags (late/rush/qc), matching the
   forge-pill color budget. */
.forge-panel-link {
    margin-left: auto; text-transform: none; letter-spacing: 0;
    font: 600 11px var(--ff-ui); color: var(--acc); text-decoration: none;
}
.forge-panel-link:hover { text-decoration: underline; }
.forge-att-tag {
    flex: 0 0 auto; font: 600 10px/1 var(--ff-mono); letter-spacing: .04em;
    padding: 3px 6px; border-radius: 4px; white-space: nowrap;
}
.forge-att-tag.is-late { background: color-mix(in srgb, var(--no) 16%, transparent);   color: var(--no); }
.forge-att-tag.is-rush { background: color-mix(in srgb, var(--warn) 16%, transparent); color: var(--warn); }
.forge-att-tag.is-qc   { background: color-mix(in srgb, var(--warn) 16%, transparent); color: var(--warn); }

/* Pipeline rows */
.forge-pipe-row { display: flex; align-items: center; gap: 8px; padding: 3px 0; }
.forge-pipe-label { flex: 0 0 96px; font: 12px var(--ff-ui); color: var(--txt); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.forge-pipe-bar { flex: 1; height: 6px; background: var(--inp); border-radius: 3px; overflow: hidden; }
.forge-pipe-fill { display: block; height: 6px; border-radius: 3px; background: var(--acc); }
.forge-pipe-fill.stage-pending    { background: var(--muted); }
.forge-pipe-fill.stage-scheduled  { background: var(--acc); }
.forge-pipe-fill.stage-production  { background: var(--acc2); }
.forge-pipe-fill.stage-qc          { background: var(--warn); }
.forge-pipe-fill.stage-shipped     { background: var(--ok); }
.forge-pipe-n { flex: 0 0 24px; text-align: right; font: 12px var(--ff-mono); color: var(--dim); }

/* Panel list rows (in-production, recent) */
.forge-prow {
    display: flex; align-items: center; gap: 8px; padding: 6px 4px;
    border-radius: 5px; cursor: pointer;
}
.forge-prow:hover { background: var(--pn-h); }
.forge-prow:focus-visible { outline: 2px solid var(--acc); outline-offset: -2px; }
.forge-prow-dot { flex: 0 0 7px; width: 7px; height: 7px; border-radius: 50%; }
.forge-prow-dot.is-cab  { background: var(--acc-cabinet); }
.forge-prow-dot.is-door { background: var(--acc-door); }
.forge-prow-name { flex: 1; font: 13px var(--ff-ui); color: var(--txt); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.forge-prow-meta { flex: 0 0 auto; font: 11px var(--ff-mono); color: var(--dim); }

/* Quick actions */
.forge-quick { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.forge-quick button {
    font: 600 12px/1 var(--ff-ui); color: var(--txt);
    background: var(--inp); border: 1px solid var(--bdr); border-radius: 6px;
    padding: 9px 8px; cursor: pointer; text-align: center;
}
.forge-quick button:hover { border-color: var(--acc); color: var(--acc); }

/* Responsive: command rail drops below the grid on narrow screens */
@media (max-width: 1100px) {
    .forge-side { flex-basis: auto; width: 100%; }
}

/* ================================================================
   PR-UI-FORGE-8 — twin studio launchers below the KPI ribbon.
   Cabinet Studio is admin-only; the auto-FIT grid collapses its
   track + gap when display:none'd (shell.css:2235) so Door Studio
   fills the row cleanly (auto-FILL would leave a dead column).
   ================================================================ */
.forge-studio-launch {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 12px;
    margin: 14px 0 18px;
}
.forge-studio-btn {
    display: flex; align-items: center; gap: 14px;
    min-height: 76px; padding: 0 22px; text-align: left; cursor: pointer;
    background: var(--pn);
    border: 1px solid var(--bdr);
    border-left-width: 3px; border-left-color: var(--bdr);
    border-radius: 8px;
    font-family: var(--ff-ui); color: var(--txt);
    transition: border-color 140ms cubic-bezier(.22,1,.36,1),
                background   140ms cubic-bezier(.22,1,.36,1);
}
.forge-studio-btn.is-cabinet { border-left-color: color-mix(in srgb, var(--acc-cabinet) 60%, var(--bdr)); }
.forge-studio-btn.is-door    { border-left-color: color-mix(in srgb, var(--acc-door) 65%, var(--bdr)); }
.fsb-ico { flex: 0 0 38px; width: 38px; height: 38px; display: grid; place-items: center; border-radius: 6px; }
.fsb-ico svg { width: 20px; height: 20px; }
.forge-studio-btn.is-cabinet .fsb-ico { color: var(--acc-cabinet); background: color-mix(in srgb, var(--acc-cabinet) 14%, transparent); }
.forge-studio-btn.is-door    .fsb-ico { color: color-mix(in srgb, var(--acc-door) 80%, var(--txt)); background: color-mix(in srgb, var(--acc-door) 18%, transparent); }
.fsb-txt { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.fsb-title { font-size: 15px; font-weight: 600; line-height: 1.2; letter-spacing: -.01em; color: var(--txt); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsb-sub { font-size: 11px; font-weight: 400; font-family: var(--ff-mono); line-height: 1; letter-spacing: .06em; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.forge-studio-btn:hover { border-color: var(--bdr-h); }
.forge-studio-btn.is-cabinet:hover { background: color-mix(in srgb, var(--acc-cabinet) 7%, var(--pn)); border-left-color: var(--acc-cabinet); }
.forge-studio-btn.is-door:hover    { background: color-mix(in srgb, var(--acc-door) 8%, var(--pn)); border-left-color: var(--acc-door); }
.forge-studio-btn:active { background: color-mix(in srgb, var(--acc) 5%, var(--pn)); }
.forge-studio-btn:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }
/* Lone Door button (non-admin): a touch taller so it reads as a deliberate anchor */
body:not([data-role="admin"]) .forge-studio-btn { min-height: 64px; }
@media (prefers-reduced-motion: reduce) { .forge-studio-btn { transition: none; } }

/* ==================================================================
   PR-FORGE-DENSITY (2026-06-13) — operator: "scrolls down too much /
   takes up too much space." Tighten the top chrome (header → KPI →
   studio launchers) so the jobs grid is in view with minimal scroll.
   app.css loads after shell.css, so these win for equal specificity.
   ================================================================== */
/* Header: drop the consumer-app subtitle + slim the padding. The h1
   (shop name) carries identity; the generic tagline was a "website"
   signal + a redundant second line above the jobs heading. */
#hub-template-body .hub-page-header { padding: 16px var(--sp-6) 6px; }
#hub-template-body .hub-page-header .hub-subtitle { display: none; }
#hub-template-body .hub-page-header h1 { font-size: 20px; line-height: 1.15; }

/* KPI ribbon: shorter tiles, tighter pad + top gap. The number stays
   mono + prominent for shop-floor scan, just a touch smaller. */
#hub-template-body .kpi-strip { padding: 12px var(--sp-6) 0; gap: 10px; }
#hub-template-body .kpi-tile { min-height: 56px; padding: 10px 14px; gap: 2px; }
#hub-template-body .kpi-tile-icon { width: 26px; height: 26px; margin-bottom: 4px; }
#hub-template-body .kpi-tile-value { font-size: 23px; }
#hub-template-body .kpi-tile-label { font-size: 10px; }

/* Studio launchers: shorter, tighter margins. */
.forge-studio-launch { margin: 10px 0 12px; gap: 10px; }
.forge-studio-btn { min-height: 58px; padding: 0 18px; gap: 12px; }
.forge-studio-btn .fsb-ico { flex-basis: 32px; width: 32px; height: 32px; }
.forge-studio-btn .fsb-ico svg { width: 17px; height: 17px; }
.forge-studio-btn .fsb-title { font-size: 14px; }

/* Command-center area: pull it up under the launchers. */
#hub-template-body .hub-content-area { padding-top: 0; }

/* PR-FORGE-NAV (2026-06-13): small "opens in new tab" glyph on nav items
   that leave the SPA (Shop Floor). Pushed to the right, dimmed. */
.sidebar-nav-item .nav-ext { margin-left: auto; padding-left: 6px; font-size: 12px; line-height: 1; color: var(--muted, var(--dim)); opacity: .75; }
.sidebar-nav-item:hover .nav-ext { opacity: 1; }

/* PR-FORGE-HUB-STATES (2026-06-13): jobs-grid empty state — icon + message. */
.hub-jobs-empty .forge-empty { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 28px 16px; color: var(--dim); }
.hub-jobs-empty .forge-empty-ico { color: var(--muted, var(--dim)); opacity: .7; }
.hub-jobs-empty .forge-empty-msg { font-size: 13px; }
/* PR-FORGE-HUB-PROGRESS (2026-06-13): coarse stage-ordinal progress under
   the Stage pill. Display-only; fill colors mirror the pipeline stages. */
.forge-jobs-grid .fjg-stage { white-space: nowrap; }
/* PR-HOME-REDESIGN BF-3 (2026-06-13): .fjg-prog (per-row mini stage bar)
   removed — it added vertical bulk; the stage pill carries the stage. */

/* PR-FORGE-HUB-DUEDATE (2026-06-13): due-date urgency coloring. */
.forge-jobs-grid .fjg-due { white-space: nowrap; }
.forge-jobs-grid .fjg-due[data-urgency="soon"] { color: var(--warn); }
.forge-jobs-grid .fjg-due[data-urgency="now"]  { color: var(--no); font-weight: 600; }

/* PR-FORGE-CAB-CUSTOMERS (2026-06-13): forge hairline data-grid + summary
   strip (replaces the sparse .li card list on the Customers tab). */
.cust-strip{display:flex;flex-wrap:wrap;gap:18px;align-items:baseline;padding:10px 14px;margin-bottom:10px;background:var(--pn);border:1px solid var(--bdr);border-radius:8px;font-size:12px;color:var(--dim);}
.cust-strip b{color:var(--txt);font-weight:600;font-variant-numeric:tabular-nums;}
.cust-strip .cust-strip-sep{width:1px;align-self:stretch;background:var(--bdr);}
.cust-grid{width:100%;border-collapse:collapse;font-size:12.5px;background:var(--sf);border:1px solid var(--bdr);border-radius:8px;overflow:hidden;}
.cust-grid thead th{background:var(--pn);color:var(--dim);text-align:left;font-weight:700;font-size:10px;letter-spacing:.8px;text-transform:uppercase;padding:9px 12px;border-bottom:1px solid var(--bdr);white-space:nowrap;}
.cust-grid thead th.num{text-align:right;}
.cust-grid thead th.cg-actions{text-align:right;}
.cust-grid tbody td{padding:9px 12px;border-bottom:1px solid var(--bdr);color:var(--txt);vertical-align:middle;}
.cust-grid tbody td.num{text-align:right;font-variant-numeric:tabular-nums;}
.cust-grid tbody td.dim{color:var(--dim);}
.cust-grid tbody tr:hover{background:var(--pn-h);}
.cust-grid .cg-name{color:var(--txt);font-weight:600;}
.cust-grid .cg-actions{text-align:right;white-space:nowrap;}
.cust-grid .cg-detail td{background:var(--bg);padding:0 12px;border-bottom:1px solid var(--bdr);}
.cust-grid .cg-detail .cg-detail-inner{padding:6px 0 10px;}
@media(max-width:760px){.cust-grid thead{display:none;}.cust-grid,.cust-grid tbody,.cust-grid tr,.cust-grid td{display:block;width:100%;}.cust-grid tbody tr{border-bottom:1px solid var(--bdr);padding:6px 0;}.cust-grid tbody td{border:none;padding:3px 12px;}.cust-grid tbody td.num{text-align:left;}}

/* ═══════════════════════════════════════════════════════════════════
   PR-EDIT-CABINETS PORT (2026-07-14): styles for the grafted editor UI.
   Fullscreen viewport, the ⓘ microcopy tooltip, the resolved-slide
   readout, topbar cabinet nav, bottom-bar type/section meta, and the
   narrow-panel Faces two-column→stack fix. The codespace's parallel
   pane-resize vars (--ec-left-w/.cab-resizing/.cab-resize-handle) and
   category-rail modal restructure were intentionally NOT ported — HEAD
   already has --cab-lw/--cab-rw pane resize and the V2 tab-rail nav.
   Fullscreen rules therefore key off HEAD's --cab-lw/--cab-rw.
   ═══════════════════════════════════════════════════════════════════ */
/* PR-VIEW-FULLSCREEN (2026-07-14): the ⤢ button is TRUE full screen —
   the grid becomes a fixed overlay covering every piece of app chrome
   (topbar, page header, statusbar), paired with a browser
   requestFullscreen. The in-viewer toolbar stays visible so the operator
   can toggle back (Esc also exits). */
.cab-editor-grid.cab-fullscreen{
    position:fixed;
    inset:0;
    z-index:9998;
    background:var(--bg);
    height:100vh;
    width:100vw;
}
body[data-view-fullscreen="true"]{overflow:hidden;}
body[data-view-fullscreen="true"] #forge-cmd-bar,
body[data-view-fullscreen="true"] #app-topbar,
body[data-view-fullscreen="true"] #app-statusbar,
body[data-view-fullscreen="true"] #app-bottom-nav{display:none !important;}
/* PR-VIEW-FS-LEFTNAV (2026-07-14): the LEFT rail (Library + Placed) stays
   usable in fullscreen. Its ‹ collapse toggle still works. The right
   panel appears only while Edit Cabinet mode is on (ec-editing). */
.cab-editor-grid.cab-fullscreen,
.cab-editor-grid.cab-fullscreen.cab-right-collapsed{grid-template-columns:var(--cab-lw,248px) 1fr 0;}
.cab-editor-grid.cab-fullscreen.cab-left-collapsed{grid-template-columns:0 1fr 0;}
.cab-editor-grid.cab-fullscreen.ec-editing{grid-template-columns:var(--cab-lw,248px) 1fr var(--cab-rw,336px) !important;}
.cab-editor-grid.cab-fullscreen.ec-editing.cab-left-collapsed{grid-template-columns:0 1fr var(--cab-rw,336px) !important;}
.cab-editor-grid.cab-fullscreen .cab-pane{opacity:0;pointer-events:none;overflow:hidden;border:none;}
#cv-left-pill{position:absolute;left:14px;top:14px;z-index:8;display:none;padding:9px 14px;font-size:12px;font-weight:600;border-radius:9px;border:1px solid var(--bdr);background:var(--pn);color:var(--white);cursor:pointer;box-shadow:0 8px 24px rgba(0,0,0,.4);}
#cv-left-pill:hover{border-color:var(--acc2);color:var(--acc2);}
.cab-editor-grid.cab-fullscreen .cab-pane-left{opacity:1;pointer-events:auto;}
.cab-editor-grid.cab-fullscreen.ec-editing .cab-pane-right{opacity:1;pointer-events:auto;}

/* PR-MICROCOPY: ⓘ tooltip — parameter depth lives on hover. */
.ced-help-ic{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-left:6px;border-radius:50%;font-size:11px;font-style:normal;color:var(--dim);cursor:help;user-select:none;vertical-align:-2px;}
.ced-help-ic:hover,.ced-help-ic:focus-visible{color:var(--acc2);}
/* PR-SLIDE-REAR-CLEARANCE: resolved-slide readout (engine's actual pick). */
.ced-slide-resolved{margin-top:8px;font-size:12px;}
.ced-slide-resolved .ced-slide-pick{font-weight:700;color:var(--acc2);font-variant-numeric:tabular-nums;}
.ced-slide-resolved .ced-slide-warn{margin-top:4px;color:var(--no);font-size:11.5px;line-height:1.4;}

/* PR-CED-CATS: topbar cabinet ◀/▶ nav. */
#cab-editor-modal[data-layout="v2"] .ced-cabnav{display:flex;gap:4px;}
#cab-editor-modal[data-layout="v2"] .ced-cabnav-btn{min-width:34px;min-height:34px;border:1px solid var(--bdr);border-radius:6px;background:var(--inp,#1c2029);color:var(--white);font-size:13px;cursor:pointer;line-height:1;}
#cab-editor-modal[data-layout="v2"] .ced-cabnav-btn:hover{border-color:var(--acc2);color:var(--acc2);}
/* PR-CED-CATS: bottom-bar meta — type chip + section selector. */
#cab-editor-modal[data-layout="v2"] .ced-bottombar-meta{margin-right:auto;display:flex;align-items:center;gap:14px;}
#cab-editor-modal[data-layout="v2"] .ced-type-chip{font-size:12px;font-weight:600;color:var(--dim);border:1px solid var(--bdr);border-radius:6px;padding:6px 10px;text-transform:capitalize;}
#cab-editor-modal[data-layout="v2"] .ced-section-sel-wrap{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--dim);}
#cab-editor-modal[data-layout="v2"] .ced-section-sel-wrap[hidden]{display:none;}
#cab-editor-modal[data-layout="v2"] #ced-section-sel{background:var(--inp,#1c2029);color:var(--white);border:1px solid var(--bdr);border-radius:6px;padding:6px 8px;font-size:12px;min-height:34px;}

/* PR-CED-FACES-NARROW (2026-07-10): the Faces pane renders inside the
   ~300-380px V2 right panel. STACK the canvas column and the Custom
   Openings column — the old fixed-340px side column crushed the canvas
   to a sliver. Container queries pick two columns back up with room. */
#cab-editor-pane-faces{container-type:inline-size;}
.ced-faces-cols{display:flex;flex-direction:column;gap:14px;align-items:stretch;}
.ced-faces-main{flex:1 1 auto;min-width:0;width:100%;}
.ced-faces-side{display:flex;flex-direction:column;gap:10px;width:100%;min-width:0;}
@container (min-width: 640px){
    .ced-faces-cols{flex-direction:row;align-items:flex-start;}
    .ced-faces-side{width:340px;flex:0 0 340px;}
}

/* ── PR-JOBLINE-1 (2026-07-16): "move a job down the line" control ──────────
   Shared stage badge + accept/advance buttons + ⋯ menu (step-back / cancel /
   mark-paid) + Paid pill, plus a floating batch action bar. Rendered on the
   home All-Jobs list, the Projects tab, and the Cabinet + Door studio headers. */
.jl{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap;vertical-align:middle;}
.jl-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:700;letter-spacing:.02em;text-transform:uppercase;background:var(--pn-h);color:var(--ink,#334155);border:1px solid var(--bdr,#cbd5e1);}
.jl-badge[data-stage="Pending"]{background:color-mix(in srgb,var(--dim) 15%,transparent);color:var(--dim);border-color:color-mix(in srgb,var(--dim) 40%,transparent);}
.jl-badge[data-stage="Scheduled"]{background:color-mix(in srgb,var(--warn) 15%,transparent);color:var(--warn);border-color:color-mix(in srgb,var(--warn) 40%,transparent);}
.jl-badge[data-stage="InProduction"]{background:color-mix(in srgb,var(--acc) 15%,transparent);color:var(--acc);border-color:color-mix(in srgb,var(--acc) 40%,transparent);}
.jl-badge[data-stage="QC"]{background:color-mix(in srgb,var(--acc2) 15%,transparent);color:var(--acc2);border-color:color-mix(in srgb,var(--acc2) 40%,transparent);}
.jl-badge[data-stage="Shipped"]{background:color-mix(in srgb,var(--ok) 15%,transparent);color:var(--ok);border-color:color-mix(in srgb,var(--ok) 40%,transparent);}
.jl-badge[data-stage="Cancelled"]{background:color-mix(in srgb,var(--no) 15%,transparent);color:var(--no);border-color:color-mix(in srgb,var(--no) 40%,transparent);}
.jl-step{display:inline-flex;align-items:center;gap:4px;padding:5px 12px;min-height:32px;border-radius:6px;font-size:12px;font-weight:700;cursor:pointer;white-space:nowrap;border:1px solid var(--bdr,#cbd5e1);background:var(--pn);color:var(--ink,#222);}
.jl-step.jl-primary{background:var(--acc,#2563eb);border-color:var(--acc,#2563eb);color:#fff;}
.jl-step:hover{filter:brightness(1.06);}
.jl-step:disabled{opacity:.5;cursor:default;}
.jl-more{position:relative;display:inline-flex;}
.jl-more-btn{min-height:32px;min-width:32px;padding:2px 8px;border-radius:6px;cursor:pointer;border:1px solid var(--bdr,#cbd5e1);background:var(--pn);color:var(--ink,#222);font-weight:800;line-height:1;}
.jl-menu{position:absolute;top:calc(100% + 4px);right:0;z-index:60;min-width:170px;display:flex;flex-direction:column;gap:2px;padding:6px;border-radius:8px;background:var(--pn);border:1px solid var(--bdr,#cbd5e1);box-shadow:0 8px 24px rgba(0,0,0,.18);}
.jl-menu[hidden]{display:none;}
.jl-mi{text-align:left;padding:7px 10px;min-height:36px;border:none;border-radius:5px;background:transparent;color:var(--txt);font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap;}
.jl-mi:hover{background:var(--pn-h);}
.jl-mi.jl-danger{color:var(--no);}
.jl-mi.jl-danger:hover{background:color-mix(in srgb,var(--no) 15%,transparent);}
.jl-paid{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:700;background:color-mix(in srgb,var(--ok) 15%,transparent);color:var(--ok);border:1px solid color-mix(in srgb,var(--ok) 40%,transparent);}
.jl-done{font-size:12px;color:var(--dim,#94a3b8);font-weight:600;}
.jl-wait{display:inline-block;width:12px;height:12px;}
.forge-jobs-grid .fjg-act{white-space:nowrap;text-align:right;}
input.jl-cb{width:18px;height:18px;cursor:pointer;vertical-align:middle;accent-color:var(--acc,#2563eb);}
.jl-batchbar{position:fixed;left:50%;bottom:20px;transform:translateX(-50%);z-index:1200;display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:12px;background:var(--pn-h);color:var(--txt);box-shadow:0 12px 40px rgba(0,0,0,.35);}
.jl-batchbar[hidden]{display:none;}
.jl-bb-count{font-weight:700;font-size:13px;}
.jl-bb-btn{padding:7px 14px;min-height:38px;border-radius:8px;font-size:13px;font-weight:700;cursor:pointer;border:1px solid color-mix(in srgb,var(--bdr) 70%,transparent);background:color-mix(in srgb,var(--bdr) 30%,transparent);color:var(--txt);}
.jl-bb-btn.jl-primary{background:var(--acc,#2563eb);border-color:var(--acc,#2563eb);}
.jl-bb-btn:hover{filter:brightness(1.1);}
.jl-bb-x{background:transparent;border:none;color:var(--dim);font-size:13px;font-weight:600;cursor:pointer;padding:6px 8px;}
.jl-bb-x:hover{color:var(--txt);}

/* ── PR-JOBS-HUB (2026-07-17): the Jobs tab hub ─────────────────────────────── */
.jh-filters{margin-bottom:14px;}
.jh-tabs{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:10px;}
.jh-tab{padding:6px 12px;border-radius:999px;border:1px solid var(--bdr,#e2e8f0);background:var(--pn);color:var(--ink,#334155);font-size:13px;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:6px;}
.jh-tab[data-active="true"]{background:var(--acc,#2563eb);border-color:var(--acc,#2563eb);color:#fff;}
.jh-n{font-size:11px;font-weight:700;opacity:.8;background:rgba(127,127,127,.15);border-radius:999px;padding:0 6px;min-width:16px;text-align:center;}
.jh-tab[data-active="true"] .jh-n{background:rgba(255,255,255,.25);opacity:1;}
.jh-row2{display:flex;gap:10px;flex-wrap:wrap;align-items:center;}
.jh-segs{display:inline-flex;border:1px solid var(--bdr,#e2e8f0);border-radius:8px;overflow:hidden;}
.jh-seg{padding:6px 12px;border:none;background:var(--pn);color:var(--dim,#64748b);font-size:12.5px;font-weight:600;cursor:pointer;border-right:1px solid var(--bdr,#e2e8f0);}
.jh-seg:last-child{border-right:none;}
.jh-seg[data-active="true"]{background:var(--pn-h);color:var(--ink,#1e293b);}
.jh-search{flex:1;min-width:160px;padding:7px 12px;border-radius:8px;border:1px solid var(--bdr,#e2e8f0);background:var(--inp);color:var(--ink,#1e293b);font-size:13px;}
.jh-sort{padding:7px 10px;border-radius:8px;border:1px solid var(--bdr,#e2e8f0);background:var(--inp);color:var(--ink,#1e293b);font-size:13px;cursor:pointer;}
.jh-summary{display:flex;gap:20px;flex-wrap:wrap;padding:10px 14px;margin-bottom:12px;background:var(--bg);border:1px solid var(--bdr,#e2e8f0);border-radius:10px;font-size:13px;color:var(--dim,#64748b);}
.jh-summary strong{color:var(--ink,#1e293b);font-size:15px;}
.jh-summary em{font-style:normal;opacity:.75;}
.jh-tablewrap{overflow-x:auto;border:1px solid var(--bdr,#e2e8f0);border-radius:10px;background:var(--pn);}
.jh-table{width:100%;border-collapse:collapse;font-size:13.5px;}
.jh-table thead th{text-align:left;padding:10px 12px;font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--dim,#64748b);border-bottom:1px solid var(--bdr,#e2e8f0);white-space:nowrap;}
.jh-table td{padding:10px 12px;border-bottom:1px solid var(--bdr,#eef2f7);color:var(--ink,#1e293b);vertical-align:middle;}
.jh-tr{cursor:pointer;}
.jh-tr:hover{background:var(--pn-h);}
.jh-tr:last-child td{border-bottom:none;}
.jh-name{font-weight:600;}
.jh-mono{font-variant-numeric:tabular-nums;white-space:nowrap;}
.jh-price{font-weight:600;}
.jh-dim{color:var(--dim,#94a3b8);}
.jh-type{display:inline-block;padding:1px 7px;border-radius:6px;font-size:10px;font-weight:700;letter-spacing:.03em;}
.jh-cab{background:color-mix(in srgb,var(--acc) 15%,transparent);color:var(--acc);}
.jh-door{background:color-mix(in srgb,var(--acc2) 15%,transparent);color:var(--acc2);}
.jh-rush{display:inline-block;padding:1px 6px;border-radius:6px;font-size:10px;font-weight:700;background:color-mix(in srgb,var(--no) 15%,transparent);color:var(--no);}
.jh-paid{display:inline-flex;align-items:center;padding:1px 8px;border-radius:999px;font-size:11px;font-weight:700;background:color-mix(in srgb,var(--ok) 15%,transparent);color:var(--ok);}
.jh-stage{display:inline-block;padding:2px 9px;border-radius:999px;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.02em;background:var(--pn-h);color:var(--dim);}
.jh-stage[data-stage="Pending"]{background:color-mix(in srgb,var(--dim) 15%,transparent);color:var(--dim);}
.jh-stage[data-stage="Scheduled"]{background:color-mix(in srgb,var(--warn) 15%,transparent);color:var(--warn);}
.jh-stage[data-stage="InProduction"]{background:color-mix(in srgb,var(--acc) 15%,transparent);color:var(--acc);}
.jh-stage[data-stage="QC"]{background:color-mix(in srgb,var(--acc2) 15%,transparent);color:var(--acc2);}
.jh-stage[data-stage="Shipped"]{background:color-mix(in srgb,var(--ok) 15%,transparent);color:var(--ok);}
.jh-stage[data-stage="Cancelled"]{background:color-mix(in srgb,var(--no) 15%,transparent);color:var(--no);}
.jh-empty{padding:40px;text-align:center;color:var(--dim,#94a3b8);border:1px dashed var(--bdr,#e2e8f0);border-radius:10px;}
.jh-drawer{position:fixed;inset:0;z-index:1300;}
.jh-drawer[hidden]{display:none;}
.jh-drawer-bg{position:absolute;inset:0;background:rgba(15,23,42,.4);}
.jh-drawer-panel{position:absolute;top:0;right:0;height:100%;width:min(440px,92vw);background:var(--pn);border-left:1px solid var(--bdr,#e2e8f0);box-shadow:-8px 0 32px rgba(0,0,0,.18);padding:22px 24px;overflow-y:auto;}
.jh-d-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;margin-bottom:14px;}
.jh-d-title{font-size:20px;font-weight:700;color:var(--ink,#1e293b);line-height:1.2;}
.jh-d-sub{font-size:12.5px;color:var(--dim,#64748b);margin-top:3px;}
.jh-d-x{border:none;background:transparent;font-size:18px;color:var(--dim,#64748b);cursor:pointer;line-height:1;}
.jh-d-ctrl{margin-bottom:16px;}
.jh-d-dl{display:grid;grid-template-columns:110px 1fr;gap:9px 14px;font-size:13.5px;margin:0 0 18px;}
.jh-d-dl dt{color:var(--dim,#64748b);}
.jh-d-dl dd{margin:0;color:var(--ink,#1e293b);}
.jh-d-actions{display:flex;gap:8px;flex-wrap:wrap;}
.jh-btn{padding:9px 15px;border-radius:8px;border:1px solid var(--bdr,#e2e8f0);background:var(--pn);color:var(--ink,#1e293b);font-weight:600;font-size:13.5px;cursor:pointer;}
.jh-btn.jh-primary{background:var(--acc,#2563eb);border-color:var(--acc,#2563eb);color:#fff;}
.jh-btn:hover{filter:brightness(1.05);}
.jh-d-msg{margin-top:12px;font-size:13px;color:var(--dim,#64748b);}

/* ======================================================================
   PR-RESPONSIVE-STUDIO (2026-07-30) — full phone/tablet studio + ultrawide
   ======================================================================
   Operator: "optimize the ui to work on phones and ipads aswell" +
   "everything is equal from ultrawide monitors to small phones" + full
   editing on phone. The pre-existing <=900px rule (app.css:1974) STACKED
   the 3 panes (library 240 / viewer 220 / params 240) which is cramped for
   real editing. This replaces the stack with OVERLAY DRAWERS so the 3D
   viewport stays full-bleed and the Cabinet Library (left) + Inspector
   (right) slide over it — reusing state that already exists:
     • LEFT  drawer open  = grid :not(.cab-left-collapsed) — driven by the
       existing toggleCabLeft() / #cv-hamburger / .cab-left-reopen tab.
     • RIGHT drawer open  = a cabinet/wall is selected, i.e. the params form
       is visible — pure CSS :has(#cab-params-form:not(.hidden)). Zero new
       studio JS; auto-opens on select, auto-closes on deselect.
   Touch already arrives as PointerEvents in app-editor.js, so we only add
   touch-action (stop the browser hijacking a 3D drag as scroll) + coarse-
   pointer target bumps. Scrim-tap-to-close is wired in _restoreCabLeftCollapsed.
   Comes AFTER the 1974 rule in source order, so it wins at equal specificity;
   the child-combinator selectors are also higher specificity than `.cab-pane`.
   ====================================================================== */

/* 3D viewport: never let a touch-drag on the canvas scroll/zoom the page.
   Safe at every size (desktop mouse is unaffected by touch-action). */
#bevy-canvas, #plan-poster { touch-action: none; }

/* Coarse pointer (finger): bump the floating studio controls to the 44px
   WCAG-AAA / Apple-HIG floor at EVERY width, not just <=599px. */
@media (pointer: coarse) {
  .cab-view-bar .cv-btn,
  .cab-act-cluster .cv-btn,
  .cab-view-bar #vc-view,
  .cab-placed-panel .cpp-foot button { min-height: var(--touch-min, 44px); }
  .cab-resizer { width: 16px; }   /* fatter drag-to-resize hit area */
}

/* Ultrawide (>=1920px): the operator asked that big monitors USE the space.
   Give the library + inspector rails more room when the operator hasn't
   manually dragged them (inline --cab-lw guards the same way the 1200px
   down-rule does). The 3D viewport still gets the lion's share (1fr). */
@media (min-width: 1920px) {
  .cab-editor-grid:not([style*="--cab-lw"]) { --cab-lw: 300px; --cab-rw: 360px; }
}
@media (min-width: 2560px) {
  .cab-editor-grid:not([style*="--cab-lw"]) { --cab-lw: 340px; --cab-rw: 400px; }
}

/* ── Overlay-drawer studio (<=900px: phones + tablet portrait) ────────── */
@media (max-width: 900px) {
  /* Viewport fills the whole editor; panes float over it. Override the
     stacked-rows layout AND the collapsed/editing column variants. */
  .cab-editor-grid,
  .cab-editor-grid.cab-left-collapsed,
  .cab-editor-grid.ec-editing,
  .cab-editor-grid.ec-editing.cab-left-collapsed,
  .cab-editor-grid.cab-fullscreen.cab-left-collapsed,
  .cab-editor-grid.cab-fullscreen.ec-editing.cab-left-collapsed {
    grid-template-columns: 1fr !important;
    grid-template-rows: 1fr !important;
  }
  .cab-editor-grid > .cab-viewer {
    grid-column: 1; grid-row: 1;
    min-height: 0;                 /* was 220px — let it own the whole cell */
  }

  /* Both side panes become fixed-height overlay drawers. */
  .cab-editor-grid > .cab-pane {
    position: absolute; top: 0; bottom: 0;
    width: min(86vw, 360px);
    max-height: none !important;   /* kill the 240px stack cap */
    z-index: var(--z-drawer, 50);
    background: var(--bg);
    box-shadow: var(--shadow-5, 0 12px 40px rgba(0,0,0,.36));
    transition: transform var(--dur-chrome, 150ms) var(--ease-out);
    will-change: transform;
  }
  .cab-editor-grid > .cab-pane-left  {
    left: 0; border-right: 1px solid var(--bdr); border-bottom: none;
    transform: translateX(-102%);
  }
  .cab-editor-grid > .cab-pane-right {
    right: 0; border-left: 1px solid var(--bdr); border-top: none;
    transform: translateX(102%);
  }
  /* Inner scroll: the pane body must scroll as one region on a phone. */
  .cab-editor-grid > .cab-pane .cab-pane-body { overflow-y: auto; }

  /* OPEN states — reuse existing app state, no new JS. */
  .cab-editor-grid:not(.cab-left-collapsed) > .cab-pane-left { transform: translateX(0); }
  .cab-editor-grid:has(#cab-params-form:not(.hidden)) > .cab-pane-right { transform: translateX(0); }

  /* Scrim behind an open drawer (grid ::after; tap = close, wired in JS).
     pointer-events:none when no drawer is open so 3D interaction is normal. */
  .cab-editor-grid::after {
    content: ""; position: absolute; inset: 0;
    z-index: calc(var(--z-drawer, 50) - 1);
    background: var(--scrim, rgba(0,0,0,.42));
    opacity: 0; pointer-events: none;
    transition: opacity var(--dur-chrome, 150ms) var(--ease-out);
  }
  .cab-editor-grid:not(.cab-left-collapsed)::after,
  .cab-editor-grid:has(#cab-params-form:not(.hidden))::after {
    opacity: 1; pointer-events: auto;
  }

  /* The "Cabinets" reopen tab + floating controls sit above the canvas. */
  .cab-left-reopen { z-index: calc(var(--z-drawer, 50) + 1); }
  /* Phone-only Done button in the inspector header (added in markup). */
  .cab-pane-right .cab-inspector-done { display: inline-flex; }
}
/* The inspector Done button is phone-only. */
.cab-pane-right .cab-inspector-done { display: none; }

/* ── Door Studio on phones (<=600px): stack + give the preview real height.
   The <=767px rule already drops the 480px min-width floor; this makes the
   split genuinely usable at phone widths. ─────────────────────────────── */
@media (max-width: 600px) {
  .ds-param-panel { min-width: 0 !important; width: 100% !important; }
  .ds-viewport, .ds-viewport-preview { min-width: 0 !important; }
  .ds-preview-col, #ds-preview-col { min-height: 42vh; }
}

/* ── Studio dialogs never wider than the phone. Most already cap at 90vw;
   this catches the stragglers + keeps them height-bounded + scrollable. ─ */
@media (max-width: 600px) {
  .vgate-modal .vgate-panel,
  .gs-modal .gs-panel,
  .shortcuts-modal .sc-panel,
  .sync-modal .sync-panel {
    width: min(94vw, 560px) !important;
    max-width: 94vw !important;
    max-height: 90svh;
    overflow: auto;
  }
}
/* /PR-RESPONSIVE-STUDIO ─────────────────────────────────────────────── */
