  :root{
    --radius-s: 2px;
    --radius-m: 4px;
    --radius-l: 6px;
    --sidebar-w: 220px;
  }

  *{box-sizing:border-box;}
  html,body{margin:0;padding:0;}

  body{
    min-height:100vh;
    background:var(--bg);
    color:var(--ink);
    font-family:var(--font-body);
    transition:background .25s ease, color .25s ease;
    position:relative;
    overflow-x:hidden;
  }

  /* soft color blobs behind the sidebar so the glass blur has something to catch */
  .blob{
    position:fixed;
    border-radius:50%;
    filter:blur(70px);
    z-index:0;
    pointer-events:none;
  }
  .blob-a{ width:340px; height:340px; top:-80px; left:-100px; background:var(--blob-a); }
  .blob-b{ width:300px; height:300px; top:340px; left:60px; background:var(--blob-b); }
  .blob-c{ width:260px; height:260px; bottom:-60px; left:-60px; background:var(--blob-c); }

  /* ============ THEMES ============
     Each theme sets colours and a default pair of fonts. A font class on <body>
     overrides those fonts — the two settings are independent, so any font can be
     used with any theme. The font rules live after every theme block for that
     reason; see "FONT FAMILIES" below. */

  /* ---- GRAPHITE (default): neutral dark, blue accent ----
     Replaces the amber-on-charcoal default. Amber on near-black is high-chroma on a
     dark ground, which vibrates on an LCD over a long shift; a desaturated slate with
     a single blue accent stays legible for hours and lets the warning colours mean
     something, because they are the only saturated things on screen. */
  body.theme-graphite{
    --bg:#151719;
    --surface:#1E2124;
    --surface-2:#25292D;
    --ink:#E8EAED;
    --muted:#9AA0A6;
    --line:#33383D;
    --accent:#4F9CF9;
    --accent-ink:#0B1220;
    --blue:#4F9CF9;
    --rust:#F2725C;
    --good:#4ADE80;
    --font-head:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --font-body:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --radius-card: 10px;
    --shadow: 0 4px 16px rgba(0,0,0,.4);
    --shadow-hover: 0 10px 26px rgba(0,0,0,.5);
    --blob-a: rgba(79,156,249,.14);
    --blob-b: rgba(74,222,128,.08);
    --blob-c: rgba(129,140,248,.10);
  }

  /* ---- DAYLIGHT: light, high contrast ---- */
  body.theme-daylight{
    --bg:#F7F8FA;
    --surface:#FFFFFF;
    --surface-2:#F1F3F6;
    --ink:#1A1D21;
    --muted:#5F6B7A;
    --line:#DFE3E8;
    --accent:#2563EB;
    --accent-ink:#FFFFFF;
    --blue:#2563EB;
    --rust:#DC2626;
    --good:#059669;
    --font-head:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --font-body:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --radius-card: 10px;
    --shadow: 0 1px 3px rgba(16,24,40,.08), 0 1px 2px rgba(16,24,40,.06);
    --shadow-hover: 0 8px 20px rgba(16,24,40,.12);
    --blob-a: rgba(37,99,235,.10);
    --blob-b: rgba(5,150,105,.08);
    --blob-c: rgba(220,38,38,.06);
  }

  /* ---- FOREST: dark green ---- */
  body.theme-forest{
    --bg:#121A16;
    --surface:#1A241E;
    --surface-2:#212D25;
    --ink:#E6EDE8;
    --muted:#8FA396;
    --line:#2C3A31;
    --accent:#4ADE80;
    --accent-ink:#0A1710;
    --blue:#5EAAD8;
    --rust:#F0836A;
    --good:#4ADE80;
    --font-head:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --font-body:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --radius-card: 10px;
    --shadow: 0 4px 16px rgba(0,0,0,.4);
    --shadow-hover: 0 10px 26px rgba(0,0,0,.5);
    --blob-a: rgba(74,222,128,.12);
    --blob-b: rgba(94,170,216,.08);
    --blob-c: rgba(240,131,106,.07);
  }

  /* ---- COPPER: warm light ---- */
  body.theme-copper{
    --bg:#FBF7F1;
    --surface:#FFFFFF;
    --surface-2:#F5EFE6;
    --ink:#2B241E;
    --muted:#7C6E60;
    --line:#E6DCCC;
    --accent:#C2643A;
    --accent-ink:#FFFFFF;
    --blue:#4A7B8C;
    --rust:#B54A2E;
    --good:#5A8A5E;
    --font-head:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --font-body:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --radius-card: 10px;
    --shadow: 0 2px 10px rgba(120,80,50,.10);
    --shadow-hover: 0 10px 24px rgba(120,80,50,.16);
    --blob-a: rgba(194,100,58,.12);
    --blob-b: rgba(74,123,140,.10);
    --blob-c: rgba(90,138,94,.08);
  }

  /* ---- MIDNIGHT: deep blue, violet accent ---- */
  body.theme-midnight{
    --bg:#0F1420;
    --surface:#171E2E;
    --surface-2:#1E2638;
    --ink:#E4E8F2;
    --muted:#8F98AE;
    --line:#2A3348;
    --accent:#818CF8;
    --accent-ink:#0B1020;
    --blue:#60A5FA;
    --rust:#FB7185;
    --good:#34D399;
    --font-head:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --font-body:'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
    --radius-card: 10px;
    --shadow: 0 4px 16px rgba(0,0,0,.45);
    --shadow-hover: 0 10px 28px rgba(0,0,0,.55);
    --blob-a: rgba(129,140,248,.16);
    --blob-b: rgba(96,165,250,.10);
    --blob-c: rgba(52,211,153,.07);
  }

  /* ============ THEME: STEEL YARD (industrial) ============ */
  body.theme-steel{
    --bg:#14171A;
    --surface:#1D2124;
    --surface-2:#22262A;
    --ink:#E9E7E1;
    --muted:#8B9096;
    --line:#2C3135;
    --accent:#F2A93B;
    --accent-ink:#14171A;
    --blue:#5B93AC;
    --rust:#D9713C;
    --good:#7FAE7A;
    --font-head:'Arial Black', 'Arial Narrow', Impact, sans-serif;
    --font-body:Consolas, 'Courier New', monospace;
    --radius-card: 0px;
    --shadow: 0 6px 18px rgba(0,0,0,.45), 0 1px 0 rgba(255,255,255,.03) inset;
    --shadow-hover: 0 12px 28px rgba(0,0,0,.55);
    --blob-a: rgba(242,169,59,.18);
    --blob-b: rgba(91,147,172,.14);
    --blob-c: rgba(217,113,60,.12);
  }

  /* ============ THEME: FLEET LEDGER (clean/professional) ============ */
  body.theme-ledger{
    --bg:#F5F3EE;
    --surface:#FFFFFF;
    --surface-2:#FBFAF7;
    --ink:#22303C;
    --muted:#6B7A87;
    --line:#DDE3E4;
    --accent:#1F3A52;
    --accent-ink:#FFFFFF;
    --blue:#2F6E86;
    --rust:#B5502E;
    --good:#2F7A63;
    --font-head:Georgia, 'Times New Roman', serif;
    --font-body:-apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --radius-card: 2px;
    --shadow: 0 2px 10px rgba(31,58,82,.08), 0 1px 2px rgba(31,58,82,.06);
    --shadow-hover: 0 10px 24px rgba(31,58,82,.14);
    --blob-a: rgba(31,58,82,.10);
    --blob-b: rgba(47,110,134,.10);
    --blob-c: rgba(181,80,46,.08);
  }

  /* ============ THEME: RUST & ROAD (warm/approachable) ============ */
  body.theme-rust{
    --bg:#FAF3E9;
    --surface:#FFFCF6;
    --surface-2:#F3E8D8;
    --ink:#2E2620;
    --muted:#8C7C6A;
    --line:#E7D9C4;
    --accent:#B5502E;
    --accent-ink:#FFF8F0;
    --blue:#516B5C;
    --rust:#B5502E;
    --good:#5C6B4F;
    --font-head:'Trebuchet MS', Verdana, sans-serif;
    --font-body:-apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --radius-card: 14px;
    --shadow: 0 6px 20px rgba(181,80,46,.10);
    --shadow-hover: 0 14px 30px rgba(181,80,46,.18);
    --blob-a: rgba(181,80,46,.14);
    --blob-b: rgba(81,107,92,.12);
    --blob-c: rgba(181,80,46,.10);
  }

  /* ============ FONT FAMILIES ============
     Applied as a second class on <body>, after the theme, so the choice of typeface
     is independent of the choice of colours. Every stack ends in a generic family:
     Inter is loaded from Google Fonts and a slow or blocked network must still leave
     the app readable rather than falling back to Times. */
  body.font-inter{
    --font-head:'Inter', -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --font-body:'Inter', -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  }
  body.font-system{
    --font-head:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --font-body:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  }
  body.font-mono{
    --font-head:'JetBrains Mono', Consolas, 'Courier New', monospace;
    --font-body:'JetBrains Mono', Consolas, 'Courier New', monospace;
  }
  body.font-serif{
    --font-head:'Source Serif 4', Georgia, 'Times New Roman', serif;
    --font-body:'Source Serif 4', Georgia, 'Times New Roman', serif;
  }
  body.font-rounded{
    --font-head:'Nunito', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --font-body:'Nunito', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    font-size:15px;
  }

  /* Numbers in tables and totals align by column whatever the chosen face, because a
     price that jitters between rows is hard to scan and easy to misread. */
  .report-table .num,
  .invoice-lines .num,
  .stat .value{ font-variant-numeric:tabular-nums; }

  /* ===================== THEME SWITCHER BAR ===================== */
  .switcher{
    position:relative;
    z-index:5;
    display:flex;
    gap:8px;
    align-items:center;
    padding:14px 28px;
    background:var(--surface-2);
    border-bottom:1px solid var(--line);
  }
  .switcher span{
    font-size:12px;
    color:var(--muted);
    margin-right:6px;
    font-family:var(--font-body);
  }
  .swatch-btn{
    border:1px solid var(--line);
    background:var(--surface);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:12px;
    padding:6px 14px;
    cursor:pointer;
    border-radius:var(--radius-m);
    transition:box-shadow .15s ease, transform .15s ease;
  }
  .swatch-btn:hover{ box-shadow:var(--shadow); transform:translateY(-1px); }
  .swatch-btn.active{
    background:var(--accent);
    color:var(--accent-ink);
    border-color:var(--accent);
  }

  /* ===================== APP SHELL ===================== */
  .shell{
    position:relative;
    z-index:1;
    display:flex;
    align-items:flex-start;
  }

  /* ---- glass navy sidebar ---- */
  .sidebar{
    position:sticky;
    top:0;
    width:var(--sidebar-w);
    /* Full height: the theme bar that used to take the top 49px now lives in Settings. */
    min-height:100vh;
    flex-shrink:0;
    padding:26px 14px;
    /* A column so Sign out can be pushed to the foot regardless of how many nav
       entries there are, and the submenu can scroll without moving it. */
    display:flex;
    flex-direction:column;
    background:linear-gradient(180deg, rgba(20,36,54,.72), rgba(15,28,44,.68));
    backdrop-filter:blur(16px) saturate(150%);
    -webkit-backdrop-filter:blur(16px) saturate(150%);
    border-right:1px solid rgba(255,255,255,.08);
    box-shadow:8px 0 30px rgba(0,0,0,.25);
  }
  .side-logo{
    font-family:var(--font-head);
    color:#F3F1EA;
    font-size:18px;
    letter-spacing:.5px;
    padding:0 10px 22px;
    border-bottom:1px solid rgba(255,255,255,.1);
    margin-bottom:16px;
  }
  .side-logo small{
    display:block;
    font-family:var(--font-body);
    font-weight:normal;
    font-size:10.5px;
    color:rgba(255,255,255,.55);
    margin-top:4px;
    letter-spacing:.2px;
  }
  .nav-item{
    display:flex;
    align-items:center;
    gap:10px;
    padding:10px 12px;
    margin-bottom:4px;
    border-radius:8px;
    color:rgba(255,255,255,.78);
    font-family:var(--font-body);
    font-size:13px;
    cursor:pointer;
    border-left:3px solid transparent;
    transition:background .15s ease, box-shadow .15s ease, color .15s ease, transform .1s ease;
  }
  .nav-item svg{ width:16px; height:16px; flex-shrink:0; opacity:.85; }
  .nav-item:hover{
    background:rgba(255,255,255,.08);
    box-shadow:0 4px 14px rgba(0,0,0,.25);
    color:#fff;
    /* Padding, not transform. A nav item is already the full width of the rail, so
       translateX(2px) pushed it 2px past the edge and .side-nav -- which scrolls
       vertically, and so cannot leave the horizontal axis visible -- grew a
       horizontal scrollbar under the pointer. Shifting the TEXT inside the box gives
       the same nudge without the box ever moving. */
    padding-left:14px;
    padding-right:10px;
  }
  .nav-item.active{
    background:rgba(255,255,255,.12);
    border-left:3px solid var(--accent);
    color:#fff;
    box-shadow:0 4px 14px rgba(0,0,0,.3);
  }

  /* Takes the slack so the sign-out block below it sits at the foot. A long reports
     submenu scrolls here rather than pushing Sign out off the screen. */
  .side-nav{
    flex:1;
    min-height:0;
    overflow-y:auto;
    /* Belt and braces. overflow-y:auto means the horizontal axis cannot stay
       `visible`, so anything wider than the rail becomes a sideways scrollbar. The
       real fix is that nothing here is wider -- see .nav-item:hover, which nudges
       its padding rather than transforming the box -- and this stops a future
       overflow from turning into a scrollbar again. */
    overflow-x:clip;
  }

  .side-signout{
    margin:0;
    padding-top:14px;
    border-top:1px solid rgba(255,255,255,.1);
  }
  /* Reuses .nav-item so it reads as part of the same rail, but it is a button in a
     form, so the button chrome has to be undone explicitly. */
  .nav-signout{
    width:100%;
    background:none;
    border:none;
    border-left:3px solid transparent;
    text-align:left;
    font:inherit;
    font-family:var(--font-body);
    font-size:13px;
    color:rgba(255,255,255,.6);
    margin-bottom:0;
  }
  .nav-signout:hover{
    background:rgba(220,80,70,.18);
    color:#fff;
    transform:none;
  }

  /* ===================== MAIN CONTENT ===================== */
  .wrap{
    flex:1;
    min-width:0;
    max-width:1180px;
    margin:0 auto;
    padding:32px 28px 64px;
  }

  .topbar{
    display:flex;
    justify-content:space-between;
    align-items:flex-end;
    gap:16px;
    flex-wrap:wrap;
    margin-bottom:28px;
    border-bottom:2px solid var(--line);
    padding-bottom:18px;
  }
  .topbar-right{
    display:flex;
    align-items:center;
    gap:10px;
    flex-wrap:wrap;
  }

  /* What is left: minutes and days. Links, because the answer to "that number is low"
     is always the Billing page, and a chip that looks informative but does nothing
     wastes the one click somebody was about to make. */
  .top-chip{
    display:flex;
    flex-direction:column;
    align-items:center;
    padding:5px 12px;
    border-radius:9px;
    border:1px solid var(--line);
    background:var(--surface);
    text-decoration:none;
    line-height:1.15;
    transition:border-color .15s ease, transform .1s ease;
  }
  .top-chip:hover{ border-color:var(--accent); transform:translateY(-1px); }
  .top-chip-value{
    font-family:var(--font-head);
    font-size:16px;
    color:var(--ink);
    font-variant-numeric:tabular-nums;
  }
  .top-chip-label{
    font-family:var(--font-body);
    font-size:9.5px;
    text-transform:uppercase;
    letter-spacing:.05em;
    color:var(--muted);
  }
  /* The tone carries the warning. Someone who never reads the number still sees it
     stop being green. */
  .top-chip.warn{ border-color:#c89b3c; }
  .top-chip.warn .top-chip-value{ color:#c89b3c; }
  .top-chip.bad{ border-color:var(--rust); }
  .top-chip.bad .top-chip-value{ color:var(--rust); }

  @media (prefers-reduced-motion:reduce){
    .top-chip{ transition:none; }
    .top-chip:hover{ transform:none; }
  }

  /* Narrow screens: the chips matter more than the strapline. */
  @media screen and (max-width:700px){
    .wordmark small{ display:none; }
    .top-chip{ padding:4px 9px; }
  }
  .wordmark{
    font-family:var(--font-head);
    font-size:24px;
    letter-spacing:0.5px;
    margin:0;
    color:var(--ink);
  }
  .wordmark small{
    display:block;
    font-family:var(--font-body);
    font-size:12px;
    color:var(--muted);
    font-weight:normal;
    letter-spacing:0.3px;
    margin-top:4px;
  }
  .yard-select{
    font-family:var(--font-body);
    font-size:13px;
    color:var(--muted);
    text-align:right;
  }
  .yard-select b{color:var(--ink); font-size:15px; display:block;}

  /* stat row */
  .stats{
    display:grid;
    grid-template-columns:repeat(4,1fr);
    gap:16px;
    margin-bottom:28px;
  }
  .stat{
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:var(--radius-card);
    padding:18px 18px 16px;
    box-shadow:var(--shadow);
    transition:transform .18s ease, box-shadow .18s ease;
  }
  .stat:hover{ transform:translateY(-3px); box-shadow:var(--shadow-hover); }
  .stat .label{
    font-family:var(--font-body);
    font-size:11px;
    color:var(--muted);
    letter-spacing:0.4px;
    margin-bottom:10px;
  }
  .stat .value{
    font-family:var(--font-head);
    font-size:30px;
    color:var(--ink);
    line-height:1;
  }
  .stat .delta{
    font-family:var(--font-body);
    font-size:12px;
    margin-top:8px;
  }
  .delta.up{color:var(--good);}
  .delta.warn{color:var(--rust);}

  /* A figure that just changed, live.
     These tiles update without anyone touching the page, and a silent swap cannot be
     told apart from a number that was always there. The accent border and brief lift
     say "this one moved" and then get out of the way. */
  .stat-changed{
    border-color:var(--accent);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent),
               var(--shadow);
  }
  .stat-changed .value{
    animation:stat-pop .5s ease-out;
  }
  @keyframes stat-pop{
    0%  { transform:scale(1);    color:var(--accent); }
    35% { transform:scale(1.07); color:var(--accent); }
    100%{ transform:scale(1); }
  }
  /* The tile animates on arrival, which is motion nobody asked for. Anyone who has
     asked the OS to reduce motion still gets the border -- the information -- without
     the movement. */
  @media (prefers-reduced-motion:reduce){
    .stat-changed .value{ animation:none; }
    .stat{ transition:none; }
  }

  /* main grid */
  .grid{
    display:grid;
    grid-template-columns:1.4fr 1fr;
    gap:20px;
  }

  .panel{
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:var(--radius-card);
    padding:20px 20px 8px;
    margin-bottom:20px;
    box-shadow:var(--shadow);
    transition:transform .18s ease, box-shadow .18s ease;
  }
  .panel:hover{ transform:translateY(-2px); box-shadow:var(--shadow-hover); }
  .panel h2{
    font-family:var(--font-head);
    font-size:16px;
    margin:0 0 4px;
    color:var(--ink);
    letter-spacing:0.2px;
  }
  .panel .sub{
    font-family:var(--font-body);
    font-size:12px;
    color:var(--muted);
    margin-bottom:16px;
  }

  /* calls table */
  table{width:100%; border-collapse:collapse; font-family:var(--font-body); font-size:13px;}
  th{
    text-align:left;
    font-size:11px;
    color:var(--muted);
    font-weight:normal;
    padding:6px 8px;
    border-bottom:1px solid var(--line);
  }
  td{
    padding:10px 8px;
    border-bottom:1px solid var(--line);
    color:var(--ink);
  }
  tr{ transition:background .15s ease; }
  tr:hover td{ background:var(--surface-2); }
  tr:last-child td{border-bottom:none;}
  .tag{
    display:inline-block;
    padding:2px 8px;
    font-size:11px;
    border-radius:12px;
    font-family:var(--font-body);
  }
  .tag.found{background:color-mix(in srgb, var(--good) 18%, transparent); color:var(--good);}
  .tag.missing{background:color-mix(in srgb, var(--rust) 18%, transparent); color:var(--rust);}
  .tag.pending{background:color-mix(in srgb, var(--blue) 18%, transparent); color:var(--blue);}

  /* Generic status tones, used by the admin area. Named by meaning rather than by
     colour so a palette change does not turn "ok" red. */
  .tag.ok{background:color-mix(in srgb, var(--good) 18%, transparent); color:var(--good);}
  .tag.warn{background:color-mix(in srgb, #c89b3c 20%, transparent); color:#c89b3c;}
  .tag.bad{background:color-mix(in srgb, var(--rust) 18%, transparent); color:var(--rust);}
  .tag.muted{background:color-mix(in srgb, var(--muted) 16%, transparent); color:var(--muted);}

  /* chart */
  .chart-box{padding-bottom:16px;}
  .bars{display:flex; align-items:flex-end; gap:10px; height:120px; margin-top:10px;}
  .bar-col{flex:1; display:flex; flex-direction:column; align-items:center; gap:6px;}
  .bar{width:100%; background:var(--line); border-radius:var(--radius-s) var(--radius-s) 0 0; position:relative; transition:filter .15s ease, transform .15s ease;}
  .bar:hover{ filter:brightness(1.15); transform:scaleY(1.02); }
  .bar.now{background:var(--accent);}
  .bar-label{font-family:var(--font-body); font-size:10px; color:var(--muted);}

  /* unanswered list */
  .uq-item{
    display:flex;
    justify-content:space-between;
    align-items:center;
    padding:10px 8px;
    margin:0 -8px;
    border-bottom:1px solid var(--line);
    font-family:var(--font-body);
    font-size:13px;
    border-radius:6px;
    transition:background .15s ease;
  }
  .uq-item:hover{ background:var(--surface-2); }
  .uq-item:last-child{border-bottom:none;}
  .uq-item .q{color:var(--ink);}
  .uq-item .channel{font-size:11px; color:var(--muted);}
  .count-badge{
    background:var(--rust);
    color:#fff;
    font-family:var(--font-body);
    font-size:11px;
    padding:1px 8px;
    border-radius:10px;
  }

  /* inventory mini */
  .inv-row{
    display:flex;
    justify-content:space-between;
    padding:8px;
    margin:0 -8px;
    border-bottom:1px dashed var(--line);
    font-family:var(--font-body);
    font-size:13px;
    border-radius:6px;
    transition:background .15s ease;
  }
  .inv-row:hover{ background:var(--surface-2); }
  .inv-row:last-child{border-bottom:none;}
  .inv-name{color:var(--ink);}
  .inv-qty{color:var(--muted);}
  .inv-qty.low{color:var(--rust); font-weight:bold;}

  /* chat mock */
  .chat-mock{font-family:var(--font-body); font-size:13px;}
  .msg{margin-bottom:14px; max-width:88%;}
  .msg.user{margin-left:auto; text-align:right;}
  .bubble{
    display:inline-block;
    padding:9px 13px;
    border-radius:var(--radius-m);
    background:var(--surface-2);
    color:var(--ink);
    border:1px solid var(--line);
    box-shadow:var(--shadow);
  }
  .msg.user .bubble{background:var(--accent); color:var(--accent-ink); border-color:var(--accent);}
  .feedback{display:flex; gap:6px; margin-top:4px; font-size:11px; color:var(--muted);}

  @media (max-width: 860px){
    .stats{grid-template-columns:repeat(2,1fr);}
    .grid{grid-template-columns:1fr;}
    .sidebar{ display:none; }
  }

  /* ===================== LOGIN ===================== */
  .login-shell{
    position:relative;
    z-index:1;
    min-height:100vh;
    display:flex;
    align-items:center;
    justify-content:center;
    padding:24px;
  }
  .login-card{
    width:100%;
    max-width:400px;
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:var(--radius-card);
    padding:34px 32px 30px;
    box-shadow:var(--shadow);
  }
  .login-card .wordmark{ font-size:26px; margin-bottom:4px; }
  .login-sub{
    font-family:var(--font-body);
    font-size:12.5px;
    color:var(--muted);
    margin:0 0 26px;
    padding-bottom:18px;
    border-bottom:1px solid var(--line);
  }
  .field{ margin-bottom:16px; }
  .field label{
    display:block;
    font-family:var(--font-body);
    font-size:11px;
    letter-spacing:.4px;
    color:var(--muted);
    margin-bottom:6px;
  }
  .field input{
    width:100%;
    padding:10px 12px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:13.5px;
    transition:border-color .15s ease, box-shadow .15s ease;
  }
  .field input:focus{
    outline:none;
    border-color:var(--accent);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
  }
  .btn-primary{
    width:100%;
    margin-top:6px;
    padding:11px 16px;
    background:var(--accent);
    color:var(--accent-ink);
    border:1px solid var(--accent);
    border-radius:var(--radius-m);
    font-family:var(--font-body);
    font-size:13.5px;
    letter-spacing:.3px;
    cursor:pointer;
    transition:transform .12s ease, box-shadow .15s ease, opacity .15s ease;
  }
  .btn-primary:hover:not(:disabled){ transform:translateY(-1px); box-shadow:var(--shadow-hover); }
  .btn-primary:disabled{ opacity:.6; cursor:not-allowed; }
  .alert{
    padding:10px 12px;
    margin-bottom:16px;
    border-radius:var(--radius-m);
    font-family:var(--font-body);
    font-size:12.5px;
    background:color-mix(in srgb, var(--rust) 14%, transparent);
    border:1px solid color-mix(in srgb, var(--rust) 45%, transparent);
    color:var(--rust);
  }
  .login-foot{
    margin-top:22px;
    padding-top:16px;
    border-top:1px solid var(--line);
    font-family:var(--font-body);
    font-size:11.5px;
    color:var(--muted);
    line-height:1.6;
  }

  /* sidebar nav items are real links once wired to the router */
  .nav-item{ text-decoration:none; }
  a.nav-item, a.nav-item:visited{ color:rgba(255,255,255,.78); }
  a.nav-item.active, a.nav-item:hover{ color:#fff; }

  .signout-btn{
    background:none;
    border:none;
    padding:0;
    font:inherit;
    color:var(--muted);
    cursor:pointer;
    text-decoration:underline;
  }
  .signout-btn:hover{ color:var(--ink); }

  .empty-note{
    font-family:var(--font-body);
    font-size:12.5px;
    color:var(--muted);
    padding:14px 0 18px;
  }

  /* FocusOnNavigate moves focus to the <h1> for screen readers. Keep that behavior
     but don't paint a focus ring on a heading nobody clicked — real keyboard focus
     on interactive elements still shows one via :focus-visible. */
  h1[tabindex="-1"]:focus{ outline:none; }

  /* ===================== INVENTORY / IMPORT ===================== */
  .toolbar{
    display:flex;
    flex-wrap:wrap;
    gap:10px;
    align-items:center;
    margin-bottom:16px;
  }
  .toolbar-search{
    flex:1;
    min-width:220px;
    padding:9px 12px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:13px;
  }
  .toolbar-search:focus{
    outline:none;
    border-color:var(--accent);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
  }
  .toolbar-select{
    padding:9px 10px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:13px;
  }
  .toolbar-check{
    display:flex;
    align-items:center;
    gap:6px;
    font-family:var(--font-body);
    font-size:12.5px;
    color:var(--muted);
    white-space:nowrap;
  }
  .btn-secondary{
    padding:9px 14px;
    background:var(--surface-2);
    color:var(--ink);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    font-family:var(--font-body);
    font-size:13px;
    cursor:pointer;
    text-decoration:none;
    white-space:nowrap;
    transition:box-shadow .15s ease, transform .12s ease;
  }
  .btn-secondary:hover{ transform:translateY(-1px); box-shadow:var(--shadow); }

  /* Wide tables scroll inside their own box rather than the page. */
  .table-scroll{ overflow-x:auto; }
  .table-scroll table{ min-width:720px; }
  td.num, th.num{ text-align:right; white-space:nowrap; }
  .cell-strong{ color:var(--ink); }
  .cell-sub{ font-size:11px; color:var(--muted); }
  .cell-warn{ color:var(--rust); font-size:12px; }
  .qty-low{ color:var(--rust); font-weight:bold; }
  td.fits{ max-width:230px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

  .pager{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:14px;
    padding:14px 0 18px;
    font-family:var(--font-body);
    font-size:12.5px;
    color:var(--muted);
  }
  .pager-btn{
    padding:6px 12px;
    background:var(--surface-2);
    color:var(--ink);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    font-family:var(--font-body);
    font-size:12.5px;
    cursor:pointer;
  }
  .pager-btn:disabled{ opacity:.4; cursor:not-allowed; }
  .pager-count{ opacity:.75; }

  .upload-zone{
    padding:26px 20px;
    border:1px dashed var(--line);
    border-radius:var(--radius-m);
    background:var(--surface-2);
    text-align:center;
    margin-bottom:16px;
  }
  .upload-hint{
    margin-top:10px;
    font-family:var(--font-body);
    font-size:12px;
    color:var(--muted);
    line-height:1.6;
  }

  .hint-block{
    padding:14px;
    margin:16px 0;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    font-family:var(--font-body);
    font-size:12.5px;
    color:var(--ink);
  }
  .hint-cols{ display:flex; flex-wrap:wrap; gap:6px; margin:10px 0; }
  .hint-col{
    padding:3px 8px;
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:10px;
    font-size:11px;
    color:var(--muted);
  }
  .hint-col.req{ color:var(--accent); border-color:var(--accent); }

  .alert-warn{
    padding:10px 12px;
    margin-bottom:16px;
    border-radius:var(--radius-m);
    font-family:var(--font-body);
    font-size:12.5px;
    line-height:1.6;
    background:color-mix(in srgb, var(--accent) 12%, transparent);
    border:1px solid color-mix(in srgb, var(--accent) 40%, transparent);
    color:var(--ink);
  }

  .file-summary{
    padding:10px 12px;
    margin-bottom:16px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    font-family:var(--font-body);
    font-size:12.5px;
    color:var(--ink);
  }

  .map-table{ width:100%; }
  .map-table td{ vertical-align:top; padding:10px 8px; }
  .map-table td:first-child{ max-width:300px; }

  .form-actions{ display:flex; gap:10px; flex-wrap:wrap; padding:16px 0 8px; }
  .form-actions .btn-primary{ width:auto; margin-top:0; text-decoration:none; display:inline-block; }

  .result-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:12px; margin-bottom:8px; }
  .result-tile{
    padding:14px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
  }
  .result-tile .label{ font-family:var(--font-body); font-size:11px; color:var(--muted); }
  .result-tile .value{ font-family:var(--font-head); font-size:26px; color:var(--ink); margin-top:6px; }
  .result-tile .value.warn{ color:var(--rust); }

  .err-row{
    display:flex;
    gap:8px;
    padding:6px 0;
    border-bottom:1px solid var(--line);
    font-size:12px;
  }
  .err-row:last-child{ border-bottom:none; }
  .err-line{ color:var(--rust); white-space:nowrap; }

  @media (max-width: 700px){
    .result-grid{ grid-template-columns:1fr; }
  }

  /* ===================== FIND A PART ===================== */
  .find-form{
    display:flex;
    flex-wrap:wrap;
    gap:12px;
    align-items:flex-end;
    padding-bottom:18px;
    margin-bottom:16px;
    border-bottom:1px solid var(--line);
  }
  .find-field{ display:flex; flex-direction:column; gap:6px; }
  .find-field label{
    font-family:var(--font-body);
    font-size:11px;
    letter-spacing:.4px;
    color:var(--muted);
  }
  .find-field input{
    width:150px;
    padding:9px 12px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:13px;
  }
  .find-field input:focus{
    outline:none;
    border-color:var(--accent);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
  }
  .find-go{ width:auto; margin-top:0; }

  .fit-entry{
    font-size:12px;
    color:var(--muted);
    padding:1px 0;
  }
  /* The entry whose range actually brackets the searched year. */
  .fit-entry.hit{
    color:var(--good);
    font-weight:bold;
  }

  @media (max-width: 700px){
    .find-field, .find-field input{ width:100%; }
    .find-form{ flex-direction:column; align-items:stretch; }
  }

  /* ===================== VIN LOOKUP ===================== */
  .vin-row{
    display:flex;
    flex-wrap:wrap;
    gap:12px;
    align-items:flex-end;
    padding-bottom:16px;
    margin-bottom:16px;
    border-bottom:1px dashed var(--line);
  }
  .vin-field input{ width:240px; letter-spacing:.5px; text-transform:uppercase; }
  .vin-go{ height:37px; }
  .vin-result{
    display:flex;
    flex-direction:column;
    gap:2px;
    padding:6px 12px;
    background:color-mix(in srgb, var(--good) 12%, transparent);
    border:1px solid color-mix(in srgb, var(--good) 40%, transparent);
    border-radius:var(--radius-m);
    font-family:var(--font-body);
  }
  .vin-vehicle{ font-size:13px; color:var(--ink); font-weight:bold; }

  @media (max-width: 700px){
    .vin-row{ flex-direction:column; align-items:stretch; }
    .vin-field input, .vin-go{ width:100%; }
  }

  /* ===================== MODAL / PART EDIT ===================== */
  .modal-backdrop{
    position:fixed;
    inset:0;
    background:rgba(0,0,0,.55);
    backdrop-filter:blur(2px);
    z-index:40;
  }
  .modal{
    position:fixed;
    top:50%;
    left:50%;
    transform:translate(-50%,-50%);
    width:min(620px, calc(100vw - 32px));
    max-height:calc(100vh - 64px);
    display:flex;
    flex-direction:column;
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:var(--radius-card);
    box-shadow:0 24px 60px rgba(0,0,0,.5);
    z-index:41;
  }
  .modal-head{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:12px;
    padding:18px 20px 14px;
    border-bottom:1px solid var(--line);
  }
  .modal-head h2{
    margin:0;
    font-family:var(--font-head);
    font-size:17px;
    color:var(--ink);
  }
  .modal-close{
    background:none;
    border:none;
    color:var(--muted);
    font-size:24px;
    line-height:1;
    cursor:pointer;
    padding:0 4px;
  }
  .modal-close:hover{ color:var(--ink); }
  .modal-body{ padding:18px 20px; overflow-y:auto; }
  .modal-foot{
    display:flex;
    gap:10px;
    padding:14px 20px 18px;
    border-top:1px solid var(--line);
  }
  .modal-foot .btn-primary{ width:auto; margin-top:0; }

  .edit-grid{
    display:grid;
    grid-template-columns:repeat(2, 1fr);
    gap:12px;
    margin-bottom:18px;
  }
  .edit-grid .find-field input{ width:100%; }

  .fitment-block{
    padding-top:16px;
    border-top:1px solid var(--line);
  }
  .fitment-block label{
    display:block;
    font-family:var(--font-body);
    font-size:11px;
    letter-spacing:.4px;
    color:var(--muted);
    margin-bottom:6px;
  }
  .fitment-block textarea{
    width:100%;
    padding:10px 12px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:13px;
    resize:vertical;
  }
  .fitment-block textarea:focus{
    outline:none;
    border-color:var(--accent);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
  }
  .fitment-actions{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:10px;
    margin-top:10px;
  }

  /* Echo back what the free text actually parsed to, before it is saved. */
  .parse-preview{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:6px;
    margin-top:10px;
  }
  .parse-chip{
    padding:2px 9px;
    background:color-mix(in srgb, var(--good) 16%, transparent);
    border:1px solid color-mix(in srgb, var(--good) 40%, transparent);
    border-radius:11px;
    font-family:var(--font-body);
    font-size:11.5px;
    color:var(--ink);
  }

  .gap-actions{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:10px;
    margin-bottom:12px;
  }
  .gap-row{ cursor:pointer; }
  .gap-row:hover .inv-name{ color:var(--accent); }

  @media (max-width: 600px){
    .edit-grid{ grid-template-columns:1fr; }
  }

  /* ===================== CHAT ===================== */
  .chat-intro{ padding-bottom:14px; }
  .chip-row{ display:flex; flex-wrap:wrap; gap:8px; margin-top:8px; }
  .suggest-chip{
    padding:6px 12px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:14px;
    color:var(--ink);
    font-family:var(--font-body);
    font-size:12px;
    cursor:pointer;
    transition:border-color .15s ease, transform .12s ease;
  }
  .suggest-chip:hover{ border-color:var(--accent); transform:translateY(-1px); }

  .chat-log{
    display:flex;
    flex-direction:column;
    gap:4px;
    max-height:460px;
    overflow-y:auto;
    padding:4px 2px 12px;
  }

  .msg-meta{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:8px;
    margin-top:5px;
    font-family:var(--font-body);
    font-size:11px;
    color:var(--muted);
  }
  /* Names the fixed backend function behind the number, so a figure is traceable. */
  .fn-tag{
    padding:1px 7px;
    border:1px solid var(--line);
    border-radius:9px;
    background:var(--surface-2);
    font-size:10.5px;
  }
  .fn-tag.warn{ color:var(--rust); border-color:color-mix(in srgb, var(--rust) 45%, transparent); }

  .feedback-inline{ display:flex; align-items:center; gap:4px; }
  .vote{
    background:none;
    border:none;
    cursor:pointer;
    font-size:13px;
    padding:0 2px;
    line-height:1;
  }
  .vote:hover{ transform:scale(1.15); }

  .chat-chart{
    margin-top:10px;
    padding:12px 14px 10px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    max-width:min(420px, 88%);
  }
  .chat-chart-title{
    font-family:var(--font-body);
    font-size:11px;
    color:var(--muted);
    margin-bottom:8px;
  }
  /* The bar strip is its own block below the title, so a full-height bar can never
     reach up into it. A single-series chart also gets a sane bar width. */
  .chat-chart .bars{ height:96px; margin-top:0; align-items:flex-end; }
  .chat-chart .bar-col{ max-width:64px; }

  .chat-input{
    display:flex;
    gap:10px;
    padding-top:14px;
    border-top:1px solid var(--line);
  }
  .chat-input input{
    flex:1;
    padding:10px 12px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:13px;
  }
  .chat-input input:focus{
    outline:none;
    border-color:var(--accent);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
  }
  .chat-send{ width:auto; margin-top:0; }

  .chat-foot{ padding-top:12px; line-height:1.6; }

  .chat-toolbar{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:10px;
    padding-bottom:14px;
    margin-bottom:14px;
    border-bottom:1px solid var(--line);
  }
  .chat-toolbar label{ font-family:var(--font-body); }
  /* RTL answers keep their own direction without flipping the whole layout. */
  .bubble[dir="rtl"]{ text-align:right; }

  /* ===================== MARKDOWN IN CHAT ===================== */
  .bubble p{ margin:0 0 8px; }
  .bubble p:last-child{ margin-bottom:0; }
  .bubble ul{ margin:6px 0; padding-left:20px; }
  .bubble li{ margin:2px 0; }
  .bubble code{
    padding:1px 5px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:3px;
    font-size:.92em;
  }
  .md-table-wrap{ overflow-x:auto; margin:8px 0; }
  .md-table{
    border-collapse:collapse;
    font-size:12.5px;
    min-width:auto;
  }
  .md-table th, .md-table td{
    padding:5px 10px;
    border:1px solid var(--line);
    text-align:left;
    white-space:nowrap;
  }
  .md-table th{
    background:var(--surface-2);
    color:var(--muted);
    font-weight:normal;
    font-size:11px;
  }
  /* An assistant bubble holding a table needs room to breathe. */
  .msg:not(.user) .bubble{ max-width:100%; }

  .chat-input textarea{
    flex:1;
    min-height:38px;
    max-height:140px;
    padding:10px 12px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:13px;
    resize:none;
    overflow-y:auto;
  }
  .chat-input textarea:focus{
    outline:none;
    border-color:var(--accent);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent);
  }

  /* A table inside an RTL answer keeps its own column order: the data is Latin-scripted
     (category names, numbers), so mirroring it makes the header line up with the wrong
     column. Only the surrounding prose flows right-to-left. */
  .bubble[dir="rtl"] .md-table-wrap{ direction:ltr; }
  .bubble[dir="rtl"] .md-table th,
  .bubble[dir="rtl"] .md-table td{ text-align:left; }
  /* Header labels may be Persian while the data is Latin — force the same direction
     on both so a column heading sits over its own column. */
  .bubble[dir="rtl"] .md-table th{ unicode-bidi:plaintext; }

  /* ===================== INVOICE ===================== */
  .invoice-card{
    margin-top:10px;
    padding:14px 16px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:12px;
    font-family:var(--font-body);
    font-size:12.5px;
  }
  /* A draft must never read as a finished document — the amber edge is the cue
     that this is a proposal with nothing recorded behind it yet. */
  .invoice-card.draft{ border-left:3px solid var(--accent); }
  .invoice-card.issued{ border-left:3px solid var(--ok, #4C9A6A); }
  .invoice-card.void{ border-left:3px solid var(--rust); opacity:.75; }

  .invoice-head{
    display:flex;
    justify-content:space-between;
    align-items:flex-start;
    gap:12px;
    padding-bottom:10px;
    border-bottom:1px solid var(--line);
  }
  .invoice-number{ font-family:var(--font-display, inherit); font-size:15px; font-weight:600; }
  .invoice-status{
    padding:2px 9px;
    border:1px solid var(--line);
    border-radius:10px;
    font-size:10.5px;
    white-space:nowrap;
  }
  .invoice-card.draft .invoice-status{
    color:var(--accent);
    border-color:color-mix(in srgb, var(--accent) 45%, transparent);
  }
  .invoice-card.void .invoice-status{ color:var(--rust); }

  .invoice-lines{ width:100%; border-collapse:collapse; margin:10px 0 4px; }
  .invoice-lines th,
  .invoice-lines td{ padding:5px 6px; text-align:left; }
  .invoice-lines thead th{
    font-size:10.5px;
    text-transform:uppercase;
    letter-spacing:.05em;
    color:var(--muted);
    border-bottom:1px solid var(--line);
  }
  .invoice-lines tbody tr + tr td{ border-top:1px solid color-mix(in srgb, var(--line) 55%, transparent); }
  .invoice-lines .num{ text-align:right; white-space:nowrap; }
  .invoice-lines tfoot td{ padding-top:6px; color:var(--muted); }
  .invoice-lines tfoot .invoice-total td{
    padding-top:8px;
    border-top:1px solid var(--line);
    color:var(--ink);
    font-weight:600;
    font-size:13.5px;
  }

  .invoice-warnings{
    margin:8px 0 0;
    padding:8px 10px 8px 26px;
    border-radius:8px;
    background:color-mix(in srgb, var(--accent) 10%, transparent);
    color:var(--ink);
    font-size:11.5px;
    line-height:1.6;
  }
  .invoice-warnings.error{ background:color-mix(in srgb, var(--rust) 14%, transparent); }

  .invoice-actions{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    justify-content:space-between;
    gap:10px;
    margin-top:12px;
  }

  /* ---- Printing ----
     The card is printed where it sits. Everything else on the page is hidden and
     the card's ancestors are unwrapped, so an invoice inside a scrolling chat log
     still prints as a full page rather than a clipped box. */
  @media print{
    body.printing-invoice *{ visibility:hidden !important; }
    body.printing-invoice .printing,
    body.printing-invoice .printing *{ visibility:visible !important; }

    body.printing-invoice .printing{
      position:absolute;
      left:0;
      top:0;
      width:100%;
      max-width:none;
      margin:0;
      padding:0;
      border:none;
      border-radius:0;
      background:#fff;
      color:#000;
      font-size:12pt;
      opacity:1;
    }

    /* The log clips and scrolls on screen; on paper it must do neither. */
    body.printing-invoice .chat-log{
      max-height:none !important;
      overflow:visible !important;
    }

    /* Any scroll box inside the printed area, whatever table it wraps. A scroll
       container still clips on paper -- there is nothing to scroll with -- so the
       columns past the edge would simply be missing from the invoice. */
    body.printing-invoice .printing .table-scroll{
      max-height:none !important;
      overflow:visible !important;
      border:none;
    }

    /* Fixed pixel column widths are sized for a screen. On paper let the content
       decide, inside the width the page actually has. */
    body.printing-invoice .printing .calls-table{
      table-layout:auto !important;
      min-width:0 !important;
      width:100% !important;
      font-size:10pt;
    }
    body.printing-invoice .printing .calls-table th,
    body.printing-invoice .printing .calls-table td{
      width:auto !important;
      white-space:normal;
      overflow:visible;
      border-color:#999;
      color:#000;
    }
    body.printing-invoice .printing .calls-table thead{ display:table-header-group; }
    body.printing-invoice .printing .calls-table tr{ break-inside:avoid; }

    body.printing-invoice .printing .invoice-actions{ display:none !important; }
    body.printing-invoice .printing .invoice-status{ border:1px solid #000; }
    body.printing-invoice .printing .invoice-lines th,
    body.printing-invoice .printing .invoice-lines td{ border-color:#999; }
    body.printing-invoice .printing .invoice-warnings{
      border:1px solid #999;
      background:none;
    }

    @page{ margin:16mm; }
  }

  /* ===================== VOICE ===================== */
  .voice-toggle{
    display:flex;
    align-items:center;
    gap:6px;
    font-family:var(--font-body);
    font-size:11.5px;
    color:var(--muted);
    cursor:pointer;
    user-select:none;
  }
  .voice-toggle input{ accent-color:var(--accent); cursor:pointer; }

  .voice-note{ padding:6px 2px 0; font-size:11.5px; }

  .mic-btn{
    flex:0 0 auto;
    display:inline-flex;
    align-items:center;
    justify-content:center;
    width:38px;
    height:38px;
    padding:0;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:10px;
    color:var(--ink);
    cursor:pointer;
    transition:border-color .15s ease, color .15s ease, background .15s ease;
  }
  .mic-btn svg{ width:17px; height:17px; }
  .mic-btn:hover:not(:disabled){ border-color:var(--accent); }
  .mic-btn:disabled{ opacity:.5; cursor:not-allowed; }

  /* While listening the button is unmistakable: the pulse is the only signal that
     the microphone is actually open. */
  .mic-btn.listening{
    background:var(--accent);
    border-color:var(--accent);
    color:var(--accent-ink);
    animation:mic-pulse 1.4s ease-in-out infinite;
  }

  @keyframes mic-pulse{
    0%, 100%{ box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
    50%     { box-shadow:0 0 0 6px color-mix(in srgb, var(--accent) 0%, transparent); }
  }

  /* Someone who sets "reduce motion" still needs to know the mic is live, so the
     state stays visible — only the animation stops. */
  @media (prefers-reduced-motion: reduce){
    .mic-btn.listening{ animation:none; }
  }

  /* An RTL card keeps its figures table in LTR: prices and quantities are Latin
     numerals, and mirroring the columns puts the total under the wrong heading. */
  .invoice-card[dir="rtl"] .invoice-lines{ direction:ltr; }
  .invoice-card[dir="rtl"] .invoice-lines th:first-child,
  .invoice-card[dir="rtl"] .invoice-lines td:first-child{ direction:rtl; text-align:right; }
  .invoice-card[dir="rtl"] .invoice-head{ text-align:right; }

  /* ---- Open draft bar ----
     Sits directly above the composer, because its whole job is to answer "where is
     what I am about to say going to end up?" before the person says it. */
  .open-draft-bar{
    display:flex;
    align-items:center;
    gap:10px;
    margin:10px 0 0;
    padding:8px 12px;
    background:color-mix(in srgb, var(--accent) 12%, transparent);
    border:1px solid color-mix(in srgb, var(--accent) 45%, transparent);
    border-radius:10px;
    font-family:var(--font-body);
    font-size:12px;
    color:var(--ink);
  }
  .open-draft-text{ flex:1; }
  .open-draft-bar strong{ font-size:13px; }

  /* A live indicator: the draft is accepting whatever is said next. */
  .open-dot{
    flex:0 0 auto;
    width:8px;
    height:8px;
    border-radius:50%;
    background:var(--accent);
    animation:open-pulse 2s ease-in-out infinite;
  }

  @keyframes open-pulse{
    0%, 100%{ opacity:1; }
    50%     { opacity:.35; }
  }

  @media (prefers-reduced-motion: reduce){
    .open-dot{ animation:none; }
  }

  .open-draft-close{ padding:4px 12px; font-size:11.5px; }

  /* ===================== REPORTS ===================== */

  /* Submenu under the Reports nav entry. Indented and quieter than a top-level
     item, so the hierarchy is readable without a second colour. */
  .nav-sub{
    display:flex;
    flex-direction:column;
    margin:2px 0 6px;
    padding-left:12px;
    border-left:1px solid rgba(255,255,255,.12);
    margin-left:22px;
  }
  .nav-subitem{
    padding:5px 10px;
    border-radius:6px;
    color:rgba(255,255,255,.62);
    font-family:var(--font-body);
    font-size:11.5px;
    text-decoration:none;
    transition:color .12s ease, background .12s ease;
  }
  .nav-subitem:hover{ color:#fff; background:rgba(255,255,255,.06); }
  .nav-subitem.active{ color:var(--accent); background:rgba(255,255,255,.08); }

  /* ---- Landing page ---- */
  .report-group{ margin-bottom:22px; }
  .report-group-label{
    margin-bottom:10px;
    font-family:var(--font-body);
    font-size:10.5px;
    text-transform:uppercase;
    letter-spacing:.08em;
    color:var(--muted);
  }
  .report-cards{
    display:grid;
    grid-template-columns:repeat(auto-fill, minmax(230px, 1fr));
    gap:12px;
  }
  .report-card{
    display:block;
    padding:14px 16px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:10px;
    text-decoration:none;
    color:var(--ink);
    transition:border-color .15s ease, transform .12s ease;
  }
  .report-card:hover{ border-color:var(--accent); transform:translateY(-1px); }
  .report-card-title{ font-family:var(--font-head); font-size:14px; margin-bottom:4px; }
  .report-card-blurb{
    font-family:var(--font-body);
    font-size:11.5px;
    color:var(--muted);
    line-height:1.5;
  }

  /* ---- Report page ---- */
  .report-head{
    display:flex;
    align-items:flex-start;
    justify-content:space-between;
    gap:16px;
    flex-wrap:wrap;
  }
  .report-actions{ display:flex; gap:8px; flex-shrink:0; }
  .report-actions button{ padding:6px 14px; font-size:11.5px; }

  .report-filters{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:10px;
    margin:14px 0 4px;
    padding:12px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:10px;
  }
  .range-picker{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
  .date-field{ min-width:140px; }
  .vehicle-field{ max-width:170px; }

  .report-print-area{ padding-top:16px; }

  /* The print header is for paper only — on screen the page title already says this. */
  .print-header{ display:none; }

  .report-body .stat-row,
  .report-print-area .stat-row{
    display:flex;
    flex-wrap:wrap;
    gap:14px;
    margin-bottom:18px;
  }
  .report-print-area .stat-row .stat{ flex:1 1 150px; margin:0; }

  /* A 500-row report must not turn the page into a 16,000px scroll. The table gets
     its own scroll box with a sticky header, so the column names stay readable and
     the filters above stay reachable. Print overrides this — see the print block,
     where the report must run to its full length across pages.

     Scoped to a report table on purpose. Unscoped, this capped EVERY .table-scroll in
     the app, including the paged Calls and Inventory tables: a 25-row page was clipped
     mid-row with its own inner scrollbar, which reads as "the list ends here" and hides
     the pager's last rows. Those tables are already bounded by their page size, so they
     do not need a cap of their own. */
  .table-scroll:has(.report-table){
    max-height:62vh;
    overflow-y:auto;
    border:1px solid var(--line);
    border-radius:8px;
  }

  .report-table{
    width:100%;
    border-collapse:collapse;
    font-family:var(--font-body);
    font-size:12.5px;
  }
  .table-scroll .report-table thead th{
    position:sticky;
    top:0;
    z-index:1;
    background:var(--surface);
  }
  .report-table th,
  .report-table td{ padding:8px 10px; text-align:left; vertical-align:top; }
  .report-table thead th{
    font-size:10.5px;
    text-transform:uppercase;
    letter-spacing:.05em;
    color:var(--muted);
    border-bottom:1px solid var(--line);
    white-space:nowrap;
  }
  .report-table tbody tr + tr td{
    border-top:1px solid color-mix(in srgb, var(--line) 55%, transparent);
  }
  .report-table tbody tr:hover td{ background:var(--surface-2); }
  .report-table .num{ text-align:right; white-space:nowrap; }

  /* Rows that are the reason to open the report get a left edge. */
  .report-table .row-low td:first-child{ box-shadow:inset 2px 0 0 var(--accent); }
  .report-table .row-out td:first-child{ box-shadow:inset 2px 0 0 var(--rust); }
  .report-table .row-void{ opacity:.6; }

  /* Fitment text is long; cap it so one row cannot stretch the table. */
  .fits-cell{ max-width:280px; }

  .report-note{ margin-top:12px; line-height:1.6; }
  .gap-list-label{ margin-top:14px; }
  .gap-list{
    margin:6px 0 12px;
    padding-left:20px;
    font-family:var(--font-body);
    font-size:12.5px;
    line-height:1.8;
  }

  /* Links in panel copy follow the theme; browser blue reads as foreign here. */
  .chat-foot a,
  .report-print-area a,
  .empty-note a{
    color:var(--accent);
    text-decoration:underline;
    text-underline-offset:2px;
  }
  .chat-foot a:hover,
  .report-print-area a:hover,
  .empty-note a:hover{ opacity:.8; }

  /* A stat whose value is itself the judgement carries the colour on the figure. */
  .stat .value.up{ color:var(--good); }
  .stat .value.warn{ color:var(--rust); }

  /* `screen` for the same reason as .calls-table below: paper is narrower than 760px,
     so without it a printed report got a 560px minimum inside a clipping box. */
  @media screen and (max-width:760px){
    .report-print-area{ overflow-x:auto; }
    .report-table{ min-width:560px; }
    .report-head{ flex-direction:column; }
  }

  /* ---- Printing a report ----
     Same mechanism as the invoice card: the region stays in the DOM and everything
     else is hidden, so the stylesheet still applies. Colours are dropped because a
     dark theme on paper wastes toner and reads badly. */
  @media print{
    body.printing-invoice .report-print-area.printing{
      color:#000;
      background:#fff;
    }
    body.printing-invoice .printing .print-header{
      display:block;
      margin-bottom:14px;
      padding-bottom:10px;
      border-bottom:2px solid #000;
    }
    body.printing-invoice .printing .print-yard{ font-size:11pt; font-weight:600; }
    body.printing-invoice .printing .print-title{ font-size:16pt; margin:2px 0; }
    body.printing-invoice .printing .print-filters{ font-size:10pt; }
    body.printing-invoice .printing .print-date{ font-size:9pt; color:#444; }

    body.printing-invoice .printing .stat{
      background:none;
      border:1px solid #999;
    }
    body.printing-invoice .printing .stat .value{ color:#000 !important; font-size:15pt; }
    body.printing-invoice .printing .stat .label{ color:#444; }

    body.printing-invoice .printing .report-table{ font-size:9pt; }
    body.printing-invoice .printing .report-table th,
    body.printing-invoice .printing .report-table td{
      border-color:#999;
      color:#000;
    }
    body.printing-invoice .printing .report-table thead th{
      border-bottom:1px solid #000;
      color:#000;
    }
    /* On paper the table must run its full length across pages, not scroll. */
    body.printing-invoice .printing .table-scroll{
      max-height:none;
      overflow:visible;
      border:none;
    }
    /* Repeat the header on every page of a long table. */
    body.printing-invoice .printing .report-table thead{ display:table-header-group; }
    body.printing-invoice .printing .report-table thead th{ position:static; }
    body.printing-invoice .printing .report-table tr{ break-inside:avoid; }
    body.printing-invoice .printing .fn-tag{ border:1px solid #666; color:#000; }
    body.printing-invoice .printing .cell-sub{ color:#444; }
    body.printing-invoice .printing .fits-cell{ max-width:none; }
  }


  /* ===================== LETTERHEAD ===================== */
  /* The yard's identity on anything it prints. Three columns: mark, business, and
     the document's own title on the right, which is where a reader looks first to
     find out what a piece of paper is. */
  .letterhead{
    display:flex;
    align-items:flex-start;
    gap:16px;
    flex-wrap:wrap;
  }
  .letterhead-logo{
    /* Height fixed, width free: a logo is usually wider than tall, and constraining
       the width instead would squash a square one. */
    height:56px;
    width:auto;
    max-width:220px;
    object-fit:contain;
    flex:0 0 auto;
  }
  .letterhead-text{ flex:1 1 220px; min-width:0; }
  .letterhead-line{
    font-family:var(--font-body);
    font-size:11.5px;
    color:var(--muted);
    line-height:1.5;
  }
  /* Right-aligned and last in the source, so it reads as the document's own heading
     rather than part of the address block. */
  .letterhead-doc{
    flex:0 0 auto;
    margin-left:auto;
    text-align:right;
  }

  .invoice-terms{
    margin-top:14px;
    padding-top:10px;
    border-top:1px solid var(--line);
    font-family:var(--font-body);
    font-size:11px;
    line-height:1.6;
    color:var(--muted);
    white-space:pre-wrap;
  }
  .invoice-terms-note{ border-top:none; padding-top:4px; }

  @media print{
    body.printing-invoice .printing .letterhead{
      border-bottom:2px solid #000;
      padding-bottom:10px;
      margin-bottom:14px;
      /* The flex row must not wrap on paper: a logo dropping onto its own line
         pushes the whole header down a third of the page. */
      flex-wrap:nowrap;
    }
    body.printing-invoice .printing .letterhead-logo{
      height:52px;
      /* Browsers strip background images at print by default but leave <img>
         alone; this makes sure the yard's mark is not dropped to save ink. */
      -webkit-print-color-adjust:exact;
      print-color-adjust:exact;
    }
    body.printing-invoice .printing .letterhead-line{ color:#333; font-size:9pt; }
    body.printing-invoice .printing .invoice-terms{
      color:#333;
      border-color:#999;
      font-size:8.5pt;
    }
  }

  /* ===================== PLANS & BILLING ===================== */
  .plan-grid{
    display:grid;
    /* auto-fit rather than a fixed count: three plans should not leave a gap where a
       fourth would go, and two should not each take half the screen. */
    grid-template-columns:repeat(auto-fit, minmax(230px, 1fr));
    gap:16px;
    margin-bottom:18px;
  }
  .plan-card{
    position:relative;
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    gap:8px;
    padding:18px;
    border:1px solid var(--line);
    border-radius:var(--radius-card);
    background:var(--surface);
  }
  .plan-card.chosen{
    border-color:var(--accent);
    box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent);
  }
  /* The plan the yard is already on. Distinct from `chosen`, which is what they are
     about to pick -- confusing the two would let someone buy what they already have
     without noticing. */
  .plan-card.current{ border-color:var(--good); }
  .plan-badge{
    position:absolute;
    top:-9px;
    right:14px;
    padding:2px 8px;
    border-radius:999px;
    background:var(--good);
    color:#fff;
    font-family:var(--font-body);
    font-size:10px;
    letter-spacing:.04em;
  }
  .plan-name{
    font-family:var(--font-head);
    font-size:15px;
    color:var(--ink);
  }
  .plan-price{
    font-family:var(--font-head);
    font-size:22px;
    color:var(--ink);
    line-height:1.1;
  }
  .plan-trial{
    font-family:var(--font-body);
    font-size:11.5px;
    color:var(--good);
  }
  .plan-blurb{
    font-family:var(--font-body);
    font-size:12px;
    color:var(--muted);
    line-height:1.55;
  }
  .plan-limits{ font-size:11.5px; }
  /* Pushed to the foot so every card's button sits on one line however long the
     descriptions above them are. */
  .plan-card > button,
  .plan-card > .plan-cta{ margin-top:auto; align-self:stretch; text-align:center; }
  .plan-cta{ text-decoration:none; display:block; padding:8px 12px; }

  .topup-form{ margin-top:6px; }

  .plan-minutes{
    font-family:var(--font-body);
    font-size:12.5px;
    color:var(--accent);
    font-weight:600;
  }

  /* ---- minutes used ---- */
  .minutes-head{
    display:flex;
    justify-content:space-between;
    align-items:flex-start;
    gap:16px;
    margin-bottom:12px;
  }
  .minutes-big{
    font-family:var(--font-head);
    font-size:26px;
    color:var(--ink);
    line-height:1.1;
  }
  /* The denominator is context, not the number being read. */
  .minutes-of{
    font-family:var(--font-body);
    font-size:13px;
    color:var(--muted);
    font-weight:normal;
  }
  .minutes-bar{
    height:10px;
    border-radius:999px;
    background:color-mix(in srgb, var(--ink) 10%, transparent);
    overflow:hidden;
    margin-bottom:12px;
  }
  .minutes-fill{
    height:100%;
    border-radius:999px;
    transition:width .3s ease;
  }
  .minutes-fill.ok{ background:var(--good); }
  .minutes-fill.warn{ background:#c89b3c; }
  .minutes-fill.bad{ background:var(--rust); }
  @media (prefers-reduced-motion:reduce){
    .minutes-fill{ transition:none; }
  }

  /* ---- a receipt, opened from its row ---- */
  /* The open row stays visually attached to the panel below it, so the two read as
     one thing rather than as a row and an unrelated box. */
  .row-open{ background:color-mix(in srgb, var(--accent) 8%, transparent); }
  .receipt-row > td{ padding:0 !important; background:transparent; }
  .receipt{
    padding:16px 18px;
    border-left:3px solid var(--accent);
    background:color-mix(in srgb, var(--accent) 5%, transparent);
  }
  .receipt-head{
    display:flex;
    justify-content:space-between;
    align-items:flex-start;
    gap:16px;
    margin-bottom:12px;
  }
  .receipt-title{
    font-family:var(--font-head);
    font-size:15px;
    color:var(--ink);
  }
  .receipt-amount{
    font-family:var(--font-head);
    font-size:22px;
    color:var(--ink);
    font-variant-numeric:tabular-nums;
  }
  .receipt-facts{
    display:grid;
    grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));
    gap:10px 18px;
    margin:0 0 8px;
  }
  .receipt-facts dt{
    font-family:var(--font-body);
    font-size:10.5px;
    text-transform:uppercase;
    letter-spacing:.06em;
    color:var(--muted);
    margin-bottom:2px;
  }
  .receipt-facts dd{
    margin:0;
    font-family:var(--font-body);
    font-size:13px;
    color:var(--ink);
    /* A Stripe intent id is long and must not push the grid wide. */
    overflow-wrap:anywhere;
  }

  /* ---- the public plans page ---- */
  .plans-shell{
    display:block;
    padding:48px 20px 40px;
    max-width:980px;
    margin:0 auto;
  }
  .plans-head{ text-align:center; margin-bottom:28px; }
  .plans-head .login-sub{ max-width:620px; margin:10px auto 0; }
  .plans-public{ margin-bottom:24px; }
  .plans-empty{
    padding:32px;
    text-align:center;
    border:1px solid var(--line);
    border-radius:var(--radius-card);
    background:var(--surface);
  }
  .plans-foot{
    display:flex;
    justify-content:center;
    align-items:center;
    gap:10px;
    font-family:var(--font-body);
    font-size:12.5px;
  }

  /* ---- sign up ---- */
  .register-card{ max-width:420px; }
  .login-links{
    display:flex;
    justify-content:center;
    align-items:center;
    gap:10px;
    margin-top:14px;
    font-family:var(--font-body);
    font-size:12.5px;
  }
  .signup-steps{
    display:flex;
    gap:6px;
    margin:14px 0 18px;
  }
  /* Three equal segments that fill in as the person advances: a progress bar that
     names its steps, so "one more thing" is visible rather than implied. */
  .signup-step{
    flex:1;
    padding:5px 4px;
    border-radius:6px;
    border:1px solid var(--line);
    background:transparent;
    color:var(--muted);
    font-family:var(--font-body);
    font-size:10.5px;
    text-align:center;
    letter-spacing:.02em;
  }
  .signup-step.current{
    border-color:var(--accent);
    color:var(--ink);
  }
  .signup-step.done{
    border-color:var(--good);
    background:color-mix(in srgb, var(--good) 12%, transparent);
    color:var(--ink);
  }
  .signup-done{
    padding:14px;
    border:1px solid var(--line);
    border-radius:9px;
    font-family:var(--font-body);
    font-size:13px;
    line-height:1.6;
    margin-bottom:14px;
  }
  .signup-done p{ margin:0 0 6px; }
  .signup-done p:last-child{ margin-bottom:0; }

  /* ---- logo upload ---- */
  .logo-row{
    display:flex;
    align-items:flex-start;
    gap:18px;
    flex-wrap:wrap;
  }
  /* A fixed box so the panel does not jump when a logo is added or removed, and so a
     very wide or very tall image is previewed at the size it will actually print. */
  .logo-preview{
    flex:0 0 auto;
    display:flex;
    align-items:center;
    justify-content:center;
    width:190px;
    height:76px;
    padding:8px;
    border:1px dashed var(--line);
    border-radius:8px;
    /* White, not the theme surface: the logo is printed on white paper, and a dark
       preview would hide exactly the problem a yard needs to see -- dark artwork
       that vanishes on the page. */
    background:#fff;
  }
  .logo-preview img{ max-width:100%; max-height:100%; object-fit:contain; }
  .logo-empty{ font-size:11.5px; }
  .logo-actions{
    flex:1 1 260px;
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    gap:8px;
    min-width:0;
  }

  /* ===================== SETTINGS ===================== */
  .setting-block{ margin-bottom:24px; }
  .setting-label{
    margin-bottom:10px;
    font-family:var(--font-body);
    font-size:10.5px;
    text-transform:uppercase;
    letter-spacing:.08em;
    color:var(--muted);
  }
  .setting-row{
    display:flex;
    justify-content:space-between;
    padding:8px 0;
    border-bottom:1px solid var(--line);
    font-family:var(--font-body);
    font-size:13px;
  }
  .setting-row:last-child{ border-bottom:none; }

  .theme-grid,
  .font-grid{
    display:grid;
    grid-template-columns:repeat(auto-fill, minmax(210px, 1fr));
    gap:12px;
  }

  .theme-card,
  .font-card{
    display:flex;
    flex-direction:column;
    gap:6px;
    padding:14px;
    background:var(--surface-2);
    border:1px solid var(--line);
    border-radius:10px;
    text-align:left;
    color:var(--ink);
    cursor:pointer;
    transition:border-color .15s ease, transform .12s ease;
  }
  .theme-card:hover,
  .font-card:hover{ border-color:var(--accent); transform:translateY(-1px); }
  .theme-card.active,
  .font-card.active{
    border-color:var(--accent);
    box-shadow:0 0 0 1px var(--accent) inset;
  }

  /* Four bands of the actual palette: the choice is made by looking, not by reading. */
  .theme-swatch{ display:flex; height:34px; border-radius:6px; overflow:hidden; }
  .theme-swatch span{ flex:1; }

  .theme-name,
  .font-name{
    display:flex;
    align-items:center;
    justify-content:space-between;
    font-family:var(--font-head);
    font-size:13.5px;
  }
  .theme-tick{ color:var(--accent); font-size:12px; }
  .theme-blurb{
    font-family:var(--font-body);
    font-size:11px;
    color:var(--muted);
    line-height:1.5;
  }

  /* Each sample is set in the face it names, overriding the page font. */
  .font-sample{ font-size:15px; padding:4px 0; }
  .font-card.font-inter .font-sample{ font-family:'Inter', sans-serif; }
  .font-card.font-system .font-sample{ font-family:-apple-system, 'Segoe UI', Roboto, sans-serif; }
  .font-card.font-mono .font-sample{ font-family:'JetBrains Mono', Consolas, monospace; font-size:13px; }
  .font-card.font-serif .font-sample{ font-family:'Source Serif 4', Georgia, serif; }
  .font-card.font-rounded .font-sample{ font-family:'Nunito', sans-serif; }

  /* ===================== INVOICE DETAIL ===================== */
  .draft-banner{
    display:flex;
    align-items:center;
    gap:10px;
    margin:14px 0 4px;
    padding:10px 14px;
    background:color-mix(in srgb, var(--accent) 12%, transparent);
    border:1px solid color-mix(in srgb, var(--accent) 45%, transparent);
    border-radius:10px;
    font-family:var(--font-body);
    font-size:12px;
    line-height:1.6;
  }

  .status-draft{ color:var(--accent); }
  .status-issued{ color:var(--good); }
  .status-void{ color:var(--rust); }

  /* A whole row opens the invoice, so it has to look like it does something. */
  .row-link{ cursor:pointer; }
  .row-link:hover td{ background:var(--surface-2); }
  .row-link a{ color:var(--accent); text-decoration:none; }
  .row-link a:hover{ text-decoration:underline; }

  .report-table tfoot td{ padding-top:8px; color:var(--muted); }
  .report-table tfoot .invoice-total td{
    border-top:1px solid var(--line);
    color:var(--ink);
    font-weight:600;
    font-size:13.5px;
  }

  /* Voiding is destructive, so it sits apart from the ordinary actions and is not
     styled like something to click on the way past. */
  .danger-row{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:10px;
    margin-top:20px;
    padding-top:16px;
    border-top:1px solid var(--line);
  }
  .btn-quiet{
    padding:6px 12px;
    background:none;
    border:1px solid var(--line);
    border-radius:6px;
    color:var(--muted);
    font-family:var(--font-body);
    font-size:11.5px;
    cursor:pointer;
  }
  .btn-quiet:hover{ color:var(--rust); border-color:var(--rust); }
  .btn-danger{
    padding:6px 14px;
    background:var(--rust);
    border:1px solid var(--rust);
    border-radius:6px;
    color:#fff;
    font-family:var(--font-body);
    font-size:11.5px;
    cursor:pointer;
  }
  .btn-danger:disabled{ opacity:.6; cursor:not-allowed; }

  @media print{
    body.printing-invoice .printing .draft-banner,
    body.printing-invoice .printing .danger-row{ display:none !important; }
  }

  /* ===================== DRAFT LINE EDITOR ===================== */
  /* A draft's lines are edited in place. Everything here is apparatus: it is inside
     the print area for the quantity boxes but must never reach paper. */
  /* Visible on screen, gone on paper. The markup only emits these cells for a draft,
     so there is nothing to hide unless a draft is being printed — which is a real
     case, since staff do print a quote for a customer to take away. */
  @media print{
    .no-print{ display:none !important; }
  }
  body.printing-invoice .printing .no-print{ display:none !important; }

  .qty-input{
    width:62px;
    padding:4px 6px;
    text-align:right;
    border:1px solid var(--line);
    border-radius:6px;
    background:var(--card);
    color:var(--ink);
    font-family:var(--font-body);
    font-size:12.5px;
    font-variant-numeric:tabular-nums;
  }
  .qty-input:focus{ outline:2px solid var(--accent); outline-offset:-1px; }
  .qty-input:disabled{ opacity:.55; }

  /* Keep the actions column exactly as wide as the button, so × sits beside its own
     row's figures rather than drifting to the far edge of the table. */
  .report-table th.no-print,
  .report-table td.no-print{ width:34px; padding-left:4px; padding-right:4px; }

  /* A × that is easy to hit but not easy to hit by accident: quiet until hovered,
     and it only turns red once the pointer is actually on it. */
  .line-remove{
    width:26px;
    height:26px;
    padding:0;
    background:none;
    border:1px solid transparent;
    border-radius:6px;
    color:var(--muted);
    font-size:16px;
    line-height:1;
    cursor:pointer;
    opacity:.75;
  }
  .line-remove:hover{ opacity:1; }
  .line-remove:hover{
    color:var(--rust);
    border-color:var(--rust);
    background:color-mix(in srgb, var(--rust) 10%, transparent);
  }
  .line-remove:disabled{ opacity:.4; cursor:not-allowed; }

  .line-editor{
    margin-top:22px;
    padding-top:18px;
    border-top:1px solid var(--line);
  }
  .line-editor .editor-gap{ margin-top:20px; }

  .line-add-row{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    gap:10px;
    margin-bottom:10px;
  }
  .line-search{ flex:1; min-width:240px; }

  .part-matches{
    list-style:none;
    margin:0 0 6px;
    padding:0;
    border:1px solid var(--line);
    border-radius:8px;
    overflow:hidden;
  }
  .part-matches li + li{ border-top:1px solid var(--line); }

  .part-match{
    display:flex;
    align-items:baseline;
    gap:12px;
    width:100%;
    padding:9px 12px;
    background:none;
    border:none;
    text-align:left;
    font-family:var(--font-body);
    font-size:13px;
    color:var(--ink);
    cursor:pointer;
  }
  .part-match:hover{ background:color-mix(in srgb, var(--accent) 10%, transparent); }
  .part-match:disabled{ opacity:.5; cursor:not-allowed; }
  .part-match-name{ flex:1; min-width:0; }
  /* The figure that will land on the invoice, so it reads before the click, not after. */
  .part-match-price{
    font-variant-numeric:tabular-nums;
    font-weight:600;
    white-space:nowrap;
  }

  /* ===================== EXPANDABLE INVOICE ROWS ===================== */
  /* A list of invoices showing only a total does not answer the question anybody has,
     which is what is ON the invoice. These rows unfold in place, so the lines can be
     read without losing the list. */
  .expander{ width:26px; padding-left:8px; padding-right:0; }
  .caret{
    display:inline-block;
    color:var(--muted);
    font-size:15px;
    line-height:1;
    transition:transform .15s ease;
  }
  .caret.down{ transform:rotate(90deg); color:var(--accent); }
  .row-open > td{ background:color-mix(in srgb, var(--accent) 7%, transparent); }

  .row-detail > td{
    padding:14px 18px 16px 34px;
    background:color-mix(in srgb, var(--accent) 4%, transparent);
    border-bottom:1px solid var(--line);
  }

  /* Deliberately lighter than the list above it, so the nesting reads as nesting
     rather than as a second list that happens to be indented. */
  .detail-table{
    width:100%;
    border-collapse:collapse;
    font-size:12.5px;
  }
  .detail-table th{
    text-align:left;
    padding:4px 10px 6px;
    font-size:10px;
    letter-spacing:.5px;
    text-transform:uppercase;
    color:var(--muted);
    border-bottom:1px solid var(--line);
  }
  .detail-table td{
    padding:6px 10px;
    border-bottom:1px solid color-mix(in srgb, var(--line) 50%, transparent);
  }
  .detail-table .num{ text-align:right; font-variant-numeric:tabular-nums; }
  .detail-table tfoot td{
    border-bottom:none;
    color:var(--muted);
  }
  .detail-table tfoot .invoice-total td{
    font-weight:700;
    color:var(--ink);
    border-top:1px solid var(--line);
  }

  .detail-actions{ margin-top:10px; }
  .detail-actions .btn-secondary{
    padding:5px 12px;
    font-size:11.5px;
    text-decoration:none;
    display:inline-flex;
    align-items:center;
  }

  /* The primary action on the invoices landing page. It is a banner rather than one
     more card because starting an invoice is why most people open this section, and a
     button that looks like its neighbours is a button nobody finds. */
  .invoice-start{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    justify-content:space-between;
    gap:16px;
    padding:16px 18px;
    margin-bottom:20px;
    border:1px solid var(--accent);
    border-radius:10px;
    background:color-mix(in srgb, var(--accent) 8%, transparent);
  }
  .invoice-start-title{
    font-family:var(--font-head);
    font-size:15px;
    color:var(--ink);
    margin-bottom:3px;
  }
  .invoice-start .btn-primary{ white-space:nowrap; }

  /* ---- change password ---- */
  /* Capped so the three boxes stay a form rather than stretching across a wide screen
     as if they were a table. */
  .pw-form{
    display:grid;
    grid-template-columns:repeat(auto-fit, minmax(210px, 1fr));
    gap:14px;
    max-width:760px;
    margin-bottom:14px;
  }
  .pw-field{ display:flex; flex-direction:column; gap:5px; }
  .pw-field input{ width:100%; }

  /* Actions on an invoice card sit together at the end of the row. */
  .card-actions{ display:flex; align-items:center; gap:8px; }
  .card-actions .btn-secondary,
  .card-actions .btn-primary{
    padding:6px 14px;
    font-size:11.5px;
    text-decoration:none;
    display:inline-flex;
    align-items:center;
  }
  a.open-draft-close{ text-decoration:none; display:inline-flex; align-items:center; }

  /* ===================== WHATSAPP SETTINGS ===================== */
  /* The status strip answers "is it on?" before the form asks for anything, because
     that is the question someone opening this panel actually has. */
  .wa-status{
    display:flex;
    align-items:center;
    gap:12px;
    padding:12px 14px;
    margin-bottom:16px;
    border:1px solid var(--line);
    border-radius:9px;
  }
  .wa-status > div{ flex:1; min-width:0; }
  .wa-status-title{ font-family:var(--font-head); font-size:14px; color:var(--ink); }

  .wa-dot{
    width:9px; height:9px;
    border-radius:50%;
    flex-shrink:0;
    background:var(--muted);
  }
  /* Green only when messages are actually being answered. "Ready" is amber, because
     filled-in-but-off is a real state a yard needs to be able to see. */
  .wa-status.on{ border-color:#3f9e5a; background:color-mix(in srgb, #3f9e5a 8%, transparent); }
  .wa-status.on .wa-dot{ background:#3f9e5a; box-shadow:0 0 0 3px color-mix(in srgb, #3f9e5a 25%, transparent); }
  .wa-status.ready{ border-color:#c89b3c; background:color-mix(in srgb, #c89b3c 8%, transparent); }
  .wa-status.ready .wa-dot{ background:#c89b3c; }

  /* ---- the public wa.me link and its QR ---- */
  .wa-qr-block{
    display:flex;
    flex-wrap:wrap;
    gap:20px;
    align-items:flex-start;
    margin-top:18px;
    padding-top:18px;
    border-top:1px solid var(--line);
  }

  /* The card is what gets printed and photographed, so it is always light with a dark
     code regardless of the app theme: a QR inverted by a dark theme will not scan, and
     printing a dark card wastes a cartridge. */
  .wa-qr-card{
    background:#ffffff;
    color:#111111;
    border:1px solid #e3e3e3;
    border-radius:10px;
    padding:16px;
    text-align:center;
  }
  .wa-qr{ line-height:0; }
  .wa-qr svg{ display:block; width:200px; height:200px; }
  .wa-qr-caption{ margin-top:10px; }
  .wa-qr-name{ font-family:var(--font-head); font-size:14px; color:#111111; }
  .wa-qr-caption .wa-mono{ color:#333333; font-size:12px; }
  .wa-qr-caption .cell-sub{ color:#666666; font-size:11px; }

  .wa-qr-actions{
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    gap:8px;
    flex:1;
    min-width:180px;
  }

  @media print{
    /* Only the card prints: the surrounding settings page is noise on paper. */
    body.printing-invoice .wa-qr-card{
      border:none;
      padding:0;
    }
  }

  /* Token expiry. Louder than the status row above it, because it reports a channel
     that has gone quiet while still looking connected. */
  .wa-token-warn{
    padding:12px 14px;
    margin-bottom:16px;
    border:1px solid var(--line);
    border-left-width:3px;
    border-radius:9px;
  }
  .wa-token-warn .cell-sub{ margin:4px 0 10px; line-height:1.55; }
  .wa-token-warn.warn{
    border-color:#c89b3c;
    background:color-mix(in srgb, #c89b3c 8%, transparent);
  }
  .wa-token-warn.bad{
    border-color:#b4523f;
    background:color-mix(in srgb, #b4523f 10%, transparent);
  }

  .wa-hint{
    display:block;
    margin-top:4px;
    font-size:11px;
    line-height:1.5;
    color:var(--muted);
  }
  .wa-hint strong{ color:var(--ink); font-weight:600; }

  /* A quiet confirmation that a secret is stored, without showing any of it. */
  .wa-saved{
    margin-left:6px;
    padding:1px 6px;
    border-radius:4px;
    font-size:9.5px;
    letter-spacing:.4px;
    text-transform:uppercase;
    background:color-mix(in srgb, #3f9e5a 18%, transparent);
    color:#3f9e5a;
  }

  .wa-inline{ display:flex; gap:8px; align-items:center; }
  .wa-inline input{ flex:1; min-width:0; }

  /* Selectable and wrapping: this gets copied into Meta's dashboard by hand. */
  .wa-callback{
    padding:10px 12px;
    border:1px solid var(--line);
    border-radius:7px;
    background:color-mix(in srgb, var(--accent) 5%, transparent);
    overflow-wrap:anywhere;
    user-select:all;
  }
  .wa-callback code{
    font-family:var(--font-mono, ui-monospace, monospace);
    font-size:12px;
    color:var(--ink);
  }

  .wa-missing{
    margin-top:12px;
    padding:9px 12px;
    border-left:3px solid #c89b3c;
    border-radius:0 6px 6px 0;
    background:color-mix(in srgb, #c89b3c 8%, transparent);
    font-size:12px;
    color:var(--ink);
  }

  /* ---- WhatsApp setup wizard ---- */
  /* The fields come from four different screens in Meta's dashboard. A flat form gives
     no clue which, so the steps are numbered and named after where you have to go. */
  .wiz-steps{
    display:flex;
    gap:6px;
    margin-bottom:16px;
    flex-wrap:wrap;
  }
  .wiz-step{
    display:flex;
    align-items:center;
    gap:7px;
    padding:7px 12px;
    background:none;
    border:1px solid var(--line);
    border-radius:7px;
    color:var(--muted);
    font-family:var(--font-body);
    font-size:12px;
    cursor:pointer;
    transition:border-color .15s ease, color .15s ease;
  }
  .wiz-step:hover{ color:var(--ink); }
  .wiz-step.current{
    border-color:var(--accent);
    color:var(--ink);
    background:color-mix(in srgb, var(--accent) 8%, transparent);
  }
  .wiz-step.done{ color:#3f9e5a; border-color:color-mix(in srgb, #3f9e5a 45%, transparent); }

  .wiz-num{
    display:inline-flex;
    align-items:center;
    justify-content:center;
    width:19px; height:19px;
    flex-shrink:0;
    border-radius:50%;
    background:var(--line);
    font-size:10.5px;
    font-weight:600;
  }
  .wiz-step.current .wiz-num{ background:var(--accent); color:#fff; }
  .wiz-step.done .wiz-num{ background:#3f9e5a; color:#fff; }

  .wiz-body{
    padding:16px 18px;
    border:1px solid var(--line);
    border-radius:9px;
    margin-bottom:12px;
  }
  .wiz-title{
    font-family:var(--font-head);
    font-size:15px;
    color:var(--ink);
    margin-bottom:7px;
  }
  .wiz-text{
    margin:0 0 12px;
    font-size:13px;
    line-height:1.6;
    color:var(--muted);
  }
  .wiz-text strong, .wiz-list strong{ color:var(--ink); font-weight:600; }

  .wiz-list{
    margin:0 0 12px;
    padding-left:20px;
    font-size:13px;
    line-height:1.9;
    color:var(--muted);
  }
  .wiz-list a{ color:var(--accent); }

  /* Context that is worth reading but is not an instruction. */
  .wiz-note{
    padding:9px 12px;
    border-left:3px solid var(--accent);
    border-radius:0 6px 6px 0;
    background:color-mix(in srgb, var(--accent) 7%, transparent);
    font-size:12px;
    line-height:1.6;
    color:var(--ink);
  }
  .wiz-note code{
    font-family:var(--font-mono, ui-monospace, monospace);
    font-size:11.5px;
    padding:1px 5px;
    border-radius:4px;
    background:color-mix(in srgb, var(--ink) 10%, transparent);
  }

  .wiz-nav{ display:flex; align-items:center; gap:10px; }
  .wiz-spacer{ flex:1; }

  /* Text button for a secondary escape hatch, e.g. "hide these steps". */
  .wa-link{
    margin-top:10px;
    padding:0;
    background:none;
    border:none;
    color:var(--muted);
    font-family:var(--font-body);
    font-size:11.5px;
    text-decoration:underline;
    cursor:pointer;
  }
  .wa-link:hover{ color:var(--ink); }

  /* ---- compact view, once the channel works ---- */
  .wa-summary{
    border:1px solid var(--line);
    border-radius:9px;
    overflow:hidden;
    margin-bottom:12px;
  }
  .wa-row{
    display:flex;
    align-items:baseline;
    justify-content:space-between;
    gap:16px;
    padding:9px 14px;
    font-size:13px;
  }
  .wa-row + .wa-row{ border-top:1px solid var(--line); }
  .wa-mono{
    font-family:var(--font-mono, ui-monospace, monospace);
    font-size:12px;
  }
  .wa-wrap{ overflow-wrap:anywhere; text-align:right; }

  /* ===================== PLATFORM ADMIN =====================
     A visually distinct area, on purpose. These pages change what every customer is
     charged, so they should not look like the yard screens an operator uses all day --
     the banner and the accent bar are there to make "I am in the admin area" obvious
     at a glance rather than something you infer from the URL. */
  .admin-bar{
    display:flex;
    flex-wrap:wrap;
    align-items:center;
    justify-content:space-between;
    gap:12px;
    margin-bottom:18px;
    padding:14px 16px;
    border:1px solid var(--line);
    border-left:3px solid var(--accent);
    border-radius:var(--radius-m, 10px);
    background:var(--surface-2);
  }
  .admin-bar-title{
    display:flex;
    align-items:center;
    gap:10px;
    flex-wrap:wrap;
    font-family:var(--font-head);
    font-size:15px;
    color:var(--ink);
  }
  .admin-badge{
    padding:2px 8px;
    border-radius:4px;
    background:var(--accent);
    color:#fff;
    font-size:10px;
    letter-spacing:.08em;
    font-family:var(--font-body);
  }

  .admin-tabs{ display:flex; flex-wrap:wrap; gap:4px; }
  .admin-tab{
    padding:7px 14px;
    border-radius:7px;
    font-size:13px;
    color:var(--muted);
    text-decoration:none;
    transition:background .15s ease, color .15s ease;
  }
  .admin-tab:hover{ background:var(--surface-3, var(--surface-2)); color:var(--ink); }
  .admin-tab.current{ background:var(--accent); color:#fff; }
  /* Pushed away from the tabs: it leaves the area rather than moving within it. */
  .admin-exit{ margin-left:10px; border:1px solid var(--line); }

  /* Same shape as the WhatsApp status row, reused so the two settings areas read
     alike. */
  .admin-status{
    display:flex;
    align-items:center;
    gap:12px;
    padding:12px 14px;
    margin-bottom:16px;
    border:1px solid var(--line);
    border-radius:9px;
  }
  .admin-status > div{ flex:1; min-width:0; }
  .admin-status.ok{
    border-color:#3f9e5a;
    background:color-mix(in srgb, #3f9e5a 8%, transparent);
  }
  .admin-status.ok .wa-dot{
    background:#3f9e5a;
    box-shadow:0 0 0 3px color-mix(in srgb, #3f9e5a 25%, transparent);
  }
  .admin-status.warn{
    border-color:#c89b3c;
    background:color-mix(in srgb, #c89b3c 8%, transparent);
  }
  .admin-status.warn .wa-dot{ background:#c89b3c; }
  .admin-status.off .wa-dot{ background:var(--muted); }

  /* Sub-tabs within a single admin page. Visually lighter than .admin-tab above them,
     so the two levels do not compete for the eye. */
  .admin-subtabs{
    display:flex;
    flex-wrap:wrap;
    gap:6px;
    margin-bottom:16px;
  }
  .admin-subtab{
    display:inline-flex;
    align-items:center;
    gap:6px;
    padding:8px 14px;
    border:1px solid var(--line);
    border-radius:8px;
    background:transparent;
    color:var(--muted);
    font-family:var(--font-body);
    font-size:13px;
    cursor:pointer;
    transition:background .15s ease, color .15s ease, border-color .15s ease;
  }
  .admin-subtab:hover{ color:var(--ink); border-color:var(--muted); }
  .admin-subtab.current{
    background:var(--surface-2);
    color:var(--ink);
    border-color:var(--accent);
  }
  /* A quiet confirmation that a section is already filled in, not a decoration. */
  .admin-tick{ color:#3f9e5a; font-size:12px; }

  /* The admin form stacks. It does NOT reuse .pw-form, which is an auto-fit grid built
     for the short password form: dropped in here it packed unrelated fields into three
     or four columns of unequal height, so labels, hints and boxes ran into each other.
     Rows that genuinely belong side by side say so with .admin-row-2 / -3. */
  .admin-form{
    display:flex;
    flex-direction:column;
    gap:16px;
    max-width:720px;
    margin-bottom:16px;
  }
  .admin-field{ display:flex; flex-direction:column; gap:6px; min-width:0; }
  /* min-width:0 above and width:100% here: without both, a long placeholder makes a
     grid column refuse to shrink and the row overflows its panel. */
  .admin-field input,
  .admin-field select{ width:100%; }
  .admin-field .wa-hint{ margin-top:0; }

  /* Field rows. Collapse to one column on a narrow screen rather than squeezing three
     number boxes into a phone's width. */
  /* align-items:start so a field whose hint wraps onto two lines does not stretch the
     input beside it into a taller box than its own label suggests. */
  .admin-row-2, .admin-row-3{ display:grid; gap:14px; align-items:start; }
  .admin-row-2{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .admin-row-3{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
  @media (max-width: 760px){
    .admin-row-2, .admin-row-3{ grid-template-columns:1fr; }
  }

  /* A checkbox reads left-to-right, unlike every other field here, so the column
     direction is overridden. width:auto stops the 100% rule above from stretching the
     box across the row -- which is what put "Use TLS" on top of the Port field. */
  .admin-check{ flex-direction:row; align-items:center; gap:8px; }
  .admin-check input[type="checkbox"]{ width:auto; flex:0 0 auto; margin:0; }

  .admin-todo{ margin:0 0 16px; padding-left:20px; }
  .admin-todo li{ margin-bottom:6px; line-height:1.6; }
  .admin-todo a{ color:var(--accent); }

  .admin-checks{ display:flex; flex-direction:column; gap:8px; }
  .admin-check-row{
    display:grid;
    grid-template-columns:auto 1fr auto;
    align-items:center;
    gap:10px;
    padding:8px 0;
    border-bottom:1px solid var(--line);
  }
  .admin-check-row:last-child{ border-bottom:none; }
  @media (max-width: 560px){
    .admin-check-row{ grid-template-columns:auto 1fr; }
    .admin-check-row .cell-sub{ grid-column:2; }
  }

  /* ---- plan cards ---- */
  .plan-grid{
    display:grid;
    grid-template-columns:repeat(auto-fill, minmax(240px, 1fr));
    gap:14px;
  }
  .plan-card{
    display:flex;
    flex-direction:column;
    gap:8px;
    padding:16px;
    border:1px solid var(--line);
    border-radius:10px;
    background:var(--surface-2);
  }
  /* A retired plan is dimmed but still legible: it is history, not an error. */
  .plan-card.retired{ opacity:.6; }
  .plan-head{ display:flex; justify-content:space-between; align-items:flex-start; gap:8px; }
  .plan-name{ font-family:var(--font-head); font-size:15px; color:var(--ink); }
  .plan-price{ font-family:var(--font-head); font-size:20px; color:var(--accent); }
  .plan-desc{ line-height:1.5; }
  .plan-limits{ font-size:12px; color:var(--ink); }
  .plan-warn{ font-size:11px; line-height:1.5; }
  .plan-actions{ display:flex; gap:8px; margin-top:auto; padding-top:8px; }

  /* The admin link sits apart from the daily navigation above it: a separator makes
     clear it leads somewhere else, not to another yard screen. */
  .nav-admin{
    margin-top:10px;
    padding-top:10px;
    border-top:1px solid rgba(255,255,255,.12);
  }
  .nav-admin-link.active{ color:#fff; }

  /* A call that arrived while the page was open. The tint fades but does not vanish:
     someone glancing back after a minute still needs to see which rows are new, and an
     animation that clears itself would have taken that away. */
  tr.call-new td{
    background:color-mix(in srgb, var(--accent) 12%, transparent);
    animation:call-arrive 1.2s ease-out;
  }
  @keyframes call-arrive{
    from{ background:color-mix(in srgb, var(--accent) 38%, transparent); }
    to{   background:color-mix(in srgb, var(--accent) 12%, transparent); }
  }

  /* The caller's untranslated words, set apart from the searched-for part above them. */
  .call-original{
    display:flex;
    align-items:center;
    gap:6px;
    margin-top:2px;
    font-style:italic;
  }
  .call-lang{
    padding:1px 5px;
    border-radius:3px;
    background:var(--surface-2);
    font-style:normal;
    font-size:10px;
    letter-spacing:.04em;
  }

  /* "See all calls" under a panel that shows only the newest few. Right-aligned and
     quiet: it is a way out of the panel, not a call to action competing with the rows. */
  .panel-footer-link{
    padding:10px 2px 2px;
    text-align:right;
    font-family:var(--font-body);
    font-size:12.5px;
  }
  .panel-footer-link a{ color:var(--muted); text-decoration:none; }
  .panel-footer-link a:hover{ color:var(--ink); text-decoration:underline; }

  /* ---- opening a call ---- */

  .call-open{ color:var(--ink); text-decoration:none; border-bottom:1px solid transparent; }
  .call-open:hover{ color:var(--accent); border-bottom-color:var(--accent); }

  /* Date over time, on the Calls page only. Stacked rather than on one line because
     the column is narrow and "17 Sep 2026 14:05" either wraps mid-date or is clipped
     exactly where the year is. */
  .c-date{
    display:block;
    font-size:11px;
    color:var(--muted);
    line-height:1.3;
  }
  .c-clock{
    display:block;
    font-variant-numeric:tabular-nums;
    line-height:1.3;
  }
  /* The duration sits under the clock rather than beside it. On one line "01:32
     15:56" reads as two times, which is exactly how it was misread. */
  .c-time .cell-inline{
    display:block;
    margin-left:0;
    font-size:10.5px;
    color:var(--muted);
  }
  .c-time .cell-inline::before{ content:"⏱ "; opacity:.7; }
  /* The underline on hover belongs to the whole stack, not to each line. */
  .call-open:has(.c-date){ border-bottom:none; }
  .call-open:has(.c-date):hover .c-clock{ color:var(--accent); }
  .call-open:has(.c-date):hover .c-date{ color:var(--accent); }

  /* Which calls have words or audio. A single glyph rather than a word: this sits
     inline on a row that must not wrap, and "Transcript" costs 70px on every row to
     say what a mark says in 12. The full wording is in the title attribute. */
  .call-dot{
    margin-left:5px;
    font-size:11px;
    color:var(--muted);
    cursor:default;
  }

  /* ---- the calls table, sized to keep every row on one line ----

     Fixed layout so the browser honours these widths instead of negotiating them from
     content: with auto layout a single long outcome string widens its column and
     squeezes the rest until something wraps, and row heights stop being uniform. */
  .calls-table{ table-layout:fixed; width:100%; }
  .calls-table th, .calls-table td{
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
  }
  .calls-table .c-time   { width:112px; }
  .calls-table .c-caller { width:124px; }
  .calls-table .c-vehicle{ width:150px; }
  .calls-table .c-vin    { width:96px;  }
  .calls-table .c-part   { width:auto;  }
  .calls-table .c-outcome{ width:140px; }
  .calls-table .c-result { width:88px;  }
  .calls-table .c-quoted { width:64px;  }

  /* Secondary text that used to sit on its own line under the primary value. Inline
     keeps the row one line tall; the muted colour still separates the two. */
  .cell-inline{
    margin-left:6px;
    font-size:11px;
    color:var(--muted);
  }
  .calls-table .call-original{
    display:inline;
    margin-top:0;
    font-style:italic;
  }

  .calls-table .c-action { width:78px; overflow:visible; }

  .calls-compact th, .calls-compact td{ padding-top:6px; padding-bottom:6px; }
  .calls-compact .tag{ padding:1px 7px; font-size:10.5px; }

  /* Sized to sit inside a compact row without setting the row's height. */
  .btn-tiny{ padding:3px 10px; font-size:11.5px; }
  a.btn-tiny{ display:inline-block; text-decoration:none; }

  /* ---- building a quote from a caller's requests ---- */

  /* A row that opens something. The pointer and the hover tint are what say so --
     without them a clickable row is indistinguishable from a dead one. */
  tr.row-click{ cursor:pointer; }
  tr.row-click:hover td{
    background:color-mix(in srgb, var(--accent) 7%, transparent);
  }

  /* The secondary way out of a clickable row: quieter than the row's own action, and
     only obvious once the row is hovered, so it does not compete for the first click. */
  .row-aside{
    margin-left:7px;
    font-size:10.5px;
    color:var(--muted);
    text-decoration:none;
    opacity:0;
    transition:opacity .12s ease;
  }
  tr.row-click:hover .row-aside{ opacity:1; }
  .row-aside:hover{ color:var(--accent); text-decoration:underline; }
  /* Keyboard users never hover, so focus has to reveal it too. */
  .row-aside:focus{ opacity:1; outline:1px solid var(--accent); outline-offset:2px; }

  /* The caller's own shopping list, above the working table. Deliberately not a table:
     it is something to read and copy from, not something to operate. */
  .asked-for{
    margin:4px 0 20px;
    padding:12px 14px;
    border:1px solid var(--line);
    border-left:3px solid var(--accent);
    border-radius:var(--radius-m);
    background:var(--surface-2);
  }
  .asked-for-title{
    font-size:10.5px;
    text-transform:uppercase;
    letter-spacing:.05em;
    color:var(--muted);
    margin-bottom:8px;
  }
  .asked-for-list{
    list-style:none;
    margin:0;
    padding:0;
    font-family:var(--font-body);
    font-size:13.5px;
    line-height:1.85;
    color:var(--ink);
  }
  .asked-qty{
    display:inline-block;
    min-width:30px;
    color:var(--muted);
    font-variant-numeric:tabular-nums;
  }
  .asked-original{ margin-left:7px; font-style:italic; color:var(--muted); }

  /* The parts nobody can tick. These are the reason this box exists, so they are the
     one thing in it that carries colour. */
  .asked-todo{
    margin-left:8px;
    padding:1px 7px;
    border-radius:3px;
    background:color-mix(in srgb, var(--rust) 18%, transparent);
    color:var(--rust);
    font-size:11px;
    white-space:nowrap;
  }
  .asked-skip{ margin-left:8px; font-size:11px; color:var(--muted); }

  .asked-for-note{
    margin-top:10px;
    padding-top:9px;
    border-top:1px solid var(--line);
    font-family:var(--font-body);
    font-size:12px;
    line-height:1.6;
    color:var(--muted);
  }

  /* ---- holds ---- */

  .calls-table .c-ref    { width:78px; }
  .calls-table .c-left   { width:120px; }
  /* Wide enough for a four-figure hold. The shared .c-quoted is sized for the
     two-figure prices on the call lists and clipped "$210.00" to "$210...." here. */
  .calls-table .c-holdval{ width:96px; }
  .calls-table .c-holdact{ width:160px; overflow:visible; white-space:nowrap; }

  /* A hold with hours left. Tinted rather than merely tagged, because the reason
     this page exists is to make these findable without reading every row. */
  tr.hold-urgent td{
    background:color-mix(in srgb, var(--rust) 9%, transparent);
  }

  .holds-footnote{
    margin-top:12px;
    padding:10px 12px;
    border-top:1px solid var(--line);
    font-family:var(--font-body);
    font-size:12.5px;
    line-height:1.6;
    color:var(--muted);
  }

  /* Confirmation of something that succeeded, beside .error which reports what
     did not. Quieter than an error: nothing went wrong. */
  .ok-note{
    margin:10px 0;
    padding:9px 12px;
    border:1px solid var(--line);
    border-left:3px solid var(--moss, var(--accent));
    border-radius:var(--radius-m);
    background:var(--surface-2);
    font-family:var(--font-body);
    font-size:12.5px;
    color:var(--ink);
  }

  .quote-field{ width:100%; max-width:230px; }

  .quote-lines .c-pick{ width:36px; text-align:center; overflow:visible; }
  .quote-lines .c-qty { width:72px; }
  /* These rows carry two lines of detail in places, so they are not clamped to the
     one-line height the scanning lists use. */
  .quote-lines td{ white-space:normal; }

  .qty-input{
    width:56px;
    padding:3px 6px;
    background:var(--surface-2);
    color:var(--ink);
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    font-family:var(--font-body);
    font-size:12.5px;
    text-align:right;
  }
  .qty-input:disabled{ opacity:.45; }

  /* An unticked line stays readable -- it is still a record of what was asked for --
     but recedes so the chosen lines are what the eye follows. */
  .quote-lines tr.line-off td{ opacity:.5; }

  .quote-total{
    display:flex;
    align-items:baseline;
    justify-content:space-between;
    gap:12px;
    margin-top:12px;
    padding:10px 12px;
    border-top:1px solid var(--line);
    font-family:var(--font-body);
    font-size:13px;
    color:var(--muted);
  }
  .quote-total strong{ font-size:17px; color:var(--ink); }

  .quote-actions{
    display:flex;
    align-items:center;
    gap:12px;
    margin-top:14px;
  }

  /* Narrow screens cannot fit eight columns; let the table scroll sideways in its own
     box rather than crushing the columns into wrapping again.
     `screen` matters: a printed page is also narrower than 900px, so without it this
     forced an 820px table onto ~180mm of paper and the scroll box clipped the right
     hand columns off the invoice. */
  @media screen and (max-width:900px){
    .calls-table{ table-layout:auto; min-width:820px; }
  }

  /* ---- one call in full ---- */

  .call-detail-head{ margin-bottom:14px; }

  .call-facts{
    display:grid;
    grid-template-columns:repeat(auto-fit, minmax(190px, 1fr));
    gap:14px 18px;
    margin:0 0 20px;
    padding:0;
  }
  .call-fact dt{
    font-size:10.5px;
    text-transform:uppercase;
    letter-spacing:.05em;
    color:var(--muted);
    margin-bottom:3px;
  }
  .call-fact dd{
    margin:0;
    font-family:var(--font-body);
    font-size:13px;
    color:var(--ink);
    word-break:break-word;
  }

  .call-audio{ margin-bottom:20px; }
  .call-audio audio{ width:100%; max-width:520px; }
  .call-audio-title{
    font-size:10.5px;
    text-transform:uppercase;
    letter-spacing:.05em;
    color:var(--muted);
    margin-bottom:8px;
  }
  /* An expired link is a fact about the link, not a failure of the call. Stated in
     words rather than left for the player to fail silently. */
  .call-audio-note{
    margin-top:8px;
    padding:8px 10px;
    border:1px solid var(--line);
    border-radius:var(--radius-m);
    background:var(--surface-2);
    font-family:var(--font-body);
    font-size:12px;
    line-height:1.55;
    color:var(--muted);
    max-width:520px;
  }

  /* A flex column so each bubble can size to its own content. Without this the list
     items fill the row, and a one-word Persian line ("آره") becomes a full-width bar
     with the text pinned to the far edge and a long empty gap beside it. */
  .transcript-lines{
    list-style:none;
    margin:0;
    padding:0;
    display:flex;
    flex-direction:column;
    align-items:flex-start;
  }
  .transcript-line{
    display:flex;
    flex-direction:column;
    gap:3px;
    max-width:74%;
    margin-bottom:10px;
    padding:9px 12px;
    border-radius:var(--radius-m);
    background:var(--surface-2);
    border:1px solid var(--line);
  }
  /* The assistant's lines sit opposite the caller's, so the two sides of the
     conversation are told apart at a glance rather than by reading the labels. */
  .transcript-line.from-assistant{
    align-self:flex-end;
    background:color-mix(in srgb, var(--accent) 10%, var(--surface-2));
  }
  .transcript-who{
    font-size:10px;
    text-transform:uppercase;
    letter-spacing:.05em;
    color:var(--muted);
  }
  /* text-align follows the line's own dir, so a Persian line reads from its own
     margin rather than being pinned to the left. */
  .transcript-text{
    font-family:var(--font-body);
    font-size:13px;
    line-height:1.6;
    color:var(--ink);
    white-space:pre-wrap;
    word-break:break-word;
  }
  .transcript-text[dir="rtl"]{ text-align:right; }
  .transcript-text[dir="ltr"]{ text-align:left; }

  @media (max-width:640px){
    .transcript-line{ max-width:100%; }
  }
