/* ===== Design tokens mirror the mobile app (allquote-rn/theme.js) so web and
   app read as one product: same teal brand, neutral dark surfaces, soft 14px
   corners, thin rgba borders, high-contrast text. Light mode = app's `light`
   palette; dark overrides below = app's `dark` palette. ===== */
:root{
  --brand-spring:#2EA98C; --brand-core:#118173; --brand-pine:#0A514A; --brand-ink:#0C3F3A;
  --teal:var(--brand-core); --teal-dark:var(--brand-pine); --teal-light:#e9f5f2;
  /* brandSoft (app theme.js light): a faint teal wash for active pills + the FAB
     glow. The app uses rgba(brand,0.10); we expose it as a token so cards, the
     sidebar active state and the FAB share ONE source of truth. */
  --brand-soft:rgba(17,129,115,.10);
  --ink:#1a1d21; --slate:#475569; --muted:#64748b;
  --line:#E9EFED; --bg:#F6F8F7; --card:#ffffff;
  --green:#16a34a; --amber:#d97706; --red:#dc2626; --blue:#2563eb; --link:var(--brand-core);
  --aq-wordmark-all:var(--brand-core); --aq-wordmark-quote:var(--brand-ink);
  /* Radius scale — 14/10/7 as before, PLUS --radius-lg (20px) to match the app's
     GlassCard.js (borderRadius:20). Cards/stat tiles use the larger corner. */
  --radius:14px; --radius-sm:10px; --radius-xs:7px; --radius-lg:20px;
  /* Spacing scale (4px base) — a consistent rhythm shared with the app's 16px
     card padding. Additive: existing fixed px values are unchanged. */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px;
  --control-h:40px; --label-gap:6px;
  --tile-grid-gap:14px;
  --shadow:0 1px 3px rgba(15,23,42,.08),0 8px 24px rgba(15,23,42,.06);
  /* Sidebar widths as tokens so the body padding stays in sync with the full rail
     and the collapsed icon rail. */
  --dsb-w:264px;
  --dsb-rail-w:64px;
  --app-sidebar-offset:0px;
  --page-gutter:clamp(16px,1.25vw,24px);
}
/* ===== Dark mode (toggled in Settings; <html data-theme="dark">). The app is
   built on these variables, so most of the UI re-themes from the overrides here.
   Teal remains the dark accent for links/icons, active states and highlights; the
   app background and surfaces stay neutral charcoal. ===== */
html[data-theme="dark"]{
  /* Traditional dark palette: neutral backgrounds, Spring/Core Teal accents,
     off-white text, brighter semantic colours. */
  --teal:#2EA98C; --teal-light:rgba(46,169,140,.16); --raised:#26272b;
  /* Teal accent wash for active and focused states on the neutral dark surface. */
  --brand-soft:rgba(46,169,140,.16);
  --ink:#f4f5f6; --slate:#c9d0d6; --muted:#969ca6;
  --line:#2e2f33; --bg:#121214; --card:#1d1e21; --link:#2EA98C;
  --green:#22c55e; --amber:#fbbf24; --red:#f87171; --blue:#60a5fa;
  /* Keep teal as an accent token only; ordinary text uses --ink/--slate/--muted. */
  --teal-dark:#2EA98C;
  --aq-wordmark-all:#2EA98C; --aq-wordmark-quote:#f4f5f6;
  --shadow:0 1px 3px rgba(0,0,0,.5),0 10px 28px rgba(0,0,0,.4);
}
html[data-theme="dark"]{color-scheme:dark}
/* Bottom nav: inactive icons stay neutral grey, only the current tab is teal. */
html[data-theme="dark"] .botnav a.active,
html[data-theme="dark"] .botnav a.bn-cta{color:#2EA98C}
html[data-theme="dark"] .pill,
html[data-theme="dark"] .lifecycle .lc.done,
html[data-theme="dark"] .orb-label,
html[data-theme="dark"] .brand .wordmark .w2{color:var(--aq-wordmark-quote)}
html[data-theme="dark"] .badge.draft{background:var(--raised);color:#cbd5e1}
html[data-theme="dark"] .lifecycle .lc{background:var(--raised);color:#b5bdc8}
html[data-theme="dark"] .li-row.review{background:#2c2710}
html[data-theme="dark"] .li-row.expanded{background:var(--raised);border:1px solid var(--line)}
html[data-theme="dark"] .compare tbody tr:nth-child(even){background:#202124}
html[data-theme="dark"] input,
html[data-theme="dark"] select,
html[data-theme="dark"] textarea{background:var(--raised);color:var(--ink)}
html[data-theme="dark"] input::placeholder,
html[data-theme="dark"] textarea::placeholder{color:var(--muted)}
/* Browser autofill forces a light background + dark text on inputs (the "light
   boxes" in dark mode). WebKit won't let you set the background directly, so paint
   over it with a huge inset box-shadow and override the text fill colour. */
html[data-theme="dark"] input:-webkit-autofill,
html[data-theme="dark"] input:-webkit-autofill:hover,
html[data-theme="dark"] input:-webkit-autofill:focus,
html[data-theme="dark"] input:-webkit-autofill:active,
html[data-theme="dark"] select:-webkit-autofill,
html[data-theme="dark"] textarea:-webkit-autofill{
  -webkit-text-fill-color:var(--ink);
  -webkit-box-shadow:0 0 0 1000px var(--raised) inset;
  box-shadow:0 0 0 1000px var(--raised) inset;
  caret-color:var(--ink);
  border:1px solid var(--line);
  transition:background-color 9999s ease-in-out 0s;
}
/* Filled accent controls with white text use Core Teal in dark mode; Spring Teal
   is too bright for white text (2.93:1). */
html[data-theme="dark"] .daygrid label:has(input:checked),
html[data-theme="dark"] .btn:not(.ghost):not(.danger),
html[data-theme="dark"] .banner,
html[data-theme="dark"] .tag,
html[data-theme="dark"] .botnav a.bn-cta .ic,
html[data-theme="dark"] .lifecycle .lc.cur,
html[data-theme="dark"] #aq-dialer .aq-dial-head,
html[data-theme="dark"] .seg.on,
html[data-theme="dark"] .seg-btn.on,
html[data-theme="dark"] .seg-b.on,
html[data-theme="dark"] .tg-dhead.today .dom,
html[data-theme="dark"] .stepnum,
html[data-theme="dark"] .invfilters .ctab.active,
html[data-theme="dark"] .ctab.active,
html[data-theme="dark"] .bub.out,
html[data-theme="dark"] .feat-mode input:checked + span,
html[data-theme="dark"] .dt-seg button.on,
html[data-theme="dark"] .pm-opt[data-on="1"],
html[data-theme="dark"] .infoi:hover,
html[data-theme="dark"] .infoi:focus-visible,
html[data-theme="dark"] .nba-act.nba-primary,
html[data-theme="dark"] .bt-save,
html[data-theme="dark"] .bt-opt.is-on,
html[data-theme="dark"] .ai-opt.is-on,
html[data-theme="dark"] .prog-badge,
html[data-theme="dark"] .verb,
html[data-theme="dark"] [style*="background:var(--teal);"][style*="color:#fff"],
html[data-theme="dark"] [style*="background:var(--teal,#118173);"][style*="color:#fff"]{
  --teal:#118173;
  --teal-dark:#118173;
}
html[data-theme="dark"] .banner .btn{background:#f4f5f6;color:#118173;border-color:transparent}
html[data-theme="dark"] .banner .btn:hover{background:#fff;color:#118173}
html[data-theme="dark"] .btn.danger:hover{background:#3b1115;border-color:#7f1d1d;color:#fecaca}
html[data-theme="dark"] .promo-code{background:var(--raised);color:#2EA98C;border:1px solid var(--line)}
html[data-theme="dark"] .demo-flash{background:var(--card)!important;border-color:rgba(46,169,140,.38)!important;color:var(--ink)!important}
/* Weekday picker: a fixed 7-across grid (equal, shrinkable cols so it never wraps
   OR overflows). The native checkbox is hidden; a ticked day shows as a teal chip. */
.daygrid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:5px}
.daygrid label{display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;
  padding:8px 0;border:1px solid var(--line);border-radius:7px;cursor:pointer;white-space:nowrap;overflow:hidden;user-select:none}
.daygrid input{position:absolute;opacity:0;width:0;height:0}
.daygrid label:has(input:checked){background:var(--teal);color:#fff;border-color:var(--teal)}
/* Compact header buttons: full label on desktop, icon-only on phones (no wrapping). */
.btn{white-space:nowrap}
@media (max-width:640px){ .btn-lbl{display:none} }
/* Collapsible cards — tap the header to fold everything under it. */
.card.cc-collapsed > *:not(:first-child){display:none !important}
.card .cc-chev{color:var(--muted)}
/* "Available now" toggle switch (dashboard). */
.av-track{position:absolute;inset:0;background:var(--line);border-radius:999px;transition:background .15s}
.av-track::after{content:"";position:absolute;top:3px;left:3px;width:24px;height:24px;border-radius:50%;background:#fff;transition:left .15s ease;box-shadow:0 1px 3px rgba(0,0,0,.35)}
.av-switch .avail-switch-in:checked + .av-track{background:#22c55e}
.av-switch .avail-switch-in:checked + .av-track::after{left:25px}
html[data-theme="dark"] .acct-menu a:hover{background:var(--raised)}
html[data-theme="dark"] .brand .wordmark .w1{color:var(--aq-wordmark-all)}
html[data-theme="dark"] img.shadowed,
html[data-theme="dark"] .invoice-paper{filter:none}
*{box-sizing:border-box}
.ic{vertical-align:-.18em;flex:none}  /* inline line-icons (icon() macro) */
html,body{margin:0;padding:0;overflow-x:clip;max-width:100%;width:100%;overscroll-behavior-x:none;-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,Helvetica,Arial,sans-serif;
  color:var(--ink);background:var(--bg);line-height:1.55;-webkit-font-smoothing:antialiased}
a{color:var(--link);text-decoration:none}
a:hover{text-decoration:underline}
h1,h2,h3{line-height:1.2;margin:0 0 .4em}
/* Wave-4b #45: the ONE standard page header — title on the left, optional action
   buttons on the right, wrapping cleanly on narrow screens. Main pages use this
   block so every screen opens the same way. */
.page-head{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 6px}
.page-head h1{margin:0;font-size:24px}
.page-head .page-actions{display:flex;gap:6px;flex-wrap:wrap;align-items:center;justify-content:flex-end}
.container{max-width:1080px;margin:0 auto;padding:0 20px}
/* Authenticated app pages use the whole sidebar-adjusted viewport. Public pages
   keep the marketing/document caps below. */
.authed main.container{width:100%;max-width:1600px;margin:0 auto;padding-left:var(--page-gutter);padding-right:var(--page-gutter);min-width:0}
/* Public wide pages keep the public-site cap; nested authenticated wide containers
   can still use the full capped main column. */
.container.wide{max-width:1080px}
.authed main.container.wide{max-width:1600px}
.authed .container.wide:not(main){max-width:1600px}
/* One page width everywhere when logged in — narrow stays for auth pages only */
.authed .narrow{max-width:1600px}
.narrow{max-width:760px}

/* Nav */
.nav{background:var(--card);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:40}
.nav .container{display:flex;align-items:center;gap:18px;height:62px}
.authed .nav .container{width:100%;max-width:1600px;margin:0 auto;padding-left:var(--page-gutter);padding-right:var(--page-gutter)}
.brand{font-weight:800;font-size:20px;color:var(--ink);display:flex;align-items:center;gap:calc(var(--aq-lockup-icon,34px) * .28)}
.brand .dot{width:26px;height:26px;border-radius:7px;background:var(--teal);display:inline-flex;
  align-items:center;justify-content:center;color:#fff;font-size:14px}
.aq-lockup{display:inline-flex;align-items:center;gap:calc(var(--aq-lockup-icon,34px) * .28);vertical-align:middle;text-decoration:none}
.aq-lockup-stacked{flex-direction:column;justify-content:center;gap:14px;text-align:center}
.aq-lockup-icon-wrap{display:inline-flex;align-items:center;justify-content:center;flex:none}
.brand .mark,.aq-lockup .mark{display:block;border-radius:calc(var(--aq-lockup-icon,34px) * .225);flex:none;width:var(--aq-lockup-icon,34px);height:var(--aq-lockup-icon,34px)}
.brand .wordmark,.aq-wordmark{font-family:Manrope,-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,Helvetica,Arial,sans-serif;font-weight:800;font-size:var(--aq-lockup-text,20px);line-height:1;letter-spacing:-.025em;color:#0C3F3A}
.brand .wordmark .w1,.aq-wordmark .aq-wordmark-all{color:var(--aq-wordmark-all,#118173)}
.brand .wordmark .w2,.aq-wordmark .aq-wordmark-quote{color:var(--aq-wordmark-quote,#0C3F3A)}
.aq-lockup-single .wordmark span{color:#0C3F3A}
.brand:hover{text-decoration:none}
.header-search-wrap{position:relative;display:flex;align-items:center;flex:0 1 430px;min-width:260px;max-width:460px;color:var(--muted);z-index:61}
.header-search{display:flex;align-items:center;position:relative;width:100%;color:var(--muted)}
.header-search .ic{position:absolute;left:12px;z-index:1;color:var(--muted);pointer-events:none}
.header-search input{width:100%;height:var(--control-h);border:1px solid var(--line);border-radius:10px;background:var(--card);
  color:var(--ink);font:inherit;font-size:14px;outline:0;padding:0 48px 0 38px}
.header-search input::placeholder{color:var(--muted)}
.header-search input:focus{border-color:var(--teal);background:var(--card);box-shadow:0 0 0 3px var(--brand-soft)}
.header-search .kbd{position:absolute;right:10px;font-size:11px;font-weight:800;color:var(--muted);
  border:1px solid var(--line);border-radius:6px;padding:1px 5px;background:var(--card);pointer-events:none}
.header-search-results{position:absolute;top:calc(100% + 8px);left:0;width:min(620px,calc(100vw - var(--app-sidebar-offset) - 40px));
  min-width:100%;max-height:min(460px,70vh);overflow-y:auto;background:var(--card);border:1px solid var(--line);
  border-radius:12px;box-shadow:0 18px 44px rgba(2,6,23,.20);padding:6px;color:var(--ink)}
.header-search-results[hidden]{display:none}
.hsearch-item{display:flex;align-items:center;gap:10px;padding:10px 11px;border-radius:9px;color:var(--ink);text-decoration:none;font-size:14px}
.hsearch-item:hover,.hsearch-item.sel{background:var(--brand-soft);text-decoration:none}
.hsearch-item .cmdk-path{display:flex;align-items:center;gap:6px;flex:1;min-width:0;flex-wrap:wrap;line-height:1.35}
.hsearch-item .cmdk-crumb{display:inline-flex;align-items:center;gap:4px;white-space:nowrap}
.hsearch-item .cmdk-crumb .ic{position:static;flex:0 0 auto;color:var(--muted);pointer-events:none}
.hsearch-item .cmdk-sep{color:var(--muted);font-size:12px}
.hsearch-divider{margin:6px 4px 3px;padding-top:7px;border-top:1px solid var(--line);color:var(--muted);font-size:10px;font-weight:800;letter-spacing:.05em;text-transform:uppercase}
.hsearch-empty{padding:14px 12px;color:var(--muted);font-size:14px;text-align:center}
.header-search-icon{display:none;align-items:center;justify-content:center;width:var(--control-h);height:var(--control-h);border:1px solid var(--line);
  border-radius:10px;background:var(--card);color:var(--muted);cursor:pointer;padding:0;flex:0 0 auto}
.header-search-icon:hover{color:var(--teal);background:var(--bg)}
.nav .spacer{flex:1}
.nav a.navlink{color:var(--slate);font-weight:600;font-size:15px;white-space:nowrap}
.nav a.navlink:hover{color:var(--teal);text-decoration:none}
.pill{font-size:12px;font-weight:700;padding:3px 9px;border-radius:999px;background:var(--teal-light);color:var(--teal-dark)}
/* Nav: secondary links flow inline on desktop, collapse into a hamburger on mobile. */
.nav-extra{display:contents}
.nav-burger{display:none;background:none;border:1px solid var(--line);border-radius:9px;
  padding:5px 8px;cursor:pointer;color:var(--ink);align-items:center}
.nav-burger:hover{background:var(--bg)}
/* Mobile: compact bar (logo + Dashboard / Invoices / + Quote + hamburger). */
@media(max-width:720px){
  .nav{position:relative}
  .nav .container{flex-wrap:nowrap;gap:8px}
  .nav .brand .wordmark{display:none}
  .header-search-wrap{display:none}
  .header-search-icon{display:inline-flex}
  .nav a.navlink,.nav .pill{font-size:13px}
  .nav-burger{display:inline-flex}
  .nav-extra{display:none}
  .nav-extra.open{display:flex;flex-direction:column;position:absolute;top:calc(100% - 1px);right:8px;
    background:var(--card);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow);
    padding:8px;min-width:190px;z-index:50;gap:2px}
  .nav-extra.open a.navlink{padding:9px 12px;border-radius:8px;font-size:15px}
  .nav-extra.open a.navlink:hover{background:var(--bg);text-decoration:none}
  .banner{padding:28px 20px}
  .banner h2{font-size:23px}
}

/* Buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;cursor:pointer;
  min-height:var(--control-h);font-weight:700;font-size:15px;padding:0 18px;border-radius:10px;border:1px solid transparent;
  background:var(--teal);color:#fff;transition:.15s;text-decoration:none;
  white-space:nowrap}            /* never wrap/break a button label mid-word */
.btn:hover{background:var(--teal-dark);text-decoration:none}
.btn.lg{padding:14px 26px;font-size:17px}
.btn.block{width:100%}
.btn.ghost{background:var(--card);color:var(--ink);border-color:var(--line)}
.btn.ghost:hover{background:var(--bg);border-color:var(--muted)}
.btn.danger{background:var(--card);color:var(--red);border-color:#fecaca}
.btn.danger:hover{background:#fef2f2}
.btn.sm{height:var(--control-h);padding:0 12px;font-size:13px}
.btn.rec{background:var(--red);border-color:var(--red);color:#fff;animation:pulse 1.3s ease-in-out infinite}
.btn.rec:hover{background:#b91c1c}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(220,38,38,.45)}50%{box-shadow:0 0 0 6px rgba(220,38,38,0)}}
/* Voice input: an animated sound-wave instead of a mic emoji, and an AI gradient
   glow while listening instead of a red recording light. */
.wave{display:inline-flex;align-items:center;gap:2px;height:16px}
.wave span{width:2.5px;border-radius:2px;background:currentColor}
.wave span:nth-child(1){height:5px}.wave span:nth-child(2){height:11px}
.wave span:nth-child(3){height:16px}.wave span:nth-child(4){height:9px}
.wave span:nth-child(5){height:6px}
.btn.listening{background:linear-gradient(120deg,var(--teal),#6366f1);border-color:transparent;color:#fff;
  animation:aiglow 1.7s ease-in-out infinite}
.btn.listening .wave span{animation:eq .9s ease-in-out infinite}
.btn.listening .wave span:nth-child(2){animation-delay:.12s}
.btn.listening .wave span:nth-child(3){animation-delay:.24s}
.btn.listening .wave span:nth-child(4){animation-delay:.36s}
.btn.listening .wave span:nth-child(5){animation-delay:.48s}
@keyframes eq{0%,100%{height:4px}50%{height:16px}}
@keyframes aiglow{0%,100%{box-shadow:0 0 0 0 rgba(99,102,241,.5)}50%{box-shadow:0 0 0 8px rgba(99,102,241,0)}}
@media(prefers-reduced-motion:reduce){.btn.listening,.btn.listening .wave span{animation:none}}
/* ChatGPT-style voice orb: a greeny-blue orb drops over the job box while listening. */
.voice-field{position:relative}
.voice-orb{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:16px;border-radius:10px;background:rgba(248,250,252,.82);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  opacity:0;transform:translateY(-22px);pointer-events:none;transition:opacity .3s ease,transform .45s cubic-bezier(.2,.8,.2,1)}
.voice-field.listening .voice-orb{opacity:1;transform:translateY(0);pointer-events:auto;cursor:pointer}
.orb-wrap{position:relative;width:104px;height:104px}
.orb{position:absolute;inset:0;border-radius:50%;
  background:radial-gradient(circle at 33% 30%,#6ee7d6 0%,#22d3ee 40%,#6366f1 88%);
  box-shadow:0 12px 50px rgba(56,189,248,.55);animation:orb-breathe 2.6s ease-in-out infinite}
.orb::after{content:"";position:absolute;inset:-28%;border-radius:50%;z-index:-1;
  background:conic-gradient(from 0deg,#34d399,#22d3ee,#6366f1,#34d399);filter:blur(20px);opacity:.6;
  animation:orb-spin 6s linear infinite}
.orb-label{font-weight:700;color:var(--ink);font-size:14px}
@keyframes orb-breathe{0%,100%{transform:scale(1)}50%{transform:scale(1.1)}}
@keyframes orb-spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.voice-orb{transition:opacity .2s}.orb,.orb::after{animation:none}}

/* Cards — matched to the app's GlassCard.js (borderRadius:20, 1px border). The
   larger --radius-lg corner + hairline --line border + soft --shadow read like the
   RN surface. Padding stays generous (24px desktop; the mobile block trims it). */
.card{display:flow-root;background:var(--card);border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:24px;box-shadow:var(--shadow)}
.card + .card{margin-top:18px}
.card + .tile,
.tile + .card,
.tile + .tile,
.card + .tiles,
.card + .cards,
.card + .toolgrid,
.card + .report-grid,
.card + .schedule-wide-grid,
.tiles + .card,
.cards + .card,
.toolgrid + .card,
.report-grid + .card,
.schedule-wide-grid + .card{margin-top:18px}
/* ...but cards inside grid/tile boards are spaced by the grid GAP, so this
   stacked-card top margin would push every grid item after the first downward.
   Keep the reset broad because pages use .grid plus local tile containers. */
.grid > .card + .card,
.tiles > .card + .card,
.cards > .card + .card,
.toolgrid > .card + .card,
.flex > .card + .card,
.report-grid > .card + .card{margin-top:0}
.grid{display:grid;gap:18px;align-items:stretch}
.tiles,.cards,.toolgrid,.report-grid{display:grid;gap:var(--tile-grid-gap,14px);align-items:stretch}
.grid>*,.tiles>*,.cards>*,.toolgrid>*,.report-grid>*{min-width:0}
.chip-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0;max-width:100%}
.chip-row>*{min-width:0}
.chip-row .badge,.chip-row button,.chip-row a{white-space:normal;overflow-wrap:anywhere}
.grid > .card,
.tiles > .card,
.cards > .card,
.report-grid > .card{height:100%}
.grid.cols-2{grid-template-columns:1fr 1fr}
.grid.cols-3{grid-template-columns:repeat(3,1fr)}
.grid.cols-4{grid-template-columns:repeat(4,1fr)}
@media(max-width:780px){.grid.cols-2,.grid.cols-3{grid-template-columns:1fr}.grid.cols-4{grid-template-columns:1fr 1fr}}
/* Quote editor: 2-up (lines | side panel) on desktop, single scrollable column
   on mobile. (Was an inline grid-template-columns that ignored the breakpoint.) */
.quote-grid{display:grid;gap:18px;grid-template-columns:2fr 1fr;align-items:start}
@media(max-width:820px){.quote-grid{grid-template-columns:1fr}}
/* Let columns shrink below their content so the line-item controls row scrolls
   within itself (overflow-x) instead of widening the whole page on mobile. */
.quote-grid>*{min-width:0}
#litable,.li-row{min-width:0}
.btn-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}

/* Shared toolbar controls: fields and commands keep one stable metric, while
   flexible children are allowed to shrink instead of widening the page. */
.control-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0;max-width:100%}
.control-row>*{min-width:0}
.control-row .control-grow{flex:1 1 220px;min-width:min(220px,100%)}
.control-row>.btn,.control-row>form>.btn{height:var(--control-h)}
.search-control{position:relative;display:flex;align-items:center;flex:1 1 220px;min-width:min(220px,100%);max-width:100%;margin:0}
.search-control>.ic{position:absolute;left:12px;z-index:1;color:var(--muted);pointer-events:none}
.search-control>input[type=search]{min-width:0;width:100%;padding-left:38px}

/* Compact page-view selectors share the same geometry and remain above their
   associated content on narrow screens. */
.segmented-control{display:inline-flex;max-width:100%;border:1px solid var(--line);border-radius:8px;overflow:hidden;background:var(--card)}
.segmented-control>button,.segmented-control>a{height:var(--control-h);padding:0 15px;border:0;border-right:1px solid var(--line);background:var(--card);color:var(--muted);font:inherit;font-size:13px;font-weight:750;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:6px;text-decoration:none;white-space:nowrap}
.segmented-control>:last-child{border-right:0}
.segmented-control>.on,.segmented-control>[aria-selected="true"],.segmented-control>[aria-current="page"]{background:var(--teal);color:#fff}
@media(max-width:620px){
  .control-row{align-items:stretch}
  .control-row .control-grow,.search-control{flex-basis:100%;min-width:0}
  .segmented-control{display:flex;width:100%}
  .segmented-control>button,.segmented-control>a{flex:1 1 0;min-width:0;padding-inline:8px}
}

/* Forms */
label{display:block;font-weight:600;font-size:14px;margin:0 0 var(--label-gap);color:var(--ink)}
.hint{font-size:13px;color:var(--muted);font-weight:400}
input[type=text],input[type=email],input[type=password],input[type=number],input[type=color],input[type=tel],
input[type=date],input[type=time],input[type=datetime-local],input[type=search],input[type=url],
select,textarea{width:100%;padding:11px 13px;border:1px solid var(--line);border-radius:10px;
  font-size:15px;font-family:inherit;background:var(--card);color:var(--ink)}
input[type=text],input[type=email],input[type=password],input[type=number],input[type=tel],
input[type=date],input[type=time],input[type=datetime-local],input[type=search],input[type=url],select{
  min-height:var(--control-h);box-sizing:border-box;line-height:20px}
input[type=text],input[type=email],input[type=password],input[type=number],input[type=tel],
input[type=date],input[type=time],input[type=datetime-local],input[type=search],input[type=url],
select:not([multiple]):not([size]){height:var(--control-h)}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--teal);
  box-shadow:0 0 0 3px var(--teal-light)}
textarea{resize:vertical;min-height:120px}
/* Colour selectors — STANDING RULE: the chosen colour ALWAYS shows as a FILLED
   rounded blotch, never the browser's thin colour bar or a hollow ring. The native
   <input type=color> is stretched invisibly over the swatch so the OS picker still
   opens on click/keyboard. The hairline border keeps a white/pale swatch visible on
   white (light) and dark backgrounds. base.html JS repaints --sw on input; the inline
   --sw set in markup means it's filled before JS runs and with JS disabled. Size is
   overridable per use with an inline width/height. */
.colour-blotch{position:relative;display:inline-flex;width:34px;height:34px;flex:0 0 auto;
  border-radius:9px;border:1px solid var(--line);background:var(--sw,#118173);
  cursor:pointer;vertical-align:middle}
.colour-blotch:focus-within{outline:2px solid var(--teal);outline-offset:2px}
.colour-blotch input[type=color]{position:absolute;inset:0;width:100%;height:100%;margin:0;
  padding:0;border:0;opacity:0;cursor:pointer;background:transparent}
.field{margin-bottom:16px}
.field-control{display:flex;flex-direction:column;gap:var(--label-gap);min-width:0;margin:0;color:var(--ink)}
.field-control>input,.field-control>select,.field-control>textarea{margin:0}
.form-actions-row{display:flex;align-items:flex-end;gap:8px;flex-wrap:wrap}.form-actions-row>.field{margin:0;min-width:180px}.form-actions-row>.btn{height:var(--control-h);display:inline-flex;align-items:center;justify-content:center}
.num,input[type=number],input[type=date],input[type=time],input[type=datetime-local],.money,.pricing-row-amount,.bal-item .v{font-variant-numeric:tabular-nums lining-nums}
.row{display:flex;gap:14px}
.row > *{flex:1}
@media(max-width:640px){.row{flex-direction:column;gap:0}}
/* Wave-4b #9: .grid2 was used by the claims forms but never defined, so the inputs
   rendered as an unstructured stack. Standard 2-col-then-stack form grid. */
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px}
@media(max-width:700px){.grid2{grid-template-columns:1fr}}
.grid2 > label{margin:0}

/* Flash */
.flash{padding:12px 16px;border-radius:10px;margin-bottom:14px;font-weight:600;font-size:14px}
.flash.success{background:#dcfce7;color:var(--ink)}
.flash.error{background:#fee2e2;color:#991b1b}
.flash.info{background:#dbeafe;color:#1e40af}

/* Badges */
.badge{font-size:12px;font-weight:700;padding:3px 9px;border-radius:999px;display:inline-block;white-space:nowrap}
.badge.draft{background:#f1f5f9;color:#475569}
.badge.sent{background:#dbeafe;color:#1e40af}
.badge.accepted{background:#dcfce7;color:#166534}
.badge.declined{background:#fee2e2;color:#991b1b}
.badge.est{background:#fef3c7;color:#92400e}
.badge.invoiced{background:#e0e7ff;color:#3730a3}   /* job invoiced, not yet paid */
.badge.partial{background:#fef3c7;color:#92400e}    /* invoice part-paid */
.badge.complete{background:#bbf7d0;color:#14532d}   /* job paid in full → complete */
/* Dark mode: the light badge/flash tints above are bright pills on a dark card and the
   dark text on them washes out. Re-tint to a deep hue + light text so they stay legible
   AND sit on the dark surface. (Only .badge.draft had an override before.) */
html[data-theme="dark"] .badge.sent{background:#15294a;color:#bfdbfe}
html[data-theme="dark"] .badge.accepted{background:#14331f;color:#86efac}
html[data-theme="dark"] .badge.declined{background:#3a1b1b;color:#fca5a5}
html[data-theme="dark"] .badge.est{background:#3a2a14;color:#fcd34d}
html[data-theme="dark"] .badge.invoiced{background:#23244d;color:#c7d2fe}
html[data-theme="dark"] .badge.partial{background:#3a2a14;color:#fcd34d}
html[data-theme="dark"] .badge.complete{background:#14331f;color:#86efac}
html[data-theme="dark"] .flash.success{background:#14331f;color:var(--ink)}
html[data-theme="dark"] .flash.error{background:#3a1b1b;color:#fca5a5}
html[data-theme="dark"] .flash.info{background:#15294a;color:#bfdbfe}
/* Theme-aware row highlights — replace hardcoded #fffbeb / #fef2f2 / #fff7ed <tr>
   backgrounds that left --ink (light in dark mode) text invisible on a near-white row.
   Translucent tints read correctly on BOTH the light (#fff) and dark (#172234) card. */
tr.row-warn, .row-warn{background:rgba(217,119,6,.13)}
tr.row-danger, .row-danger{background:rgba(220,38,38,.13)}
tr.row-info, .row-info{background:rgba(37,99,235,.12)}

/* Tables */
.table-wrap{width:100%;max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}
.table-wrap table{min-width:600px}
/* PO/Reece order line tables have enough fixed columns that the global 600px
   floor makes descriptions unreadably narrow. Give the name column room and let
   narrow viewports scroll horizontally instead of breaking words. */
.card .po-lines-table,
.card .reece-preview-table,
.card .reece-cart-table{max-width:none;table-layout:auto;overflow-wrap:normal;word-break:normal}
.card .po-lines-table{min-width:900px}
.card .reece-preview-table{min-width:860px}
.card .reece-cart-table{min-width:980px}
.po-lines-table th,.po-lines-table td,
.reece-preview-table th,.reece-preview-table td,
.reece-cart-table th,.reece-cart-table td{overflow-wrap:normal;word-break:normal;vertical-align:top}
.po-line-desc{min-width:380px;width:44%;text-align:left;white-space:normal}
.po-line-qty{min-width:116px;text-align:center;white-space:nowrap}
.po-line-unit{min-width:82px;text-align:center;white-space:nowrap}
.po-line-received{min-width:112px;text-align:center;white-space:nowrap}
.po-line-money{min-width:116px;text-align:right;white-space:nowrap}
.po-line-total-label{text-align:right;white-space:nowrap}
.reece-line-desc{min-width:340px;width:38%;text-align:left;white-space:normal}
.reece-qty-col{min-width:96px;text-align:center;white-space:nowrap}
.reece-unit-col{min-width:86px;text-align:center;white-space:nowrap}
.reece-input-col{min-width:118px;text-align:center;white-space:nowrap}
.reece-status-col{min-width:150px;text-align:left;white-space:normal}
.reece-money-col{min-width:120px;text-align:right;white-space:nowrap}
.reece-action-col{min-width:68px;text-align:right;white-space:nowrap}
.po-line-desc .hint,
.reece-line-desc .hint{white-space:nowrap}
/* Job/title column: a sensible width floor so long job descriptions get room
   instead of wrapping into many lines while the fixed date/status columns hog
   the row. The table scrolls horizontally, so widening this is safe. */
.col-job{min-width:260px}
/* Quote/invoice number column: never wrap the reference (e.g. "Q-1001"). */
.col-id{white-space:nowrap}
/* Promo codes table (8 cols): keep headings + short cells on one line so the
   table scrolls instead of squishing every heading into a narrow stack. */
.promo-table{min-width:780px}
.promo-table th{white-space:nowrap}
/* "Verify" links under a market-priced line: where the suggested price came from. */
.li-verify{display:block;font-size:11px;color:var(--muted);margin-top:3px;line-height:1.5}
.li-verify a{color:var(--teal)}
.compare tbody tr:nth-child(even){background:var(--bg)}
.compare tbody td{vertical-align:middle}
.compare th{vertical-align:bottom}

/* CSS bar charts (team analytics) — dependency-free, accurate heights because
   the bar % is relative to .bar-track (flex:1), with labels sitting outside it. */
.chart{display:flex;align-items:stretch;gap:8px;height:200px;overflow-x:auto;padding-bottom:2px}
.bar-col{flex:1 0 36px;display:flex;flex-direction:column;min-width:36px}
.bar-track{flex:1;display:flex;align-items:flex-end;justify-content:center;gap:0}
.bar{width:62%;background:var(--teal);border-radius:6px 6px 0 0;min-height:2px;transition:height .2s}
.bar:hover{filter:brightness(1.08)}
.bar-val{text-align:center;font-size:11px;font-weight:700;margin-top:5px}
.bar-lbl{text-align:center;font-size:11px;color:var(--muted);white-space:nowrap}
table{width:100%;border-collapse:collapse}
th,td{text-align:left;padding:11px 10px;border-bottom:1px solid var(--line);font-size:14px}
th{font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
/* Headings are short labels — inside a scroll wrapper never let them break into
   squished multi-line stacks on mobile; the table scrolls sideways instead.
   Scoped to .table-wrap so bare (narrow) tables can't overflow the page.
   Long free-text CELLS (job titles, descriptions) still wrap. */
.table-wrap th{white-space:nowrap}
/* Money/number cells stay on one line so amounts never split. */
td.num,th.num{text-align:right;white-space:nowrap}
/* Phones: titles truncate so the MONEY (total + status) stays on screen — a
   horizontally-scrolled-away total is an invisible total. */
@media(max-width:640px){
  td.col-job,th.col-job{min-width:0;max-width:26vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  th,td{padding:11px 6px}
}
tr:last-child td{border-bottom:none}

/* ===== Stat / KPI tiles — matched to the app's KpiCard (multicoloured) =====
   Each tile carries its own accent (data-accent) used on the value + the round
   icon chip, exactly like the RN dashboard. brandSoft-style chip background,
   20px radius card, accent-coloured number. Light + dark parity below. */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
@media(max-width:780px){.stats{grid-template-columns:1fr 1fr}}
.stat{position:relative;background:var(--card);border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:16px 16px 15px;overflow:hidden;transition:border-color .15s,box-shadow .15s,background .15s}
.stat .stat-top{display:flex;align-items:flex-start;gap:8px;min-height:26px}
.stat .l{flex:1;min-width:0;font-size:11px;font-weight:700;letter-spacing:.03em;color:var(--muted);
  line-height:1.35;padding-right:2px}
/* Round icon chip (app: 26px circle, brandSoft bg, accent-coloured glyph). */
.stat .stat-chip{flex:0 0 auto;width:30px;height:30px;border-radius:50%;display:inline-flex;
  align-items:center;justify-content:center;color:var(--stat-accent,var(--teal));
  background:var(--stat-soft,var(--teal-light))}
.stat .stat-chip .ic{display:block}
.stat .v{font-size:27px;font-weight:800;letter-spacing:-.5px;line-height:1.1;
  color:var(--ink)}
/* App-style spacing only when the tile has the new header row (label + chip).
   Legacy .stat tiles (team_analytics: .v then .l, no .stat-top) keep their own flow. */
.stat .stat-top+.v{margin-top:12px}
.stat .v+.l{margin-top:5px}
/* Metric picker kebab — tucked beside the chip, quiet until hover. */
.stat .stat-kebab{flex:0 0 auto;background:none;border:0;cursor:pointer;color:var(--muted);
  font-size:18px;line-height:1;padding:0 2px;margin:-2px -4px 0 0;opacity:.55;transition:opacity .12s}
.stat:hover .stat-kebab{opacity:1}
.stat .dash-pick{position:absolute;top:42px;right:10px;z-index:30;background:var(--card);
  border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 22px rgba(0,0,0,.16);padding:6px}
.stat:hover{border-color:var(--stat-accent,var(--teal));
  box-shadow:0 6px 18px color-mix(in srgb,var(--stat-accent,var(--teal)) 16%,transparent)}
/* Accent palette — the app's exact KpiCard tile colours (light mode). */
.stat[data-accent="brand"]{--stat-accent:var(--teal);--stat-soft:var(--teal-light)}
.stat[data-accent="green"]{--stat-accent:#16a34a;--stat-soft:rgba(22,163,74,.10)}
.stat[data-accent="amber"]{--stat-accent:#d97706;--stat-soft:rgba(217,119,6,.10)}
.stat[data-accent="blue"]{--stat-accent:#2563eb;--stat-soft:rgba(37,99,235,.10)}
.stat[data-accent="violet"]{--stat-accent:#7c3aed;--stat-soft:rgba(124,58,237,.10)}
@media(max-width:380px){.stat .v{font-size:24px}}
/* Dark mode: brighten accents to the app's dark palette + softer chip fills. */
html[data-theme="dark"] .stat[data-accent="brand"]{--stat-accent:#2EA98C;--stat-soft:rgba(46,169,140,.16)}
html[data-theme="dark"] .stat[data-accent="green"]{--stat-accent:#22c55e;--stat-soft:rgba(34,197,94,.16)}
html[data-theme="dark"] .stat[data-accent="amber"]{--stat-accent:#fbbf24;--stat-soft:rgba(251,191,36,.16)}
html[data-theme="dark"] .stat[data-accent="blue"]{--stat-accent:#60a5fa;--stat-soft:rgba(96,165,250,.16)}
html[data-theme="dark"] .stat[data-accent="violet"]{--stat-accent:#c084fc;--stat-soft:rgba(192,132,252,.16)}

/* Landing */
.hero{padding:72px 0 48px;text-align:center}
.hero h1{font-size:48px;letter-spacing:-.02em;margin-bottom:18px}
.hero p.sub{font-size:20px;color:var(--slate);max-width:620px;margin:0 auto 28px}
.hero .cta{display:flex;gap:14px;justify-content:center;flex-wrap:wrap}
@media(max-width:640px){.hero h1{font-size:34px}.hero p.sub{font-size:17px}}
.kicker{color:var(--muted);font-weight:800;letter-spacing:.06em;text-transform:uppercase;font-size:13px;margin-bottom:14px}
.section{padding:48px 0}
.feature{padding:22px}
.feature .ico{width:44px;height:44px;border-radius:12px;background:var(--teal-light);color:var(--teal-dark);
  display:flex;align-items:center;justify-content:center;font-size:22px;margin-bottom:14px}
.feature .ico svg{width:22px;height:22px}
.feature h3{font-size:18px}
.feature p{color:var(--slate);font-size:15px;margin:0}
.banner{background:linear-gradient(135deg,var(--teal),var(--teal-dark));color:#fff;border-radius:18px;
  padding:40px;text-align:center;margin:20px 0}
.banner h2{color:#fff;font-size:28px}
.banner .btn{background:var(--card);color:var(--teal-dark)}
.banner .btn:hover{background:#e9f5f2}
.promo-code{background:var(--card);color:#118173;padding:1px 8px;border-radius:6px;letter-spacing:1px}
.logos{display:flex;gap:14px 26px;justify-content:center;flex-wrap:wrap;color:var(--muted);font-weight:700;
  font-size:12px;letter-spacing:.08em;text-transform:uppercase;margin-top:18px}

/* Rotating integrations banner: a seamless auto-scrolling marquee. The track holds
   the chips TWICE and slides left by 50%, so it loops with no visible jump. */
.marquee{overflow:hidden;width:100%;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent)}
.marquee-track{display:flex;gap:30px;width:max-content;animation:marquee 28s linear infinite}
.marquee:hover .marquee-track{animation-play-state:paused}
.intg{display:inline-flex;align-items:center;gap:9px;white-space:nowrap;font-weight:700;font-size:18px;
  letter-spacing:-.01em;color:var(--slate);background:var(--card);border:1px solid var(--line);
  border-radius:12px;padding:11px 20px;box-shadow:0 1px 2px rgba(15,23,42,.05)}
/* Brand chips: official colours + a brand-coloured dot, so they read as a logo
   lockup without shipping the trademarked artwork. */
.intg-xero{color:#1AB4D7;border-color:#1AB4D733}
.intg-myob{color:#6300A5;border-color:#6300A533}
.intg-qbo{color:#2CA01C;border-color:#2CA01C33}
.intg-stripe{color:#635BFF;border-color:#635BFF33}
.intg-xero::before,.intg-myob::before,.intg-qbo::before,.intg-stripe::before{
  content:"";width:9px;height:9px;border-radius:50%;background:currentColor;flex:none}
/* Real brand logos: uniform height on a white chip so every brand's own colours
   read correctly regardless of the source artwork's aspect ratio. */
.intg-logo{padding:12px 24px}
.intg-logo img{height:26px;width:auto;display:block}
@keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media(prefers-reduced-motion:reduce){
  .marquee{-webkit-mask-image:none;mask-image:none}
  .marquee-track{animation:none;flex-wrap:wrap;justify-content:center;width:auto;gap:14px}
}

/* Pricing */
.plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:18px;align-items:start}
@media(max-width:560px){.plans{grid-template-columns:1fr}}
.plan{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:26px;position:relative}
.plan.featured{border:2px solid var(--teal);box-shadow:var(--shadow)}
.plan .price{font-size:40px;font-weight:800;margin:8px 0}
.plan .price span{font-size:16px;color:var(--muted);font-weight:600}
.plan ul{list-style:none;padding:0;margin:18px 0}
.plan li{padding:7px 0 7px 26px;position:relative;color:var(--slate);font-size:15px}
.plan li:before{content:"✓";position:absolute;left:0;color:var(--green);font-weight:800}
.tag{position:absolute;top:-12px;right:20px;background:var(--teal);color:#fff;font-size:12px;
  font-weight:700;padding:4px 12px;border-radius:999px}

/* Misc */
.muted{color:var(--muted)}
.center{text-align:center}
.mt{margin-top:18px}.mt2{margin-top:32px}
.flex{display:flex;align-items:center;gap:12px}
.flex.between{justify-content:space-between;flex-wrap:wrap}
.tag-trade{font-size:13px;color:var(--slate)}
.empty{text-align:center;padding:48px 20px;color:var(--muted)}
.empty .big{font-size:48px;margin-bottom:8px}
/* Stacked line-item rows: description full-width on top, controls below — far
   clearer than the old cramped table (description was truncated, the type
   dropdown was squashed) and it wraps cleanly on mobile. */
/* Light two-line rows: description on its own line, then Type/Qty/Unit/Unit$/Total
   inline beneath. Just a separator between lines — no heavy boxes. */
/* Group headers on the review screen (Labour / Materials / Other). */
.li-group-head{font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;
  color:var(--muted);margin:16px 0 4px;padding-left:2px}
.li-group-head:first-child{margin-top:2px}
/* Left status bar is a real border (reserves space) + a left gutter, so the
   description/controls inputs sit beside it and never overlap it. */
.li-row{padding:10px 4px 10px 12px;border-bottom:1px solid var(--line);border-left:3px solid transparent}
.li-row.review{background:#fffbeb}
.li-row.saved:not(.review){border-left-color:var(--green)}
.li-desc{width:100%;font-size:15px;padding:8px 10px}
.li-badge{margin-top:5px}
.li-badge:empty{display:none}
/* Line 2: Type/Qty/Unit/Unit$/Total stay on ONE line (never wrap to 3+ lines);
   on a very narrow phone this row scrolls horizontally on its own rather than
   widening the page. */
.li-controls{display:flex;flex-wrap:nowrap;align-items:center;gap:8px;margin-top:8px;overflow-x:auto;padding-bottom:3px}
.li-controls select{flex:none;padding:6px 7px;font-size:13px;width:auto}
.li-ctl{flex:none;font-size:11px;color:var(--muted);display:inline-flex;align-items:center;gap:4px}
.li-ctl input{flex:none;padding:6px 7px;font-size:13px;width:58px}
.li-ctl input.unit{width:50px}
.li-ctl input.price{width:92px}   /* Unit $ — room for larger dollar amounts */
.li-total{flex:none;margin-left:auto;font-size:14px;white-space:nowrap;padding-left:6px}
/* Expanded review line: stack the controls full-width so they're easy to read/edit
   on a phone instead of the cramped horizontal-scroll strip. */
.li-row.expanded{background:#fffdf5;padding:12px;border-radius:10px}
.li-row.expanded .li-controls{flex-direction:column;align-items:stretch;overflow-x:visible;gap:10px}
.li-row.expanded .li-controls select{width:100%}
.li-row.expanded .li-ctl{justify-content:space-between;font-size:14px;color:var(--ink)}
.li-row.expanded .li-ctl input{width:60%;max-width:none}
.li-row.expanded .li-total{margin-left:0;align-self:flex-end;font-size:16px}
.notice{background:var(--teal-light);border:1px solid var(--teal);color:var(--ink);
  padding:12px 16px;border-radius:10px;font-size:14px}
/* Combined upload dropbox */
.dropbox{display:flex;flex-direction:column;align-items:center;gap:2px;text-align:center;cursor:pointer;
  border:2px dashed var(--line);border-radius:12px;background:var(--bg);padding:20px 16px;transition:.15s}
.dropbox:hover,.dropbox.drag{border-color:var(--teal);background:var(--teal-light)}
.spinner{display:none;align-items:center;gap:10px;color:var(--slate);font-weight:600;margin-top:14px}
.spinner.on{display:flex}
.dots{width:18px;height:18px;border:3px solid var(--teal-light);border-top-color:var(--teal);
  border-radius:50%;animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

/* --- notifications bell --- */
.bell-wrap{position:relative;display:inline-flex}
.bell-btn{position:relative;background:none;border:0;cursor:pointer;color:var(--muted);padding:6px;border-radius:8px;display:inline-flex;align-items:center}
.bell-btn:hover{color:var(--teal);background:color-mix(in srgb,var(--teal) 12%,transparent)}
.bell-badge{position:absolute;top:0;right:0;min-width:16px;height:16px;padding:0 4px;border-radius:9px;background:#e11d48;color:#fff;font-size:11px;font-weight:700;line-height:16px;text-align:center}
.bell-panel{position:absolute;top:calc(100% + 8px);right:0;width:340px;max-width:86vw;background:var(--card);border:1px solid var(--line);border-radius:12px;box-shadow:0 12px 32px rgba(2,6,23,.18);z-index:60;overflow:hidden}
@media(max-width:720px){.bell-panel{position:fixed;top:62px;left:10px;right:10px;width:auto;max-width:none}}
.bell-head{display:flex;justify-content:space-between;align-items:center;padding:12px 14px;border-bottom:1px solid var(--line)}
.linkbtn{background:none;border:0;color:var(--teal);font-weight:600;cursor:pointer;font-size:13px}
.bell-items{max-height:60vh;overflow-y:auto}
.bell-item{display:block;padding:11px 14px;border-bottom:1px solid var(--line);text-decoration:none;color:var(--ink)}
.bell-item:hover{background:var(--bg)}
.bell-item.unread{background:color-mix(in srgb,var(--teal) 8%,transparent)}
.bell-item.unread .bi-title{font-weight:700}
.bi-title{font-size:14px}
.bi-body{font-size:13px;color:var(--muted);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bi-ago{font-size:11px;color:var(--muted);margin-top:3px}
.bell-foot{display:block;text-align:center;padding:10px;font-size:13px;font-weight:600;color:var(--teal);text-decoration:none}
.bell-foot:hover{background:var(--bg)}
.bell-empty{padding:20px 14px;color:var(--muted);text-align:center;font-size:14px}
/* unread bubble on dashboard quote rows */
.qbubble{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:#e11d48;color:#fff;font-size:11px;font-weight:700;vertical-align:middle}

/* Narrow screens: let the nav wrap instead of widening the whole page */
/* Keep the nav on ONE line on phones: shrink the gap and drop the wordmark
   (logo stays) so every icon fits without squishing or wrapping. */
@media(max-width:600px){.nav .container{gap:9px;flex-wrap:nowrap}.nav .brand .wordmark{display:none}}
@media(max-width:430px){.nav .container{gap:7px}.acct-name{display:none}}

/* ── Audit tidy-up (styling only; no theme change) ─────────────────────────
   Opt-in wrapping for long button labels (the .btn default is white-space:nowrap,
   which overflows on narrow phones for long single-word labels). */
.btn.wrap{white-space:normal;text-align:center;line-height:1.25}
/* Cap line-item number inputs so the fixed pixel widths never overflow their row. */
.li-ctl input{max-width:100%}
/* Wide tables nested inside a card (not just direct children) get a horizontal
   scroller on small screens instead of overflowing/clipping. */
@media(max-width:720px){
  .card table:not(.table-wrap table){display:block;overflow-x:auto;-webkit-overflow-scrolling:touch}
}
/* Four-up stat tiles go single-column on the narrowest phones so big numbers
   don't crowd/clip. */
@media(max-width:380px){.stats{grid-template-columns:1fr}}

/* ── App-parity polish (allquote-rn) ───────────────────────────────────────
   Purely cohesive/visual: makes web cards, buttons, nav and focus rings read
   like the mobile app — soft 14px corners, thin borders, bright teal accent,
   subtle press feedback. No layout/overflow/table-alignment changes. Every
   rule reuses the existing CSS variables so light/dark parity is automatic. */

/* Cards: the app gives surfaces a touch more lift + a slightly tighter hairline
   border. GlassCard.js uses a 20px corner (--radius-lg); the smooth transition is
   for the hover lift. (The mobile block below trims back to --radius for the
   tighter phone shell.) */
.card{border-radius:var(--radius-lg);transition:border-color .15s,box-shadow .15s}

/* Buttons: app uses a 10px corner + a soft active-press dip. The primary teal
   gains a faint brand-tinted glow so the CTA "pops" like the app's FAB/buttons. */
.btn{border-radius:var(--radius-sm)}
.btn:active{transform:translateY(.5px)}
.btn:not(.ghost):not(.danger){box-shadow:0 1px 2px color-mix(in srgb,var(--teal) 35%,transparent)}
html[data-theme="dark"] .btn:not(.ghost):not(.danger){
  box-shadow:0 1px 14px color-mix(in srgb,var(--teal) 28%,transparent)}
@media(prefers-reduced-motion:reduce){.btn:active{transform:none}}

/* Inputs/select/textarea: app rounds to 10px. (Spec radius scale 14/10/7.) */
input[type=text],input[type=email],input[type=password],input[type=number],
input[type=color],input[type=tel],input[type=date],input[type=time],input[type=datetime-local],
input[type=search],input[type=url],select,textarea{border-radius:var(--radius-sm)}

/* Focus ring: the app's signature teal halo. In dark mode --teal-light is a dim
   surface (not a glow), so paint the halo from the bright --teal at low alpha. */
html[data-theme="dark"] input:focus,
html[data-theme="dark"] select:focus,
html[data-theme="dark"] textarea:focus{
  box-shadow:0 0 0 3px color-mix(in srgb,var(--teal) 22%,transparent)}

/* Nav: thinner, app-like sticky bar shadow once you scroll under it. */
.nav{box-shadow:0 1px 0 var(--line)}

/* Pills/badges already use 999px (app circular indicators) — leave as-is.
   Nav burger + small chips match the app's 7px tighter radius. */
.nav-burger{border-radius:var(--radius-xs)}

/* Brand wordmark stays branded even though ordinary --ink is neutral text. */
.brand .wordmark .w1{color:var(--aq-wordmark-all)}

/* Feature/icon tiles + dropbox: round to the app's 14px card corner so the
   landing page reads like the app's onboarding cards. */
.feature .ico{border-radius:var(--radius)}
.dropbox{border-radius:var(--radius)}

/* ── Mobile app-parity (allquote-rn) ───────────────────────────────────────
   Tighten the MOBILE web shell so it reads like the RN app (the app loads
   allquote.com.au in a webview). Mirrors the app's Header (components/Header.js)
   and its tidy dark card rhythm. Bottom-nav + side-drawer styling live inline in
   base.html; this block covers the TOP bar + content spacing on small screens.
   Desktop (>720px) is untouched; every colour comes from the theme tokens so
   light/dark parity is automatic. */
@media(max-width:720px){
  /* Top bar → the app's Header: a tidy 56px row, the brand mark left, action
     icons (messages/bell/☰) clustered right with even breathing room. */
  .nav .container{height:56px;gap:10px}
  .nav a.navlink{padding:6px}
  /* The icon-only action links in the bar (messages, bell, new, dashboard) get an
     even, app-like 34px tap target so the right cluster lines up like Header.js. */
  .nav .container>a.navlink,
  .nav .container>.bell-wrap>.bell-btn{display:inline-flex;align-items:center;justify-content:center}
  /* Account ☰ button reads as the app's menu button (square, subtle, teal on press). */
  .acct-btn{border-color:transparent;background:none}
  .acct-btn:active{background:var(--teal-light);color:var(--teal)}
  /* Content: the app sits cards on a tinted page with a little side gutter rather
     than edge-to-edge, so they read as discrete surfaces like the RN screens. */
  main.container{padding-left:14px;padding-right:14px}
  .card{border-radius:var(--radius)}
  /* Section headings on mobile match the app's compact screen titles. */
  main.container h1{font-size:22px}
  main.container h2{font-size:19px}
}

/* Job list tables: fixed operational columns, flexible ellipsis job name. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.aq-job-table-wrap{width:100%;position:relative}
.aq-job-table{width:100%;border-collapse:collapse;table-layout:fixed;font-size:13px}
.aq-job-table th,.aq-job-table td{
  padding:8px 9px;border-top:1px solid var(--line);text-align:left;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle
}
.aq-job-table thead th{border-top:0;border-bottom:1px solid var(--line);color:var(--muted);font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.04em;background:var(--bg)}
.aq-job-table .aq-job-col-num{width:94px}
.aq-job-table .aq-job-col-status{width:118px}
.aq-job-table .aq-job-col-date{width:108px}
.aq-job-table .aq-job-col-hours{width:96px}
.aq-job-table .aq-job-col-actions{width:42px}
.aq-job-num a{color:var(--muted);font-weight:800;text-decoration:none}
.aq-job-name-cell{min-width:0}
.aq-job-name-line{display:flex;align-items:center;gap:6px;min-width:0}
.aq-job-name-wrap{display:flex;align-items:center;gap:9px;min-width:0}
.aq-job-icon{width:32px;height:32px;border-radius:8px;border:1px solid var(--line);background:var(--brand-soft);color:var(--teal);display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:850;overflow:hidden;flex:0 0 32px}
.aq-job-icon img{width:100%;height:100%;display:block;object-fit:cover}
.aq-job-name{display:block;flex:1 1 auto;min-width:0;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:inherit;text-decoration:none;font-weight:750}
.aq-job-name:focus-visible,.aq-job-num a:focus-visible,.job-kebab-btn:focus-visible{outline:2px solid var(--teal);outline-offset:2px;border-radius:6px}
.aq-job-status .badge{max-width:100%;overflow:hidden;text-overflow:ellipsis}
.aq-job-actions{overflow:visible!important;text-align:right}
.job-kebab{position:relative;display:inline-flex;justify-content:flex-end}
.job-kebab-btn{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--muted);cursor:pointer;padding:0}
.job-kebab-btn[aria-expanded="true"],.job-kebab-btn:hover{border-color:var(--teal);color:var(--teal);background:var(--teal-light)}
.job-kebab-menu{position:absolute;right:0;top:calc(100% + 5px);z-index:70;min-width:164px;border:1px solid var(--line);border-radius:8px;background:var(--card);box-shadow:0 12px 28px rgba(2,6,23,.18);padding:5px}
.job-kebab-menu form{margin:0}
.job-kebab-menu button{width:100%;display:flex;align-items:center;gap:8px;border:0;background:transparent;color:var(--ink);font:inherit;font-size:13px;font-weight:700;text-align:left;border-radius:6px;padding:8px 9px;cursor:pointer;white-space:nowrap}
.job-kebab-menu button:hover,.job-kebab-menu button:focus{background:var(--bg)}
.job-kebab-menu button.danger{color:#dc2626}
@media(max-width:680px){
  .aq-job-table .aq-job-hours,.aq-job-table .aq-job-col-hours{display:none}
  .aq-job-table .aq-job-col-num{width:82px}
  .aq-job-table .aq-job-col-status{width:104px}
  .aq-job-table .aq-job-col-date{width:94px}
}
[data-file-dropzone]{transition:background-color .15s ease,box-shadow .15s ease}
[data-file-dropzone].is-file-dragging{background:var(--brand-soft);box-shadow:0 0 0 2px var(--teal)}
