/* =====================================================================
   Scanalyse — Monograph design system  (served at /assets/theme.css)
   SINGLE SOURCE OF TRUTH: tokens (light + dark) + base + app shell.
   Warm paper palette, serif display (--display), mono figures (--mono),
   dark left sidebar. Edit a token here and every screen updates.
   ===================================================================== */
  /* Base reset: the `hidden` attribute must always beat an author `display`
     (P1 hotfix — #postov[hidden] kept display:grid and froze /ui for all users). */
  [hidden]{display:none !important}
  :root{
    --font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
    --display:"Source Serif 4",Georgia,"Times New Roman",serif;
    --mono:"IBM Plex Mono",ui-monospace,"SFMono-Regular",Menlo,Consolas,monospace;
    --bg:#f6f4ef; --panel:#fffdf9; --panel-2:#efece4; --surface-2:#efece4; --surface-3:#e7e1d3;
    --ink:#1e2128; --muted:#62656e;
    --line:#e8e3d8; --line-strong:#d9d3c6;
    --accent:#1e2128; --accent-weak:#e7e1d3; --accent-fg:#ffffff; --accent-hover:#2c313b; --brand:#1e2128;
    --ok:#15803d; --ok-bg:#e7f6ec; --warn:#b45309; --warn-bg:#fbf0db; --bad:#b91c1c; --bad-bg:#fceaea;
    --info:#1e2128; --info-bg:#eceae3; --credit:#7e22ce; --credit-bg:#f5eafe; --hl:#fdeeb0;
    --hi:#15803d; --med:#b45309; --lo:#b91c1c; --none:#5b6573;
    --radius:8px; --radius-lg:11px;
    --shadow-sm:0 1px 2px rgba(31,42,48,.06),0 1px 1px rgba(31,42,48,.04);
    --shadow-md:0 3px 12px rgba(31,42,48,.08),0 1px 2px rgba(31,42,48,.05);
    --shadow-lg:0 16px 40px rgba(31,42,48,.16);
    --header-bg:rgba(255,253,249,.82);
    --toast-bg:#1e2128; --toast-fg:#f6f4ef; --focus:#1e2128;
    --nav:#0c0d11; --nav-ink:#eceef2; --nav-muted:#8b9097; --nav-active:#1b1e25; --nav-hair:rgba(255,255,255,.16);
    --sidebar-w:236px; --sidebar-w-collapsed:64px;
  }
  [data-theme="dark"]{
    --bg:#0d0e11; --panel:#15171b; --panel-2:#1c1f24; --surface-2:#1c1f24; --surface-3:#232830;
    --ink:#eceef2; --muted:#9aa0a8;
    --line:#23262b; --line-strong:#343941;
    --accent:#eceef2; --accent-weak:#232830; --accent-fg:#15171b; --accent-hover:#d7dae0; --brand:#eceef2;
    --ok:#5bd98c; --ok-bg:#10301e; --warn:#e7b667; --warn-bg:#34280f; --bad:#f0a3a3; --bad-bg:#3a1c1c;
    --info:#eceef2; --info-bg:#232830; --credit:#d8b4fe; --credit-bg:#291a3c; --hl:#48400f;
    --hi:#5bd98c; --med:#e7b667; --lo:#f0a3a3; --none:#8a93a3;
    --shadow-sm:0 1px 2px rgba(0,0,0,.4); --shadow-md:0 6px 20px rgba(0,0,0,.5); --shadow-lg:0 20px 48px rgba(0,0,0,.6);
    --header-bg:rgba(21,23,27,.74);
    --toast-bg:#2a313c; --toast-fg:#f4f6f9; --focus:#eceef2;
    --nav:#f6f4ef; --nav-ink:#1e2128; --nav-muted:#62656e; --nav-active:#e7e1d3; --nav-hair:rgba(17,19,24,.14);
  }
  /* ---- base ---- */
  *{box-sizing:border-box}
  body{margin:0;font:14px/1.5 var(--font);color:var(--ink);background:var(--bg);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
  h1,h2,h3,.display{font-family:var(--display);font-weight:600;letter-spacing:-.01em}
  .mono,.figure,.fig,td.num,th.num{font-family:var(--mono)}
  input,select,button,textarea{font-family:inherit}
  a{color:inherit}
  ::selection{background:var(--accent-weak)}
  :focus-visible{outline:3px solid var(--focus);outline-offset:2px}
  .sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
  .skip-link{position:absolute;left:8px;top:-44px;z-index:200;background:var(--accent);color:var(--accent-fg);padding:8px 14px;border-radius:0 0 8px 8px;text-decoration:none;transition:top .15s}
  .skip-link:focus{top:0}
  @media (prefers-reduced-motion: reduce){*{transition:none!important;animation:none!important;scroll-behavior:auto!important}}

  /* ---- legacy top app bar (pages not yet re-skinned still use this) ---- */
  header{position:sticky;top:0;z-index:40;min-height:56px;align-items:center;background:var(--header-bg);
    -webkit-backdrop-filter:saturate(1.4) blur(12px);backdrop-filter:saturate(1.4) blur(12px);border-bottom:1px solid var(--line)}
  header h1{font-weight:600;letter-spacing:-.01em;color:var(--ink)}
  .appnav{display:flex;gap:2px;align-items:center}
  .appnav a{padding:7px 12px;border-radius:9px;color:var(--muted);text-decoration:none;font-weight:500;font-size:13px;white-space:nowrap}
  .appnav a:hover{background:var(--surface-2);color:var(--ink)}
  .appnav a[aria-current="page"]{background:var(--accent-weak);color:var(--accent);font-weight:600}
  .theme-toggle{display:inline-grid;place-items:center;width:34px;height:34px;border-radius:9px;border:1px solid var(--line-strong);background:var(--panel);color:var(--muted);cursor:pointer;padding:0}
  .theme-toggle:hover{background:var(--surface-2);color:var(--ink)}
  .theme-toggle .moon{display:none}.theme-toggle .sun{display:block}
  [data-theme="dark"] .theme-toggle .moon{display:block}[data-theme="dark"] .theme-toggle .sun{display:none}

  /* ---- controls ---- */
  button{border-radius:var(--radius);border:1px solid var(--line-strong);background:var(--panel);color:var(--ink);font-weight:550;transition:background .12s,border-color .12s,box-shadow .12s,color .12s}
  button:hover{background:var(--surface-2)}
  button.primary{background:var(--accent);border-color:var(--accent);color:var(--accent-fg);box-shadow:var(--shadow-sm)}
  button.primary:hover{background:var(--accent-hover);border-color:var(--accent-hover);filter:none}
  button.ghost{background:var(--accent-weak);border-color:transparent;color:var(--accent)}
  input,select,textarea{background:var(--panel);color:var(--ink);border:1px solid var(--line-strong);border-radius:var(--radius)}
  input::placeholder,textarea::placeholder{color:var(--muted)}
  input[type=text],input[type=date],input[type=number]{background:var(--panel)}
  input:focus,select:focus,textarea:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-weak)}
  .card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm)}
  .toast{background:var(--toast-bg);color:var(--toast-fg);border-radius:var(--radius);box-shadow:var(--shadow-lg)}

  /* ---- token-routing for previously hard-coded surfaces (dark-mode correct) ---- */
  .cin,.combo,.combo input{background:var(--panel);color:var(--ink)}
  .combo{border-color:var(--line);box-shadow:var(--shadow-lg)}
  table.grid th{background:var(--surface-2);color:var(--muted)}
  tr.row:hover{background:var(--surface-2)}
  .pane.pdf,.previewpane,.previewpane embed,.previewpane iframe,.dpdf,.dpdf embed,.dpdf iframe{background:var(--surface-2)}
  td.edit:hover .cellbox{border-color:var(--accent)}
  td.dd:hover{background:transparent}
  td.dd .ph{color:var(--none)}
  .confbtn{border-color:transparent}
  .confbtn.hi{background:var(--ok-bg);color:var(--ok)} .confbtn.med{background:var(--warn-bg);color:var(--med)}
  .confbtn.lo{background:var(--bad-bg);color:var(--lo)} .confbtn.flag{background:var(--bad-bg);color:var(--lo)}
  .confbtn.none{background:var(--surface-3);color:var(--muted)}
  .typeflag.t-bill{background:var(--info-bg);color:var(--info)} .typeflag.t-credit{background:var(--credit-bg);color:var(--credit)}
  .pbadge{background:var(--info-bg);color:var(--info)}
  .b-Bill{background:var(--accent-weak);color:var(--accent)} .b-VendorCredit{background:var(--info-bg);color:var(--info)}
  .b-draft{background:var(--warn-bg);color:var(--warn)} .b-committed{background:var(--ok-bg);color:var(--ok)}
  .disc.bad{background:var(--bad-bg);color:var(--bad)} .disc.ok{background:var(--ok-bg);color:var(--ok)}
  .draft:hover{background:var(--surface-2)} .doc:hover{background:var(--surface-2)}
  .badge.b-ready,.badge.b-active{background:var(--ok-bg);color:var(--ok)}
  .badge.b-review,.badge.b-disabled{background:var(--warn-bg);color:var(--warn)}
  .badge.b-failed{background:var(--bad-bg);color:var(--bad)} .badge.b-posted{background:var(--info-bg);color:var(--info)}

  /* ===== App shell: dark sidebar + content (Monograph) ===== */
  .app{display:grid;grid-template-columns:var(--sidebar-w) minmax(0,1fr);min-height:100vh}
  .app.nav-collapsed{grid-template-columns:var(--sidebar-w-collapsed) minmax(0,1fr)}
  .navrail{position:sticky;top:0;align-self:start;height:100vh;background:var(--nav);color:var(--nav-ink);display:flex;flex-direction:column;padding:14px 12px;overflow:hidden;z-index:50}
  .navrail .brand{display:flex;align-items:center;height:30px;padding:0;margin:4px 0 18px;text-decoration:none;white-space:nowrap}
  .navrail .brand img{display:block}
  .navrail .brand .wordmark{height:24px;width:auto;max-width:none;margin-left:10px}   /* 2026-07-07: 30→22px — CAPS wordmark is wider; 22px ≈ 199px fits the 236px legacy rail */
  .navrail .brand .smark{display:none;height:26px;width:auto}
  [data-theme="dark"] .navrail .brand img,[data-theme="dark"] .brandpanel .brandlogo img,[data-theme="dark"] .connect .logo img{filter:invert(1)}
  .app.nav-collapsed .navrail .brand{justify-content:center}
  .app.nav-collapsed .navrail .brand .wordmark{display:none}
  .app.nav-collapsed .navrail .brand .smark{display:block}
  /* brand wordmark that flips with the active theme (auth cards on --bg) */
  img.wm-light{display:block}img.wm-dark{display:none}
  [data-theme="dark"] img.wm-light{display:none}[data-theme="dark"] img.wm-dark{display:block}
  .navrail .nav{display:flex;flex-direction:column;gap:2px;flex:1;min-height:0;overflow-y:auto;overflow-x:hidden}
  .navrail .navitem{display:flex;align-items:center;gap:11px;padding:8px 10px;border-radius:8px;color:var(--nav-muted);text-decoration:none;font:500 13.5px/1.1 var(--font);white-space:nowrap}
  .navrail .navitem svg{flex:0 0 18px;width:18px;height:18px}
  .navrail .navitem:hover{color:var(--nav-ink);background:var(--nav-active)}
  .navrail .navitem.active{color:var(--nav-ink);background:var(--nav-active);font-weight:600}
  .app.nav-collapsed .navrail .navitem{padding:8px 0;justify-content:center}
  .app.nav-collapsed .navrail .navitem .label{display:none}
  .navrail .navfoot{display:flex;align-items:center;gap:6px;margin-top:8px;padding-top:10px;border-top:1px solid var(--nav-hair);flex:0 0 auto}
  .app.nav-collapsed .navrail .navfoot{flex-direction:column}
  .navrail .iconbtn{display:inline-grid;place-items:center;width:34px;height:34px;padding:0;border-radius:8px;border:1px solid var(--nav-hair);background:transparent;color:var(--nav-muted);cursor:pointer;transition:background .12s,border-color .12s}
  .navrail .iconbtn:hover{background:var(--nav-active);border-color:var(--nav-hair);color:var(--nav-ink)}
  .navrail .iconbtn svg{width:18px;height:18px}
  .navrail .iconbtn .moon{display:none}.navrail .iconbtn .sun{display:block}
  [data-theme="dark"] .navrail .iconbtn .moon{display:block}[data-theme="dark"] .navrail .iconbtn .sun{display:none}
  .app.nav-collapsed #navCollapse svg{transform:rotate(180deg)}
  .content{min-width:0;display:flex;flex-direction:column;min-height:100vh}
  .topbar{display:flex;align-items:center;gap:14px;padding:13px 22px;border-bottom:1px solid var(--line);background:var(--bg);position:sticky;top:0;z-index:30}
  .topbar h1{margin:0;font:600 20px/1.2 var(--display);letter-spacing:-.01em;color:var(--ink)}
  .topbar .sub{color:var(--muted);font-size:13px;margin-top:2px}
  .topbar-actions{margin-left:auto;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
  .topbar .brandlogo,.topbar .theme-toggle{display:none}
  /* mobile drawer affordances (hidden on desktop) */
  .navtoggle{display:none;place-items:center;width:38px;height:38px;border-radius:8px;border:1px solid var(--line-strong);background:var(--panel);color:var(--ink);cursor:pointer;flex:0 0 auto;padding:0}
  .navtoggle:hover{background:var(--surface-2)}
  .navtoggle svg{width:20px;height:20px}
  .navscrim{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:70;opacity:0;visibility:hidden;transition:opacity .2s}
  @media (max-width:860px){
    .app,.app.nav-collapsed{grid-template-columns:var(--sidebar-w-collapsed) minmax(0,1fr)}
    .navrail .navitem{padding:8px 10px}
    .navrail .navitem .label{display:none}
    .navrail .brand{justify-content:center}
    .navrail .brand .wordmark{display:none}
    .navrail .brand .smark{display:block}
  }

  /* ---- phones: sidebar becomes an off-canvas drawer ---- */
  @media (max-width:640px){
    .app,.app.nav-collapsed{grid-template-columns:1fr}
    .navrail{position:fixed;left:0;top:0;width:248px;height:100vh;transform:translateX(-100%);transition:transform .22s ease;z-index:80;padding:16px 12px}
    .app.nav-open .navrail{transform:translateX(0);box-shadow:var(--shadow-lg)}
    .app.nav-open .navscrim{opacity:1;visibility:visible}
    .navrail .brand{justify-content:flex-start;margin:2px 0 14px}
    .navrail .brand .wordmark{display:block}
    .navrail .brand .smark{display:none}
    .navrail .navitem{padding:11px 12px}
    .navrail .navitem .label{display:inline}
    #navCollapse{display:none}
    .navtoggle{display:inline-grid}
    .topbar{padding:11px 15px;gap:11px}
    .topbar h1{font-size:17px}
  }

  @media (prefers-contrast: more){:root{--muted:#33404f;--line:#9aa3b1}[data-theme="dark"]{--muted:#c6cfdc;--line:#5b6573}}

  /* =====================================================================
     v3 TOKEN SET — Design v3 program, Wave 0 (docs/KICKOFF_DESIGN_V3.md)
     Source: v3-handoff prototype `themeVarsStr()` / `ACCENTS()` verbatim.
     ADDITIVE-FROZEN after Wave 0: append only — never rename or remove.
     Everything above this banner is the pre-v3 Monograph base (untouched).
     ===================================================================== */
  :root{
    /* surfaces + text (v3 names; light values from themeVarsStr() L) */
    --s2:#efece4; --s3:#e7e1d3; --sub:#44474e; --lineS:#d9d3c6;
    --row-line:#efece4; --row-sel:#eae4d4; --row-focus:#f1eee6; --bar:#d8d2c2;
    --ink-solid:#1e2128;
    --ok-line:#bfe6cc; --ok-deep:#14532d;
    --warn-line:#f3d27a; --warn-deep:#7c4a02;
    --nav-soft:#c8ccd4; --nav-track:#3a3f47;
    /* v3 shadows (kept as new names so legacy --shadow-* stay stable) */
    --shadow-v3-sm:0 1px 2px rgba(31,42,48,.06);
    --shadow-v3-md:0 3px 12px rgba(31,42,48,.1);
    --shadow-v3-lg:0 24px 60px rgba(20,22,26,.3);
    /* wordmark colourway (sidebar rail is dark in v3; paper is default) */
    --logo-color:#f6f4ef; --logo-accent:#eceef2;
    /* density (Aa popover + Review toggle; compact is the default) */
    --row-pad-y:4px; --cell-pad-y:6px;
    /* v3 rail geometry (legacy --sidebar-w untouched) */
    --v3-rail-w:206px; --v3-rail-w-collapsed:58px;
    /* DASH-17: text/hairlines ON an ink-solid surface (dashboard resume card).
       AA at 11px against each theme's --ink-solid (light 7.0:1, dark 6.6:1). */
    --onink-muted:#a6acb5; --onink-line:rgba(255,255,255,.28);
  }
  [data-theme="dark"]{
    --s2:#1c1f24; --s3:#232830; --sub:#b6bcc6; --lineS:#343941;
    --row-line:#1f2227; --row-sel:#2b3040; --row-focus:#20242b; --bar:#3a4048;
    --ink-solid:#2a313c;
    --onink-muted:#b3bac4; --onink-line:rgba(255,255,255,.28);
    --ok-line:#1e5c38; --ok-deep:#9fe6bb;
    --warn-line:#6b5420; --warn-deep:#f0cf9a;
    --shadow-v3-sm:0 1px 2px rgba(0,0,0,.4);
    --shadow-v3-md:0 6px 20px rgba(0,0,0,.5);
    --shadow-v3-lg:0 20px 48px rgba(0,0,0,.6);
  }
  [data-density="comfortable"]{--row-pad-y:8px;--cell-pad-y:9px;--row-fs:13.5px}   /* 2026-07-07: Cosy also scales row text (Max) — --row-fs default lives in the pack tokens below */

  /* ---- accent pairs (ACCENTS(): ink default = no attribute needed) ---- */
  [data-accent="blue"]{--accent:#1D4ED8;--accent-fg:#ffffff;--accent-hover:#1a44c2;--focus:#1D4ED8;--logo-accent:#1D4ED8}
  [data-theme="dark"][data-accent="blue"]{--accent:#5b8bf5;--accent-fg:#0b1020;--accent-hover:#7ba2f7;--focus:#5b8bf5;--logo-accent:#5b8bf5}
  [data-accent="green"]{--accent:oklch(0.45 0.09 165);--accent-fg:#ffffff;--accent-hover:oklch(0.40 0.09 165);--focus:oklch(0.45 0.09 165);--logo-accent:oklch(0.45 0.09 165)}
  [data-theme="dark"][data-accent="green"]{--accent:oklch(0.72 0.1 165);--accent-fg:#0c1712;--accent-hover:oklch(0.78 0.1 165);--focus:oklch(0.72 0.1 165);--logo-accent:oklch(0.72 0.1 165)}
  [data-accent="sienna"]{--accent:oklch(0.55 0.11 45);--accent-fg:#ffffff;--accent-hover:oklch(0.50 0.11 45);--focus:oklch(0.55 0.11 45);--logo-accent:oklch(0.55 0.11 45)}
  [data-theme="dark"][data-accent="sienna"]{--accent:oklch(0.72 0.11 45);--accent-fg:#1c1008;--accent-hover:oklch(0.78 0.11 45);--focus:oklch(0.72 0.11 45);--logo-accent:oklch(0.72 0.11 45)}

  /* ---- logo colourways (logoColorStr(); rail is dark in v3) ---- */
  [data-logo="ink"]{--logo-color:#eceef2}
  [data-logo="blue"]{--logo-color:#1D4ED8}
  [data-theme="dark"][data-logo="blue"]{--logo-color:#3f6df0}
  [data-logo="accent"]{--logo-color:var(--logo-accent)}

  /* ---- v3 rail follows the theme: LIGHT rail in light mode, DARK in dark (mockup) ---- */
  [data-v3]{ --nav:var(--panel); --nav-ink:var(--ink); --nav-muted:var(--muted); --nav-active:var(--accent-weak); --nav-hair:var(--line); --nav-soft:var(--muted); }
  /* wordmark + S-mark are white assets (built for the dark rail) — invert so they read on the light rail (default colourway) */
  [data-theme="light"][data-v3]:not([data-logo]) .v3rail .v3brand{filter:invert(1)}
  /* ---- v3 dark mode keeps the rail DARK (html[data-v3] opt-in only) ---- */
  [data-theme="dark"][data-v3]{
    --nav:#15181e; --nav-ink:#eceef2; --nav-muted:#8b9097; --nav-active:#242a33; --nav-hair:rgba(255,255,255,.12);
  }

  /* =====================================================================
     v3 GLOBAL CHROME (opt-in: html[data-v3] + ShellV3.chrome.mount()).
     Class-prefixed `v3` so nothing collides with legacy pages.
     ===================================================================== */
  @keyframes v3pop{from{opacity:0;transform:scale(.985) translateY(3px)}to{opacity:1;transform:none}}
  @keyframes v3fadeUp{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
  [data-v3] body{font-size:13.5px}
  /* chrome geometry (2026-07-06, Max): FULL-WIDTH top bar, rail starts BELOW it,
     brand lives in the top bar (rendered there by chrome.mount) and clips to its
     leading S when the rail collapses — S keeps its exact position + size. */
  .v3app{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-rows:auto auto minmax(0,1fr);grid-template-areas:"top top" "strip strip" "rail main";height:100vh;overflow:hidden;background:var(--bg);color:var(--ink)}
  /* rail (below the top bar). The collapse ANIMATES the rail's own width — the auto grid
     track follows it each frame. (Transitioning grid-template-columns with minmax() tracks
     is discrete in Chrome = the "sidebar jumps" bug.) */
  .v3rail{grid-area:rail;width:var(--v3-rail-w);min-width:0;transition:width .22s cubic-bezier(.2,.6,.2,1);background:var(--nav);color:var(--nav-ink);display:flex;flex-direction:column;padding:13px 10px 10px;gap:2px;overflow:hidden}   /* r2 2026-07-07 (Max): .18 ease → .22 decelerate — softer collapse */
  .v3app.collapsed .v3rail{width:var(--v3-rail-w-collapsed)}
  /* brand — rail-scoped rules retained but DEAD (brand renders in .v3top since the full-width-header change) */
  .v3rail .v3brand{display:flex;align-items:center;min-height:24px;padding:2px 8px 6px;text-decoration:none;color:var(--logo-color)}
  .v3rail .v3brand .v3wm{display:block;height:21px;width:auto}
  .v3rail .v3brand img.v3sm{display:none;height:22px;width:auto;margin:0 auto}
  .v3app.collapsed .v3rail .v3brand{display:block;width:12px;overflow:hidden;margin:0 auto;padding:2px 0 6px}
  .v3app.collapsed .v3rail .v3brand .v3wm{display:block;height:21px;width:auto;max-width:none}
  .v3app.collapsed .v3rail .v3brand img.v3sm{display:none}
  .v3nav{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:2px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.22) transparent}
  .v3item{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px 9px 7px 11.5px;border-radius:8px;cursor:pointer;font:500 13px/1.2 var(--font);color:var(--nav-muted);background:transparent;text-decoration:none;white-space:nowrap}   /* r2 (Max): padding-left 11.5px pins the icon centre at x≈29 = the collapsed axis — icons no longer MOVE on collapse, only the rail width animates */
  .v3item:hover{color:var(--nav-ink);background:var(--nav-active)}
  .v3item.active{color:var(--nav-ink);background:var(--nav-active);font-weight:600}
  .v3item .v3ic{display:inline-grid;place-items:center;width:15px;min-height:18px;flex:0 0 auto}   /* r3 (Max: "icons move up on collapse"): row height was set by the TALLEST child — badge = 10px + 3+3 pad + 1+1 border = 18px, label line = 15.6px, icon only 15px — so hiding label+badge on collapse shrank each row (badge rows by ~3px) and icons below crept UP. Pinning the icon slot to the badge height makes every row 32px in BOTH states (uniform rhythm; nothing moves) */
  .v3item .v3lbl{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .v3item .v3badge{font:600 10px/1 var(--mono);background:var(--nav-active);border:1px solid var(--nav-hair);color:var(--nav-soft);padding:3px 6px;border-radius:999px}
  .v3app.collapsed .v3item{padding-right:0}   /* r2: no more justify-content:center snap — icon x is constant in both states (11.5px inset) */
  .v3app.collapsed .v3item .v3lbl,.v3app.collapsed .v3item .v3badge{display:none;opacity:0}   /* r2: fades via the allow-discrete transition in the pack section */
  .v3foot{display:flex;align-items:center;gap:5px;padding:8px 2px 4px;border-top:1px solid var(--nav-hair);flex-wrap:wrap}
  .v3app.collapsed .v3foot{justify-content:center;flex-direction:column}
  .v3fbtn{display:inline-grid;place-items:center;width:29px;height:29px;border-radius:8px;border:1px solid var(--nav-hair);background:transparent;color:var(--nav-ink);padding:0;cursor:pointer;font-size:13px}
  .v3fbtn:hover{background:var(--nav-active)}
  .v3fbtn.aa{font:600 12.5px/1 var(--display)}
  .v3hint{font:400 9.5px/1.6 var(--mono);color:var(--nav-muted);padding:5px 8px 0}
  .v3app.collapsed .v3hint{display:none;opacity:0}
  /* content column: dissolved — .v3top/.v3main are grid children of .v3app now */
  .v3content{display:contents}
  /* v3 top bar: full-width row, thin + stays warm-white in BOTH modes (light tokens pinned locally) */
  /* 2026-07-07 pack: pinned hexes → --chrome-* tokens (pixel-identical in light; dark now
     DIMS the bar to rail-level luminance — Max's call, supersedes warm-white-in-both-modes).
     min-height reserves the mounted height so an empty pre-JS header can't grow the page (J2). */
  .v3top{grid-area:top;position:relative;display:flex;align-items:center;gap:12px;padding:7px 16px;min-height:49px;border-bottom:1px solid var(--chrome-line);background:var(--chrome-bg);color:var(--chrome-ink);flex:0 0 auto;--panel:var(--chrome-panel);--panel-2:var(--chrome-s2);--s2:var(--chrome-s2);--s3:var(--chrome-s3);--ink:var(--chrome-ink);--muted:var(--chrome-muted);--faint:var(--chrome-faint);--line:var(--chrome-line);--lineS:var(--chrome-lineS)}
  .v3renewstrip{grid-area:strip;display:none;align-items:center;gap:12px;padding:8px 16px;border-bottom:1px solid var(--warn-line,var(--line));background:var(--warn-bg,var(--s2));color:var(--ink);font:500 12.5px/1.35 var(--font)}
  .v3renewstrip-t{min-width:0}
  .v3renewstrip-grow{flex:1}
  .v3renewstrip-a{font:600 12px/1 var(--font);color:var(--ink);text-decoration:none;white-space:nowrap;padding:6px 10px;border:1px solid var(--lineS);border-radius:8px;background:var(--panel)}
  .v3renewstrip-a:hover{background:var(--s2)}
  .v3renewstrip-x{border:0;background:transparent;color:var(--muted);font:600 18px/1 var(--font);cursor:pointer;padding:2px 6px;border-radius:6px}
  .v3renewstrip-x:hover{color:var(--ink);background:var(--panel)}
  .v3chip.v3renewro{cursor:default;font-size:11px;padding:5px 9px;opacity:.88}
  .v3chip.v3renewro .dot{background:var(--warn)}
  .v3chip.v3renewro:hover{background:var(--panel)}
  /* brand in the top bar — wordmark slightly larger (22px). The zone tracks the rail
     track exactly (rail-w minus the bar's 16px left padding) so header content starts
     at the sidebar edge in both states; the seamless S is an svg clip-path, so the S
     never moves or resizes. NOTE: colour is hard-pinned INK — :root defaults
     --logo-color to #f6f4ef (paper, for the old dark rail), which is invisible on the
     warm-white bar (the 2026-07-06 "no logo" bug). Only blue/accent colourways override. */
  .v3top .v3brand{display:flex;align-items:center;flex:0 0 auto;width:calc(var(--v3-rail-w) - 16px);padding-left:5px;overflow:hidden;text-decoration:none;color:var(--chrome-ink);transition:width .22s cubic-bezier(.2,.6,.2,1)}   /* r7: 5px inset — at 24px the S centre is 8.02px into the mark, so 16 pad + 5 inset puts the S axis at x≈29.02 = the icon axis (the standing r4 constraint; the r4 both-constraints-solve note applied to the CAPS mark and is superseded). Ink → --chrome-ink (bar dims in dark). Curve matches the rail. */
  .v3top .v3brand .v3wm{display:block;flex:0 0 auto;height:24px;width:auto;max-width:none;transition:clip-path .22s cubic-bezier(.2,.6,.2,1)}   /* flex:0 0 auto — never flex-shrink the svg: shrinking scales the artwork (preserveAspectRatio) = the "mini wordmark" bug; the S must stay full-size and be CLIPPED, not scaled. r7 sizing (Max, 2026-07-20): 22→24px, all marks slightly bigger except favicon + the connect-page S. At 24px the S optical centre sits 8.02px in; the brand inset drops 6→5px so the S axis stays x≈29.02 vs icon axis x29 (the r4 constraint, held within 0.1px). Collapse clip re-derived 14.5→15.8px (S right edge 15.60px, c starts ≈18.0px). */
  .v3top .v3brand img.v3wm{filter:invert(1)}   /* white <img> asset → ink until the inline-SVG (currentColor) swap */
  [data-theme="dark"] .v3top .v3brand img.v3wm{filter:none}   /* 2026-07-07: dark chrome — white asset already reads on the dim bar */
  .v3top .v3brand img.v3sm{display:none}
  .v3app.collapsed .v3top .v3brand{width:calc(var(--v3-rail-w-collapsed) - 16px)}
  .v3app.collapsed .v3top .v3brand .v3wm{clip-path:inset(0 calc(100% - 15.8px) 0 0)}   /* show only the leading S. r7 @24px: S ends 15.60px, c starts ≈18.0px → 15.8px clips a clean S, no c sliver */
  [data-logo="blue"] .v3top .v3brand{color:var(--logo-color)}
  [data-logo="accent"] .v3top .v3brand{color:var(--logo-accent)}
  .v3back{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border:1px solid var(--lineS);border-radius:8px;background:var(--panel);color:var(--ink);font:600 12.5px/1 var(--font);cursor:pointer;white-space:nowrap}
  .v3back:hover{background:var(--s2)}
  .v3titlebox{min-width:0}
  .v3title{font:600 17px/1.15 var(--display);letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ink)}
  .v3crumb{font:400 11.5px/1.2 var(--font);color:var(--muted);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .v3spacer{flex:1}
  .v3chip{display:inline-flex;align-items:center;gap:7px;padding:7px 11px;border:1px solid var(--lineS);border-radius:999px;background:var(--panel);white-space:nowrap;cursor:pointer;font:500 12px/1 var(--font);color:var(--ink)}
  .v3chip:hover{background:var(--s2)}
  .v3chip .dot{width:7px;height:7px;border-radius:50%;background:var(--ok);display:inline-block}
  .v3chip .sub{font:400 10.5px/1 var(--mono);color:var(--muted)}
  .v3searchbtn{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;border:1px solid var(--lineS);border-radius:9px;background:var(--panel);color:var(--muted);font:500 12.5px/1 var(--font);cursor:pointer}
  .v3searchbtn:hover{background:var(--s2);color:var(--ink)}
  .v3kbd{font:600 10px/1 var(--mono);border:1px solid var(--lineS);border-radius:5px;padding:2px 5px;background:var(--s2);color:var(--ink)}
  .v3addbtn{padding:9px 14px;border:1px solid var(--accent);border-radius:9px;background:var(--accent);color:var(--accent-fg);font:600 12.5px/1 var(--font);white-space:nowrap;cursor:pointer;text-decoration:none;display:inline-block}
  .v3addbtn:hover{background:var(--accent-hover);border-color:var(--accent-hover)}
  .v3main{grid-area:main;min-width:0;flex:1;min-height:0;overflow:auto;padding:14px 18px 32px}
  .v3screen{animation:v3fadeUp .25s ease}
  /* popover base (practice switcher, appearance, filters) */
  .v3pop{position:absolute;z-index:120;background:var(--panel);border:1px solid var(--lineS);border-radius:11px;box-shadow:var(--shadow-v3-lg);overflow:hidden;animation:v3pop .15s ease}
  .v3pop .v3popsec{padding:10px 13px 8px;border-bottom:1px solid var(--line)}
  /* appearance popover */
  .v3appear{position:fixed;z-index:140;width:238px;background:var(--panel);border:1px solid var(--lineS);border-radius:11px;box-shadow:var(--shadow-v3-lg);padding:13px 15px;animation:v3pop .15s ease;color:var(--ink)}
  .v3appear .h{font:600 10px/1 var(--font);letter-spacing:.07em;text-transform:uppercase;color:var(--muted);margin:11px 0 6px}
  .v3appear .h:first-child{margin-top:0}
  .v3seg{display:inline-flex;border:1px solid var(--lineS);border-radius:8px;overflow:hidden}
  .v3seg button{padding:6px 12px;border:0;border-radius:0;background:var(--panel);color:var(--muted);font:600 11.5px/1 var(--font);cursor:pointer}
  .v3seg button+button{border-left:1px solid var(--lineS)}
  .v3seg button.on{background:var(--s3);color:var(--ink)}
  .v3sw{width:26px;height:26px;border-radius:50%;border:1px solid var(--lineS);cursor:pointer;padding:0;outline-offset:2px}
  .v3sw.on{outline:2px solid var(--accent)}
  .v3logorow{display:flex;align-items:center;gap:9px;border:0;background:transparent;padding:4px 2px;cursor:pointer;text-align:left;width:100%;border-radius:6px;color:var(--ink);font-size:12px}
  .v3logorow:hover{background:var(--s2)}
  .v3logorow .sw{width:16px;height:16px;border-radius:5px;border:1px solid var(--lineS);display:inline-block}
  .v3logorow.on .sw{outline:2px solid var(--accent);outline-offset:1px}
  /* global filters */
  .v3filters{display:inline-flex;align-items:center;gap:8px;position:relative;flex-wrap:wrap}
  .v3fsup{display:inline-flex;align-items:center;gap:7px;padding:6px 11px;border:1px solid var(--lineS);border-radius:8px;background:var(--panel);color:var(--ink);font:600 12px/1 var(--font);cursor:pointer}
  .v3fsup:hover{background:var(--s2)}
  .v3fsup .val{font:500 12px/1 var(--font);color:var(--ink)}
  .v3fsup .cnt{font:600 10px/1 var(--mono);background:var(--accent);color:var(--accent-fg);padding:3px 6px;border-radius:999px}
  .v3fsup .v3fic{width:13px;height:13px;color:var(--muted);flex:0 0 auto}
  .v3fsup .v3fcar{color:var(--faint);font-size:10px;margin-left:1px}
  .v3fpopdate .v3fdaterow{display:flex;flex-direction:column;gap:8px;padding:4px 2px 2px}
  .v3fpopdate .v3fdlab{display:flex;flex-direction:column;gap:4px;font:600 10px/1.3 var(--font);color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
  .v3fpopdate .v3fdlab .v3fdate{width:100%}
  .v3fdate{border:1px solid var(--lineS);border-radius:8px;background:var(--panel);color:var(--ink);padding:5px 7px;font:500 11px/1 var(--mono)}
  .v3fclear{border:0;background:none;color:var(--warn);font:600 11.5px/1 var(--font);text-decoration:underline;text-underline-offset:3px;cursor:pointer;padding:0}
  .v3fpop{position:absolute;top:34px;left:0;z-index:60;width:242px;background:var(--panel);border:1px solid var(--lineS);border-radius:10px;box-shadow:var(--shadow-v3-lg);padding:7px;max-height:290px;overflow:auto;animation:v3pop .12s ease}
  .v3fpop .hint{font:400 10px/1.5 var(--mono);color:var(--muted);padding:3px 8px 6px}
  .v3fopt{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:7px;cursor:pointer;color:var(--ink)}
  .v3fopt:hover{background:var(--s2)}
  .v3fopt .box{width:14px;height:14px;border-radius:4px;border:1px solid var(--lineS);display:inline-grid;place-items:center;color:var(--accent-fg);font:700 9px/1 var(--mono);flex:0 0 auto;background:var(--panel)}
  .v3fopt.on .box{background:var(--accent);border-color:var(--accent)}
  .v3fopt .nm{font-size:12px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .v3fopt .n{font:400 10px/1 var(--mono);color:var(--muted)}
  .v3ffoot{display:flex;justify-content:space-between;padding:6px 8px 2px;border-top:1px solid var(--line);margin-top:5px}
  .v3ffoot .clear{border:0;background:none;color:var(--muted);font:600 11px/1 var(--font);text-decoration:underline;text-underline-offset:2px;cursor:pointer;padding:0}
  .v3ffoot .done{border:0;background:none;color:var(--accent);font:600 11px/1 var(--font);cursor:pointer;padding:0}
  .v3fnarrowdates{display:none;flex-direction:column;gap:6px;padding:2px 8px 8px;border-bottom:1px solid var(--line);margin-bottom:5px}
  .v3fsup.narrow{display:none}
  /* ⌘K palette */
  .v3palov{position:fixed;inset:0;background:rgba(20,22,26,.38);z-index:200;display:flex;justify-content:center;align-items:flex-start;padding-top:110px}
  .v3pal{width:600px;max-width:92vw;background:var(--panel);border:1px solid var(--lineS);border-radius:13px;box-shadow:var(--shadow-v3-lg);overflow:hidden;animation:v3pop .15s ease}
  .v3pal input{width:100%;box-sizing:border-box;border:0;border-bottom:1px solid var(--line);background:var(--panel);padding:15px 18px;font-size:14.5px;outline:none;color:var(--ink);border-radius:0}
  .v3pal input:focus{box-shadow:none;border-color:var(--line)}
  .v3palrows{max-height:380px;overflow:auto;padding:7px}
  .v3palrow{display:flex;align-items:center;gap:11px;padding:9px 11px;border-radius:8px;cursor:pointer}
  .v3palrow.on,.v3palrow:hover{background:var(--s2)}
  .v3palrow .kind{flex:0 0 62px;font:700 9.5px/1 var(--mono);letter-spacing:.05em;padding:4px 0;border-radius:5px;text-align:center}
  .v3palrow .kind.doc{color:var(--ink);background:var(--s3)}
  .v3palrow .kind.sup{color:var(--ok);background:var(--ok-bg)}
  .v3palrow .kind.scr{color:var(--muted);background:var(--s2)}
  .v3palrow .lbl{font-size:13px;font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .v3palrow .sub{font:400 11px/1 var(--mono);color:var(--muted);white-space:nowrap;margin-left:auto}
  .v3palfoot{padding:9px 16px;border-top:1px solid var(--line);font:400 10.5px/1 var(--mono);color:var(--muted);display:flex;gap:12px}
  /* toasts (queued, bottom-right) */
  .v3toasts{position:fixed;right:20px;bottom:20px;z-index:300;display:flex;flex-direction:column;gap:8px;align-items:flex-end}
  /* the 100vw clamp matches .v3popover: the container is pinned right:20px with no left,
     so a flat 420px overhangs the left edge of a 375px phone. It never bit while toasts
     said "Saved" and "Copied"; the VAT advisories are the first to put a full sentence in
     one (C3). */
  .v3toast{background:var(--toast-bg);color:var(--toast-fg);border-radius:9px;padding:12px 16px;box-shadow:var(--shadow-v3-lg);max-width:min(420px,calc(100vw - 40px));animation:v3pop .18s ease}
  /* pre-line so the overflow VAT-notes toast can put one sentence per line (C3); every
     other toast is a single line and is unaffected */
  .v3toast .msg{font-size:13px;font-weight:600;white-space:pre-line}
  .v3toast .sub{font:400 11px/1.5 var(--mono);color:var(--nav-soft);margin-top:3px}
  /* keyboard-shortcuts overlay */
  .v3keysov{position:fixed;inset:0;background:rgba(20,22,26,.38);z-index:220;display:grid;place-items:center}
  .v3keys{width:420px;max-width:92vw;background:var(--panel);border:1px solid var(--lineS);border-radius:13px;box-shadow:var(--shadow-v3-lg);padding:20px 22px;animation:v3pop .15s ease;color:var(--ink)}
  .v3keys h2{margin:0 0 4px;font:600 17px/1.2 var(--display)}
  .v3keys .note{font-size:11.5px;color:var(--muted);margin-bottom:12px}
  .v3keys .row{display:flex;align-items:center;gap:10px;padding:6px 0;border-bottom:1px solid var(--s2)}
  .v3keys .k{flex:0 0 96px;font:600 11px/1 var(--mono);border:1px solid var(--lineS);border-radius:5px;padding:4px 7px;background:var(--s2);text-align:center}
  .v3keys .d{font-size:12.5px}
  /* density-aware table helper (v3 grids opt in with .v3grid) */
  table.v3grid td{padding-top:var(--row-pad-y);padding-bottom:var(--row-pad-y)}
  table.v3grid th{padding-top:var(--cell-pad-y);padding-bottom:var(--cell-pad-y)}
  /* responsive: <1180 search folds to icon, chip hides its caption */
  @media (max-width:1180px){
    .v3searchbtn .txt,.v3searchbtn .v3kbd{display:none}
    .v3chip .sub{display:none}
    .v3filters .widedates{display:none}
    .v3fsup.narrow{display:inline-flex}
    .v3fnarrowdates{display:flex}
  }
  @media (max-width:640px){
    /* 2026-07-07 pack: phones get a DRAWER instead of no nav at all (v3 pages were
       dead-ends ≤640 — rail was display:none with no toggle; design-review §2 🔴). */
    .v3app{grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto minmax(0,1fr);grid-template-areas:"top" "strip" "main"}
    .v3rail{position:fixed;left:0;top:0;bottom:0;width:248px;z-index:180;transform:translateX(-100%);transition:transform .22s ease}
    .v3app.nav-open .v3rail{transform:translateX(0);box-shadow:var(--shadow-v3-lg)}
    .v3app.nav-open .v3navscrim{opacity:1;visibility:visible}
    .v3navtoggle{display:inline-grid}
    .v3top .v3brand{width:22px;padding-left:2px}
    .v3top .v3brand .v3wm{clip-path:inset(0 calc(100% - 15.8px) 0 0)}   /* S-only on phones (same clip-to-S technique; 15.8px = scan-line S @24px, r7) */
  }

  /* =====================================================================
     DESIGN-REVIEW PACK — 2026-07-07 (lane 7; docs/design/design-review-2026-07-06/)
     APPEND-ONLY section per the additive freeze. Contents:
     ① --chrome-* tokens (warm light bar unchanged; dark bar now DIMS — Max's call)
     ② cross-document view transitions: chrome pinned, content cross-fades (J1/J5)
     ③ pre-paint collapsed state via html.navc (set by each page's head boot) (J3)
     ④ boot transition-freeze (html.v3boot, removed by shell.js after first frame)
     ⑤ density: Cosy scales row text via --row-fs (Max) — pads were already wired
     ⑥ stable scroll gutters on real y-scrollers (J6) · drawer affordances · search centring
     ⑦ self-host font faces — COMMENTED until the .woff2 files land (see fonts/README.md)
     ===================================================================== */
  :root{
    --chrome-bg:#fffdf9; --chrome-ink:#1e2128; --chrome-muted:#62656e; --chrome-faint:#9a978c;
    --chrome-line:#e8e3d8; --chrome-lineS:#d9d3c6;
    --chrome-panel:#fffdf9; --chrome-s2:#efece4; --chrome-s3:#e7e1d3;
    --row-fs:12.5px;   /* compact default; Cosy = 13.5px (data-density block above) */
  }
  [data-theme="dark"]{
    /* dim chrome: bar sits at rail luminance (#15181e = the v3 dark rail) so the
       chrome reads as one quiet band; content stays the brightest thing on screen */
    --chrome-bg:#15181e; --chrome-ink:#eceef2; --chrome-muted:#9aa0a8; --chrome-faint:#6f7683;
    --chrome-line:#23262b; --chrome-lineS:#343941;
    --chrome-panel:#1c1f24; --chrome-s2:#242a33; --chrome-s3:#2b3240;
  }

  /* ② view transitions — same-origin MPA navs cross-fade; the rail + top bar are
     named groups with zero-duration animations = visually PINNED across pages.
     Firefox ignores the at-rule (falls back to a normal nav). */
  @view-transition{navigation:auto}
  [data-v3] .v3rail{view-transition-name:v3rail}
  [data-v3] .v3top{view-transition-name:v3top}
  ::view-transition-group(v3rail),::view-transition-group(v3top){animation-duration:0s}
  ::view-transition-old(root),::view-transition-new(root){animation-duration:.16s}
  @media (prefers-reduced-motion:reduce){@view-transition{navigation:none}}
  /* J5: where view transitions exist, the per-page slide-up is redundant motion */
  @supports (view-transition-name:none){[data-v3] .v3screen{animation:none}}

  /* ③ pre-paint collapse — html.navc mirrors .v3app.collapsed and is set in <head>,
     so a collapsed rail PAINTS collapsed (no 206→58 slide on load). Desktop-scoped:
     the phone drawer (≤640) must keep its full width. shell.js keeps both in sync. */
  @media (min-width:641px){
    html.navc .v3app .v3rail{width:var(--v3-rail-w-collapsed)}
    html.navc .v3app .v3item{padding-right:0}
    html.navc .v3app .v3item .v3lbl,html.navc .v3app .v3item .v3badge{display:none;opacity:0}
    html.navc .v3app .v3foot{justify-content:center;flex-direction:column}
    html.navc .v3app .v3hint{display:none;opacity:0}
    html.navc .v3top .v3brand{width:calc(var(--v3-rail-w-collapsed) - 16px)}
    html.navc .v3top .v3brand .v3wm{clip-path:inset(0 calc(100% - 15.8px) 0 0)}
  }
  /* ④ no width/clip transitions during boot — a late-applied state must SNAP, not slide */
  html.v3boot .v3rail,html.v3boot .v3top .v3brand,html.v3boot .v3top .v3brand .v3wm{transition:none!important}

  /* ⑤ density text-size: v3 grids opt in via the existing .v3grid helper; page-local
     grids consume var(--row-fs,12.5px) directly (rolled out per page) */
  table.v3grid td{font-size:var(--row-fs)}

  /* ⑥ layout stability + drawer + search centring */
  .v3main{scrollbar-gutter:stable}
  .v3navtoggle{display:none;place-items:center;width:36px;height:36px;border-radius:8px;border:1px solid var(--lineS);background:var(--panel);color:var(--ink);cursor:pointer;flex:0 0 auto;padding:0}
  .v3navtoggle svg{width:19px;height:19px}
  .v3navscrim{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:170;opacity:0;visibility:hidden;transition:opacity .2s}
  @media (min-width:1181px){
    /* true-centre the ⌘K search so the chrome stops shifting page-to-page as the
       right cluster (practice chip / add button) changes width */
    .v3top .v3searchbtn{position:absolute;left:50%;transform:translateX(-50%);width:min(340px,30vw)}
  }

  /* ⑦ Monograph fonts, self-hosted. LIVE since 2026-08-06: the four .woff2 files
     landed in app/static/fonts/ and their filenames are in main.py _ALLOWED_ASSETS.
     Both faces are OFL licensed and the licences ship beside them.

     SELF-HOSTED, NEVER GOOGLE FONTS AT RUNTIME. Same origin, so no CSP change, and
     no third-party request from a page that tells the reader there are no
     third-party tracking cookies.

     font-display:optional is doing real work and must stay. It means the browser
     will NOT swap the font in late: if the file is not already cached when layout
     happens, that paint keeps the fallback and the next one is instant serif from
     cache. So shipping these cannot reintroduce layout shift on a first visit,
     which is the usual cost of adopting a webfont and the reason this block waited
     for the files rather than pointing at ones that did not exist. */
  @font-face{font-family:"Source Serif 4";src:url("/assets/SourceSerif4-Semibold.woff2") format("woff2");font-weight:600;font-style:normal;font-display:optional}
  @font-face{font-family:"Source Serif 4";src:url("/assets/SourceSerif4-Regular.woff2") format("woff2");font-weight:400;font-style:normal;font-display:optional}
  @font-face{font-family:"IBM Plex Mono";src:url("/assets/IBMPlexMono-Regular.woff2") format("woff2");font-weight:400;font-style:normal;font-display:optional}
  @font-face{font-family:"IBM Plex Mono";src:url("/assets/IBMPlexMono-Medium.woff2") format("woff2");font-weight:500;font-style:normal;font-display:optional}
  /* Georgia, metric-adjusted to sit closer to Source Serif so the fallback paint
     and the webfont paint differ as little as possible. */
  @font-face{font-family:"Georgia-adjusted";src:local("Georgia");size-adjust:96%;ascent-override:92%;font-display:swap}

  /* ---- r2 (2026-07-07, Max's post-deploy feedback): softer collapse ----
     ① icons pinned to one axis (item padding-left 11.5px, both states — the old
        justify-content:center flip snapped mid-animation; now width alone animates)
     ② labels / badges / hint FADE out-in instead of popping: display transitions
        via allow-discrete (Chrome 117+ / FF 129+ / Safari 18; older = instant, as before)
     ③ one .22s decelerate curve across rail width · brand zone · clip-path
     ④ wordmark 19.4px: E→title gap (9px zone remainder + 12px bar gap = 21px)
        ≈ S→header-left gap (16px pad + 5.5px inset) */
  .v3item .v3lbl,.v3item .v3badge,.v3hint{transition:opacity .14s ease,display .14s allow-discrete}
  @starting-style{
    .v3item .v3lbl,.v3item .v3badge,.v3hint{opacity:0}
  }

  /* ---- 2026-07-09 (announced, additive): QBO sync freshness indicator (top bar).
     Spinner only while syncing; respects reduced-motion. ---- */
  .v3sync{display:inline-flex;align-items:center;gap:6px;font:600 10.5px/1 var(--mono);color:var(--muted);border:1px solid var(--lineS);border-radius:999px;padding:6px 10px;cursor:pointer;background:var(--panel);white-space:nowrap;user-select:none}
  .v3sync:hover{color:var(--ink);background:var(--s2)}
  .v3sync.busy{color:var(--accent);border-color:var(--accent)}
  .v3sync .ic{display:inline-grid;place-items:center}
  .v3sync .ic.sp{animation:v3syncspin 1s linear infinite}
  @keyframes v3syncspin{to{transform:rotate(360deg)}}
  @media (prefers-reduced-motion: reduce){.v3sync .ic.sp{animation:none;opacity:.6}}
  @media (max-width:760px){.v3sync{display:none}}

  /* ---- 2026-07-10 (announced, additive): native form controls follow the app theme.
     Without a color-scheme declaration the browser styles <input type=date> calendar
     icons (and scrollbars) for a LIGHT UA regardless of data-theme — the filter
     popover's date icons read inverted in both modes (Max). ---- */
  :root{color-scheme:light}
  [data-theme="dark"]{color-scheme:dark}

  /* ---- 2026-07-10 design-qa (appended, additive): toast subtitles must not route
     through the rail token --nav-soft — the [data-v3] flip redefines it to --muted,
     which lands ~2.8:1 on the dark toast surface in light mode. Pair text on the
     toast surface with the toast foreground token instead (overrides the .v3toast
     .sub rule above). ---- */
  .v3toast .sub{color:var(--toast-fg);opacity:.72}

  /* ---- 2026-07-10 design-qa(E) (appended, additive): the top-bar sync chip is now a
     real <button> (click-to-sync had no keyboard path as a span). The .v3sync block
     above already pins font/border/background/padding; this only clears the remaining
     UA button defaults. ---- */
  .v3sync{margin:0;-webkit-appearance:none;appearance:none}

  /* ---- 2026-07-10 (appended, additive; Max nav ruling): the chrome back button is
     retired — detail pages opt into a circular X-close at the far right of the top
     bar instead (ShellV3.chrome.mount({closeX:'/route'})). Dirty pages intercept it
     via window.__v3DirtyGuard. The .v3back rules above stay in place, now unused. ---- */
  .v3closex{width:30px;height:30px;flex:0 0 auto;display:inline-grid;place-items:center;margin:0;padding:0;border:1px solid var(--lineS);border-radius:50%;background:var(--panel);color:var(--ink);font:600 13px/1 var(--font);cursor:pointer;-webkit-appearance:none;appearance:none}
  .v3closex:hover{background:var(--s2)}
  .v3closex:focus-visible{outline:3px solid var(--focus);outline-offset:2px}

  /* =====================================================================
     E-membership W6 — company switcher (top-bar chrome + popover).
     Ported VERBATIM from docs/mockups/membership/topbar-switcher.html
     (Fable-reviewed + Max-corrected). Var-only: NO per-company colour — the
     company mark is strictly monochrome (--s3 / --ink), immune to the per-user
     data-accent system, so a bookkeeper's accent is never imposed on a client.
     DORMANT: nothing renders these classes on a legacy page (shell.js mounts the
     switcher ONLY when window.__WS is set), so the whole block is inert until
     workspace mode — byte-identical to today.
     ===================================================================== */
  /* TRIGGER — .v3chip lineage; lives in .v3top so tokens resolve to --chrome-* */
  .v3ws{display:inline-flex;align-items:center;gap:7px;flex:0 0 auto;padding:5px 11px 5px 6px;min-height:30px;border:1px solid var(--lineS);border-radius:999px;background:var(--panel);color:var(--ink);font:500 12px/1 var(--font);cursor:pointer;white-space:nowrap}
  .v3ws:hover{background:var(--s2)}
  .v3ws .nm{font:600 12px/1 var(--font);color:var(--ink);max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .v3ws .car{font-size:9px;line-height:1;color:var(--faint, var(--chrome-faint));flex:0 0 auto}
  @media (max-width:1180px){.v3ws .nm{max-width:120px}}
  @media (max-width:640px){.v3ws .nm{max-width:90px}}
  /* COMPANY MARK — deterministic monogram; strictly monochrome (no --accent) */
  .v3wsmark{width:20px;height:20px;flex:0 0 auto;border-radius:5px;background:var(--s3);color:var(--ink);font:700 9px/1 var(--mono);letter-spacing:.02em;display:inline-grid;place-items:center}
  .v3wsrow .v3wsmark,.v3wscur .v3wsmark{width:18px;height:18px}
  /* POPOVER — extends .v3pop; 6px inner padding so 3px focus rings don't clip */
  .v3wspop{width:280px;padding:6px}
  /* P1-1 review fix: the mockup's placement rule (was never ported) — hang the
     popover BELOW the trigger instead of overlaying it. The mount wraps trigger+pop
     in .v3ws-anchor (position:relative), so this positions pop within that anchor. */
  .v3ws-anchor .v3wspop{top:calc(100% + 6px);left:0}
  /* narrow-viewport right-edge clamp: a 280px pop left-aligned near the leading edge
     would overflow a small screen — right-align it and cap its width to the viewport. */
  @media (max-width:520px){.v3ws-anchor .v3wspop{left:auto;right:0;max-width:calc(100vw - 24px)}}
  /* FILTER INPUT — .v3pal input idiom scaled down */
  .v3wsfilter{width:100%;border:0;border-bottom:1px solid var(--line);background:var(--panel);padding:10px 12px;font:400 12.5px/1 var(--font);color:var(--ink);border-radius:0;outline:none;margin-bottom:2px}
  .v3wsfilter::placeholder{color:var(--muted)}
  .v3wsfilter:focus{box-shadow:none;border-color:var(--line)}
  /* ROWS region */
  .v3wsrows{list-style:none;margin:0;padding:0;max-height:380px;overflow:auto;scrollbar-width:thin}
  .v3wsh{font:600 10px/1 var(--font);letter-spacing:.07em;text-transform:uppercase;color:var(--muted);margin:11px 4px 6px}
  .v3wsli{display:flex;gap:4px;align-items:stretch}
  /* CURRENT ROW — first, non-interactive, not focusable */
  .v3wscur{display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--row-sel);margin-bottom:2px}
  .v3wscur .nm{font:600 12.5px/1.2 var(--font);color:var(--ink);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .v3wscur .chk{font:700 12px/1 var(--mono);color:var(--ink);flex:0 0 auto}
  /* ROW PRIMARY LINK — Max ruling: SAME-TAB switch to /w/{slug} */
  .v3wsrow{flex:1;display:flex;align-items:center;gap:8px;min-width:0;min-height:36px;padding:7px 9px;border-radius:8px;text-decoration:none;color:var(--ink)}
  .v3wsrow:hover{background:var(--s2)}
  .v3wsrow .nm{font:500 12.5px/1.2 var(--font);color:var(--ink);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* NEW-TAB CONTROL — always-visible ↗; target=_blank opens a real browser tab */
  .v3wshere{width:28px;height:28px;flex:0 0 auto;align-self:center;display:inline-grid;place-items:center;border-radius:7px;text-decoration:none;color:var(--muted);font-size:12px}
  .v3wshere:hover,.v3wshere:focus-visible{background:var(--s2);color:var(--ink)}
  /* OPERATOR CONSOLE ROW (superadmin only) */
  .v3wsdiv{border-top:1px solid var(--line);margin:6px 0}
  .v3wsconsole{display:block;padding:9px;border-radius:8px;text-decoration:none;font:600 10.5px/1 var(--mono);letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}
  .v3wsconsole:hover{background:var(--s2);color:var(--ink)}
  /* FOOTER */
  .v3wsfoot{border-top:1px solid var(--line);margin-top:4px;padding-top:2px}
  .v3wshint{font:400 10px/1.5 var(--mono);color:var(--muted);padding:8px 9px 2px}
  .v3wsinvite{padding:4px 9px 8px;font:400 10.5px/1.45 var(--font);color:var(--muted)}
  .v3wsinvite .em{font-family:var(--mono)}
  .v3wsempty{text-align:center;font:400 12px/1.45 var(--font);color:var(--muted);padding:18px 0}

  /* =====================================================================
     E-membership P1-3 — post-login COMPANY PICKER ("Choose a company").
     Ported VERBATIM from docs/mockups/membership/org-picker.html (Fable-reviewed).
     Var-only (no per-company colour; marks stay monochrome --s3/--ink). DORMANT:
     nothing renders these classes until identity_from_membership is ON and the
     picker route is served — byte-identical to today for every existing page.
     ===================================================================== */
  .picker{width:100%;max-width:440px;box-shadow:none;padding:0}
  .picker h1{font:600 30px/1.1 var(--display);letter-spacing:-.01em;margin:0;text-align:left;color:var(--ink)}
  .picker .sub{font:400 13.5px/1.5 var(--font);color:var(--muted);text-align:left;margin:8px 0 22px}
  /* filter (only when >=8 rows) */
  .pkfilterwrap{margin:0 0 8px}
  .pkfilterfield{position:relative}
  .pkfilterfield svg{position:absolute;left:11px;top:50%;transform:translateY(-50%);width:15px;height:15px;color:var(--muted);pointer-events:none}
  .pkfilter{width:100%;padding:10px 12px 10px 34px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--panel);color:var(--ink);font:inherit}
  .pkfilter::placeholder{color:var(--muted)}
  .pkfilter:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-weak)}
  .pkfilter:focus:not(:focus-visible){outline:none}
  .pkcount{display:block;text-align:right;font:400 11px/1 var(--mono);color:var(--muted);margin:8px 2px 6px}
  /* company list */
  .pknav{margin:0}
  .pklist{list-style:none;margin:0;padding:0}
  .pklist.scroll{max-height:min(58vh,448px);overflow-y:auto;scrollbar-gutter:stable}
  .pkli{display:flex;align-items:center;gap:4px;min-height:56px;border-bottom:1px solid var(--line)}
  .pkli:last-child{border-bottom:0}
  .pkrow{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:12px;min-height:56px;padding:10px 12px;border-radius:var(--radius);text-decoration:none;color:inherit}
  .pkrow:hover{background:var(--surface-2)}
  .pkli.sel .pkrow{background:var(--row-sel)}
  .pkmark{flex:0 0 auto;width:28px;height:28px;border-radius:7px;background:var(--s3);color:var(--ink);font:600 11px/1 var(--mono);display:grid;place-items:center}
  .pktext{min-width:0;display:flex;flex-direction:column;gap:2px}
  .pkname{font:600 14px/1.25 var(--font);color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pkmeta{font:400 11px/1.2 var(--mono);color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pkspacer{margin-left:auto}
  .pktag{flex:0 0 auto;background:var(--accent-weak);color:var(--accent);font:600 10px/1 var(--mono);letter-spacing:.05em;text-transform:uppercase;padding:3px 7px;border-radius:999px}
  .pkopen{flex:0 0 auto;width:28px;height:28px;display:grid;place-items:center;color:var(--muted);border-radius:var(--radius);text-decoration:none}
  .pkopen svg{width:15px;height:15px}
  .pkopen:hover,.pkopen:focus-visible{color:var(--ink);background:var(--s2)}
  /* filter no-match */
  .pknomatch{padding:16px 12px;color:var(--muted);font:400 13px/1.5 var(--font)}
  .lnkbtn{border:0;background:none;padding:0;margin-left:6px;color:var(--accent);font:600 13px/1 var(--font);cursor:pointer;text-decoration:underline;text-underline-offset:3px}
  /* footer identity strip */
  .pkfoot{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:18px;padding-top:14px;border-top:1px solid var(--line);font:400 12px/1.4 var(--font);color:var(--muted)}
  .pkfoot .em{font-family:var(--mono)}
  .pksignout{display:inline-flex;align-items:center;min-height:24px;padding:2px 2px;color:var(--accent);font-weight:600;text-decoration:none;background:none;border:0;cursor:pointer;font-family:inherit;font-size:inherit}
  .pksignout:hover{text-decoration:underline;text-underline-offset:3px}
  /* 0-active card */
  .pkfact{display:flex;align-items:center;gap:10px;background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius);padding:12px 13px;margin:0 0 16px}
  .pkfact svg{flex:0 0 auto;width:16px;height:16px;color:var(--muted)}
  .pkfact .em{font:500 13px/1.2 var(--mono);color:var(--ink);word-break:break-all}
  .pkbody{font:400 13.5px/1.6 var(--font);color:var(--muted);margin:0 0 12px}
  .pkreassure{font:400 12px/1.55 var(--font);color:var(--muted);margin:0 0 20px}
  .pkbtn2{display:block;width:100%;padding:12px;border:1px solid var(--line-strong);border-radius:var(--radius);background:var(--panel);color:var(--ink);font:600 15px/1 var(--font);text-align:center;text-decoration:none;cursor:pointer}
  .pkbtn2:hover{background:var(--surface-2)}
  @media (max-width:820px){
    .pklist.scroll{max-height:none;overflow:visible}
    .pkrow{min-height:52px}
    .pkopen{width:44px;height:44px}
    .pksignout{min-height:44px}
  }

  /* ============================================================
     WS-D — shared money/action confirm modal (ShellV3.confirm) + company plate.
     Token-only; inert until a modal is mounted, so legacy pages are byte-identical.
     Ported from docs/mockups/membership/money-confirm.html: role=alertdialog,
     company plate in the header + two-segment primary button (verb 700 + company
     500, BOTH --accent-fg @100%; weight is the only differentiator — WCAG 1.4.1).
     ============================================================ */
  .v3plate{display:inline-flex;align-items:center;gap:7px;background:var(--s2);border:1px solid var(--line);border-radius:999px;padding:5px 11px 5px 6px;max-width:220px;flex:0 0 auto}
  .v3plate .mark{flex:0 0 auto;width:20px;height:20px;border-radius:5px;background:var(--s3);color:var(--ink);font:700 9px/1 var(--mono);letter-spacing:.02em;display:inline-grid;place-items:center}
  .v3plate .nm{font:600 12.5px/1 var(--font);color:var(--ink);max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .v3cmov{position:fixed;inset:0;background:var(--overlay,rgba(20,22,26,.42));z-index:240;display:grid;place-items:center;padding:18px}
  .v3cm{width:520px;max-width:95vw;max-height:92vh;display:flex;flex-direction:column;background:var(--panel);border:1px solid var(--lineS);border-radius:13px;box-shadow:var(--shadow-v3-lg);overflow:hidden;animation:v3pop .15s ease}
  .v3cm .hd{display:flex;align-items:flex-start;gap:10px;padding:14px 18px 11px;border-bottom:1px solid var(--line)}
  .v3cm .hd .v3plateslot{display:contents}   /* WS-D: styling-only wrapper — plate stays a direct header flex child */
  .v3cm .hd .t{font:600 17px/1.2 var(--display);color:var(--ink)}
  .v3cm .hd .s{font:400 10.5px/1.4 var(--mono);color:var(--muted);margin-top:4px}
  .v3cm .x{width:30px;height:30px;flex:0 0 auto;border:1px solid var(--lineS);border-radius:8px;background:var(--panel);color:var(--muted);font-size:16px;cursor:pointer;padding:0}
  .v3cm .x:hover{background:var(--s2)}
  .v3cm .bd{padding:16px 18px;overflow:auto}
  .v3cm .bd .note{font:400 12.5px/1.55 var(--font);color:var(--sub)}
  .v3cm .bd .fig .count{font:600 13px/1.3 var(--font);color:var(--ink)}
  .v3cm .bd .fig .total{font:600 20px/1.2 var(--mono);color:var(--ink);margin:6px 0 2px}
  .v3cm .bd .fig .cap{font:400 11px/1.4 var(--font);color:var(--muted)}
  .v3cm .bd .flag{display:flex;gap:9px;align-items:flex-start;margin-top:14px;background:var(--warn-bg);border:1px solid var(--warn-line);border-radius:8px;padding:10px 12px}   /* WS-D: attention-flag strip — glyph + text, never colour-only */
  .v3cm .bd .flag .g{flex:0 0 auto;color:var(--warn-deep);font-size:14px;line-height:1.2}
  .v3cm .bd .flag .tx{font:500 12px/1.45 var(--font);color:var(--warn-deep)}
  .v3cm .ft{display:flex;align-items:center;gap:9px;padding:12px 18px;background:var(--s2);border-top:1px solid var(--line)}
  .v3cm .ft .note{font:400 10px/1.5 var(--mono);color:var(--muted)}
  .v3cm .ft .grow{flex:1}
  .v3cm .ft .sec{min-height:40px;border:1px solid var(--lineS);background:var(--panel);border-radius:8px;padding:0 16px;font:600 12px/1 var(--font);color:var(--ink);cursor:pointer}
  .v3cm .ft .sec:hover{background:var(--s3)}
  /* gap, not a text space: .verb and .co are FLEX ITEMS here, so the trailing space
     shell.js puts inside .verb ("Pay … from ") sits at the end of that item's own line box
     and CSS trims it. Every money confirm rendered "fromBredbury Car Services Ltd". */
  .v3cm .ft .go{min-height:40px;border:1px solid var(--accent);background:var(--accent);color:var(--accent-fg);border-radius:8px;padding:0 16px;font:600 12px/1 var(--font);cursor:pointer;display:inline-flex;align-items:center;gap:.35em}
  .v3cm .ft .go:hover{background:var(--accent-hover);border-color:var(--accent-hover)}
  .v3cm .ft .go .verb{font-weight:700}
  .v3cm .ft .go .co{font-weight:500}
  .v3cm .ft .go.danger{background:var(--panel);border-color:var(--lineS);color:var(--bad)}
  .v3cm .ft .go.danger:hover{background:var(--bad-bg)}
  .v3cm .ft .go:disabled{opacity:.55;cursor:default}
  /* prompt-shape field (S.prompt / S.confirm opts.input) — matches the approvals reject card's input voice */
  .v3cm .bd .lbl{display:block;font:500 11px/1 var(--font);color:var(--sub);margin-bottom:6px}
  .v3cm .bd .inrow{display:flex;gap:8px;align-items:stretch}
  .v3cm .bd .v3cm-in{flex:1;min-width:0;box-sizing:border-box;border:1px solid var(--lineS);border-radius:8px;background:var(--panel);color:var(--ink);padding:9px 11px;font:400 12.5px/1.5 var(--font)}
  .v3cm .bd textarea.v3cm-in{min-height:72px;resize:vertical}
  .v3cm .bd .v3cm-in:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-weak)}
  .v3cm .bd .inbtn{flex:0 0 auto;width:38px;border:1px solid var(--lineS);border-radius:8px;background:var(--panel);color:var(--muted);cursor:pointer;display:grid;place-items:center;padding:0}
  .v3cm .bd .inbtn:hover{background:var(--s2);color:var(--ink)}
  .v3cm .bd .inbtn[aria-pressed="true"]{background:var(--s2);color:var(--ink);border-color:var(--accent)}
  .v3cm .bd .inhint{font:400 10.5px/1.5 var(--mono);color:var(--muted);margin-top:6px}
  .v3cm-initfocus{outline:3px solid var(--focus);outline-offset:2px}
  @media (max-width:640px){ .v3cm .ft{flex-wrap:wrap} .v3cm .ft .sec,.v3cm .ft .go{min-height:44px} }

  /* ---- S.popover: the anchored explain-and-link popover (trust-chip family 5) ----
     One shell component (shell.js S.popover) for every trust chip / learned badge /
     duplicate flag / derived number. Panel voice matches .v3appear/.v3fpop; sits above
     page popovers (60/120/140) and below modals (240) and toasts (300). */
  .v3popover{position:fixed;z-index:150;width:min(288px,calc(100vw - 16px));background:var(--panel);border:1px solid var(--lineS);border-radius:11px;box-shadow:var(--shadow-v3-lg);padding:12px 14px;animation:v3pop .12s ease;color:var(--ink)}
  .v3popover:focus{outline:none}
  .v3popover .h{font:600 10px/1 var(--font);letter-spacing:.07em;text-transform:uppercase;color:var(--muted);margin-bottom:7px}
  .v3popover .tx{font:400 12px/1.55 var(--font);color:var(--sub);margin:2px 0}
  .v3popover .row{display:flex;gap:12px;justify-content:space-between;align-items:baseline;font:400 11.5px/1.6 var(--font);color:var(--sub)}
  .v3popover .row .k{color:var(--muted);white-space:nowrap}
  .v3popover .row .v{font:600 11.5px/1.6 var(--mono);color:var(--ink);text-align:right;overflow-wrap:anywhere}
  .v3popover .acts{display:flex;flex-direction:column;gap:1px;margin-top:9px;border-top:1px solid var(--line);padding-top:8px}
  .v3popover .acts .lk{display:block;font:600 12px/1.3 var(--font);color:var(--ink);text-decoration:none;border-radius:7px;padding:6px 8px;margin:0 -8px}
  .v3popover .acts .lk:hover{background:var(--s2)}
  .v3popover .acts .lk:focus-visible{outline:3px solid var(--focus);outline-offset:-2px}
  .v3popover .nt{font:400 10px/1.5 var(--mono);color:var(--muted);margin-top:8px}
