/* ===========================================================================================
   LabONE Terminal — brand token layer (frozen brand system v2.0, 2026-03-15)
   Fonts: Precision Family v2, self-hosted (see tools/brand-fonts.py). Instrument Sans carries
   every word AND every numeral (Outfit retired 08-27 morning; Space Grotesk retired 08-27 evening
   — VS, off the live Lead Pool: "looks weird to the eye, doesn't fit the terminal"). Jura is
   MIRA's name and nothing else. Paper documents (*-print, guides, OTP) keep their frozen faces.
   Canvas is Warm White #F8F6F3 — "the paper, not the ink". Pure white is reserved for cards
   sitting ON that paper, which is exactly how this app is built. Orange is never a background;
   teal appears only on MIRA/intelligence surfaces. Shadows are navy-tinted, never black.
   =========================================================================================== */
:root{
  --navy:#1A2D5A;--navy-d:#0F1B38;--orange:#E7882F;--orange-d:#D07A28;--teal:#0D8F8F;
  --red:#D64545;--green:#237A48;
  --ink:#26303F;            /* navy-cast body ink — navy is the brand's primary text presence */
  --muted:#5A6B7D; /* brand "Grey Dark". The palette's #6B7B8D is 4.0:1 on Warm White -- the brand kit's own
    contrast table marks it AA-large-only, but .muted renders at 13px. Grey Dark is the
    brand's sanctioned darker grey and clears AA for body text. */
  --line:#E2DED7;--line-s:#EDEAE4;
  --bg:#F7F6F3;             /* OWNER RULING 2026-08-27 (LABONE TINT freeze, supersedes 08-02
                               pure-white): the canvas is the Tint warm ground. White cards on a
                               pure-white canvas have no edges — the wash/ground contrast IS the
                               card language, terminal-wide. */
  --rail:#FFFFFF;           /* the split inverts: WHITE rail beside the warm canvas, seam kept
                               by the hairline — the prototype VS froze reads exactly this way. */
  --card:#FFFFFF;           /* pure white is for cards/overlays only (many rules already ask for it) */
  --warm:#EDE9E3;
  --line-input:#C9C2B8;   /* warm control border — replaces the cool var(--line-input) family */
  --ok-ink:#237A48;--bad-ink:#B33030;--amber-ink:#A15E08;  /* semantic text, all AA on warm white */
  --teal-soft:rgba(13,143,143,.12);--teal-bar:rgba(13,143,143,.5);
  --sh-s:0 1px 2px rgba(26,45,90,.06);
  --sh-m:0 2px 8px rgba(26,45,90,.08);
  --sh-l:0 4px 16px rgba(26,45,90,.15);
  /* VS 2026-08-27: Outfit RETIRED terminal-wide - too light to read at UI sizes (this file
     had already recorded it as 'grey haze'). Space Grotesk RETIRED the same evening, off the
     live Lead Pool ("looks weird to the eye, doesn't fit the terminal") - its display-grade
     glyphs had leaked onto names and labels. ONE family carries every word and every numeral:
     Instrument Sans, whose shipped cuts carry tnum (verified in the woff2 GSUB tables).
     --f-data stays a DISTINCT token on purpose: it is the DATA VOICE - weight, tracking and
     tabular figures - and the ~80 rules asking for it keep meaning "label/figure", never
     "different face". Retire a face here, at the token; never rule by rule. */
  --f-display:'Instrument Sans','Segoe UI',system-ui,sans-serif;
  --f-body:'Instrument Sans','Segoe UI',system-ui,sans-serif;
  --f-data:'Instrument Sans','Segoe UI',system-ui,sans-serif;
  --f-mira:'Jura','Instrument Sans',sans-serif;
  --w-read:760px;--w-work:1080px;--w-table:1680px;
  /* DENSITY. Base is COMPACT — the owner's desktop register, and the rail size VS signed off.
     Row height, vertical padding, tap target and the two working type steps move together, so
     a screen is never half-dense. [data-density] is stamped on <html> by the server (by role)
     and overridden per operator from the rail. */
  --row-h:34px;--row-py:var(--s2);--tap:34px;
  /* SPACING SCALE (2026-08-02). 58 distinct values became 9 steps. 4px-based with a 2 and
     a 6 for chip internals and grid gutters, because a dense operations table genuinely
     needs a half-step; ties snap DOWN, since loosening a hundred declarations by a pixel
     each is how a dense tool quietly becomes an airy one. Max shift is 2px.
     NOT applied to the rail (hand-tuned and signed off twice), to fractional px (1.5px
     borders, the logo's -17.1px optical alignment), or to anything over 54px, which is a
     layout offset and not rhythm. */
  --s0:2px;--s1:4px;--s2:6px;--s3:8px;--s4:12px;--s5:16px;--s6:24px;--s7:32px;--s8:48px;
  /* the height of every form control, measured off Flabs 2026-08-22. One token, so the whole
     Terminal changes density together and no screen drifts to its own size. */
  --ctrl-h:32px;
  /* TYPE SCALE (2026-08-02). Seven text steps, three figure steps. Two registers:
     --t-ui 14 is CHROME (nav, chips, controls, table cells), --t-body 15 is PROSE
     (paragraphs, quotes, inputs). They are one step apart on purpose and must never be
     swapped. A font-size in px anywhere below this block is drift -- snap it to a token. */
  --t-micro:10px;--t-mini:11.5px;--t-tight:13px;--t-ui:14px;--t-body:15px;
  --t-name:17px;--t-title:21px;--t-nano:9px;
  --fig-m:26px;--fig-l:34px;--fig-xl:44px;
}
*{box-sizing:border-box}
body{margin:0;font-family:var(--f-body);font-size:var(--t-body);line-height:1.55;background:var(--bg);color:var(--ink);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;
  /* with one family for words and figures, tabular lining is enforced by INHERITANCE, so a
     numeral outside the shared data-voice rule below still lines up in its column */
  font-variant-numeric:tabular-nums lining-nums}
a{color:inherit;text-decoration:none}
/* PAGE MEASURE (2026-08-02). One 760px cap used to govern every screen, so a ten-facet lead table
   rendered in a letterbox with a third of the desktop left empty on either side. Three measures
   instead, chosen by route in partials/header.ejs:
     read  760  a record you READ top to bottom — lead story, conversation, the belt's one card
     work 1080  a queue you WORK through — bookings, tasks, touchpoint feed, home
     table 1680 a grid you SCAN across — Lead Pool, Search, Field, Scoreboard
   Nothing goes edge to edge: a table still needs a margin to read as a document, not a spreadsheet. */
.wrap{width:100%;max-width:var(--w-read);margin:0 auto;padding:var(--s4)}
.wrap.w-work{max-width:var(--w-work)}
.wrap.w-table{max-width:var(--w-table);padding-left:var(--s6);padding-right:var(--s6)}
@media(max-width:820px){.wrap.w-table{padding-left:var(--s4);padding-right:var(--s4)}}
/* A wide measure is for GRIDS, never for sentences: loose prose sitting straight on a wide page
   would run to 1680px and roughly 200 characters a line. Tables, cards and filter bars stretch;
   explanatory text keeps a reading measure. */
.wrap.w-work>p,.wrap.w-table>p,.wrap.w-work>.day-sub,.wrap.w-table>.day-sub{max-width:78ch}
.content{min-height:100vh}
.signed-in .content{margin-left:232px}
.signed-in.side-collapsed .content{margin-left:72px}
/* Instrument Sans carries every heading (Outfit retired 2026-08-27); near-neutral tracking */
h1,h2,h3,.h-display{font-family:var(--f-display);letter-spacing:.005em}
h1{font-size:var(--t-title);font-weight:700;margin:var(--s2) 0 var(--s4);line-height:1.2;color:var(--navy)}
h2.sec{font-family:var(--f-data);font-size:var(--t-mini);font-weight:700;text-transform:uppercase;letter-spacing:.12em;
  color:var(--muted);margin:var(--s6) 0 var(--s3)}
/* EVERY number renders in the data voice (frozen rule 3) and lines up in a column. This single
   declaration is what makes a dense list of counts read as instrument panel rather than webpage. */
.tile b,.kpi b,.fr-kpi b,.cov-stat b,.lb-v,.nav-badge,.adh-count b,.leakhero b,.cp-score b,
.rank-badge,.revbar-amt,.trend-n,.feed-when,.lg-amt,.khead b,.sec-n,.f-meta,.cl-meta,.rem-when,
.belt-lanes a b,.o-meta,.bk-meta,.cr-score,.lp-pill,.fchip.rep,.hero-sla,.rc-amt,.kd,.atable td{
  font-family:var(--f-data);font-variant-numeric:tabular-nums lining-nums}
.mira-tag,.mira-name{font-family:var(--f-mira);letter-spacing:.05em}
h2.sec.red{color:var(--red)} h2.sec.money{color:var(--orange)} h2.sec.hot{color:#0D8F8F} h2.sec.warm{color:var(--amber-ink)}
/* Heading annotation — the "· 1,192 visible to you" that follows a page or section title. It was
   36 inline em declarations across nine views, each sized against a different parent: inside the
   Space Grotesk overline .8em resolved to ~9px, which is below anything a person should be asked
   to read. One absolute class instead, and it must RESET the overline's transform and tracking or
   it inherits uppercase letterspaced caps from h2.sec. */
.h-sub{font-family:var(--f-body);font-size:var(--t-tight);font-weight:500;color:var(--muted);
  text-transform:none;letter-spacing:0}
/* Inline icon (lib/icons.js). 1em on purpose: the icon is sized BY the type scale, so one in a
   13px chip is 13px and one in a 17px name is 17px, and no page ever hard-codes an icon size.
   Optical baseline sits slightly low because the 24-box has no descender to sit against. */
.ic-i{display:inline-block;width:1em;height:1em;flex:0 0 auto;vertical-align:-.14em}
/* the stroke set every icon used to carry as attributes (lib/icons.js sprite, perf 2026-08-18) */
.ic-i,.ic{fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
/* semantic tints so an icon can carry meaning without a wrapper: teal = the machine, orange =
   the thing to press, and the judgment inks match the text they sit beside */
.ic-i.i-mira{color:var(--teal)} .ic-i.i-act{color:var(--orange)}
.ic-i.i-ok{color:var(--ok-ink)} .ic-i.i-bad{color:var(--bad-ink)} .ic-i.i-warn{color:var(--amber-ink)}
.ic-i.i-q{color:var(--muted)}
.muted{color:var(--muted);font-weight:500;font-size:var(--t-tight)}
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(64px,1fr));gap:var(--s3);margin-bottom:var(--s3)}
.tile{background:#fff;border:1px solid var(--line);border-radius:12px;padding:var(--s4) var(--s3);text-align:center}
.tile b{display:block;font-size:var(--fig-m);color:var(--navy)} .tile span{font-size:var(--t-mini);color:var(--muted)}
.tile.red b{color:var(--red)} .tile.t-money b{color:var(--orange)} .tile.hot b{color:#0D8F8F} .tile.warm b{color:var(--amber-ink)}
.lead{display:block;background:#fff;border:1px solid var(--line);border-radius:12px;padding:var(--s4) var(--s4);margin-bottom:var(--s3)}
.lead-main{display:flex;align-items:center;justify-content:space-between;gap:var(--s3)}
.lead .name{font-weight:700;font-size:var(--t-name)}
.chip{font-size:var(--t-mini);background:#eef1f8;color:var(--navy);border-radius:999px;padding:var(--s0) var(--s3);font-weight:700}
.lead-sub{color:var(--muted);font-size:var(--t-mini);margin-top:var(--s0)}
.empty{background:#fff;border:1px dashed var(--line);border-radius:12px;padding:var(--s6);text-align:center;color:var(--muted)}
.card{background:#fff;border:1px solid var(--line);border-radius:8px;padding:var(--s5);margin:0 0 var(--s4)}
.card h1{margin:0 0 var(--s1)} .card h2{font-size:var(--t-name);margin:0 0 var(--s4)}
.meta{color:var(--muted);font-size:var(--t-tight);margin-bottom:var(--s4)}
.callbtn{display:block;background:var(--orange);color:#fff;text-align:center;font-weight:700;font-size:var(--t-name);padding:var(--s4);border-radius:12px;margin:var(--s3) 0}
.mira{background:#f0f7f7;border-left:3px solid #0D8F8F;padding:var(--s3) var(--s3);border-radius:6px;font-size:var(--t-ui)}
.warn{color:var(--red);font-weight:600}
label{display:block;font-size:var(--t-tight);color:var(--muted);font-weight:600;margin:var(--s3) 0 0}
input,select,textarea{width:100%;margin-top:var(--s1);padding:var(--s4);border:1px solid var(--line);border-radius:10px;font-size:var(--t-name);background:#fff;font-family:inherit}
/* THE ERP CONTROL BASELINE (VS 2026-08-22, density pass).
   The rule above is the MOBILE baseline -- 17px text in a 12px-padded, 10px-radius box -- right
   for the CRM screens it was written for, wrong for a Flabs clone. Any ERP control outside
   .fgrid/.dfield inherited it: Manage Users' role select measured 49px beside 32px neighbours.

   A BASELINE MUST STAY LOW IN SPECIFICITY, or it stops being a baseline and starts being an
   override. The first cut of this block was written as
       .content.erp :is(input,select,textarea):not([type=checkbox]):not([type=radio]):not([type=file])
   which each :not() pushes to (0,5,1) -- so it beat every COMPONENT rule that follows, including
   .pricecell input (0,1,1). That rule flattens the input's left corners so it can butt against
   its own rupee box; overridden, every price in the catalogue rendered with a rounded corner
   sitting on the box beside it, which is what VS saw on Package Masters.

   So: ONE class plus one element (0,1,1) -- enough to beat the bare-element mobile rule, low
   enough that any component rule after it wins. Checkboxes and radios are put back explicitly
   below, which is a deliberate override and reads as one. */
.erp input,.erp select,.erp textarea{
  margin-top:0;padding:4px 11px;font-size:var(--t-ui);border-radius:6px}
.erp input,.erp select{height:var(--ctrl-h)}
.erp textarea{height:auto;min-height:calc(var(--ctrl-h) * 2)}
.erp select[multiple]{height:auto}
/* controls that are not boxes: their size is their own */
.erp input[type=checkbox],.erp input[type=radio]{height:auto;width:auto;margin:0;padding:0;
  border-radius:0}
.erp input[type=file]{height:auto;padding:0}

button.primary{margin-top:var(--s4);width:100%;background:var(--navy);color:#fff;border:0;border-radius:10px;padding:var(--s4);font-size:var(--t-name);font-weight:700}
.back{display:inline-block;color:var(--muted);margin-bottom:var(--s3);font-weight:600}
.ok{background:#e8f5e9;color:var(--ok-ink);padding:var(--s3) var(--s4);border-radius:8px;font-weight:600}
.err{background:#fdecea;color:var(--red);padding:var(--s3) var(--s4);border-radius:8px;font-weight:600}
.timeline{list-style:none;margin:0;padding:0}
.timeline li{border-top:1px solid var(--line);padding:var(--s3) 0}
.t-top{display:flex;flex-wrap:wrap;gap:var(--s3);align-items:center;font-size:var(--t-mini)}
.t-when{color:var(--muted)} .t-chan{font-weight:700;color:var(--navy)} .t-out{background:#eef1f8;border-radius:6px;padding:var(--s0) var(--s2);font-weight:700}
.t-src{color:var(--muted);margin-left:auto} .t-sum{font-size:var(--t-ui);margin-top:var(--s0);line-height:1.45}
/* visit-history clarity (VS 2026-07-31): proof links as buttons, next-action as a CTA callout */
.t-proof{display:flex;gap:var(--s3);margin-top:var(--s2)}
.t-link{display:inline-flex;align-items:center;gap:var(--s1);padding:var(--s0) var(--s3);border:1px solid #CFC9C0;border-radius:8px;font-size:var(--t-tight);font-weight:600;color:inherit;text-decoration:none}
.t-link:hover{border-color:var(--orange);color:var(--orange)}
.t-next{margin-top:var(--s2);padding:var(--s2) var(--s3);border-left:3px solid var(--orange);background:rgba(231,136,47,.09);border-radius:0 8px 8px 0;font-size:var(--t-ui)}
.t-next-d{font-weight:700;white-space:nowrap}
.fchip.bf{color:var(--muted);height:18px;font-size:var(--t-micro);letter-spacing:.03em;text-transform:uppercase}
/* manager left column (VS 2026-08-01): segment scorecard + outcome mix + book coverage stacked so
   the column earns its height next to the tall feed (was a 4-row card in a full-height slot) */
.mgr-stack{display:flex;flex-direction:column;gap:var(--s4);min-width:0}
.seg{margin-bottom:var(--s0)}
.seg-sub{color:var(--muted);font-size:var(--t-mini);margin:-var(--s0) 0 var(--s1) 112px}
.seg-good{color:var(--ok-ink);font-weight:600}
.seg-bad{color:var(--bad-ink);font-weight:600}
.pipe-fill.pf-good{background:#2e9e5b}
.pipe-fill.pf-bad{background:#d64545}
.mgr-note{color:var(--muted);font-size:var(--t-mini);margin:var(--s3) 0 0;line-height:1.4}
.mgr-note-bad{opacity:1;color:var(--bad-ink)}
.cov-bar{height:8px;border-radius:5px;background:#EEEAE3;overflow:hidden;margin:var(--s0) 0 var(--s3)}
.cov-fill{height:100%;background:var(--navy,#1A2D5A);border-radius:5px}
.cov-row{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s2);text-align:center}
.cov-stat b{display:block;font-size:var(--t-name);line-height:1.2}
.cov-stat span{color:var(--muted);font-size:var(--t-mini);text-transform:uppercase;letter-spacing:.03em}
/* review thread (manager + owner remarks) */
.rem{padding:var(--s3) 0;border-bottom:1px solid #ECE8E1}
.rem-top{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s2);font-size:var(--t-tight);min-width:0}
.rem-top .fchip{height:19px;font-size:var(--t-mini)}
.rem-top .f-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rem-when{color:var(--muted);margin-left:auto;font-size:var(--t-mini);white-space:nowrap}
.rem-body{font-size:var(--t-ui);margin-top:var(--s1);line-height:1.45;white-space:pre-wrap;overflow-wrap:anywhere}
.rem-mini .rem-body{font-size:var(--t-tight);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rem-form{margin-top:var(--s4);display:flex;flex-direction:column;gap:var(--s3)}
.rem-form textarea{width:100%;padding:var(--s3) var(--s3);border:1px solid var(--line-input);border-radius:10px;
  font:inherit;background:var(--card,#fff);color:inherit;resize:vertical}
.rem-actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3)}
.rem-actions select{padding:var(--s2) var(--s3);border:1px solid var(--line-input);border-radius:8px;font:inherit;background:var(--card,#fff);color:inherit}
.rem-actions .btn{margin-left:auto}
/* closing list: name + neglect meta, one row each */
.cl-row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s3);padding:var(--s1) 0;
  border-bottom:1px solid #EFEBE4;min-width:0}
.cl-row:last-of-type{border-bottom:0}
.cl-row .f-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--t-ui)}
.cl-meta{color:var(--muted);font-size:var(--t-mini);white-space:nowrap;flex:0 0 auto}
/* manager Live feed (VS 2026-08-01): time-rail grid, one-line name+outcome, note = the intel line */
.feed-row{display:grid;grid-template-columns:52px minmax(0,1fr);gap:var(--s3);padding:var(--s3) 0;border-bottom:1px solid #ECE8E1}
.feed-row:last-child{border-bottom:0}
.feed-main{min-width:0} /* REQUIRED: without it the nowrap note sets the track's min-content and the card grows a horizontal scroll */
.feed-when{font-size:var(--t-mini);font-weight:700;line-height:1.35}
.feed-top{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3);min-width:0}
.feed-top .f-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:min(52vw,340px)}
.feed-top .fchip{height:19px;font-size:var(--t-mini)}
.feed-mins{font-size:var(--t-tight)}
.feed-rep{margin-left:auto;font-size:var(--t-tight);white-space:nowrap}
.feed-note{font-size:var(--t-tight);margin-top:var(--s0);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.feed-next{font-size:var(--t-tight);color:var(--orange);margin-top:var(--s0)}

/* ---- LabONE mark — the CORRECT asset (VS 2026-08-02) ----
   The app was shipping the SUPERSEDED constellation: its dots are welded together by connecting
   lines. Proof, by counting connected components in the alpha channel:
       08-assets-media/brand-kit/logo/labone-icon-white.png -> 1 shape  (dots joined by lines)
       02-sales-marketing/brand-kit/logo-kit .../icon-white -> 5 shapes (110px centre, 2x70, 2x62)
   The logo-kit README states the direction outright: "Connecting lines between the dots are
   REMOVED (fully transparent) per brand direction — DOTS ONLY." Assets now come from that kit.
   True vector lives in logo-kit/05-vector-svg for print; the app uses the PNGs because their ink
   bounds are measurable, and at a ~7x downscale they are indistinguishable from vector.

   Rule 1 stands: the wordmark is always the <img>, never CSS text. Rule 4/5 pick the variant by
   background — white on the navy rail, navy on the light sign-in page. The kit also states the
   horizontal lockup is the ONLY approved arrangement, which is what both surfaces use.

   MEASURED with PIL, not eyeballed. Re-derive after any re-export:
     python -c "from PIL import Image;import numpy as np;a=np.array(Image.open(P).convert('RGBA'))[:,:,3];ys,xs=np.nonzero(a>8);print(xs.min(),ys.min(),xs.max(),ys.max())"

   labone-horizontal-white.png 1200x350  ink x169..1029, y58..292  (861px = 71.8% of the box)
                                         constellation x169..320, three dot-islands
   labone-icon-white.png        512x512  ink x101..419, y113..406  (319px = 62.3% of the box) */
.side-top{align-items:flex-start}
/* H=52px, NOT the old 48px: this lockup is taller relative to its ink, so 48px would render only
   118.1px of ink and breach the brand's 120px UI floor. 52px gives 127.9px. */
.brand img{display:block;height:52px;width:auto;max-width:none}
.brand{display:flex;flex-direction:column;align-items:flex-start;min-width:0;
  /* Put the constellation on the nav's icon column: the icons below sit 22px from the rail edge
     (.side-nav 10px + .side-link 12px). At H=52 the box carries 25.1px of transparent air before
     its first dot, and .side-top adds 14px: 22 - 25.1 - 14 = -17.1px. What overhangs the rail is
     transparent padding, never ink. Box is 178.3px, ending 175.2px in — clear of the collapse
     button, which starts at 192px. */
  margin-left:-17.1px}
.brand .mark-full{display:block} .brand .mark-icon{display:none}
.side-collapsed .brand .mark-full{display:none}
/* 52px box -> 32.4px of ink (the mark fills 62.3% of its own square), clearing the 32px icon floor.
   A 32px BOX would render only 20px of ink, which is the bug this replaced. */
.side-collapsed .brand .mark-icon{display:block;height:52px}
/* No tier word (VS 2026-08-02): the logo carries the brand on its own. The product name lives in
   <title>, the PWA manifest and the apple-web-app title. */
/* Collapsed rail: the icon box must be 52px for its ink to clear the 32px floor, but 52px + the
   26px collapse button + 28px of padding is 106px in a 72px rail — they have never fitted side by
   side (the old 32px icon overflowed too, it was just small enough not to show). Stack them: icon
   centred on top, chevron beneath. 72 - 20px padding = 52px content, an exact fit for the icon. */
.side-collapsed .side-top{flex-direction:column;align-items:center;gap:6px;padding:14px 10px 12px}
.side-collapsed .brand{margin-left:0;align-items:center;width:auto}

.day-sub{margin:-var(--s2) 0 var(--s4)}

/* ---- lead head ---- */
.lead-head .goal{margin:var(--s3) 0 0;font-size:var(--t-body)}
.nextline{margin:var(--s3) 0 0;font-size:var(--t-ui)}
.badge{font-size:var(--t-micro);font-weight:700;text-transform:uppercase;letter-spacing:.4px;border-radius:6px;padding:var(--s0) var(--s2);margin-left:var(--s2)}
.badge.red{background:#fdecea;color:var(--red)}

/* ---- MIRA context panel ---- */
.mira-panel{border-left:5px solid #0D8F8F}
.mira-panel.heat-hot{border-left-color:var(--orange);background:#fff8f0}
.mira-panel.heat-warm{border-left-color:#0D8F8F;background:#f0f7f7}
.mira-panel.heat-cold{border-left-color:#6B7B8D;background:#F4F1EC}
.mira-panel.heat-won{border-left-color:#2e9e5b;background:#eefaf1}
.mira-panel.heat-none,.mira-panel.heat-new{border-left-color:#c3cad6;background:#F4F1EC}
.mira-row{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-bottom:var(--s2)}
.mira-tag{font-weight:700;font-size:var(--t-mini);letter-spacing:1px;background:var(--navy);color:#fff;border-radius:6px;padding:var(--s0) var(--s3)}
.heat-pill{font-size:var(--t-mini);font-weight:700;border-radius:999px;padding:var(--s0) var(--s3);text-transform:uppercase;letter-spacing:.3px}
.heat-pill.heat-hot{background:var(--orange);color:#fff}
.heat-pill.heat-warm{background:#0D8F8F;color:#fff}
.heat-pill.heat-cold{background:#6B7B8D;color:#fff}
.heat-pill.heat-won{background:#2e9e5b;color:#fff}
.mira-when{color:var(--muted);font-size:var(--t-mini);margin-left:auto}
.mira-head{font-size:var(--t-name);font-weight:700;margin:var(--s1) 0}
.mira-next{background:#fff;border:1px dashed var(--line);border-radius:8px;padding:var(--s3) var(--s3);font-size:var(--t-ui);margin:var(--s3) 0}
.mira-line{font-size:var(--t-ui);margin:var(--s2) 0;line-height:1.45}
.mira-chips{display:flex;flex-wrap:wrap;gap:var(--s2);margin:var(--s3) 0 var(--s1)}
.mira-chips .chip{background:#fff;border:1px solid var(--line)}
.mira-chips .chip.good{background:#eefaf1;color:var(--ok-ink);border-color:#cdeccf}
.mira-chips .chip.warnchip{background:#fff4e5;color:var(--amber-ink);border-color:#f3dcb8}
.mira-foot{font-size:var(--t-mini);color:var(--muted);margin:var(--s3) 0 0;font-style:italic}

/* ---- timeline: human vs MIRA ---- */
.timeline li.human{border-left:3px solid var(--orange);padding-left:var(--s3)}
.timeline li.auto{border-left:3px solid #0D8F8F;padding-left:var(--s3)}

/* ---- CO-PILOT card ---- */
.copilot{border:2px solid var(--navy);background:#fff}
.cp-top{display:flex;gap:var(--s4);align-items:center;margin-bottom:var(--s2)}
.cp-score{flex:0 0 auto;width:62px;height:62px;border-radius:14px;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#fff}
.cp-score b{font-size:var(--fig-m);line-height:1} .cp-score span{font-size:var(--t-micro);text-transform:uppercase;letter-spacing:.5px}
.cp-score.sc-hot{background:var(--orange)} .cp-score.sc-warm{background:#0D8F8F} .cp-score.sc-cool{background:#5A6B7D} .cp-score.sc-cold{background:#6B7B8D}
.cp-verdict{flex:1}
.cp-label{font-size:var(--t-name);font-weight:700}
.cp-label.sc-hot{color:var(--amber-ink)} .cp-label.sc-warm{color:#0D8F8F} .cp-label.sc-cool{color:#5A6B7D} .cp-label.sc-cold{color:#6B7B8D}
.cp-why{font-size:var(--t-mini);color:var(--muted);margin-top:var(--s0);line-height:1.4}
.cp-watch{background:#fdecea;color:var(--red);font-weight:700;border-radius:8px;padding:var(--s3) var(--s3);margin:var(--s3) 0;font-size:var(--t-tight)}
.cp-block{margin:var(--s4) 0 0}
.cp-h{display:inline-block;font-size:var(--t-micro);font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--navy);background:#eef1f8;border-radius:5px;padding:var(--s0) var(--s2);margin-bottom:var(--s1)}
.cp-open{font-size:var(--t-name);font-weight:600;color:var(--ink);margin:var(--s1) 0;line-height:1.45}
.cp-list{margin:var(--s1) 0 0;padding-left:var(--s5)} .cp-list li{font-size:var(--t-ui);margin:var(--s0) 0;line-height:1.4}
.cp-share{font-size:var(--t-ui);margin:var(--s1) 0;background:#fff8f0;border:1px solid #f3dcb8;border-radius:8px;padding:var(--s3) var(--s3)}
.cp-obj{font-size:var(--t-ui);margin:var(--s1) 0;color:#444}
.cp-standing{font-size:var(--t-mini);color:var(--muted);font-style:italic;margin:var(--s4) 0 0;border-top:1px solid var(--line);padding-top:var(--s3)}
.cp-lastsaid{background:#f0f7f7;border-radius:8px;padding:var(--s3) var(--s3);font-size:var(--t-ui);margin:var(--s3) 0 0}

/* ---- full WhatsApp chat ---- */
.chatcard summary{cursor:pointer;list-style:none;font-size:var(--t-body)}
.chatcard summary::-webkit-details-marker{display:none}
.chatcard[open] summary{margin-bottom:var(--s3)}
.chat{display:flex;flex-direction:column;gap:var(--s2);max-height:460px;overflow-y:auto;padding:var(--s0)}
.bubble{max-width:82%;padding:var(--s2) var(--s4);border-radius:14px;font-size:var(--t-ui);line-height:1.4;white-space:pre-wrap;word-break:break-word}
.bubble.in{align-self:flex-start;background:#eef1f8;border-bottom-left-radius:4px}
.bubble.out{align-self:flex-end;background:#dcf3ec;border-bottom-right-radius:4px}
.b-body{color:var(--ink)}
.b-meta{font-size:var(--t-micro);color:var(--muted);margin-top:var(--s0);text-align:right}

/* ---- leak banner + hero ---- */
.leakbanner{display:block;background:#fdecea;color:var(--red);border-radius:10px;padding:var(--s3) var(--s4);font-weight:700;margin-bottom:var(--s4);font-size:var(--t-ui)}
.leakbanner.ok{background:#e8f5e9;color:var(--ok-ink)}
.leakbanner b{font-size:var(--t-name)}
.leakhero{display:flex;align-items:center;gap:var(--s4);border-radius:14px;padding:var(--s5);margin-bottom:var(--s4)}
.leakhero.bad{background:#fdecea} .leakhero.good{background:#e8f5e9}
.leakhero b{font-size:var(--fig-xl);line-height:1} .leakhero.bad b{color:var(--red)} .leakhero.good b{color:var(--ok-ink)}
.leakhero span{font-size:var(--t-ui);font-weight:600}

/* ---- kanban ---- */
.kanban{display:flex;gap:var(--s3);overflow-x:auto;padding-bottom:var(--s3);-webkit-overflow-scrolling:touch}
.kcol{flex:0 0 200px;background:#EEEAE4;border-radius:12px;padding:var(--s3)}
.khead{display:flex;justify-content:space-between;align-items:center;font-weight:700;font-size:var(--t-tight);color:var(--navy);padding:var(--s1) var(--s2) var(--s3)}
.khead b{background:#fff;border-radius:999px;padding:var(--s0) var(--s3);font-size:var(--t-mini)}
.kcard{display:block;background:#fff;border:1px solid var(--line);border-radius:9px;padding:var(--s3) var(--s3);margin-bottom:var(--s2)}
.kname{display:block;font-weight:700;font-size:var(--t-ui)} .ksub{display:block;font-size:var(--t-mini);color:var(--muted);margin-top:var(--s0)}
.kmore{font-size:var(--t-mini);color:var(--muted);text-align:center;padding:var(--s1)} .kempty{color:#c3cad6;text-align:center;padding:var(--s4)}
.kcol.stage-member{background:#eefaf1} .kcol.stage-tested{background:#eef7f7} .kcol.stage-new{background:#F1EEE9}
.kcol.stage-lost{background:#fbeceb}
.kcard .temp{font-size:var(--t-micro);padding:var(--s0) var(--s1);margin-left:var(--s1);vertical-align:middle}
.kcard.age-mid{border-left:3px solid #e7b24f} .kcard.age-old{border-left:3px solid var(--red)}
/* pipeline source swimlane chips */
.swimchips{display:flex;flex-wrap:wrap;gap:var(--s2);margin:0 0 var(--s4)}
.swim{font-size:var(--t-mini);font-weight:700;background:#fff;border:1px solid var(--line);border-radius:999px;padding:var(--s1) var(--s4);color:var(--muted)}
.swim.on{background:var(--navy);color:#fff;border-color:var(--navy)}

/* ---- tiles are clickable shortcuts ---- */
a.tile{cursor:pointer}
a.tile:hover{transform:translateY(-1px);box-shadow:0 3px 10px rgba(26,45,90,.08);border-color:#cdd6ea}
.topbar{z-index:20}

/* ---- leads filter bar ---- */
.filters{display:flex;flex-wrap:wrap;gap:var(--s2);margin:0 0 var(--s4)}
.filters input[type=search]{flex:1 1 180px;min-width:150px;width:auto;margin:0;padding:var(--s3) var(--s4)}
.filters select{flex:0 1 auto;width:auto;margin:0;padding:var(--s3) var(--s3);font-size:var(--t-ui);background:#fff}
.filters .fbtn{margin:0;background:var(--navy);color:#fff;border:0;border-radius:10px;padding:var(--s3) var(--s5);font-weight:700;cursor:pointer}
.filters .clearf{align-self:center;color:var(--muted);font-weight:600;padding:0 var(--s2)}

/* ---- live dot ---- */
.livedot{display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--teal);vertical-align:middle;margin-left:var(--s2);box-shadow:0 0 0 0 rgba(46,158,91,.5)}

.livelabel{font-size:var(--t-mini);vertical-align:middle}

/* ---- lead row status chips ---- */
.leadrow .stat{font-weight:700;border-radius:5px;padding:var(--s0) var(--s2);font-size:var(--t-mini)}
.stat-replied{background:#e6f7f4;color:#0D8F8F} .stat-overdue{background:#fdecea;color:var(--red)}
.stat-mira_warm{background:#fff4e5;color:var(--amber-ink)} .stat-due_today{background:#eef1f8;color:var(--navy)}
.stat-new{background:#eafaef;color:var(--ok-ink)}
.leadrow .ago{color:var(--muted)}
/* new lead just folded in by the live poller */
.leadrow.justin{background:#FDF7EA;border-color:#F0D9A8}

/* ---- lead heat pill (human-set temperature) ---- */
.head-right{display:flex;align-items:center;gap:var(--s2)}
.temp{font-size:var(--t-micro);font-weight:700;text-transform:uppercase;letter-spacing:.4px;border-radius:5px;padding:var(--s0) var(--s2);color:#fff}
.temp.t-hot{background:var(--orange)} .temp.t-warm{background:#0D8F8F} .temp.t-cool{background:#5A6B7D} .temp.t-cold{background:#6B7B8D}
.callhist{margin:-var(--s1) 0 var(--s3);font-size:var(--t-tight)}

/* ---- profile capture ---- */
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:0 var(--s4)}
@media(max-width:480px){.grid2{grid-template-columns:1fr}}
button.primary.ghost{background:#fff;color:var(--navy);border:1.5px solid var(--navy)}

/* ---- HOME hero: the freshest inbound lead, front and centre ---- */
.hero{display:block;background:linear-gradient(135deg,var(--navy),var(--navy-d));color:#fff;border-radius:16px;padding:var(--s5) var(--s5);margin:0 0 var(--s4);box-shadow:0 6px 20px rgba(26,45,90,.18)}
.hero-tag{font-size:var(--t-micro);font-weight:700;letter-spacing:1px;color:var(--orange);text-transform:uppercase}
.hero-main{display:flex;align-items:center;gap:var(--s3);margin:var(--s2) 0 var(--s0)}
.hero-name{font-size:var(--t-title);font-weight:700}
.hero-sub{font-size:var(--t-tight);color:#c9d3e8}
.hero-concern{font-size:var(--t-body);margin:var(--s3) 0 0}
.hero-call{display:inline-block;margin-top:var(--s4);background:var(--orange);color:#fff;font-weight:700;border-radius:10px;padding:var(--s3) var(--s4);font-size:var(--t-body)}

/* ---- header who-am-i (logged-in operator) ---- */
.whoami{margin-left:auto;font-size:var(--t-mini);color:#c9d3e8;font-weight:700;border:1px solid rgba(255,255,255,.25);border-radius:999px;padding:3px 10px}
.topbar .whoami + .logout{margin-left:10px}

/* ---- inbox (Phase 1) ---- */
.inbox{list-style:none;margin:0;padding:0}
.convrow{background:#fff;border:1px solid var(--line);border-left:4px solid #c3cad6;border-radius:12px;margin-bottom:var(--s3)}
.convrow a{display:block;padding:var(--s4) var(--s4)}
.convrow.heat-hot{border-left-color:var(--orange)} .convrow.heat-warm{border-left-color:#0D8F8F}
.convrow.heat-cold,.convrow.heat-new,.convrow.heat-none{border-left-color:#6B7B8D} .convrow.heat-won{border-left-color:#2e9e5b}
.convrow.awaiting{background:#fff8f0;border-left-color:var(--orange)}
.c-top{display:flex;align-items:center;justify-content:space-between;gap:var(--s3)}
.c-name{font-weight:700;font-size:var(--t-name)}
.c-badges{display:flex;gap:var(--s1);align-items:center}
.c-badges .badge{margin-left:0}
.badge.human{background:var(--orange);color:#fff} .badge.bot{background:#eef1f8;color:var(--navy)}
.c-last{font-size:var(--t-tight);color:#444;margin-top:var(--s1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.c-meta{font-size:var(--t-mini);color:var(--muted);margin-top:var(--s0)}

/* ---- conversation: handoff + send (Phase 2) ---- */
.conv-status{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-top:var(--s3)}
.modebtn{border:0;border-radius:8px;padding:var(--s2) var(--s4);font-weight:700;font-size:var(--t-tight);cursor:pointer}
.modebtn.takeover{background:var(--orange);color:#fff}
.modebtn.handback{background:#fff;color:var(--navy);border:1.5px solid var(--navy)}
.winstate{font-size:var(--t-mini);font-weight:700;border-radius:999px;padding:var(--s0) var(--s3);margin-left:auto}
.winstate.open{background:#e8f5e9;color:var(--ok-ink)}
.winstate.closed{background:#f1f3f7;color:var(--muted)}
.sendbox{display:flex;gap:var(--s3);align-items:flex-end;margin-top:var(--s3)}
.sendbox textarea{margin:0;flex:1}
.sendbox button.primary{margin:0;width:auto;padding:var(--s4) var(--s5)}
.sendbox textarea:disabled{background:#F4F1EC;color:#9aa3b2}
.bubble.out.desk{background:#fff0db;border:1px solid #f3d49b}

/* ---- Phase 3: booking panel ---- */
.booking .orders{list-style:none;margin:0 0 var(--s4);padding:0}
.booking .order{border:1px solid var(--line);border-radius:12px;padding:var(--s3) var(--s4);margin-bottom:var(--s3)}
.booking .order.ord-scheduled{border-left:3px solid var(--orange);background:#fff8f0}
.booking .order.ord-req{border-left:3px solid #0D8F8F;background:#f0f7f7}
.booking .order.ord-off{border-left:3px solid var(--muted);background:#F4F1EC}
.booking .order.ord-done{border-left:3px solid #2e7d32;background:#f3faf4}
.o-top{display:flex;align-items:center;gap:var(--s3)}
.o-name{font-weight:700;color:var(--navy)}
.o-meta{display:flex;flex-wrap:wrap;gap:var(--s3);font-size:var(--t-tight);color:var(--ink);margin-top:var(--s1)}
.o-type{background:#eef1f8;color:var(--navy);border-radius:6px;padding:var(--s0) var(--s2);font-weight:700}
.o-cancel{color:var(--muted)}
.o-rem{font-size:var(--t-mini);color:var(--muted);margin-top:var(--s1)}
.o-cancelform{display:flex;gap:var(--s3);align-items:center;margin-top:var(--s3)}
.o-cancelform input{margin-top:0;font-size:var(--t-tight);padding:var(--s2) var(--s3)}
.badge.ord-scheduled{background:#fff0df;color:var(--amber-ink)}
.badge.ord-req{background:#e6f4f4;color:#0D8F8F}
.badge.ord-off{background:#eef0f4;color:var(--muted)}
.badge.ord-done{background:#e8f5e9;color:var(--ok-ink)}
.booking button.ghost,.cadence button.ghost,.consent button.ghost{background:transparent;border:1px solid var(--line);color:var(--navy);border-radius:10px;padding:var(--s3) var(--s4);font-weight:700;width:auto;margin-top:0}
.booking button.ghost.danger,.cadence button.ghost.danger,.consent button.ghost.danger{border-color:#f1c3c0;color:var(--red)}
/* ---- Phase 4: cadence panel ---- */
.cad-state{display:flex;flex-wrap:wrap;gap:var(--s3);margin-bottom:var(--s2)}
.cad-btns{display:flex;flex-wrap:wrap;gap:var(--s3);align-items:flex-end;margin-top:var(--s3)}
.chip.good{background:#e8f5e9;color:var(--ok-ink)}
.chip.warnchip{background:#fdecea;color:var(--red)}

/* ---- Phase 5: funnel report + speed-to-lead ---- */
.fr-head{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s5);justify-content:space-between;align-items:flex-start}
.fr-kpis{display:flex;flex-wrap:wrap;gap:var(--s5)}
.fr-kpi{display:flex;flex-direction:column;align-items:flex-end}
.fr-kpi b{font-size:var(--t-title);color:var(--navy);line-height:1.1}
.fr-kpi small{font-size:var(--t-mini);color:var(--muted)}
.fr-kpi.red b{color:var(--red)}
.fr-ladder{margin-top:var(--s4);display:flex;flex-direction:column;gap:var(--s2)}
.fr-stage{position:relative;border-radius:8px;background:#F1EEE9;overflow:hidden}
.fr-bar{position:absolute;left:0;top:0;bottom:0;background:var(--navy);opacity:.14}
.fr-bar.stage-member{background:#2e7d32;opacity:.22}
.fr-row{position:relative;display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s4);font-size:var(--t-tight)}
.fr-label{font-weight:700;color:var(--navy);min-width:78px}
.fr-count{font-weight:700} .fr-count small{color:var(--muted);font-weight:500}
.fr-conv{margin-left:auto;font-weight:700;color:var(--ok-ink)}
.fr-conv.low{color:var(--red)}
.fr-age{color:var(--muted);min-width:92px;text-align:right;font-size:var(--t-mini)}
.fr-foot{margin-top:var(--s3)}
.hero-sla{display:inline-block;margin-top:var(--s3);font-size:var(--t-mini);font-weight:700;border-radius:8px;padding:var(--s1) var(--s3);background:rgba(255,255,255,.16);color:#fff}
.hero-sla.breach{background:var(--red);color:#fff}
.hero-sla.done{background:rgba(46,125,50,.9);color:#fff}
.tile.book b{color:var(--orange)}
.lead.coll.soon{border-left:3px solid var(--orange)}
.soonchip{background:#fff0df;color:var(--amber-ink)}

/* ---- Phase 6: snippets + stats + nav scroll ---- */
.snips{display:flex;flex-wrap:wrap;gap:var(--s2);margin-top:var(--s3)}
.snip{font-size:var(--t-mini);background:#eef1f8;color:var(--navy);border:1px solid var(--line);border-radius:999px;padding:var(--s1) var(--s3);font-weight:600;width:auto;margin:0;cursor:pointer;text-align:left}
.snip:hover{background:#e3e8f5}
.tplbox textarea{margin-top:0}
.consentform .cad-btns{margin-top:var(--s3)}
.opstat{padding:var(--s4) var(--s4)}
.opstat.me{border:2px solid var(--navy);background:#fff}
.op-top{display:flex;flex-wrap:wrap;gap:var(--s2) var(--s4);justify-content:space-between;align-items:baseline}
.op-name{font-weight:700;color:var(--navy);font-size:var(--t-name)}
.op-nums{font-size:var(--t-tight);color:var(--ink)} .op-nums .wins{color:var(--ok-ink)}
.op-mix{display:flex;flex-wrap:wrap;gap:var(--s2);margin-top:var(--s3)}
/* keep the growing top nav usable on a phone: scroll instead of breaking the bar */
.topbar nav{flex:1 1 auto;min-width:0;display:flex;gap:var(--s3);overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.topbar nav::-webkit-scrollbar{display:none}
.topbar nav a{white-space:nowrap}

/* ---- Phase 6.3/6.6: AI suggest + media attach ---- */
.suggestbtn{margin-top:var(--s3);background:#eef1f8;border:1px solid var(--line);color:var(--navy);border-radius:10px;padding:var(--s3) var(--s4);font-weight:700;width:auto;cursor:pointer}
.suggestbtn:disabled{opacity:.6;cursor:default}
.suggest-note{font-size:var(--t-mini);color:var(--muted);margin-left:var(--s3)}
.mediabox{margin-top:var(--s3);border-top:1px dashed var(--line);padding-top:var(--s3)}
.mediabox input[type=file]{font-size:var(--t-tight);padding:var(--s3)}

/* ---- Phase 6.7: brochure library ---- */
.brochures{display:flex;flex-wrap:wrap;gap:var(--s3);align-items:center;margin-top:var(--s3)}
.brocform{display:inline;margin:0}
.broc{background:#fff0df;border:1px solid #f3d6ad;color:var(--amber-ink);border-radius:999px;padding:var(--s2) var(--s4);font-weight:700;font-size:var(--t-tight);width:auto;margin:0;cursor:pointer}
.broc:hover{background:#ffe6c7}

/* ---- Homepage rework: live-conversation queue + slim recovery strip ---- */
.slim{font-size:var(--t-tight);color:var(--muted);margin:var(--s0) 0 var(--s2);line-height:1.5}
.slim .slim-k{font-weight:700;margin-right:var(--s1)}
.slim .slim-k.money{color:var(--orange)}
.slim a{font-weight:700;color:var(--navy)}
.lead.convo{border-left:3px solid transparent}
.lead.convo.awaiting{border-left-color:var(--orange)}
.chip.mode{font-size:var(--t-micro);letter-spacing:.3px}
.chip.mode.human{background:#fdecdc;color:#b5641a}
.chip.mode.bot{background:#e6f4f4;color:#0D8F8F}
.lead-sub .await{color:var(--orange);font-weight:700}
.convo-last{font-size:var(--t-tight);color:var(--ink);margin-top:var(--s2);line-height:1.4}
.convo-last .who{font-weight:700;color:var(--muted)}
.convo-sum{font-size:var(--t-tight);color:var(--muted);margin-top:var(--s1);line-height:1.45;border-left:2px solid var(--line);padding-left:var(--s3)}
.convo-concern{font-size:var(--t-tight);margin-top:var(--s1);color:var(--navy);font-weight:700}
.convo-act{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);margin-top:var(--s3);flex-wrap:wrap}
.convo-act .next{font-size:var(--t-tight);font-weight:700;color:var(--ink)}
.convo-act .acts{display:flex;gap:var(--s3);flex-shrink:0}
.convo-act .brief{background:var(--navy);color:#fff;font-weight:700;font-size:var(--t-tight);border-radius:9px;padding:var(--s2) var(--s4)}
.convo-act .leadlink{border:1px solid var(--line);color:var(--navy);font-weight:700;font-size:var(--t-tight);border-radius:9px;padding:var(--s2) var(--s4)}

/* ---- Nav tab badges (forcing function) ---- */
.topbar nav a{position:relative;white-space:nowrap}
.nav-badge{display:inline-block;margin-left:5px;min-width:17px;padding:0 6px;height:17px;line-height:17px;border-radius:999px;background:var(--orange);color:#fff;font-size:var(--t-mini);font-weight:700;text-align:center;vertical-align:middle}
.nav-badge.danger{background:var(--red)}
.nav-badge.zero{background:rgba(255,255,255,.16);color:#7fd49a;min-width:0;padding:0 5px;font-weight:700}

/* ---- Almost-paid recovery chips (clearly tappable) ---- */
.recover{margin:var(--s1) 0 var(--s4)}
.recover-k{display:block;font-size:var(--t-mini);font-weight:700;color:var(--orange);text-transform:uppercase;letter-spacing:.5px;margin-bottom:var(--s2)}
.recover-chips{display:flex;flex-wrap:wrap;gap:var(--s3)}
.recover-chip{display:inline-flex;align-items:center;gap:var(--s3);background:#fff;border:1.5px solid var(--orange);border-radius:999px;padding:var(--s2) var(--s3) var(--s2) var(--s4);font-weight:700;color:var(--navy);box-shadow:0 1px 3px rgba(231,136,47,.18)}
.recover-chip .rc-amt{background:var(--orange);color:#fff;border-radius:999px;padding:var(--s0) var(--s3);font-size:var(--t-tight);font-weight:700}
.recover-chip .rc-go{color:var(--orange);font-weight:700;font-size:var(--t-body);margin-right:var(--s0)}
.recover-chip:active{transform:translateY(1px)}
.recover-more{display:inline-flex;align-items:center;padding:var(--s2) var(--s4);border-radius:999px;border:1px dashed var(--line);color:var(--muted);font-weight:700;font-size:var(--t-tight)}

/* ---- Call transcripts / Training library (e-learning) ---- */
.chip.gold{background:#fdf3da;color:#9a6a00;border-color:#f0dca0}
/* .filterbar and public/forms.js DELETED 081c: no view has carried the class since the
   .tbar-search toolbar replaced it, so the script that auto-submitted those bars was
   loaded by nothing and the rules styled nothing. */
.filterbar button{margin-top:0}
.btnlink{display:inline-block;text-align:center;text-decoration:none}
button.ghost,.ghost.btnlink{background:#fff;color:var(--navy);border:1px solid var(--line);border-radius:10px;padding:var(--s3) var(--s4);font-weight:700;width:auto}
.tx-list{display:flex;flex-direction:column;gap:var(--s3)}
.tx-row{display:block;text-decoration:none;color:var(--ink);margin:0;padding:var(--s4) var(--s5)}
.tx-row:active{transform:translateY(1px)}
.tx-top{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap}
.tx-label{font-weight:700;color:var(--navy);font-size:var(--t-body)}
.tx-chips{margin-left:auto;display:flex;gap:var(--s2);flex-wrap:wrap}
.tx-snip{color:var(--ink);font-size:var(--t-tight);margin:var(--s2) 0 var(--s1);line-height:1.35}
.tx-meta{font-size:var(--t-mini)}
.tx-mini{list-style:none;padding:0;margin:0 0 var(--s3)}
.tx-mini li{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;padding:var(--s2) 0;border-top:1px solid var(--line)}
.tx-mini li:first-child{border-top:0}
.tx-mini a{font-weight:700;color:var(--navy);text-decoration:none}
.tx-full,.learn-body{white-space:pre-wrap;word-wrap:break-word;font-family:inherit;font-size:var(--t-ui);line-height:1.5;background:#F4F1EC;border:1px solid var(--line);border-radius:10px;padding:var(--s4);margin:var(--s2) 0 0;max-height:60vh;overflow:auto}
.learnings{background:#fbfaf2;border-color:#efe7c8}
.learn-body{background:#fff;border-color:#efe7c8}
.upload summary{cursor:pointer;font-size:var(--t-body);padding:var(--s1) 0}
.chkline{display:flex;align-items:center;gap:var(--s3);flex-direction:row;font-weight:600;color:var(--ink);margin-top:var(--s4)}
.chkline input{width:auto;margin-top:0}
.learnform{display:flex;align-items:center;gap:var(--s4);flex-wrap:wrap}
.learnform button{margin-top:var(--s4);width:auto;padding:var(--s4) var(--s5)}

/* ---- Tasks: do-now action queue (P1-4) ---- */
.sec-n{display:inline-block;background:#eef1f8;color:var(--navy);border-radius:999px;padding:var(--s0) var(--s3);font-size:var(--t-mini);font-weight:700;margin-left:var(--s1)}
.task{display:flex;gap:var(--s3);align-items:flex-start;justify-content:space-between;background:#fff;border:1px solid var(--line);border-left:3px solid var(--line);border-radius:12px;padding:var(--s4) var(--s4);margin-bottom:var(--s3)}
.task.t-awaiting{border-left-color:#0D8F8F} .task.t-overdue{border-left-color:var(--red)} .task.t-today{border-left-color:var(--amber-ink)} .task.t-unpaid{border-left-color:var(--orange)}
.task-main{min-width:0;flex:1}
.task-name{font-weight:700;color:var(--navy);font-size:var(--t-name);text-decoration:none}
.task-why{font-size:var(--t-tight);color:var(--muted);margin-top:var(--s0);display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
.task-prev{font-size:var(--t-tight);color:var(--ink);margin-top:var(--s1);font-style:italic;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.task-actions{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;justify-content:flex-end;flex:0 0 auto;max-width:62%}
.badge.money{background:#fff4e5;color:var(--amber-ink)}
.callmini{display:inline-block;background:var(--orange);color:#fff;font-weight:700;font-size:var(--t-tight);padding:var(--s3) var(--s4);border-radius:9px;text-decoration:none;white-space:nowrap}
.callmini.reply{background:#0D8F8F}
.ghost.mini,button.ghost.mini{padding:var(--s2) var(--s3);font-size:var(--t-tight);font-weight:700;border-radius:9px;width:auto;margin-top:0}
button.ghost.good{color:var(--ok-ink);border-color:#cdeccf}
.snoozeform,.doneform{display:inline-flex;align-items:center;gap:var(--s1);margin:0}
.snoozeform .sn-label{font-size:var(--t-mini);color:var(--muted);font-weight:700}
.task-clear{padding:var(--s1) var(--s0) var(--s4);font-size:var(--t-tight)}
@media(max-width:480px){.task{flex-direction:column} .task-actions{max-width:100%;justify-content:flex-start;width:100%}}

/* ---- Named playbooks (P0-3) ---- */
.playbooks{display:flex;flex-direction:column;gap:var(--s3);margin:var(--s4) 0}
.pbform{margin:0}
.pb-btn{display:block;width:100%;text-align:left;background:#fff;border:1px solid var(--line);border-left:3px solid var(--navy);border-radius:10px;padding:var(--s3) var(--s4);margin:0;font-family:inherit;cursor:pointer}
.pb-btn:active{transform:translateY(1px)}
.pb-btn.danger{border-left-color:var(--red)}
.pb-label{display:block;font-weight:700;color:var(--navy);font-size:var(--t-body)}
.pb-btn.danger .pb-label{color:var(--red)}
.pb-desc{display:block;color:var(--muted);font-size:var(--t-tight);font-weight:500;margin-top:var(--s0)}

/* Bookings queue + Admin cockpit (2026-06-30) */
.booking{display:flex;flex-direction:column;gap:var(--s3)}
.bk-head{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s3)}
.bk-name{font-weight:700;color:var(--navy);text-decoration:none;font-size:var(--t-name)}
.bk-name:active{transform:translateY(1px)}
.bk-meta{font-size:var(--t-tight)}
.bk-actions{display:flex;flex-wrap:wrap;gap:var(--s3);align-items:center}
.bk-confirm{display:flex;flex-wrap:wrap;gap:var(--s3);align-items:flex-end;padding-top:var(--s3);border-top:1px solid var(--line)}
.bk-confirm label{display:flex;flex-direction:column;font-size:var(--t-mini);color:var(--muted);font-weight:700;gap:var(--s0)}
.bk-confirm input,.bk-confirm select{padding:var(--s3) var(--s3);border:1px solid var(--line);border-radius:9px;font-size:var(--t-body);font-family:inherit}
.bk-decline{margin-top:-var(--s0)}
.admin-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--s4)}
.admin-tile{display:flex;flex-direction:column;gap:var(--s2);text-decoration:none;color:inherit}
.admin-tile:active{transform:translateY(1px)}
.admin-tile b{color:var(--navy);font-size:var(--t-name)}

/* Guide page (2026-07-01) */
.guide-hero{background:linear-gradient(135deg,var(--navy),var(--navy-d));color:#fff;border:none}
.guide-hero h1{color:#fff;margin:0 0 var(--s1)}
.guide-hero .muted{color:rgba(255,255,255,.82)}
.ask-card{border:1px solid var(--line);border-top:3px solid var(--orange,#E7882F)}
.ask-head{display:flex;align-items:center;gap:var(--s3);margin-bottom:var(--s3)}
.ask-ico{width:30px;height:30px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;background:rgba(231,136,47,.12);color:var(--orange,#E7882F)}
.ask-box{display:flex;gap:var(--s3);align-items:flex-end}
.ask-box textarea{flex:1;padding:var(--s3) var(--s4);border:1px solid var(--line);border-radius:10px;font-family:inherit;font-size:var(--t-body);resize:vertical}
.ask-box .primary{white-space:nowrap}
.ask-chips{display:flex;flex-wrap:wrap;gap:var(--s2);margin-top:var(--s3)}
.ask-chip{background:#F2EFEA;border:1px solid var(--line);color:var(--navy);border-radius:999px;padding:var(--s2) var(--s4);font-size:var(--t-tight);font-weight:600;cursor:pointer;font-family:inherit}
.ask-chip:active{transform:translateY(1px)}
.ask-answer{margin-top:var(--s4);padding:var(--s4) var(--s5);background:#F5F2ED;border:1px solid var(--line);border-left:3px solid var(--navy);border-radius:10px;white-space:pre-wrap;line-height:1.5;font-size:var(--t-body)}
.ask-note{font-size:var(--t-mini);margin:var(--s3) 0 0}
.callout{display:flex;gap:var(--s4);align-items:flex-start}
.callout-ico{flex:0 0 40px;width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center}
.gold-rule{border-left:4px solid var(--orange,#E7882F)}
.gold-rule .callout-ico{background:rgba(231,136,47,.14);color:var(--orange,#E7882F)}
.gold-rule b{color:var(--navy);font-size:var(--t-name)}
.gold-rule p{margin:var(--s1) 0 0}
.guard{border-left:4px solid var(--navy)}
.guard .callout-ico{background:rgba(26,45,90,.1);color:var(--navy)}
.guard-list{margin:0;padding-left:var(--s5)}
.guard-list li{margin:var(--s1) 0}
.guide-sec{color:var(--navy);margin:var(--s6) 0 var(--s2);font-size:var(--t-name)}
.loop-flow{display:flex;gap:var(--s3);overflow-x:auto;padding:var(--s1) 0 var(--s2)}
.loop-step{flex:0 0 auto;min-width:150px;background:#fff;border:1px solid var(--line);border-radius:12px;padding:var(--s4) var(--s4);display:flex;flex-direction:column;gap:var(--s0)}
.loop-step b{color:var(--navy)}
.loop-step .muted{font-size:var(--t-mini)}
.loop-n{width:24px;height:24px;border-radius:50%;background:var(--navy);color:#fff;font-weight:700;font-size:var(--t-tight);display:flex;align-items:center;justify-content:center;margin-bottom:var(--s1)}
.feat-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:var(--s4)}
.feat{padding:0;overflow:hidden}
.feat>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:var(--s3);padding:var(--s4) var(--s5);font-size:var(--t-body)}
.feat>summary::-webkit-details-marker{display:none}
.feat>summary b{color:var(--navy)}
.feat>summary .muted{font-size:var(--t-mini);margin-left:auto;text-align:right}
.feat-ico{width:32px;height:32px;border-radius:9px;background:rgba(26,45,90,.08);color:var(--navy);display:inline-flex;align-items:center;justify-content:center;flex:0 0 32px}
.feat[open]>summary{border-bottom:1px solid var(--line)}
.feat-body{padding:var(--s4) var(--s5) var(--s5)}
.feat-body p{margin:0 0 var(--s3)}
.feat-body ol,.feat-body ul{margin:var(--s2) 0 0;padding-left:var(--s5)}
.feat-body li{margin:var(--s1) 0}
.faq details{margin-bottom:var(--s3)}
.faq summary{cursor:pointer;font-weight:700;color:var(--navy);list-style:none}
.faq summary::-webkit-details-marker{display:none}
.faq summary:before{content:'+ ';color:var(--orange,#E7882F);font-weight:700}
.faq details[open] summary:before{content:'\2013 '}

/* ---- Call Command — the self-driving call engine (2026-07-01) ---- */
h2.sec.cool{color:#5A6B7D}
.badge.warm{background:#fff4e5;color:var(--amber-ink)}
.chip.heat-hot{background:#fff0e6;color:#c85a12} .chip.heat-warm{background:#e7f4f4;color:#0D8F8F}
.chip.heat-cool{background:#eef1f8;color:var(--navy)} .chip.heat-cold{background:#eef0f3;color:var(--muted)}
.callhead .ch-row{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s4)}
#sound-toggle{flex:0 0 auto;white-space:nowrap}
#sound-toggle[data-on="1"]{border-color:#cdeccf;color:var(--ok-ink);background:#f2fbf3}
.adherence{background:#fff;border:1px solid var(--line);border-radius:14px;padding:var(--s4) var(--s5);margin:0 0 var(--s4)}
.adh-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s3);flex-wrap:wrap;font-size:var(--t-ui)}
.adh-count b{color:var(--navy);font-size:var(--t-name)}
.adh-now{font-weight:700;font-size:var(--t-tight)} .adh-now.live{color:var(--red)} .adh-now.clear{color:var(--ok-ink)}
.adh-bar{height:9px;background:#eef1f8;border-radius:999px;margin-top:var(--s3);overflow:hidden}
.adh-bar span{display:block;height:100%;background:var(--teal);border-radius:999px}
.callrow{display:flex;gap:var(--s3);align-items:flex-start;justify-content:space-between;background:#fff;border:1px solid var(--line);border-left:4px solid var(--line);border-radius:12px;padding:var(--s4) var(--s4);margin-bottom:var(--s3)}
.callrow.k-overdueTimed,.callrow.k-overdueDay{border-left-color:var(--red)}
.callrow.k-dueToday{border-left-color:var(--orange)}
.callrow.k-untimed{border-left-color:#5A6B7D}
.callrow.soon{border-left-color:#c9d3e8;background:#fbfcfe}
.cr-main{min-width:0;flex:1}
.cr-top{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap}
.cr-name{font-weight:700;color:var(--navy);font-size:var(--t-name)}
.cr-score{margin-left:auto;font-size:var(--t-mini);font-weight:700;color:var(--muted);background:#eef1f8;border-radius:999px;padding:var(--s0) var(--s3)}
.cr-why{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-top:var(--s1);font-size:var(--t-tight)}
.cr-kind{font-weight:700;text-transform:uppercase;letter-spacing:.3px;font-size:var(--t-mini)}
.cr-kind.red{color:var(--red)} .cr-kind.warm{color:var(--amber-ink)} .cr-kind.cool{color:#5A6B7D}
.cr-when{font-size:var(--t-mini)}
.cr-pitch{margin-top:var(--s2);font-size:var(--t-ui);color:var(--ink)}
.cr-hist{margin-top:var(--s0);font-size:var(--t-mini)}
.cr-actions{display:flex;flex-direction:column;align-items:stretch;gap:var(--s2);flex:0 0 auto;max-width:150px}
.cr-actions .callmini{text-align:center}
.callmini.ghosty{background:#fff;color:var(--navy);border:1px solid var(--line)}
.resched{margin-top:0}
.resched>summary{list-style:none;cursor:pointer;text-align:center;font-size:var(--t-tight);color:var(--navy);border:1px solid var(--line);border-radius:9px;padding:var(--s2) var(--s3);font-weight:700}
.resched>summary::-webkit-details-marker{display:none}
.resched[open]>summary{background:#F2EFEA}
.resched-form{margin:var(--s3) 0 0}
.presets{display:flex;flex-wrap:wrap;gap:var(--s2)}
.preset{cursor:pointer;font-family:inherit;border:1px solid var(--line)}
.custom{display:flex;gap:var(--s2);align-items:center;margin-top:var(--s2);flex-wrap:wrap}
.custom input{width:auto;flex:1;margin-top:0;padding:var(--s3) var(--s3);font-size:var(--t-ui);min-width:96px}
.sched{padding:var(--s2) var(--s4)}
.schedrow{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) 0;border-top:1px solid var(--line)}
.schedrow:first-child{border-top:0}
.schedrow .cr-name{font-size:var(--t-body)} .schedrow .cr-when{margin-right:auto}
.empty.small{padding:var(--s5);font-size:var(--t-ui)}
.ch-title{font-size:var(--t-name);margin:0 0 var(--s0)}
.callhead{margin-top:var(--s2)}
/* "In funnel" chip on live-MIRA cards + quick filters on Leads */
.chip.funnel{background:#e8f6ee;color:#1e7a44;border:1px solid #bfe6cd}
.lead.returning{border-left:3px solid #2e9e5b}
.quickf{display:flex;flex-wrap:wrap;gap:var(--s3);margin:0 0 var(--s4)}
.qchip{display:inline-flex;align-items:center;gap:var(--s2);background:#fff;border:1px solid var(--line);border-radius:999px;padding:var(--s2) var(--s4);font-weight:700;font-size:var(--t-tight);color:var(--navy)}
.qchip .qhint{font-weight:600;font-size:var(--t-mini);color:var(--muted)}
.qchip.on{background:var(--navy);color:#fff;border-color:var(--navy)}
.qchip.on .qhint{color:#c9d3e8}
.qchip.clear{color:var(--muted);font-weight:600}
.callprompt{display:flex;align-items:center;gap:var(--s4);background:linear-gradient(135deg,var(--navy),var(--navy-d));color:#fff;border-radius:14px;padding:var(--s4) var(--s5);margin:0 0 var(--s4)}
.callprompt:active{transform:translateY(1px)}
.callprompt .cp-n{flex:0 0 auto;font-size:var(--fig-l);font-weight:700;line-height:1;color:#fff;background:rgba(231,136,47,.22);border:1px solid rgba(231,136,47,.5);border-radius:12px;padding:var(--s3) var(--s4);min-width:58px;text-align:center}
.callprompt .cp-txt{font-size:var(--t-ui);line-height:1.35;color:rgba(255,255,255,.92)}
.callprompt .cp-txt b{color:#fff}
.adh-sub{font-size:var(--t-mini);margin-top:var(--s2)}
.more{padding:var(--s3) var(--s0) var(--s1);font-size:var(--t-tight);font-weight:600}
.secnote{margin:-var(--s1) 0 var(--s3);font-size:var(--t-tight)}
.livehint{display:flex;align-items:center;gap:var(--s2);margin:var(--s4) var(--s0)}
.dot{width:9px;height:9px;border-radius:50%;background:var(--teal);display:inline-block;box-shadow:0 0 0 0 rgba(13,143,143,.5)}

@media(max-width:480px){.callrow{flex-direction:column}.cr-actions{flex-direction:row;flex-wrap:wrap;max-width:100%;width:100%}.cr-score{margin-left:0}}

/* ===================== Counter capture (walk-in / camp) ===================== */
.counter-form .cf-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3) var(--s4)}
.counter-form label{font-size:var(--t-mini);color:var(--muted);font-weight:600;margin:0}
.counter-form .req{color:var(--red)}
.counter-form input,.counter-form select{margin-top:var(--s1)}
.cf-check{display:flex;align-items:center;gap:var(--s3);margin-top:var(--s4);font-size:var(--t-ui);color:var(--ink);font-weight:600}
.cf-check.small{font-size:var(--t-mini);margin-top:var(--s3)}
.cf-check input{width:auto;margin:0}
.counter-flash{line-height:1.5}
.counter-form button.primary{margin-top:var(--s4)}
.log{padding:var(--s2) var(--s4)}
.logrow{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) 0;border-top:1px solid var(--line)}
.logrow:first-child{border-top:0}
.logrow.test{color:var(--muted);}
.lg-item{font-weight:700;font-size:var(--t-name);flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lg-meta{flex:0 0 auto;font-size:var(--t-mini)}
.lg-amt{flex:0 0 auto;font-weight:700;color:var(--navy)}
@media(max-width:520px){.counter-form .cf-grid{grid-template-columns:1fr}}

/* ===================== Left sidebar navigation (replaces the old top bar) ===================== */
.sidebar{position:fixed;top:0;left:0;bottom:0;width:232px;background:var(--navy);color:#c9d3e8;display:flex;flex-direction:column;z-index:40;box-shadow:2px 0 12px rgba(16,27,56,.12)}
.side-collapsed .sidebar{width:72px}
.side-top{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:16px 14px 12px}
.side-top .brand{font-weight:700;letter-spacing:.3px;font-size:var(--t-name);white-space:nowrap;overflow:hidden}
.side-collapse{flex:0 0 auto;background:transparent;border:0;color:#8fa1c4;cursor:pointer;padding:4px;border-radius:8px;display:flex}
.side-collapse:hover{background:rgba(255,255,255,.08);color:#fff}
.side-collapse svg{width:18px;height:18px}
.side-collapsed .side-collapse svg{transform:rotate(180deg)}
.side-collapsed .side-top{justify-content:center}
.side-nav{flex:1 1 auto;overflow-y:auto;padding:6px 10px;scrollbar-width:thin;display:flex;flex-direction:column}
.nav-group{margin:4px 0 12px}
/* SECTION-LINK GROUPS PACK TIGHT (VS 2026-08-14: "too much spacing... looks cheap"). The
   12px group margin was designed for multi-item blocks with headings; five single-link
   groups stacked those margins into dead bands. A headerless group is one row of a list —
   the link's own padding is all the rhythm it needs. :has() is already load-bearing here. */
.side-nav > .nav-group:not(:has(.nav-h)){margin:0}
.nav-h{font-size:var(--t-micro);font-weight:700;letter-spacing:1.2px;text-transform:uppercase;color:#6f82a8;padding:6px 10px 4px}
/* the owner rail's headings became static <p> labels (2026-08-14, non-collapsible rail);
   a p brings browser default margins a button never had — strip them or the rail grows
   the very dead bands the single-link rule above exists to kill */
p.nav-h{margin:0}
.side-collapsed .nav-h{color:var(--muted);text-align:center;font-size:var(--t-micro);letter-spacing:.5px;padding:6px 0 4px}
.side-link{display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:10px;color:#c4cfe6;font-weight:600;font-size:var(--t-body);position:relative;white-space:nowrap;margin:1px 0}
.side-link:hover{background:rgba(255,255,255,.07);color:#fff}
.side-link.on{background:rgba(231,136,47,.16);color:#fff}
.side-link.on::before{content:"";position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:var(--orange)}
.side-link .ic{width:20px;height:20px;flex:0 0 auto}
.side-label{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis}
.side-collapsed .side-link{justify-content:center;padding:11px 0}
.side-collapsed .side-label{display:none}
.nav-badge{flex:0 0 auto;min-width:20px;text-align:center;font-size:var(--t-mini);font-weight:700;background:var(--orange);color:#fff;border-radius:999px;padding:2px 7px;line-height:1.4}
.nav-badge.danger{background:var(--red)}
.nav-badge.zero{background:rgba(255,255,255,.12);color:#8fe3b0;padding:2px 6px}
.side-collapsed .nav-badge{position:absolute;top:5px;right:14px;min-width:8px;width:8px;height:8px;padding:0;font-size:0;border-radius:999px}
.side-collapsed .nav-badge.zero{display:none}
/* two stacked bands, never one row (2026-08-10): five controls in a 220px rail truncated the lens
   select to "Vi" and the operator's name to "D". Tools stack, identity sits on its own line. */
.side-foot{flex:0 0 auto;padding:12px 14px;border-top:1px solid rgba(255,255,255,.08);display:flex;flex-direction:column;align-items:stretch;gap:8px}
.side-who{display:flex;align-items:center;gap:10px;min-width:0}
.side-foot .whoami{flex:1 1 auto;min-width:0;font-size:var(--t-mini);color:#c9d3e8;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.side-foot .logout button{background:transparent;border:1px solid rgba(255,255,255,.4);color:#fff;border-radius:8px;padding:6px 12px;font-weight:700;cursor:pointer}
.side-foot .logout button:hover{background:rgba(255,255,255,.1)}
.side-collapsed .side-foot{padding:10px 8px}
.side-collapsed .side-foot .whoami{display:none}
.nav-toggle{display:none;position:fixed;top:10px;left:10px;z-index:50;width:42px;height:42px;background:var(--navy);border:0;border-radius:10px;cursor:pointer;flex-direction:column;gap:4px;align-items:center;justify-content:center;box-shadow:0 2px 8px rgba(16,27,56,.25)}
.nav-toggle span{width:20px;height:2px;background:#fff;border-radius:2px}
.nav-scrim{display:none;position:fixed;inset:0;background:rgba(16,27,56,.45);z-index:35}
@media(max-width:820px){
  .sidebar{transform:translateX(-100%);width:250px;box-shadow:none}
  .side-collapsed .sidebar{width:250px}
  .nav-open .sidebar{transform:translateX(0);box-shadow:2px 0 24px rgba(16,27,56,.4)}
  .nav-open .nav-scrim{display:block}
  .signed-in .content,.signed-in.side-collapsed .content{margin-left:0}
  .signed-in .nav-toggle{display:flex}
  /* MENU BUTTON SHARES THE TITLE ROW (VS 2026-08-14, plan item 1). The toggle is fixed at
     x10-52,y10-52 and every page used to be pushed down a blank 60px band to clear it. Now
     a page that STARTS with a short, provably-paddable element reserves 52px beside it
     instead — the button and the title read as one row and ~50px comes back on every screen.

     Audited across all 135 views before writing this: only 83 lead with an h1, and 41 lead
     with something a naive rule would have hidden — 35 with a back link (the whole ERP record
     set), four with a card (inbox, admin, bookings, error), chat.ejs with no h1 at all, plus
     .dept-bar and .lens-banner which header.ejs injects INSIDE .wrap ahead of any page markup.

     So the default stays the safe 60px band and the tightening is OPT-IN, gated by :has()
     (already load-bearing in this file). Gate and reserve share one condition, so they can
     never come apart; an unrecognised first child — including a view written next month —
     silently keeps the band. Failure costs 50px of space, never a covered control, and a
     browser without :has() drops both rules together and lands exactly on today's behaviour.
     min-height pushes the first element's box to the button's bottom edge, so what follows
     clears it too; a short back link alone would leave the NEXT element under the button. */
  .signed-in .wrap{padding-top:60px}
  .signed-in .wrap:has(>h1:first-child),
  .signed-in .wrap:has(>.dept-bar:first-child),
  .signed-in .wrap:has(>.back:first-child),
  .signed-in .wrap:has(>.day-sub:first-child){padding-top:10px}
  .signed-in .wrap:has(>h1:first-child)>h1:first-child,
  .signed-in .wrap:has(>.dept-bar:first-child)>.dept-bar:first-child,
  .signed-in .wrap:has(>.day-sub:first-child)>.day-sub:first-child{margin-top:0;min-height:44px;padding-left:52px}
  /* .back is an inline-block anchor: MARGIN, not padding — padding would stretch its own tap
     area left under the button, so a thumb aiming at the menu could land on "back" instead. */
  .signed-in .wrap:has(>.back:first-child)>.back:first-child{margin-top:0;min-height:44px;margin-left:52px}
  /* the orange rule under a title is position:absolute;left:0 (see .wrap>h1::after) — without
     this it would ship hidden behind the navy button */
  .signed-in .wrap:has(>h1:first-child)>h1:first-child::after{left:52px}
  .side-collapsed .side-label{display:inline}
  .side-collapsed .side-link{justify-content:flex-start;padding:10px 12px}
  .side-collapsed .nav-badge{position:static;min-width:20px;width:auto;height:auto;padding:2px 7px;font-size:var(--t-mini)}
  .side-collapsed .nav-h{text-align:left;font-size:var(--t-micro);letter-spacing:1.2px;padding:6px 10px 4px}
  .side-collapsed .side-foot{padding:12px 14px}
  .side-collapsed .side-foot .whoami{display:block}
}

/* OWNERSHIP (item 4): claim + scope filter */
.owner-line{display:flex;align-items:center;gap:var(--s3);margin:var(--s3) 0 var(--s0);flex-wrap:wrap}
.owner-tabs{display:flex;gap:var(--s2);margin-top:var(--s3);flex-wrap:wrap}
.owner-tabs .tab{font-size:var(--t-mini);font-weight:700;padding:var(--s1) var(--s4);border-radius:999px;background:#eef1f8;color:var(--navy);text-decoration:none}
.owner-tabs .tab.on{background:var(--navy);color:#fff}

/* ANALYTICS (item 3): revenue bars. The .atable skin that used to live here was a SECOND table
   grammar — 13px, uppercase Space Grotesk heads, no column rules — sitting beside .dtable's in the
   same terminal. 106 folded both into one skin; see "ONE TABLE SKIN" further down. */
.atable td.win{font-weight:700;color:var(--ok-ink)}
.cac-form{display:flex;gap:var(--s3);align-items:flex-end;flex-wrap:wrap}
.revbar-row{display:flex;align-items:center;gap:var(--s3);margin:var(--s1) 0}
.revbar-mo{width:66px;font-size:var(--t-mini);color:var(--muted);font-weight:700}
.revbar-track{flex:1;height:14px;background:#eef1f8;border-radius:999px;overflow:hidden}
.revbar-fill{display:block;height:100%;background:var(--navy);border-radius:999px}
.revbar-amt{width:96px;text-align:right;font-weight:700;font-size:var(--t-mini)}

/* ---- 2026-07-24 two-tab CRM: lead rows carry inline actions (row is a flex DIV now, not an <a>) ---- */
.leadflex{display:flex;align-items:stretch;gap:var(--s3)}
.leadflex .lead-open{flex:1;min-width:0;text-decoration:none;color:inherit;display:block}
.lead-actions{display:flex;align-items:center;gap:var(--s2);flex:0 0 auto}
.lead-actions .btn{padding:var(--s3) var(--s4);white-space:nowrap}
.outdrop{position:relative;display:inline-block}
.outdrop>summary{list-style:none;cursor:pointer}
.outdrop>summary::-webkit-details-marker{display:none}
.outdrop[open]>.outcomebar{position:absolute;right:0;top:calc(100% + 4px);z-index:30;background:var(--card,#fff);border:1px solid var(--line-input);border-radius:10px;padding:var(--s3);display:flex;flex-direction:column;gap:var(--s2);min-width:16rem;box-shadow:0 6px 18px rgba(26,45,90,.22)}
.outcomebar button,.outcomebar a.btn{text-align:left;font-size:var(--t-tight)}
.outcomebar .cbrow{display:flex;gap:var(--s1);align-items:center;flex-wrap:wrap}
@media (max-width:640px){ .leadflex{flex-wrap:wrap} .lead-actions{width:100%;justify-content:flex-end} .outdrop[open]>.outcomebar{right:auto;left:0} }

/* ---- 2026-07-24 fix-round (verify panel): a REAL .btn component — anchors and buttons alike.
   Until now only button.primary existed; <a class="btn"> rendered as plain text everywhere. ---- */
/* CONTROL METRICS MEASURED OFF THE REFERENCE (2026-08-16, live at 1440px), not estimated from a
   screenshot: button 32px tall, 6px radius, 1px border, 12px side padding, 14px label. Ours was
   40/10/1.5 — a whole step chunkier, which is why the two screens never lined up side by side.
   The TYPEFACE stays ours (VS: "you dont have to copy their font, just the sizing and spacing").
   Weight is the one measured value not cloned: theirs is 400 in Roboto, ours is 500 in Instrument
   Sans, which renders lighter at the same number. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);background:#fff;color:var(--navy);border:1px solid var(--line-input);border-radius:6px;padding:0 var(--s4);min-height:32px;font-weight:500;font-size:var(--t-ui);text-decoration:none;cursor:pointer;line-height:1.2}
.btn.primary{background:var(--navy);color:#fff;border-color:var(--navy)}
.btn:active{transform:translateY(1px)}
.outcomebar button,.outcomebar a.btn{min-height:44px;width:100%;text-align:left;justify-content:flex-start;font-size:var(--t-ui);border:1.5px solid var(--line);border-radius:10px;background:#fff;color:var(--navy);padding:var(--s3) var(--s4);font-weight:700;cursor:pointer}
.outcomebar a.btn.primary{background:var(--navy);color:#fff;border-color:var(--navy)}
.outcomebar .cbrow button{width:auto;flex:1}
/* mobile: the dropdown becomes a fixed bottom sheet — never off-screen, always thumb-reach */
@media (max-width:640px){
  .outdrop[open]>.outcomebar{position:fixed;left:8px;right:8px;bottom:8px;top:auto;min-width:0;max-height:70vh;overflow-y:auto;box-shadow:0 -6px 30px rgba(26,45,90,.35)}
}

/* ---- WORK QUEUE v2: the belt (VS 2026-07-29) ---- */
.belt-card{border-left:5px solid #2e9e5b;padding:var(--s5) var(--s5)}
.belt-card.belt-amber{border-left-color:#e3a008}
.belt-card.belt-red{border-left-color:#d64545}
.belt-head{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap;margin-bottom:var(--s2)}
.belt-badge{font-weight:700}
.belt-why{font-size:var(--t-ui)}
.belt-name{margin:var(--s0) 0 var(--s1)}
.belt-meta{display:flex;gap:var(--s3);flex-wrap:wrap;font-size:var(--t-tight);margin-bottom:var(--s2)}
.belt-quote{margin:var(--s3) 0;padding:var(--s3) var(--s4);border-left:3px solid var(--line-input);background:#F1EDE6;border-radius:6px;font-size:var(--t-body)}
.belt-summary{font-size:var(--t-tight);margin:var(--s1) 0}
.belt-actions{display:flex;gap:var(--s3);margin:var(--s3) 0;flex-wrap:wrap}
.belt-actions .btn{min-height:44px;display:inline-flex;align-items:center}
.belt-outcomes{position:static;display:flex;flex-direction:column;gap:var(--s2);border-top:1px dashed var(--line-input);padding-top:var(--s3);margin-top:var(--s1);max-width:30rem}
/* belt card v3 (VS 2026-07-29): concise outcome grid + date/slot scheduler */
.belt-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:var(--s2)}
.belt-grid .btn,.belt-grid button{width:100%;min-height:38px;padding:var(--s3) var(--s3);font-size:var(--t-ui);white-space:nowrap}
.belt-sched{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap;margin-top:var(--s3);padding:var(--s3) var(--s4);border:1.5px dashed var(--line-input);border-radius:10px}
.belt-sched-lbl{font-weight:700;font-size:var(--t-tight)}
.belt-sched input[type=date],.belt-sched select{padding:var(--s3) var(--s3);border:1px solid var(--line-input);border-radius:8px;background:var(--card,#fff);color:inherit;font:inherit;min-height:38px}
.belt-sched .btn{min-height:38px;padding:var(--s3) var(--s5)}
.belt-skip{display:flex;gap:var(--s3);align-items:center;margin-top:var(--s4)}
.belt-skip select{padding:var(--s3);border-radius:8px;border:1px solid var(--line-input);background:var(--card,#fff);color:inherit}
.belt-skip input[type=text]{flex:1;min-width:12rem;padding:var(--s3) var(--s3);border-radius:8px;border:1px solid var(--line-input);background:var(--card,#fff);color:inherit;font:inherit}

/* ---- CAMP DAY (VS 2026-07-29): field-team surface — big thumb targets, review front & center ---- */
.camp-form{display:flex;flex-direction:column;gap:var(--s4);padding:var(--s5) var(--s5)}
.camp-sticky{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3);padding:var(--s3);border:1.5px dashed var(--line-input);border-radius:10px}
.camp-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3)}
/* the hidden attribute must ALWAYS win — author display rules (e.g. .fld{display:flex}) silently
   defeat the UA's [hidden]{display:none} (2026-08-01: the Other-type specify field showed always) */
[hidden]{display:none!important}
.camp-form .fld{display:flex;flex-direction:column;gap:var(--s1)}
.camp-form .fld label{font-size:var(--t-tight);font-weight:600}
.fld-hint{color:var(--muted);font-size:var(--t-mini)}
.fld-hint-warn{color:var(--bad-ink);font-weight:600;opacity:1}
.camp-form input[type=text],.camp-form input[type=tel],.camp-form input[type=number],.camp-form select{padding:var(--s3) var(--s4);border:1px solid var(--line-input);border-radius:10px;background:var(--card,#fff);color:inherit;font:inherit}
.camp-tests{display:flex;gap:var(--s3);flex-wrap:wrap}
.camp-chip{display:inline-flex;align-items:center;gap:var(--s2);padding:var(--s3) var(--s4);border:1.5px solid var(--line-input);border-radius:999px;cursor:pointer;font-weight:600;font-size:var(--t-ui)}
.camp-chip input{accent-color:var(--navy,#1A2D5A);width:1.05rem;height:1.05rem}
.camp-chip:has(input:checked){border-color:var(--navy,#1A2D5A);background:rgba(26,45,90,.08)}
.camp-chip.ok:has(input:checked){border-color:#2e9e5b;background:rgba(46,158,91,.12)}
.camp-chip.no:has(input:checked){border-color:#d64545;background:rgba(214,69,69,.1)}
.camp-review{border:2px solid #e3a008;border-radius:12px;padding:var(--s4) var(--s4);background:rgba(227,160,8,.06)}
.camp-review-head{font-weight:700}
.camp-review-btns{display:flex;gap:var(--s3);flex-wrap:wrap;margin-top:var(--s2)}
.camp-sale summary{cursor:pointer;font-weight:700;padding:var(--s2) 0}
/* checkbox rows: box + text packed LEFT together — a generic label rule was spreading them apart */
.camp-form .ck{display:flex;gap:var(--s3);align-items:center;justify-content:flex-start;text-align:left;font-size:var(--t-ui);width:100%;margin:0}
.camp-form .ck input{flex:0 0 auto;width:1.15rem;height:1.15rem;margin:0;accent-color:var(--navy,#1A2D5A)}
.camp-form .ck span{flex:1 1 auto}
.camp-submit{padding:var(--s4);font-size:var(--t-name);border-radius:12px}
.campered{display:flex;gap:var(--s3);padding:var(--s3) var(--s1);font-size:var(--t-tight);flex-wrap:wrap}
/* ---- FIELD SALES list views (VS 2026-07-31 "salesforce best practices"): strict column grids,
   compact 22px chips, semantic stage colors, truncate-not-wrap. Own classes — never the B2C .lead/
   .chip pair, whose flex-stretch inflated chips into giant ovals on these pages. ---- */
.ftable{display:flex;flex-direction:column;overflow-x:auto}
.frow{display:grid;gap:var(--s2) var(--s4);align-items:center;padding:var(--s3) var(--s3);border-bottom:1px solid #ECE8E1;font-size:var(--t-body);min-height:44px}
.frow:last-child{border-bottom:0}
.frow:hover{background:rgba(26,45,90,.045)}
.f-main{min-width:0}
.f-name{display:block;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
a.f-name{color:inherit;text-decoration:none}
a.f-name:hover{text-decoration:underline;color:var(--navy,#1A2D5A)}
.f-sub{color:var(--muted);display:block;font-size:var(--t-mini);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fchip{display:inline-flex;align-items:center;justify-content:center;height:22px;padding:0 var(--s3);border-radius:11px;font-size:var(--t-mini);font-weight:600;white-space:nowrap;width:fit-content;background:rgba(26,45,90,.07)}
.fchip.t{background:rgba(26,45,90,.09)}
.s-new{background:#EEEAE3}
.s-visited{background:rgba(26,45,90,.1);color:var(--navy)}
.s-in-discussion{background:rgba(227,160,8,.16);color:#9a6a00}
.s-partner{background:rgba(46,158,91,.16);color:var(--ok-ink)}
.s-declined{background:rgba(214,69,69,.13);color:var(--bad-ink)}
.s-dormant{background:#EEEAE3}
.fdot{width:10px;height:10px;border-radius:50%;display:inline-block;justify-self:center}
.p-high{background:#e3453e}.p-medium{background:#e3a008}.p-low{background:#b8b8b8}
.f-meta{color:var(--muted);font-size:var(--t-tight);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:right}
.f-act{display:flex;gap:var(--s1)}
.f-act .btn{min-height:30px;padding:var(--s0) var(--s3);font-size:var(--t-tight)}
.f-note{grid-column:1/-1;font-size:var(--t-tight);padding:var(--s0) var(--s2) var(--s0);border-left:3px solid rgba(46,158,91,.45);background:rgba(46,158,91,.05);border-radius:6px;margin-top:var(--s0)}
.f-ck{display:flex;align-items:center}
.f-ck input{width:1.05rem;height:1.05rem;accent-color:var(--navy,#1A2D5A)}
/* per-view column plans (desktop) */
/* route grid (VS 2026-08-01): fixed DUE + action tracks so every row lines up whether or not
   the account has a phone — an `auto` action column collapsed and shifted DUE out of column */
.ft-route .frow,.ft-route .fhead{grid-template-columns:minmax(132px,1.6fr) minmax(98px,0.98fr) minmax(110px,1.10fr) 14px minmax(72px,0.72fr) minmax(132px,1.32fr)}
.ft-route .f-meta{text-align:right}
.ft-route .f-act{justify-content:flex-end}
.ft-week .frow,.ft-week .fhead{grid-template-columns:minmax(64px,0.64fr) minmax(170px,1.7fr) minmax(104px,1.04fr) minmax(118px,1.18fr) 16px 1fr}
/* manager variants (2026-07-31): +Executive column on Week/Accounts so he sees who follows what.
   Tracks are budgeted to fit the 760px wrap (bleed fix: the first cut's mins totalled ~820px and
   poked out of the card); .ftable overflow-x is the safety net at any zoom — scroll, never bleed. */
.ft-week.mgr .frow,.ft-week.mgr .fhead{grid-template-columns:minmax(64px,0.64fr) minmax(150px,1.7fr) minmax(96px,0.96fr) minmax(104px,1.04fr) 16px minmax(96px,0.96fr) auto;gap:var(--s2) var(--s3)}
.ft-book.mgr .frow,.ft-book.mgr .fhead{grid-template-columns:auto minmax(150px,1.6fr) minmax(96px,0.96fr) minmax(104px,1.04fr) 16px minmax(96px,0.96fr) minmax(140px,1.3fr);gap:var(--s2) var(--s3)}
.fchip.rep{background:rgba(26,45,90,.08);color:inherit;max-width:96px;overflow:hidden}
.fhead a{color:inherit;text-decoration:none;cursor:pointer}
.fhead a:hover{color:var(--orange);opacity:1}
.ft-book .frow{grid-template-columns:auto minmax(170px,1.6fr) minmax(104px,1.04fr) minmax(118px,1.18fr) 16px minmax(210px,1.3fr)}
.ft-log .frow{grid-template-columns:minmax(90px,110px) minmax(150px,1.3fr) minmax(104px,1.04fr) minmax(150px,auto) auto 1fr}
.ft-team .frow{grid-template-columns:minmax(140px,1fr) repeat(5,auto) minmax(90px,auto)}
.ft-ord .frow{grid-template-columns:minmax(160px,1.4fr) minmax(130px,1.30fr) minmax(100px,1.00fr) minmax(96px,0.96fr) 1fr}
/* column header strip */
.fhead{color:var(--muted);display:grid;gap:var(--s2) var(--s4);padding:var(--s0) var(--s3) var(--s2);font-size:var(--t-mini);font-weight:700;letter-spacing:.04em;text-transform:uppercase}
.ft-book .fhead{grid-template-columns:auto minmax(170px,1.6fr) minmax(104px,1.04fr) minmax(118px,1.18fr) 16px minmax(210px,1.3fr)}
/* mobile: columns collapse to a wrapped two-line card */
@media (max-width:760px){
  .ftable .frow,.ftable .fhead{display:flex;flex-wrap:wrap;align-items:center}
  .fhead{display:none}
  .f-main{flex:1 1 200px}
  .f-meta{width:100%;text-align:left;margin-top:var(--s0)}
}

/* ---- MANAGER DASHBOARD (VS 2026-07-31): KPI tiles, CSS trend bars, pipeline bars ---- */
.kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:var(--s3);margin:var(--s2) 0 var(--s4)}
.kpi{background:var(--card,#fff);border:1px solid #E2DED7;border-radius:12px;padding:var(--s3) var(--s2);text-align:center}
.kpi b{display:block;font-size:var(--t-title);line-height:1.2}
.kpi span{color:var(--muted);font-size:var(--t-mini);text-transform:uppercase;letter-spacing:.03em}
.kpi-bad b{color:var(--bad-ink)}.kpi-good b{color:var(--ok-ink)}
/* period-over-period delta chip on each KPI tile (VS 2026-08-01) */
.kd{display:block;font-style:normal;font-size:var(--t-mini);font-weight:700;margin-top:var(--s0);letter-spacing:.01em}
.kd-up{color:var(--ok-ink)}.kd-down{color:var(--bad-ink)}.kd-flat{color:var(--muted);font-weight:400}
.mgr-2col{display:grid;grid-template-columns:1fr 1fr;gap:var(--s4);margin:var(--s2) 0}
@media (max-width:820px){ .mgr-2col{grid-template-columns:1fr} }
.trend{display:flex;align-items:flex-end;gap:var(--s1);height:96px}
.trend-col{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:var(--s0);min-width:0}
.trend-bar{width:100%;max-width:26px;background:rgba(26,45,90,.35);border-radius:4px 4px 0 0}
.trend-bar.trend-today{background:var(--navy,#1A2D5A)}
/* week-ahead states: an empty day is the actionable one, a full day is capacity reached */
.trend-bar.ta-empty{background:rgba(214,69,69,.3)}
.trend-bar.ta-full{background:#2e9e5b}
/* Sunday = rest day, never an unfilled gap: a flat neutral rule, no red, label reads "off" */
.trend-bar.ta-rest{background:#CFC9C0}
.trend-d.td-rest{color:var(--muted);font-style:italic}
.trend-n{color:var(--muted);font-size:var(--t-mini)}
.trend-d{color:var(--muted);font-size:var(--t-micro)}
/* leaderboard: fixed equal metric columns, centered header AND value, tabular numerals —
   auto-width chip columns made the row read ragged/unjustified (VS 2026-07-31) */
.lb{grid-template-columns:minmax(170px,1fr) repeat(7,minmax(66px,88px)) !important;justify-items:center}
.lb .f-main{justify-self:start}
.fhead.lb span{text-align:center;width:100%}
.lb-v{font-weight:700;font-variant-numeric:tabular-nums;font-size:var(--t-body)}
.lb-bad{color:var(--bad-ink)}.lb-good{color:var(--ok-ink)}
@media (max-width:760px){ .lb{justify-items:start} .lb .lb-v::before{content:attr(data-l);font-weight:400;color:var(--muted);margin-right:var(--s1)} }
.pipe-row{display:flex;align-items:center;gap:var(--s3);margin:var(--s1) 0}
.pipe-bar{flex:1;height:10px;background:#EFEBE4;border-radius:5px;overflow:hidden}
.pipe-fill{height:100%;background:rgba(26,45,90,.55);border-radius:5px}
.mgr-line{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap;padding:var(--s1) 0;font-size:var(--t-ui);border-bottom:1px solid #F1EDE6}
.mgr-line:last-child{border-bottom:0}

/* live visit-selfie camera (VS 2026-07-31): mirrored preview, captured shot stays true */
.selfie-cam{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap}
.selfie-cam video{max-width:min(260px,70vw);border-radius:12px;transform:scaleX(-1)}
.selfie-cam img{max-width:min(200px,55vw);border-radius:12px;border:2px solid #2e9e5b}
@media (max-width:640px){ .camp-grid,.camp-sticky{grid-template-columns:1fr} }

/* ---- SEARCH database rows (VS 2026-07-29 "value-packed"): line 3 = what they WANT ---- */
.lead-ctx{display:flex;gap:var(--s4);flex-wrap:wrap;font-size:var(--t-tight);margin-top:var(--s0)}
.lead-ctx .ctx-goal{font-weight:600}
/* card v2 (VS 2026-07-30): state chip (due beats handled) + her latest note, verbatim */
.chip-state{font-weight:700}
.chip-state-red{background:rgba(214,69,69,.12);border-color:rgba(214,69,69,.55);color:#d64545}
.chip-state-amber{background:rgba(227,160,8,.12);border-color:rgba(227,160,8,.55)}
.chip-state-ok{background:rgba(46,158,91,.12);border-color:rgba(46,158,91,.5)}
.lead-note{font-size:var(--t-tight);margin-top:var(--s0);padding:var(--s1) var(--s3);border-left:3px solid rgba(46,158,91,.5);background:rgba(46,158,91,.06);border-radius:6px}
/* lead-page v2 (VS 2026-07-30): secondary sections collapse to one-line cards */
details.card>summary{cursor:pointer;font-size:var(--t-name);padding:var(--s0) 0}
details.card[open]>summary{margin-bottom:var(--s3)}
details.card>summary .muted{font-weight:400}
.cp-more>summary{cursor:pointer;font-weight:700;margin:var(--s2) 0;font-size:var(--t-ui)}
.chip-gc{background:rgba(46,158,91,.14);border-color:rgba(46,158,91,.5)}
.chip-stop{background:rgba(214,69,69,.12);border-color:rgba(214,69,69,.5)}
.nexthuman{font-weight:600}
.belt-next .beltrow{color:var(--muted);display:flex;gap:var(--s3);align-items:center;padding:var(--s3) var(--s1);flex-wrap:wrap}
.belt-next .beltrow .muted{font-size:var(--t-tight)}
.belt-badge-s{font-size:var(--t-mini)}
.belt-snoozed{color:var(--muted);}
.belt-red{color:#d64545}
.belt-amber{color:var(--amber-ink)}
@media (max-width:640px){ .belt-outcomes{max-width:none} }

/* ---- belt lanes (VS 2026-07-29): nav sub-items + on-page lane switcher ---- */
.side-sub{padding-left:2.6rem;font-size:var(--t-tight);font-weight:500}
.side-collapsed .side-sub{display:none}
.belt-lanes{display:flex;gap:var(--s3);flex-wrap:wrap;margin:var(--s2) 0 var(--s4)}
.belt-lanes a{padding:var(--s2) var(--s4);border:1px solid var(--line-input);border-radius:999px;font-size:var(--t-ui);text-decoration:none;color:inherit}
.belt-lanes a b{margin-left:var(--s1)}
.belt-lanes a.lane-on{background:#1A2D5A;color:#fff;border-color:#1A2D5A}

/* NEW-COMMENT FLAG (VS 2026-08-01): the rep must not be able to miss a remark */
.rem-alert{border-left:4px solid var(--orange);background:rgba(231,136,47,.07)}
.rem-alert .btn{margin:var(--s0) var(--s1) var(--s0) 0}
.rem-dot{display:inline-block;background:var(--orange);color:#fff;border-radius:9px;padding:0 var(--s2);
  font-size:var(--t-mini);font-weight:700;vertical-align:middle;margin-left:var(--s1);letter-spacing:.02em}
.rem-new-badge{background:var(--orange);color:#fff;border-radius:10px;padding:var(--s0) var(--s3);font-size:var(--t-mini);
  font-weight:700;text-transform:uppercase;letter-spacing:.03em;vertical-align:middle;margin-left:var(--s2)}
.fchip.rem-new{background:var(--orange);color:#fff;height:18px;font-size:var(--t-micro);font-weight:700;letter-spacing:.04em}
.rem-unread{background:rgba(231,136,47,.07);border-radius:8px;padding-left:var(--s3);padding-right:var(--s3);margin:0 -var(--s3)}

/* rep scorecard (VS 2026-08-01): own rank + his row highlighted on the team board */
.rank-card{display:flex;align-items:center;gap:var(--s4);padding:var(--s4) var(--s5);border-left:4px solid var(--orange)}
.rank-badge{flex:0 0 auto;min-width:52px;height:52px;display:flex;align-items:center;justify-content:center;
  background:var(--navy,#1A2D5A);color:#fff;border-radius:14px;font-size:var(--t-title);font-weight:700}
.frow.lb-me{background:rgba(231,136,47,.09);border-radius:10px}
.frow.lb-me .f-name{font-weight:700}

/* the third route action is a WORD, not an icon: 'Log' cannot be misread next to call/WhatsApp */
.log-btn{font-weight:700;border-color:rgba(26,45,90,.45);color:var(--navy,#1A2D5A);padding:var(--s0) var(--s3)}
.log-btn:hover{background:var(--navy,#1A2D5A);color:#fff}

/* India silhouette used wherever a map is referenced (VS 2026-08-01): the business is
   Dehradun-only, so a world-map glyph was never the right symbol. */
/* India is a tall, narrow silhouette — at 1.05em the north-east arm dropped below a pixel, so the
   glyph gets slightly more room than a line icon would need. */
.ic-in{width:1.2em;height:1.2em;vertical-align:-.22em;margin-right:var(--s0);flex:0 0 auto}

/* LEAD POOL (VS 2026-08-01): Salesforce-style faceted list view over a 5k-row pool */
.lp-bar{padding:var(--s3) var(--s3);display:flex;flex-direction:column;gap:var(--s2);margin-bottom:var(--s3)}
.lp-beat{display:flex;flex-wrap:wrap;gap:var(--s3);align-items:center;padding:var(--s3) var(--s4);margin-bottom:var(--s3);border-left:4px solid var(--orange)}
.lp-beat .muted{font-size:var(--t-tight)}
.lp-beat input[type=date],.lp-beat input[type=text]{padding:var(--s2) var(--s3);border:1px solid var(--line-input);border-radius:8px;font:inherit;background:var(--card,#fff);color:inherit}
.lp-beat .btn{margin-left:auto}

/* FILTER BAR — six picklists in a fixed grid. This replaced six stacked chip rows that each held two
   or three chips and then ran ~70% empty to the right. The content column is only ~760px, so the
   controls are laid on an auto-fit grid rather than a flex row: at full width that resolves to six
   equal columns and TWO tidy lines, and it degrades to more lines on a phone without a single
   control ever escaping the card. A long value ("Collection Centre") clips inside its box — the
   native dropdown still opens full width, and the pills underneath restate what is applied in full. */
.lp-f{display:grid;grid-template-columns:repeat(auto-fit,minmax(116px,1fr));gap:var(--s2);align-items:center;min-width:0}
/* the base form rules (label/input/select/button.primary near the top of this file) hang margins on
   every control for the stacked forms; inside a grid bar those margins become phantom row height */
.lp-f>*{margin:0}
.lp-q{grid-column:span 2;display:flex;align-items:center;gap:var(--s1);min-width:0;height:33px;
  border:1px solid var(--line-input);border-radius:9px;padding:0 var(--s3);background:var(--card,#fff)}
.lp-qi{color:var(--muted);font-size:var(--t-tight);flex:0 0 auto}
.lp-q input[type=search]{flex:1 1 auto;min-width:0;width:100%;border:0;outline:0;background:transparent;
  color:inherit;font:inherit;font-size:var(--t-tight);padding:0}
.lp-sel{min-width:0;width:100%;height:33px;padding:0 var(--s1);border:1px solid var(--line-input);
  border-radius:9px;font:inherit;font-size:var(--t-tight);background:var(--card,#fff);color:inherit;cursor:pointer}
.lp-sel.on{border-color:var(--navy,#1A2D5A);background:rgba(26,45,90,.08);font-weight:700}
.lp-tog{display:flex;align-items:center;justify-content:center;gap:var(--s1);height:33px;min-width:0;
  font-size:var(--t-mini);white-space:nowrap;overflow:hidden;padding:0 var(--s2);
  border:1px solid var(--line-input);border-radius:9px;cursor:pointer}
.lp-tog.on{border-color:var(--navy,#1A2D5A);background:rgba(26,45,90,.08);font-weight:700}
.lp-tog b{color:var(--muted);font-weight:700}
/* the base `input,select,textarea{width:100%}` rule near the top of this file applies to CHECKBOXES
   too, so the tick was demanding the whole cell and shoving the label out of the box. */
.lp-tog input[type=checkbox]{width:auto;min-width:0;flex:0 0 auto;margin:0;padding:0}
/* .lp-f>* above cannot beat `button.primary` (0-1-1), so the button zeroes its own margin here */
.lp-f .btn{margin:0;width:100%;min-height:33px;height:33px;padding:0 var(--s3);font-size:var(--t-tight);border-radius:9px}
/* MOBILE FILTER COLLAPSE (VS 2026-08-14, chosen over bottom-sheet and chip-scroll): the bar
   folded five-plus controls into ~4 rows of a phone before any content. Collapsed it is ONE
   row — search + Search + Filters(n) — and the pickers return behind the Filters button.
   The pills row is NEVER collapsed: pills are the applied state, and state must not hide.
   Desktop keeps the full bar; the button does not exist there. */
.lp-flt{display:none}
/* ==== MOBILE DENSITY PASS (VS 2026-08-14, plan items 2-7; item 1 pending his call) ====
   A phone was paying desktop padding out of a phone-sized budget: ~530px of chrome before
   the first data row. Every rule below exists only under 640px; desktop pixels are
   untouched. Tap targets never drop under 42px — smaller-but-missable is a false economy. */
.bp-tog{display:none}
.d-short{display:none}
@media (max-width:640px){
  /* 2 · title block: tighter margins, mini date, one thin stats line */
  h1{font-size:19px;margin:var(--s1) 0 var(--s2)}
  .h-sub{font-size:var(--t-mini)}
  .day-sub{font-size:var(--t-mini);margin:0 0 var(--s2)}
  .d-full{display:none}
  .d-short{display:inline}
  /* 3 · nav strip: economical chips, still thumb-sized */
  /* 42px is the floor, not a target: a chip small enough to miss costs a tap, and a missed
     tap costs more than the pixels it saved. The saving comes from padding and gaps. */
  .belt-lanes{gap:var(--s1);margin:var(--s1) 0 var(--s3)}
  .belt-lanes a{padding:var(--s1) var(--s3);font-size:var(--t-tight);min-height:42px;display:inline-flex;align-items:center;gap:.3rem}
  /* 4 · controls: ~44px ceiling instead of the ~54px desktop floor */
  input,select,textarea{padding:var(--s2) var(--s3);font-size:var(--t-body);min-height:42px}
  .btn.primary{min-height:44px}
  .card{padding:var(--s3);border-radius:12px;margin-bottom:var(--s3)}
  /* 5 · lens banner (owner-only surface): one line + the exit, the lecture hides */
  .lens-banner{padding:var(--s2) var(--s3)}
  .lens-x{display:none}
  .lens-banner button{min-height:36px}
  /* 6 · beat planner: collapsed to one disclosure row until someone is actually planning */
  .bp-tog{display:flex;align-items:center;justify-content:center;gap:var(--s1);width:100%;min-height:40px;white-space:nowrap}
  .bp-tog b{background:var(--navy,#1A2D5A);color:#fff;border-radius:9px;padding:0 var(--s2)}
  /* !important is load-bearing here: both planner cards carry an inline display:flex, and an
     inline style beats any stylesheet selector. The alternative is unpicking the inline
     layout on two views for a rule that only exists under 640px. */
  body:not(.bp-open) .bp-card{display:none !important}
  body.bp-open .bp-tog{border-color:var(--navy,#1A2D5A);font-weight:700}
  /* the filter bar's own controls are 33px by desktop design — under a thumb that is a miss,
     so they take the same 42px floor as everything else here */
  .lp-f .btn,.lp-sel,.lp-tog,.lp-q{min-height:42px;height:auto}
  /* THE ROW ACTIONS ARE THE JOB (found by measurement 2026-08-14, pre-existing): call and
     WhatsApp sat at 30px inside every lead and account row — the two controls a field rep
     touches most, and the two smallest on the page. 40px each costs ~10px per row and buys
     back every mis-tap. Deliberately 40, not 42: the row is a list item, not a nav chip. */
  .frow .btn,.frow .tel-btn{min-height:40px;min-width:40px}
  /* 7 · breathing room comes from the content, not the frame */
  .wrap{padding-left:var(--s3);padding-right:var(--s3)}
}
@media (max-width:640px){
  .lp-flt{display:flex;align-items:center;justify-content:center;gap:var(--s1);white-space:nowrap}
  .lp-flt b{background:var(--navy,#1A2D5A);color:#fff;border-radius:9px;padding:0 var(--s2);line-height:1.5}
  .lp-f{grid-template-columns:1fr auto auto}
  .lp-q{grid-column:1}
  .lp-bar:not(.lp-open) .lp-sel,.lp-bar:not(.lp-open) .lp-tog{display:none}
  .lp-bar.lp-open .lp-f{grid-template-columns:repeat(auto-fit,minmax(116px,1fr))}
  .lp-bar.lp-open .lp-q{grid-column:span 2}
  .lp-bar.lp-open .lp-flt{border-color:var(--navy,#1A2D5A);font-weight:700}
}
/* applied filters restated as removable pills — nothing narrows the list invisibly */
.lp-pills{display:flex;flex-wrap:wrap;gap:var(--s1);align-items:center;min-width:0}
.lp-pill{display:inline-flex;align-items:center;gap:var(--s1);max-width:100%;height:21px;padding:0 var(--s1) 0 var(--s3);
  border-radius:11px;background:var(--navy,#1A2D5A);color:#fff;font-size:var(--t-mini);font-weight:700;text-decoration:none;overflow:hidden}
.lp-pill i{color:var(--muted);font-style:normal;font-weight:600}
.lp-pill s{color:var(--muted);text-decoration:none;font-weight:700;padding:0 var(--s1);flex:0 0 auto}
.lp-pill:hover s{opacity:1}
.lp-clear{font-size:var(--t-mini);font-weight:700;text-decoration:underline;color:var(--muted);margin-left:var(--s0)}
/* budgeted to FIT the wrap — VS: never scroll sideways. Rep view drops the Territory column
   (he only ever sees his own market) and gives that width back to the name. */
.ft-pool .frow,.ft-pool .fhead{grid-template-columns:auto minmax(120px,1.5fr) minmax(100px,1.00fr) minmax(86px,0.86fr) minmax(64px,.9fr) minmax(92px,0.92fr) minmax(78px,0.78fr);gap:var(--s1) var(--s3)}
.ft-pool-rep .frow,.ft-pool-rep .fhead{grid-template-columns:auto minmax(150px,1.8fr) minmax(104px,1.04fr) minmax(80px,1fr) minmax(96px,0.96fr) minmax(78px,0.78fr);gap:var(--s1) var(--s3)}
.ft-pool .fchip{font-size:var(--t-mini);padding:0 var(--s3);max-width:100%;overflow:hidden}
.ft-pool .f-act{gap:var(--s1)}
.ft-pool .f-act .btn{padding:var(--s0) var(--s2);min-width:30px}
.nophone{color:var(--muted);font-size:var(--t-mini);white-space:nowrap}
/* the number itself on hover, so it can be read or dictated without opening the record */
.tel-btn{position:relative}
.tel-btn::after{content:attr(data-tel);position:absolute;bottom:calc(100% + 6px);right:0;
  background:var(--navy,#1A2D5A);color:#fff;padding:var(--s1) var(--s3);border-radius:7px;font-size:var(--t-mini);
  font-weight:700;white-space:nowrap;opacity:0;pointer-events:none;z-index:20;
  box-shadow:0 2px 10px rgba(26,45,90,.25)}
.tel-btn:hover::after,.tel-btn:focus::after{opacity:1}
/* the lead name is the way into the full record — make it read as a link without shouting */
.lp-open{color:inherit;text-decoration:none;cursor:pointer}
.lp-open:hover,.lp-open:focus{text-decoration:underline;color:var(--navy,#1A2D5A)}
/* LEAD 360 */
.ld-grid,.ld-form{display:grid;grid-template-columns:minmax(96px,140px) minmax(0,1fr);gap:var(--s1) var(--s4);padding:var(--s4) var(--s4);align-items:center}
.ld-k{color:var(--muted);font-size:var(--t-mini);font-weight:700;text-transform:uppercase;letter-spacing:.04em;margin:0;display:block}
.ld-v{min-width:0;overflow-wrap:anywhere;font-size:var(--t-body)}
/* the edit form reuses the label/value grid so the record reads the same whether you are
   looking at it or fixing it */
.ld-form>.ld-in,.ld-form>.ld-pair{margin:0;min-width:0;width:100%}
.ld-in{padding:var(--s2) var(--s3);border:1px solid var(--line-input);border-radius:9px;font:inherit;
  font-size:var(--t-body);background:var(--card,#fff);color:inherit;width:100%;margin:0}
textarea.ld-in{resize:vertical;line-height:1.35}
.ld-pair{display:flex;flex-direction:column;gap:var(--s0);min-width:0}
.ld-side{font-size:var(--t-mini);color:var(--muted)}
.ld-save{grid-column:1/-1;margin-top:var(--s2);display:flex;gap:var(--s3);flex-wrap:wrap}
.ld-save .btn{flex:1 1 140px;margin:0}
@media (min-width:560px){ .ld-save .btn{flex:0 0 auto;min-width:170px} }
/* Edit is a deliberate click, so it sits on the section heading rather than inside the record */
.ld-edit{float:right;min-height:30px;padding:var(--s1) var(--s4);font-size:var(--t-tight);font-weight:700;margin:0}
.lp-comp-head{border-left:4px solid #d64545}
.lp-warn{margin:var(--s2) 0;padding:var(--s2) var(--s3);border-radius:8px;background:rgba(214,69,69,.1);
  color:#a02a2a;font-size:var(--t-tight);font-weight:600}
.frow.lp-comp{background:rgba(214,69,69,.055)}
.frow.lp-comp .f-name::before{content:"🎯 ";}
.lp-pager{display:flex;gap:var(--s3);align-items:center;margin:var(--s3) 0}

/* map legend + lead/competitor markers */
.map-legend{display:flex;flex-wrap:wrap;gap:var(--s4);align-items:center;font-size:var(--t-tight);margin:var(--s3) 0 0}
.mk{display:inline-block;width:11px;height:11px;border-radius:50%;margin-right:var(--s1);vertical-align:-1px}
.mk-due{background:#d64545}.mk-partner{background:#2e9e5b}.mk-acc{background:#1A2D5A}
.mk-lead{background:#aab4c4;border:1px solid #7a8699}
.mk-comp{background:#d64545;border:3px solid #b02020;width:13px;height:13px}

/* ===========================================================================================
   TERMINAL POLISH (VS 2026-08-01) — the layer that turns a working CRM into a branded product.
   Everything above is layout that already earns its keep; this is finish: the navy rail, the
   instrument-panel table headers, real focus states, and the one media-query fix the collapsed
   logo needs.
   =========================================================================================== */

/* The rail is the most navy-dominant surface in the app, which is the brand's intent (navy is
   60-65% colour PRESENCE). Navy -> Dark Navy vertical is the ONE gradient the brand allows. */
.sidebar{background:linear-gradient(180deg,var(--navy) 0%,var(--navy-d) 100%);box-shadow:2px 0 14px rgba(26,45,90,.16)}
.side-top{padding:18px 14px 14px;border-bottom:1px solid rgba(255,255,255,.07)}
.side-top .brand{font-size:inherit;letter-spacing:0}
.side-nav{padding-top:10px}
/* MOBILE DRAWER: below 820px the rail is a 250px drawer and keeps its full width even when the
   .side-collapsed class is set (the desktop preference persists in localStorage). The existing
   media query already re-shows .side-label for exactly this reason — the logo needs the same
   treatment or a collapsed-on-desktop user opens the phone drawer to a bare constellation icon. */
@media(max-width:820px){
  /* the drawer is 250px wide even when the desktop collapse preference is set, so EVERY collapsed
     rule has to be undone here — including the stacked side-top, or the logo centres itself and
     the two drawer states look like different products */
  .side-collapsed .side-top{flex-direction:row;align-items:flex-start;justify-content:space-between;
    gap:var(--s3);padding:var(--s5) var(--s4) var(--s4)}
  .side-collapsed .brand{margin-left:-16.3px;align-items:flex-start;width:auto}
  .side-collapsed .brand .mark-full{display:block}
  .side-collapsed .brand .mark-icon{display:none}
}

/* Column headers as the brand's `overline` token: Space Grotesk 700, +0.12em, small. This is what
   makes a data table read as an instrument rather than a spreadsheet. */
.fhead,.cov-stat span,.kpi span,.recover-k,.hero-tag,.cp-h{font-family:var(--f-data);letter-spacing:.1em}
.fhead{color:var(--muted);font-size:var(--t-mini)}

/* Cards: brand radii on the warm canvas, with the brand's own small shadow so white cards lift
   off warm white instead of relying on the border alone.
   ERP cards take Flabs' 8px corner (VS 2026-08-22, density pass); the CRM/mobile surfaces keep
   the softer 12px they were designed with -- they are ours, not a clone of anything. */
.card,.adherence{border-radius:12px;border-color:var(--line);box-shadow:var(--sh-s)}
.lp-page .card,.derp .card{border-radius:8px}
.tile,.kpi,.lead,.convrow,.task,.callrow,.kcard,.loop-step{border-color:var(--line)}
a.tile:hover{box-shadow:var(--sh-m);border-color:#cfc9c0}
.empty{border-color:var(--line)}

/* Buttons: navy is the committing action, orange stays the single call-to-action accent (the brand
   caps orange at ~2 spots per view, which is why .callbtn/.callmini keep it and .btn does not). */
.btn{font-family:var(--f-body);font-weight:500;border-color:var(--line-input)}
.btn:hover{border-color:var(--navy);box-shadow:var(--sh-s)}
.btn.primary:hover{background:var(--navy-d);border-color:var(--navy-d)}
button.primary{font-family:var(--f-body);font-weight:700;letter-spacing:.01em}

/* Real focus states. The app had none — a keyboard user could not tell where they were, which is
   both an accessibility failure and the fastest way to make a product feel unfinished. */
:focus-visible{outline:2px solid var(--orange);outline-offset:2px;border-radius:6px}
.side-link:focus-visible{outline-offset:-2px}
input:focus,select:focus,textarea:focus,.ld-in:focus,.lp-sel:focus{outline:none;border-color:var(--navy);
  box-shadow:0 0 0 3px rgba(26,45,90,.12)}
.lp-q:focus-within{border-color:var(--navy);box-shadow:0 0 0 3px rgba(26,45,90,.12)}

/* Selection + scrollbars in brand colour rather than OS blue/grey. */
::selection{background:rgba(231,136,47,.26)}
.side-nav::-webkit-scrollbar{width:6px}
.side-nav::-webkit-scrollbar-thumb{background:rgba(255,255,255,.16);border-radius:3px}
.side-nav::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.28)}

/* Chips inherit the body face and stop shouting: 600 on a 22px pill reads cleaner than 700. */
.fchip,.chip{font-family:var(--f-body);font-weight:600}
.fchip.t{background:rgba(26,45,90,.09);color:var(--navy)}
.chip{background:rgba(26,45,90,.07);color:var(--navy)}

/* MIRA surfaces are the only place teal is allowed to lead. */
.mira-tag{background:var(--teal)}
.mira,.mira-panel.heat-warm{border-left-color:var(--teal)}

/* Table rows: the hover tint keys off navy, and rows get a hair more air than the 44px minimum so
   a 9,000-row pool does not read as a wall. */
.frow:hover{background:rgba(26,45,90,.04)}

/* LEGIBILITY — reverting two mistakes I made in this same block (VS 2026-08-02: "too thin to read").
   1. I had put record NAMES on the display face. Outfit is a geometric DISPLAY type: wide apertures,
      even thin strokes, drawn to be read once at 40px. At 15-16px in a dense list it renders visibly
      lighter than Instrument Sans at the SAME numeric weight, and a screenful of names turned into
      grey haze. The brand's own type scale never asked for this — Outfit is h1-h3 and hero; UI text
      is Instrument Sans. Names go back to the body face.
   2. I had ALSO dropped .f-name from 700 to 600 to stop chips shouting. Wrong lever: it quietened
      the one thing in the row you actually scan for.
   Names are the primary scan target on every list in this app, so they get the body face at 700 and
   full navy — the strongest legible treatment the palette allows, rather than default ink. */
.f-name,.lead .name,.cr-name,.bk-name,.task-name,.op-name,.o-name,.tx-label,.c-name,.kname,
.bk-name,.f-name a,a.f-name{font-family:var(--f-body);font-weight:700;letter-spacing:0;color:var(--navy)}
a.f-name,.lp-open{color:var(--navy)}
/* the row subtitle stays lighter than the name, but never lighter than AA (see the contrast block) */
.f-sub,.lead-sub{font-weight:500}

/* The login page is the first thing anyone sees; give it the warm canvas and a lifted card. */

/* CONTRAST: small labels across this app were dimmed with `opacity` (.5-.8). Composited over the
   warm canvas that lands at 3.3-4.1:1 — under the AA 4.5:1 the brand sets as a hard rule, and it is
   exactly the text (column headers, units, subtitles) a user most needs when scanning fast. Opacity
   is also unpredictable: the same rule reads differently on a white card and a tinted row. Replaced
   with the brand's Grey Dark at full opacity, which measures 5.1:1 and renders identically anywhere. */
.fhead,.ld-k,.kpi span,.cov-stat span,.trend-d,.trend-n,.f-sub,.f-meta,.cl-meta,.rem-when,
.fld-hint,.lead-ctx,.feed-note,.mgr-note,.lp-clear,.seg-sub,.belt-summary,.o-rem,.ksub,
.kmore,.suggest-note,.tx-meta,.ask-note,.secnote,.more{opacity:1;color:var(--muted)}
/* the two that sit ON a dark rail keep their own light-on-navy colours — never let the rule above
   reach them */
.side-foot .whoami,.nav-h{color:inherit}

/* Record NAMES are never decorative type. The belt card sets a state colour on the whole card
   (.belt-red -> #d64545 inherits into everything inside it), which on the thin display face left
   the lead's name washed-out rust and hard to read at a glance — the exact complaint. The card's
   state is already carried by its left border and its badge, so the name takes it back: body face,
   700, full navy. Same treatment as every other name in the app. */
.belt-name,.belt-name a{font-family:var(--f-body);font-weight:700;letter-spacing:0;color:var(--navy);
  font-size:var(--t-name);line-height:1.25}
.belt-name .muted{color:var(--muted);font-weight:600}
/* Any heading that is NOT the Space Grotesk section label keeps a real drawn weight — an h2/h3 that
   inherits 400 would resolve to Outfit 500 and read as light grey haze at UI sizes. */
h2:not(.sec),h3{font-weight:600}

/* ===========================================================================================
   BRAND PASS v2 (VS 2026-08-02) — "make it more LabONE."
   The audit found the un-brand was not missing orange; it was 32 cool greys, three illegal
   gradients and a starved teal. The sweep above fixed the hardware. This block assigns the
   palette its ROLES, which is what the frozen system actually specifies:
     navy   = structure and emphasis (60-65% presence: text, headers, borders — never page fill)
     teal   = the machine being intelligent (MIRA, live indicators, every data visualisation)
     orange = the one thing to press (CTAs, active nav, and ONE 2px accent line per screen)
     warm   = everything that used to be generic grey
   =========================================================================================== */

/* DATA IS TEAL. The brand sanctions teal for data visualisation explicitly; every neutral data
   fill moves from navy-alpha to teal. Semantic states (good/bad/empty/full/rest) keep their
   colours; "today" keeps full navy as the emphasis mark against the teal series. */
.trend-bar{background:var(--teal-bar)}
.trend-bar.trend-today{background:var(--navy)}
.cov-fill{background:var(--teal)}
.pipe-fill{background:var(--teal-bar)}
.revbar-fill{background:var(--teal)}
.fr-bar{background:var(--teal);opacity:.16}
.fr-bar.stage-member{background:#2e9e5b;opacity:.22}

/* STRUCTURE IS NAVY. Column headers were muted grey — the brand wants navy presence exactly
   here, and full navy is also the more legible choice (12.4:1 vs 5.5:1). */
.fhead{color:var(--navy);opacity:1;border-bottom:2px solid rgba(26,45,90,.14);padding-bottom:var(--s2)}
.fhead a:hover{color:var(--orange)}

/* Section labels: navy, with a short tick that inherits the section's own semantic colour
   (h2.sec.red stays red, .money orange, .hot teal) — information, not decoration. */
h2.sec{color:var(--navy);display:flex;align-items:center;gap:var(--s3)}
h2.sec::before{content:"";flex:0 0 auto;width:3px;height:.85em;border-radius:2px;background:currentColor;opacity:.85}

/* THE one orange accent line the brand allows per composition: page titles only. Card-level
   h1s (lead names) are excluded by the child combinator, so it appears once per screen. */
.wrap>h1{position:relative;padding-bottom:var(--s3)}
.wrap>h1::after{content:"";position:absolute;left:0;bottom:0;width:34px;height:2px;border-radius:1px;background:var(--orange)}

/* Rail group headers join the overline system (Space Grotesk, like every label in the app). */
.nav-h{font-family:var(--f-data);letter-spacing:.14em}

/* Sign-in: 3px navy emphasis (the brand's emphasis line-weight) on the one card guests see. */

/* Interactive states the product register demands: disabled + loading were missing. */
.btn:disabled,button.primary:disabled,.btn[aria-disabled=true]{opacity:.45;cursor:not-allowed;transform:none}
input:disabled,select:disabled,textarea:disabled{background:#F4F1EC;color:var(--muted);cursor:not-allowed}

/* Chips: the default (typeless) chip joins the navy family instead of grey. Semantic chips
   (s-*, heat-*) keep their own colours and now sit visibly distinct from the neutral ones. */
.s-new{background:#EEEAE3;color:var(--muted)}
.s-dormant{background:#EEEAE3;color:var(--muted)}

/* MIRA surfaces read slightly more teal — the tint the brand gives the intelligence layer. */
.mira{background:#EDF6F5}
.mira-panel.heat-warm{background:#EDF6F5}
.chip.mode.bot{background:var(--teal-soft);color:#0A6E6E}
.stat-replied{background:var(--teal-soft);color:#0A6E6E}

/* Kanban "tested" stage is a data state -> teal tint; the rest keep their semantics. */
.kcol.stage-tested{background:#E9F3F2}

/* CONTACT TRUTH CHIPS (VS 2026-08-02) — "Contacted" must mean a human called.
   Navy = human effort (the brand's structural colour, and the state that deserves weight).
   Teal = the machine, per the palette's own rule that teal is MIRA and intelligence only.
   The two are unmistakable at a glance, which is the point: the owner can scan a column and see
   who has actually been worked versus who has only been automated at. */
.chip-human{background:var(--navy);color:#fff;font-weight:700}
.chip-mira{background:var(--teal-soft);color:#0A6E6E;font-weight:600}
.chip-new{background:#EEEAE3;color:var(--muted);font-weight:600}
.chip-won{background:rgba(46,158,91,.16);color:var(--ok-ink);font-weight:700}

/* ===========================================================================================
   ACCENT DOCTRINE (VS 2026-08-02, chosen from mocked variants): A3 "Signal-first" on the work
   surfaces + A2 "Inkline" discipline everywhere else.
   The operating rule: COLOUR IS A CLAIM ON ATTENTION. Only two things may make that claim on a
   working screen — a due/overdue record, and the primary CTA. Everything else holds its ink.
   =========================================================================================== */

/* ---- A2 INKLINE, global ---- */
/* Sections close with a navy rule under the label+tick, so every block reads set, not floated. */
h2.sec{border-bottom:2px solid rgba(26,45,90,.12);padding-bottom:var(--s2)}
/* Numerals step up a point — the data is the product. */
.kpi b{font-size:var(--t-title)}
.tile b{font-size:var(--fig-m)}
.fr-kpi b{font-size:var(--t-title)}

/* ---- A3 SIGNAL-FIRST: the due wash ----
   Due/overdue records stop using the left accent stripe and take a full warm wash + ring:
   visible from across the room, unmissable in a scroll, and it reads on the ROW not the edge.
   Two temperatures, matching the existing semantics: overdue = red-leaning, due today = amber. */
.callrow.k-overdueTimed,.callrow.k-overdueDay{border:1.5px solid #EAC0B0;border-left:1.5px solid #EAC0B0;background:#FDF2EC}
.callrow.k-dueToday{border:1.5px solid #F0D9A8;border-left:1.5px solid #F0D9A8;background:#FDF7EA}
.task.t-overdue{border:1.5px solid #EAC0B0;border-left:1.5px solid #EAC0B0;background:#FDF2EC}
.task.t-today{border:1.5px solid #F0D9A8;border-left:1.5px solid #F0D9A8;background:#FDF7EA}
.belt-card.belt-red{border:1.5px solid #EAC0B0;border-left:1.5px solid #EAC0B0;background:#FDF2EC}
.belt-card.belt-amber{border:1.5px solid #F0D9A8;border-left:1.5px solid #F0D9A8;background:#FDF7EA}
.lead.coll.soon{border:1.5px solid #F0D9A8;border-left:1.5px solid #F0D9A8;background:#FDF7EA}

/* The due time itself carries a dot + semantic ink, so the WHEN is scannable inside the wash. */
.cr-kind.red::before,.cr-kind.warm::before{content:"\25CF\00a0";font-size:8px;vertical-align:2px}
.nexthuman{color:var(--amber-ink);font-weight:700}

/* Neutrals recede: the machine's chips must not compete with the CTA for the eye. The MIRA-warm
   status chip was ORANGE-tinted — the one hue reserved for action — so it goes quiet warm grey.
   (The teal "MIRA only" contact chip keeps its teal: that is the machine's own semantic colour.) */
.stat-mira_warm{background:#F1EDE6;color:var(--muted)}

/* The CTA is the loudest object on a work row — nothing else on the row may be solid orange. */
.callmini{box-shadow:0 1px 4px rgba(231,136,47,.3)}
/* The overdue LABEL ink on the wash: the old --red measured 3.98:1 there — under AA for an 11px
   label. The AA red token reads 5.7:1 on the wash and stays unmistakably "late". */
.cr-kind.red{color:var(--bad-ink)}
.badge.red{color:var(--bad-ink)}

/* ===========================================================================================
   STRIPE RETIREMENT (VS 2026-08-02): the wash treatment, extended to every remaining left-stripe
   accent. Two intensities, per the accent doctrine:
     ATTENTION washes (warm) — only for states that claim a human: awaiting reply, unpaid, unread
       remark, stalled kanban card. Same family as the due/overdue washes.
     CONTEXT washes (quiet) — panels that ARE a colour's subject: teal for MIRA/automation, green
       for notes/won/on-time, navy for information, warm grey for cold/off. Ring + soft tint, so
       they read as surfaces, not signals.
   The one stripe that stays: .side-link.on::before — that is the active-nav indicator, a standard
   affordance, not a card accent. Timeline entries take DOTS instead of washes; a wash per entry
   would tint half the page.
   ============================================================================================ */

/* -- context: MIRA / automation (teal family: ring #C8E2DF) -- */
.mira{border:1px solid #C8E2DF;border-left:1px solid #C8E2DF;border-radius:8px}
.mira-panel{border:1px solid #C8E2DF;border-left:1px solid #C8E2DF}
.mira-panel.heat-warm{border-color:#C8E2DF}
.mira-panel.heat-hot{border-color:#F0D5AC;background:#FDF4E9}
.mira-panel.heat-cold{border-color:#DDD8D0}
.mira-panel.heat-won{border-color:#CBE2D0}
.mira-panel.heat-none,.mira-panel.heat-new{border-color:#DDD8D0}
.booking .order.ord-req{border:1px solid #C8E2DF;border-left:1px solid #C8E2DF}
.task.t-awaiting{border:1px solid #C8E2DF;border-left:1px solid #C8E2DF;background:#EFF7F5}

/* -- context: positive / notes / on-time (green family: ring #CBE2D0) -- */
.booking .order.ord-done{border:1px solid #CBE2D0;border-left:1px solid #CBE2D0}
.lead.returning{border:1.5px solid #CBE2D0;border-left:1.5px solid #CBE2D0}
.belt-card{border:1.5px solid #CBE2D0;border-left:1.5px solid #CBE2D0}
.f-note{border:1px solid #CBE2D0;border-left:1px solid #CBE2D0;opacity:1;color:var(--ink)}
.lead-note{border:1px solid #CBE2D0;border-left:1px solid #CBE2D0}

/* -- context: informational (navy family: ring #CFD7E4) -- */
.ask-answer{border:1px solid #CFD7E4;border-left:1px solid #CFD7E4}
.guard{border:1px solid #CFD7E4;border-left:1px solid #CFD7E4;background:#F2F4F8}
.pb-btn{border:1px solid #CFD7E4;border-left:1px solid #CFD7E4}
.pb-btn.danger{border-color:#EAC0B0}

/* -- context: neutral / cold / parked (warm grey: ring #DDD8D0) -- */
.callrow{border-left:1px solid var(--line)}
.callrow.k-untimed{border-left-color:var(--line)}
.callrow.soon{border-left:1px solid var(--line)}
.booking .order.ord-off{border:1px solid #DDD8D0;border-left:1px solid #DDD8D0}
.task{border-left:1px solid var(--line)}
.convrow{border-left:1px solid var(--line)}
.convrow.heat-hot,.convrow.heat-warm,.convrow.heat-cold,.convrow.heat-new,.convrow.heat-none,
.convrow.heat-won{border-left-color:var(--line)}   /* heat already speaks through the row's badges */
.belt-quote{border:1px solid #E7E3DC;border-left:1px solid #E7E3DC;border-radius:8px}
.lead.convo{border-left:1px solid var(--line)}

/* -- attention: a human is being asked for (orange family: wash #FDF4E9, ring #F0D5AC) -- */
.convrow.awaiting{border:1.5px solid #F0D5AC;border-left:1.5px solid #F0D5AC;background:#FDF4E9}
.lead.convo.awaiting{border:1.5px solid #F0D5AC;border-left:1.5px solid #F0D5AC;background:#FDF4E9}
.task.t-unpaid{border:1.5px solid #F0D5AC;border-left:1.5px solid #F0D5AC;background:#FDF4E9}
.booking .order.ord-scheduled{border:1.5px solid #F0D5AC;border-left:1.5px solid #F0D5AC;background:#FDF4E9}
.rem-alert{border:1.5px solid #F0D5AC;border-left:1.5px solid #F0D5AC;background:#FDF4E9}
.rank-card{border:1.5px solid #F0D5AC;border-left:1.5px solid #F0D5AC;background:#FDF4E9}
.lp-beat{border:1.5px solid #F0D5AC;border-left:1.5px solid #F0D5AC;background:#FDF4E9}
.t-next{border:1px solid #F0D5AC;border-left:1px solid #F0D5AC;border-radius:8px}
.gold-rule{border:1.5px solid #F0D5AC;border-left:1.5px solid #F0D5AC;background:#FDF4E9}

/* -- danger context (red family: wash #FDF2EC, ring #EAC0B0) -- */
.lp-comp-head{border:1.5px solid #EAC0B0;border-left:1.5px solid #EAC0B0;background:#FDF2EC}
.kcard.age-old{border:1px solid #EAC0B0;border-left:1px solid #EAC0B0;background:#FDF2EC}
.kcard.age-mid{border:1px solid #F0D9A8;border-left:1px solid #F0D9A8;background:#FDF7EA}

/* -- timeline: dots, not stripes. A 6px mark says human/auto without tinting the whole entry. -- */
.timeline li.human,.timeline li.auto{border-left:0;padding-left:var(--s5);position:relative}
.timeline li.human::before,.timeline li.auto::before{content:"";position:absolute;left:1px;top:15px;
  width:6px;height:6px;border-radius:50%}
.timeline li.human::before{background:var(--orange)}
.timeline li.auto::before{background:var(--teal)}

/* ===========================================================================================
   RAIL D — NAVY MAST, PAPER BODY (VS 2026-08-02, chosen from five mocked directions).
   The brand plate stays a navy block (frozen -white logo variant, rule 4 intact); the working
   list beneath goes warm paper at operator density: 12.5px/500, 28px rows, 15px icons, bare
   tabular counts instead of pill badges, dots instead of emoji on sub-items.
   Appended LAST so it wins the cascade over the navy-era rules above at equal specificity.
   AA note: the mock's #8B94A3 counts measured ~3.4:1 on paper — executed at --muted (5.5:1).
   =========================================================================================== */
.sidebar{background:var(--rail);color:#3D4757;box-shadow:none;border-right:1px solid var(--line)}
.side-top{background:linear-gradient(135deg,var(--navy),var(--navy-d));border-bottom:0;margin-bottom:6px}
.side-nav{padding:0 8px}
.side-nav::-webkit-scrollbar-thumb{background:rgba(26,45,90,.18)}
.side-nav::-webkit-scrollbar-thumb:hover{background:rgba(26,45,90,.32)}
.nav-h{font-size:var(--t-micro);letter-spacing:.15em;color:var(--muted);padding:10px 10px 4px}
.side-link{gap:10px;padding:0 10px;min-height:34px;font-size:var(--t-ui);font-weight:500;color:#3D4757;margin:0;border-radius:8px}
.side-link .ic{width:16px;height:16px;color:#7A8494}
.side-link:hover{background:rgba(26,45,90,.05);color:var(--navy)}
.side-link:hover .ic{color:var(--navy)}
.side-link.on{background:rgba(26,45,90,.08);color:var(--navy);font-weight:600}
.side-link.on .ic{color:var(--navy)}
.side-link.on::before{top:7px;bottom:7px;width:2px;background:var(--orange)}
/* sub-items: a 4px dot, rendered as a flex child via ::after{order:-1} — ::before is already the
   active-state orange bar, and the two must never collide */
.side-sub{padding-left:22px;font-size:var(--t-tight);font-weight:500;opacity:1;color:#4A5568}
.side-sub::after{content:"";order:-1;flex:0 0 auto;width:4px;height:4px;border-radius:50%;
  background:currentColor;opacity:.45}
/* badges become bare right-aligned tabular counts — 1057 stops being a fat orange pill */
.nav-badge{background:transparent;color:var(--muted);font-size:var(--t-mini);font-weight:500;min-width:0;padding:0}
.side-link.on .nav-badge{color:var(--amber-ink);font-weight:700}
.nav-badge.danger{background:transparent;color:var(--bad-ink);font-weight:700}
/* zero renders as a plain muted 0 (VS 2026-08-03): same voice as every other rail number */
.nav-badge.zero{background:transparent;color:var(--muted);padding:0}
/* collapsed rail: the badge falls back to the little orange presence dot, which the transparent
   restyle above would otherwise erase */
.side-collapsed .nav-badge{background:var(--orange)}
.side-foot{border-top:1px solid var(--line-s);color:var(--muted)}
.side-foot .whoami{color:var(--ink)}
.side-foot .logout button{border:1px solid var(--line-input);color:var(--ink)}
.side-foot .logout button:hover{background:rgba(26,45,90,.06)}
/* the collapse chevron lives on the navy plate and keeps its light colouring */
.side-collapse{color:#8FA1C4}
.side-collapse:hover{background:rgba(255,255,255,.1);color:#fff}

/* ---- ACCORDION GROUPS (direction E, under VS review 2026-08-02) ----
   Group headers become interactive: E's sentence-case 11px/600 ink instead of D's micro overline,
   because a header you can CLICK must look clickable. Chevron rotates when closed; closed groups
   show the sum of their badges so folded work is never silently hidden. In the collapsed 72px rail
   the accordion is ignored — icons always show, chevrons and sums hide. */
button.nav-h{display:flex;align-items:center;gap:6px;width:100%;border:0;background:transparent;
  cursor:pointer;text-align:left;font-family:var(--f-body);font-size:var(--t-tight);font-weight:600;
  letter-spacing:.02em;text-transform:none;color:var(--muted);padding:var(--s2) 10px;margin-top:var(--s1);
  /* the 10px is NOT drift: it is .side-link's own gutter, and a group header indented to
     8px would sit two pixels left of every item it heads. The rail is an excluded carve-out
     (hand-tuned and signed off twice); inside it, alignment wins over the scale. */
  border-radius:8px}
button.nav-h:hover{background:rgba(26,45,90,.05)}
button.nav-h>span:first-child{flex:1}
.ng-sum{font-family:var(--f-data);font-variant-numeric:tabular-nums;font-size:var(--t-mini);font-weight:700;
  color:var(--amber-ink)}
.ng-ch{width:11px;height:11px;flex:0 0 auto;color:var(--muted)}
.ng-closed .ng-ch{transform:rotate(-90deg)}
.ng-closed .side-link{display:none}
/* collapsed rail ignores the accordion entirely — icon nav must stay complete */
.side-collapsed .ng-closed .side-link{display:flex}
.side-collapsed .ng-ch,.side-collapsed .ng-sum{display:none}
.side-collapsed button.nav-h{justify-content:center;padding:6px 0;cursor:default;pointer-events:none}

/* ---- RAIL E FULL (VS 2026-08-02): replaces D's navy mast — the WHOLE rail is paper. The logo
   above switched to its -navy variant in the markup (brand rule 5). The chevron leaves the navy
   plate, so it recolours for the light surface. ---- */
.side-top{background:transparent;border-bottom:1px solid var(--line-s);margin-bottom:6px;padding-bottom:12px}
.side-collapse{color:var(--muted)}
.side-collapse:hover{background:rgba(26,45,90,.07);color:var(--navy)}

/* CHATGPT SURFACE MATCH (VS 2026-08-02, final): the rail's hairlines and hover states go NEUTRAL
   to match its neutral surface — a warm border on a grey rail is the mismatch all over again.
   Brand ink (navy text, orange active bar) stays; only the neutrals change. */
.sidebar{border-right-color:#E6E6E6}
.side-top{border-bottom-color:#ECECEC}
.side-link:hover{background:rgba(0,0,0,.05)}
.side-link.on{background:rgba(0,0,0,.06)}
button.nav-h:hover{background:rgba(0,0,0,.05)}
.side-collapse:hover{background:rgba(0,0,0,.06);color:var(--navy)}
.side-foot{border-top-color:#ECECEC}

/* ===========================================================================================
   B3-B5 (VS 2026-08-02): density, sunlight, identity token, streams, constellation.
   Appended last on purpose — these are system-level and must win over the component rules above.
   =========================================================================================== */

/* ---- B4 · DENSITY ------------------------------------------------------------------------
   One attribute, three consequences. COMFORTABLE is not "compact with bigger text": the rows
   grow, the gutters grow and the two working type steps grow together, because a rep reading a
   phone in the sun and an owner scanning 200 rows on a 27-inch monitor are not the same problem
   with a different font size. Compact is the base (see :root), so a missing attribute renders
   exactly what the owner signed off. */
[data-density="comfortable"]{--row-h:46px;--row-py:var(--s3);--tap:44px;
  --t-tight:13.5px;--t-ui:15px;--t-body:16px}
.frow,.lead,.callrow,.task,.feed-row,.side-link{min-height:var(--row-h)}
.frow,.feed-row{padding-top:var(--row-py);padding-bottom:var(--row-py)}
.lead{padding-top:calc(var(--row-py) + 4px);padding-bottom:calc(var(--row-py) + 4px)}
/* every control a thumb has to hit clears the tap target of the current density */
[data-density="comfortable"] .btn,[data-density="comfortable"] button.primary,
[data-density="comfortable"] .camp-chip,[data-density="comfortable"] .belt-lanes a{min-height:var(--tap)}
[data-density="comfortable"] .btn{display:inline-flex;align-items:center;justify-content:center}

/* ---- B3 · SUNLIGHT ------------------------------------------------------------------------
   Not a dark mode and not a fashion theme. PRODUCT.md's scene is a rep outdoors in Dehradun sun
   and a counter agent under tube-light; glare eats low-contrast ink, hairlines and every shadow.
   So: ink to maximum, secondary text up two steps of contrast, borders darker, shadows off (they
   are invisible outdoors and cost paint), weight up one step, taps to 48px, and every chip gets
   an edge so its shape survives when its fill washes out. The palette does not change — this is
   the same navy on the same paper, turned up. */
[data-vision="bright"]{
  --ink:#0F1B38;--muted:#3D4757;
  --line:#C6BFB4;--line-s:#D8D2C7;--line-input:#8E8578;
  --sh-s:none;--sh-m:none;--sh-l:none;
  --tap:48px}
[data-vision="bright"] body{font-weight:500}
[data-vision="bright"] .card{border-width:1.5px}
[data-vision="bright"] .chip,[data-vision="bright"] .fchip,[data-vision="bright"] .temp,
[data-vision="bright"] .qchip,[data-vision="bright"] .belt-lanes a{border:1px solid currentColor}
[data-vision="bright"] .btn,[data-vision="bright"] button.primary,
[data-vision="bright"] .camp-chip{min-height:var(--tap);border-width:2px}
[data-vision="bright"] .btn{display:inline-flex;align-items:center;justify-content:center}
[data-vision="bright"] .muted,[data-vision="bright"] .h-sub{font-weight:600}
/* the one thing that must never be lost outdoors is which record is overdue */
[data-vision="bright"] .callrow.k-overdue,[data-vision="bright"] .task.t-overdue,
[data-vision="bright"] .belt-card.belt-red{border-width:2px}

/* ---- rail display controls ---------------------------------------------------------------- */
.side-prefs{display:flex;gap:4px;flex:0 0 auto}
.side-foot{gap:8px}
.pref-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;
  border:1px solid var(--line);background:transparent;border-radius:8px;color:var(--muted);
  cursor:pointer;padding:0}
.pref-btn:hover{background:rgba(0,0,0,.05);color:var(--navy)}
.pref-btn[aria-pressed="true"]{background:rgba(26,45,90,.09);border-color:#CFD7E4;color:var(--navy)}
.pref-btn svg{width:16px;height:16px}
.side-collapsed .side-prefs{display:none}
/* at 72px there is no room for a select; the lens tools return with the labels */
.side-collapsed .side-tools{display:none}

/* ---- B5 · IDENTITY TOKEN ------------------------------------------------------------------
   Every list in this app used to start each row with text, so there was no fixed point for the
   eye and scanning meant reading. Space Grotesk because the token is closer to a label than to
   prose, and tabular initials line up down the column. Teal ring = MIRA is holding this
   conversation, which is the same meaning teal carries everywhere else. */
.mono{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:28px;height:28px;border-radius:50%;background:rgba(26,45,90,.08);color:var(--navy);
  font-family:var(--f-data);font-size:var(--t-mini);font-weight:700;line-height:1;
  letter-spacing:.01em;user-select:none}
.mono-mira{background:var(--teal-soft);color:#0A6E6E;box-shadow:inset 0 0 0 1.5px rgba(13,143,143,.4)}
.mono-won{background:rgba(35,122,72,.12);color:var(--ok-ink)}
/* Lead Pool holds facilities, not people, so its token reports the RELATIONSHIP instead of who
   last touched the record — the one fact worth knowing before the name is read. Same inks as the
   status chips beside them (s-declined / s-partner / s-visited), so the row agrees with itself. */
.mono-rival{background:rgba(214,69,69,.13);color:var(--bad-ink)}
.mono-cust{background:var(--navy);color:#fff}
.mono-lg{width:38px;height:38px;font-size:var(--t-tight)}
.mono-sm{width:22px;height:22px;font-size:var(--t-micro)}
[data-density="comfortable"] .mono{width:32px;height:32px}
[data-density="comfortable"] .mono-lg{width:42px;height:42px}
/* in sunlight every variant goes solid — a tint is the first thing glare erases, and the token
   would otherwise flatten to one navy circle and lose everything it was reporting */
/* the UNMARKED token stays outlined rather than going solid navy: filling it would make an
   untouched prospect identical to a customer in the one mode where the tints are gone */
[data-vision="bright"] .mono{background:#fff;color:var(--navy);box-shadow:inset 0 0 0 2px var(--navy)}
/* each marked variant must restate box-shadow:none — the outlined base rule above is [attr].class
   and out-specifies a bare .mono-x, so without this a green token would wear a navy ring */
[data-vision="bright"] .mono-mira{background:#0A6E6E;color:#fff;box-shadow:none}
[data-vision="bright"] .mono-won{background:var(--ok-ink);color:#fff;box-shadow:none}
[data-vision="bright"] .mono-rival{background:var(--bad-ink);color:#fff;box-shadow:none}
[data-vision="bright"] .mono-cust{background:var(--navy);color:#fff;box-shadow:none}

/* ---- B1 · CONSTELLATION -------------------------------------------------------------------
   The mark is five dots, and brand law allows the motif only where it MEANS something. Three
   placements, no more (DESIGN.md holds the list): call attempts on the belt card and on Search
   rows, pipeline stage on the lead page. Colour is judgment, not decoration — attempts run navy,
   amber at three, red at five, exactly like every other state in the app. */
.consto{display:inline-flex;align-items:center;gap:var(--s0);vertical-align:-.05em;color:var(--navy)}
.consto i{width:5px;height:5px;border-radius:50%;background:currentColor;opacity:.2}
.consto i.on{opacity:1}
.consto.c-warn{color:var(--amber-ink)} .consto.c-bad{color:var(--bad-ink)}
.consto.k-stage{color:var(--teal)}
[data-density="comfortable"] .consto i{width:6px;height:6px}
[data-vision="bright"] .consto i{opacity:.3}
[data-vision="bright"] .consto i.on{opacity:1}

/* ---- B2 · STREAMS LOSE THEIR BOXES --------------------------------------------------------
   A card says "these things belong together as a set". A timeline and a live feed are not sets,
   they are streams, and boxing a stream adds an edge the reader has to ignore on every row. So
   the card comes off and one hairline rail carries the sequence instead — the dots that already
   marked human vs machine become that rail's markers. Sets (KPI tiles, filter bars, the outcome
   grid) keep their cards, which is what makes the distinction legible at all. */
.card.stream{background:transparent;border:0;box-shadow:none;padding:0;margin-bottom:var(--s4)}
.card.stream>h2{margin-top:0}
.timeline{position:relative;padding-left:var(--s5)}
.timeline::before{content:"";position:absolute;left:5px;top:10px;bottom:10px;width:2px;
  background:var(--line-s);border-radius:1px}
.timeline li{border-top:0;padding:var(--s3) 0}
.timeline li+li{border-top:1px solid var(--line-s)}
.timeline li.human,.timeline li.auto{padding-left:0}
/* the dot must sit ON the rail: rail spans x5..x7 of the list (centre 6), the entry starts at
   its 18px padding, so the 6px dot is centred at 6 - 3 - 18 = -15px. Change one, change all three. */
.timeline li.human::before,.timeline li.auto::before{left:-15px;top:14px;box-shadow:0 0 0 3px var(--bg)}
.feed-row{border-bottom:0}
.feed-row+.feed-row{border-top:1px solid var(--line-s)}
.feed-when{color:var(--muted)}

/* ---- layout for the rows and heads that now begin with an identity token ---- */
.lead-main{gap:var(--s3)}
.lead-main .name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lead-main .head-right{flex:0 0 auto}
.belt-name,.lead-head h1,.conv-head h1,.card.lead-head h1{display:flex;align-items:center;gap:var(--s3)}
.bn-t,.lh-t{min-width:0;overflow:hidden;text-overflow:ellipsis}
.lh-stage{display:flex;align-items:center;gap:var(--s3);margin:var(--s2) 0 var(--s0);font-size:var(--t-tight);
  color:var(--muted);font-weight:600}
.attempts{display:inline-flex;align-items:center;gap:var(--s1)}
/* Lead Pool: the token lives inside the name cell, so that cell becomes the flex row and the
   name+address stack moves into .f-txt. Scoped to .ft-pool — every other field table still
   renders .f-main as a plain block. */
.ft-pool .f-main,.ft-pool-rep .f-main{display:flex;align-items:center;gap:var(--s3)}
.ft-pool .f-txt,.ft-pool-rep .f-txt{flex:1 1 auto;min-width:0}
/* on a phone the token would push the name into a two-character column — it stands down */
@media(max-width:520px){.lead-main .mono,.ft-pool .f-main>.mono{display:none}}

/* ===========================================================================================
   C · CRAFT LAYER (VS 2026-08-02): motion budget, hover, sticky heads, figures, toast, skeleton.
   =========================================================================================== */

/* ---- MOTION BUDGET: three transitions, and nothing else in the stylesheet moves ------------
   Every ad-hoc transition and both pulse keyframes were removed to get here. Layout properties
   (width, margin) are never animated, so collapsing the rail now snaps — that is deliberate, not
   an omission. The just-arrived lead keeps its meaning as a static warm wash instead of a 2.4s
   flash, because "this one is new" is information and information must survive reduced-motion. */
:root{--ease:cubic-bezier(.22,1,.36,1)}   /* ease-out-quint */
/* 1 · row press — 120ms */
.lead,.frow,.callrow,.task,a.tile,.btn,button.primary,.side-link,.pref-btn,.qchip,.belt-lanes a{
  transition:background-color 120ms var(--ease),border-color 120ms var(--ease),
             box-shadow 120ms var(--ease)}
.lead:active,.frow:active,a.tile:active,.btn:active,button.primary:active{transform:scale(.995)}
/* 2 · accordion — 180ms */
.ng-ch{transition:transform 180ms var(--ease)}
/* 3 · toast — 240ms */
.toast{transition:transform 240ms var(--ease),opacity 240ms var(--ease)}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:1ms !important;animation-duration:1ms !important;
    animation-iteration-count:1 !important;scroll-behavior:auto !important}
  .lead:active,.frow:active,a.tile:active,.btn:active,button.primary:active{transform:none}
}

/* ---- ROW HOVER: a fill, never a border, and never zebra ------------------------------------
   Finder and Mail behaviour. The fill bleeds past the card's inner padding via two box-shadow
   offsets rather than negative margins, so the row never fights the grid it sits in and nothing
   needs a z-index. One 1px divider carries the structure; alternating row colours would add a
   second, competing rhythm on top of it. */
:root{--hover:rgba(26,45,90,.045)}
.frow:hover,.beltrow:hover,.feed-row:hover,.timeline li:hover{background:var(--hover);
  box-shadow:-9px 0 0 var(--hover),9px 0 0 var(--hover)}
.lead:hover{background:var(--hover);border-color:#D6D0C6}
[data-vision="bright"]{--hover:rgba(26,45,90,.09)}

/* ---- STICKY COLUMN HEADS -------------------------------------------------------------------
   Any table long enough to scroll loses its header at about row 16, and after that every column
   is a guess. The head needs an opaque background of its own (it is transparent over scrolling
   rows otherwise) and its closing rule doubles as the shadow. */
.fhead,.atable thead th{position:sticky;top:0;z-index:3;background:var(--card)}
.fhead{padding-top:var(--s3);box-shadow:0 1px 0 rgba(26,45,90,.12)}

/* ---- FIGURES: a number is not a word ------------------------------------------------------
   Counts used to live inside sentences ("· 22 due now · 3 overdue"), which reads at prose speed
   and cannot be compared down a column. A figure is the numeral in Space Grotesk with its label
   as an overline beneath, tabular so digits line up, right-aligned wherever it sits in a table. */
.fig{display:inline-flex;flex-direction:column;gap:var(--s0);line-height:1}
.fig b{font-family:var(--f-data);font-variant-numeric:tabular-nums lining-nums;font-weight:700;
  color:var(--navy);font-size:var(--fig-m);letter-spacing:-.01em}
.fig span{font-family:var(--f-data);font-size:var(--t-nano);font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.fig-s b{font-size:var(--t-name)} .fig-l b{font-size:var(--fig-l)}
.fig.f-bad b{color:var(--bad-ink)} .fig.f-warn b{color:var(--amber-ink)}
.fig.f-ok b{color:var(--ok-ink)} .fig.f-mira b{color:var(--teal)}
.figrow{display:flex;flex-wrap:wrap;gap:var(--s6);align-items:flex-start;margin:var(--s0) 0 var(--s4)}
td .fig,.f-fig{align-items:flex-end;text-align:right}

/* ---- TOAST: the result of an action, and a way back out of it ------------------------------
   Replaces eighteen inline stripe cards that pushed the page down, sat above the fold forever,
   and carried two hard-coded hexes each. A toast reports and leaves. Bottom centre because that
   is where the thumb is on a phone and out of the way of a table on a desktop. */
.toast{position:fixed;left:50%;bottom:22px;z-index:120;display:flex;align-items:center;gap:var(--s4);
  max-width:min(560px,calc(100vw - 28px));padding:var(--s4) var(--s4) var(--s4) var(--s5);border-radius:14px;
  background:var(--navy);color:#fff;box-shadow:0 8px 28px rgba(15,27,56,.28);
  font-size:var(--t-ui);font-weight:600;
  transform:translate(-50%,calc(100% + 32px));opacity:0;pointer-events:none}
.toast.up{transform:translate(-50%,0);opacity:1;pointer-events:auto}
.toast .t-msg{min-width:0}
.toast .ic-i{flex:0 0 auto}
.toast.t-bad{background:#7C2020}
.toast.t-ok .ic-i{color:#7FD6A2}
.toast form{margin:0;display:inline}
.toast .t-undo{background:transparent;border:1px solid rgba(255,255,255,.45);color:#fff;
  border-radius:9px;padding:var(--s2) var(--s4);font-weight:700;font-size:var(--t-tight);cursor:pointer;
  font-family:var(--f-body);white-space:nowrap;margin:0;width:auto}
.toast .t-undo:hover{background:rgba(255,255,255,.14)}
.toast .t-x{background:transparent;border:0;color:rgba(255,255,255,.65);cursor:pointer;padding:var(--s0) var(--s0);
  font-size:var(--t-name);line-height:1;margin:0;width:auto;flex:0 0 auto}
.toast .t-x:hover{color:#fff}
@media(max-width:520px){.toast{left:14px;right:14px;bottom:14px;transform:translateY(calc(100% + 24px));
  max-width:none} .toast.up{transform:translateY(0)}}

/* ---- SKELETON ROWS -------------------------------------------------------------------------
   Drawn at the EXACT height of the row they stand in for, so nothing jumps when the real data
   lands. Static, not shimmering: a shimmer is a fourth transition and it is not information. */
.sk-row{display:flex;align-items:center;gap:var(--s3);min-height:var(--row-h);
  padding:var(--row-py) var(--s3);border-bottom:1px solid var(--line-s)}
.sk-row:last-child{border-bottom:0}
.sk{background:var(--line-s);border-radius:6px;height:11px;flex:0 0 auto}
.sk-mono{width:28px;height:28px;border-radius:50%}
.sk-a{flex:1 1 auto;max-width:38%} .sk-b{width:14%} .sk-c{width:9%} .sk-d{width:11%}
.sk-wrap{padding:0 var(--s3)}

/* ---- EMPTY STATE AS ACHIEVEMENT -------------------------------------------------------------
   An empty belt is the goal of the entire working day, and it used to be a grey card with a tick
   in the heading. The constellation completes — five dots lit, in teal — and the day's work sits
   under it as figures. Restrained on purpose: this is an Activity ring closing, not confetti.
   No animation, so it reads identically under reduced-motion. */
.clear-card{text-align:center;padding:var(--s7) var(--s5) var(--s6)}
.clear-card .consto{gap:var(--s2);margin-bottom:var(--s4)}
.clear-card .consto i{width:9px;height:9px}
.clear-card h2{margin:0 0 var(--s1);font-size:var(--t-title);color:var(--navy);font-weight:700}
.clear-card .figrow{justify-content:center;gap:var(--s7);margin:var(--s5) 0 var(--s4)}
.clear-card .fig{align-items:center}
.clear-card p{margin:0;max-width:46ch;margin-left:auto;margin-right:auto}

/* standing findings keep the doctrine's washes — a card that reports a STATE, not an action */
.card.w-danger{background:#FDF2EC;border:1.5px solid #EAC0B0}
.card.w-attention{background:#FDF7EA;border:1.5px solid #F0D9A8}
/* map placeholder: the area holds its exact height from first paint and Leaflet's tiles cover it */
.sk-map{background:var(--line-s);
  background-image:linear-gradient(rgba(26,45,90,.05) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(26,45,90,.05) 1px,transparent 1px);
  background-size:44px 44px}

/* ---- KEYBOARD HELP SHEET (public/keys.js) --------------------------------------------------
   Shortcuts nobody can discover exist only for the person who wrote them. "?" is the only reason
   these survive the day someone else sits at this terminal. */
.kb-scrim{position:fixed;inset:0;z-index:200;display:none;align-items:center;justify-content:center;
  background:rgba(15,27,56,.34);padding:var(--s5)}
.kb-scrim.on{display:flex}
.kb-sheet{background:var(--card);border-radius:16px;box-shadow:0 18px 50px rgba(15,27,56,.3);
  padding:var(--s6) var(--s6);min-width:min(360px,100%);max-height:80vh;overflow:auto}
.kb-sheet h2{margin:0 0 var(--s4);font-size:var(--t-name);color:var(--navy);font-weight:700}
.kb-row{display:flex;align-items:center;gap:var(--s3);padding:var(--s2) 0;font-size:var(--t-ui)}
.kb-row span{margin-left:var(--s2);color:var(--ink)}
.kb-row kbd{font-family:var(--f-data);font-size:var(--t-tight);font-weight:700;color:var(--navy);
  background:#F1EDE6;border:1px solid var(--line);border-bottom-width:2px;border-radius:6px;
  min-width:22px;padding:var(--s0) var(--s2);text-align:center;line-height:1.3}
[data-vision="bright"] .kb-row kbd{background:#fff;border-color:var(--navy)}

/* ==== OWNERSHIP + SALES FUNNEL (2026-08-03) ==================================================
   Owner chip = navy presence (a person). Unassigned = amber (a standing to-do: the number the
   redistribution system drives to zero). Stage chips are QUIET tints — the funnel is a fact strip,
   not a fruit salad; only Won (money-verified) earns the green and only Lost the red. */
.chip-owner{background:rgba(26,45,90,.08);border-color:rgba(26,45,90,.45);font-weight:600}
.chip-unowned{background:rgba(161,94,8,.10);border-color:rgba(161,94,8,.5);color:var(--amber-ink);font-weight:700;text-transform:uppercase;font-size:var(--t-tight)}
.chip-stg{font-weight:600}
.stg-contacted{background:rgba(26,45,90,.06);border-color:rgba(26,45,90,.3)}
.stg-qualified{background:var(--teal-soft);border-color:var(--teal-bar)}
.stg-promised{background:rgba(161,94,8,.08);border-color:rgba(161,94,8,.4)}
.stg-committed{background:rgba(231,136,47,.12);border-color:rgba(231,136,47,.55)}
.stg-won{background:rgba(46,158,91,.14);border-color:rgba(46,158,91,.5);color:var(--ok-ink)}
.stg-nurture{background:rgba(107,123,141,.10);border-color:rgba(107,123,141,.4)}
.stg-lost{background:rgba(214,69,69,.10);border-color:rgba(214,69,69,.45);color:var(--bad-ink)}
/* STATE STRIP — LOCKED by VS 2026-08-03 ("this is actually good, lets keep this only"):
   labeled columns, sales stage as ONE segmented control. Overline labels in the data face. */
.lh-state{display:flex;gap:var(--s6);flex-wrap:wrap;align-items:flex-start;margin:var(--s3) 0 var(--s2)}
.lh-col{display:flex;flex-direction:column;gap:var(--s2)}
.lh-lbl{font-family:var(--f-data);font-size:var(--t-tight);font-weight:500;text-transform:uppercase;
  letter-spacing:.08em;color:var(--muted)}
/* READ-ONLY REFERENCE since 2026-08-03 evening: stage moves itself from Log-this-call, so the
   strip lost its buttons (and with them the drifted UA button font — pills now carry the brand
   body face explicitly). max-width keeps it inside the viewport; on narrow phones the segmented
   bar dissolves into wrapped chips instead of bleeding off the right edge. */
.stagebar{display:inline-flex;max-width:100%;border:1px solid var(--line);border-radius:8px;overflow:hidden;background:#fff}
.stg-pill{border:0;border-right:1px solid var(--line);background:transparent;color:var(--ink);
  font-family:var(--f-body);padding:var(--s2) var(--s3);font-size:var(--t-tight);font-weight:600;white-space:nowrap}
.stg-pill:last-child{border-right:0}
.stg-pill.on{background:var(--navy);color:#fff}
@media(max-width:620px){
  .stagebar{flex-wrap:wrap;gap:var(--s1);border:0;border-radius:0;background:transparent;overflow:visible}
  .stg-pill{border:1px solid var(--line);border-radius:999px;background:#fff;padding:var(--s1) var(--s3)}
  .stg-pill.on{border-color:var(--navy)}
}
/* belt card claim + team rows */
.belt-claim{display:inline-flex;align-items:center;gap:var(--s2);margin-left:auto}
.belt-head .chip-owner{margin-left:auto}
.teamrow{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;padding:var(--s3) var(--s1)}
.teamrow .team-acts{margin-left:auto;display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap}
.inlineform{display:inline-flex;gap:var(--s2);align-items:center}
.assignform select,.teamrow select{max-width:12em}
.warn-t{color:var(--amber-ink)}
/* owner row (redesign 2026-08-03): every control shares one 32px height rhythm; the assign
   select + button read as a single joined input group instead of two strays. */
.owner-line{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap}
.owner-line .chip{line-height:1.4}
/* owner row (final, 2026-08-03): the joined-control experiment kept losing to global button
   styles and bleeding — retired. Every control is its own pill on ONE 34px line. */
.owner-line{align-items:center}
.assignform{display:inline-flex;align-items:center;gap:var(--s2)}
.assign-sel{height:34px;font-size:var(--t-tight);font-family:var(--f-ui);color:var(--ink);
  border:1px solid var(--line);border-radius:10px;background:#fff;
  padding:0 var(--s3);max-width:11em;box-sizing:border-box;align-self:center}
.owner-line button.ghost.mini,.owner-line button.primary.mini{height:34px;padding:0 var(--s4);
  box-sizing:border-box;display:inline-flex;align-items:center;margin:0;align-self:center}
.owner-line .chip{line-height:1.5;display:inline-flex;align-items:center;height:34px;box-sizing:border-box}
.script-steps{margin:var(--s2) 0 var(--s3);padding-left:1.4em}
.script-steps li{margin:var(--s2) 0}
/* COMMAND STRIP + MORE DRAWER (lead page Option 2, 2026-08-03) */
/* static ring, no transition — the motion budget is EXACTLY 3 and this is information, not motion */
.card.flash{border-color:var(--orange);box-shadow:0 0 0 2px rgba(231,136,47,.35)}
.more-drawer{margin:var(--s4) 0}
.more-drawer>summary{cursor:pointer;padding:var(--s3) var(--s2);color:var(--muted)}
.more-drawer>summary b{color:var(--ink)}
.more-drawer[open]>summary{margin-bottom:var(--s2)}
.logfull>summary{cursor:pointer}
/* belt card v4 (2026-08-03): all-white buttons, hover carries the affordance; the name IS the link */
.belt-card .btn{background:#fff}
.belt-card .btn:hover{border-color:var(--navy);background:rgba(26,45,90,.06)}
.bn-link{color:inherit;text-decoration:none;border-radius:6px}
.bn-link:hover{color:var(--navy);text-decoration:underline;text-underline-offset:3px}
/* factual briefing list (2026-08-03) */
.brief{margin:var(--s2) 0 var(--s3);padding-left:1.2em}
.brief li{margin:var(--s1) 0}
/* optional lead-details fold inside the log form (2026-08-03) */
.opt-details{margin:var(--s3) 0;border:1px dashed var(--line);border-radius:10px;padding:var(--s2) var(--s3)}
.opt-details>summary{cursor:pointer;color:var(--muted)}
.opt-details>summary b{color:var(--ink)}
.opt-details[open]{padding-bottom:var(--s3)}
/* row next-move line (2026-08-03): quiet italic — a pointer, not a note */
.lead-next{color:var(--muted);font-style:italic}
/* booker attribution chip (2026-08-03): teal = the machine booked it, navy = a person */
.chip-mira{background:var(--teal-soft);border-color:var(--teal-bar);color:var(--teal)}
/* two-step item picker (2026-08-03) */
.pickitem{display:flex;gap:var(--s2);flex-wrap:wrap;align-items:center;margin:0 0 var(--s3)}
.pickitem .pk-kind{max-width:9em}
.pickitem .pk-list{max-width:100%;min-width:14em}
.pickitem .pk-value{flex:1;min-width:12em}
/* UNIFORM GROUP HEADINGS (VS 2026-08-03): every rail group demarcates the same way — caps,
   data face, tracked. CRM was caps by accident of being an acronym; now it is the rule. */
.nav-h span:first-child{text-transform:uppercase;font-family:var(--f-data);letter-spacing:.07em}

/* ---- PERFORMANCE MIRROR (VS 2026-08-03): per-caller KPIs + funnel tracker ---- */
/* KPI tile status: the number itself wears the verdict — green on target, amber within reach,
   red off the line. Neutral tiles (no target / no data) stay navy like every other tile.
   Semantic INKS only (DESIGN.md palette law) — no fallback hexes, tokens are the truth. */
.tile.k-ok b{color:var(--ok-ink)}
.tile.k-warn b{color:var(--amber-ink)}
.tile.k-bad b{color:var(--red)}
td.k-ok{color:var(--ok-ink)} td.k-warn{color:var(--amber-ink)} td.k-bad{color:var(--bad-ink)}
.pf-tabs{display:flex;gap:var(--s2);flex-wrap:wrap;margin-bottom:var(--s3)}
.pf-tabs .chip{text-decoration:none}
.pf-tabs .chip.pf-on{background:var(--navy);border-color:var(--navy);color:#fff}
.pf-sub{margin:var(--s2) 0 0}
/* funnel rows: bar width = share of the book that has REACHED the stage (up-only ladder) */
.pf-funnel{display:flex;flex-direction:column;gap:var(--s2);margin-top:var(--s3)}
.pf-frow{display:grid;grid-template-columns:11em 1fr 13em 8em;gap:var(--s3);align-items:center}
.pf-fstage{font-family:var(--f-data);font-size:var(--t-tight);font-weight:600}
.pf-fwrap{background:rgba(26,45,90,.06);border-radius:6px;height:22px;overflow:hidden}
.pf-fbar{height:100%;border-radius:6px;border:0!important;min-width:4px}
.pf-fnums{font-size:var(--t-tight);color:var(--muted)} .pf-fnums b{color:var(--ink)}
.pf-fconv{font-size:var(--t-mini);color:var(--muted);text-align:right;white-space:nowrap}
.pf-weakrow .pf-fstage,.pf-weakrow .pf-fconv{color:var(--bad-ink);font-weight:700}
/* weakest-link callout: ATTENTION wash + ring (accent doctrine — left stripes are retired) */
.pf-weak{margin-top:var(--s3);padding:var(--s2) var(--s3);background:#FDF2EC;border:1.5px solid #EAC0B0;border-radius:10px}
.pf-weak b{color:var(--bad-ink)}
@media(max-width:720px){.pf-frow{grid-template-columns:7em 1fr;grid-auto-rows:auto}.pf-fnums{grid-column:2}.pf-fconv{grid-column:1/-1;text-align:left}}
/* 14-day rhythm: pure-CSS bar chart — height % inline, today in orange, booked count above.
   Every numeral on this page is Space Grotesk tabular (type law: a number is not a word). */
.pf-chart{display:flex;align-items:flex-end;gap:var(--s1);height:140px;margin-top:var(--s3)}
.pf-col{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:var(--s0);height:100%;min-width:0}
.pf-bar{width:100%;max-width:34px;background:var(--navy);border-radius:4px 4px 0 0;min-height:2px}
.pf-today .pf-bar{background:var(--orange)}
.pf-bk{font-family:var(--f-data);font-size:var(--t-mini);font-weight:700;color:var(--orange)}
.pf-n{font-size:var(--t-mini);color:var(--muted)}
.pf-d{font-size:var(--t-micro);color:var(--muted);white-space:nowrap}
.pf-n,.pf-d,.pf-fnums b,.pf-mn,.pf-table td b,.pf-fconv{font-family:var(--f-data);font-variant-numeric:tabular-nums}
/* outcome mix bars */
.pf-mix{display:flex;flex-direction:column;gap:var(--s1);margin-top:var(--s2)}
.pf-mrow{display:grid;grid-template-columns:11em 1fr 3em;gap:var(--s2);align-items:center}
.pf-mk{font-size:var(--t-tight)}
.pf-mwrap{background:rgba(26,45,90,.06);border-radius:5px;height:14px;overflow:hidden}
.pf-mbar{height:100%;background:var(--navy);border-radius:5px;min-width:3px}
.pf-mbar.pf-good{background:var(--green)} .pf-mbar.pf-grey{background:rgba(107,123,141,.55)}
.pf-mn{text-align:right}
/* two-up cards on wide screens */
.pf-two{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3)}
@media(max-width:900px){.pf-two{grid-template-columns:1fr}}
/* team strip table */
.pf-tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.pf-table{width:100%;border-collapse:collapse;font-size:var(--t-tight);margin-top:var(--s2)}
.pf-table th{text-align:left;font-family:var(--f-data);font-size:var(--t-mini);text-transform:uppercase;letter-spacing:.05em;color:var(--navy);padding:var(--s1) var(--s2);border-bottom:2px solid rgba(26,45,90,.14)}
.pf-table td{padding:var(--s2);border-bottom:1px solid var(--line);white-space:nowrap}
.pf-table tr.pf-cur td{background:rgba(26,45,90,.04)}
/* KPI target editor fold */
.pf-kpiform{display:flex;gap:var(--s3);flex-wrap:wrap;align-items:flex-end;margin-top:var(--s3)}
.pf-kpiform label{display:flex;flex-direction:column;gap:4px;font-size:var(--t-mini);color:var(--muted)}
.pf-kpiform input{width:8em}
.pf-kpiform button.primary{width:auto;margin:0;padding:var(--s2) var(--s4)}

/* ---- EOD DAY-CLOSE + DAILY BRIEF (VS 2026-08-03): machine counts, human sentence ---- */
.eod-card.eod-done{background:#F2F9F3;border-color:#CBE2D0} /* CONTEXT wash: green = closed, done */
.eod-form{display:flex;gap:var(--s3);align-items:flex-start;margin-top:var(--s3)}
.eod-form textarea{flex:1;margin:0}
.eod-form button.primary{width:auto;margin:0;padding:var(--s3) var(--s4);white-space:nowrap}
.eod-note{margin:var(--s2) 0 0;padding:var(--s2) var(--s3);border-left:0;background:#F2F4F8;border:1px solid #CFD7E4;border-radius:8px;font-style:italic;color:var(--ink)}
.eod-row{padding:var(--s3) 0;border-bottom:1px solid var(--line-s)}
.eod-row:last-child{border-bottom:0}
.eod-head{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap}
.eod-missing{color:var(--bad-ink);font-weight:700;font-size:var(--t-tight);text-transform:uppercase;letter-spacing:.05em;font-family:var(--f-data)}
@media(max-width:620px){.eod-form{flex-direction:column}.eod-form button.primary{width:100%}}

/* structured EOD report grid (VS 2026-08-03 "detailed, headed, fresh every day") */
.eod-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3);align-items:stretch}
.eod-grid button.primary{grid-column:1/-1;width:auto;justify-self:end;margin:0;padding:var(--s3) var(--s5)}
.eod-q{display:flex;flex-direction:column;gap:4px}
.eod-lbl{font-family:var(--f-data);font-size:var(--t-micro);font-weight:600;text-transform:uppercase;letter-spacing:.07em;color:var(--muted)}
.eod-lbl .req{color:var(--red)}
.eod-q textarea{margin:0;flex:1}
.eod-sec{margin:2px 0}
.eod-sec b{font-family:var(--f-data);font-size:var(--t-micro);text-transform:uppercase;letter-spacing:.06em;color:var(--muted);font-style:normal}
@media(max-width:720px){.eod-grid{grid-template-columns:1fr}.eod-grid button.primary{width:100%}}

/* gamified KPI tiles (VS 2026-08-03): every tile is a bar to fill; a hit milestone goes green.
   Tiles with a bar become flex columns and the bar pins to the BOTTOM (margin-top:auto), so all
   bars share one baseline whether the label wraps one line or two. */
.pf-tiles .tile{display:flex;flex-direction:column}
.pf-tiles .tile>b{flex:0 0 auto}
.tile-bar{height:6px;border-radius:999px;background:rgba(26,45,90,.08);margin-top:auto;padding-top:0;overflow:hidden}
.pf-tiles .tile>span{margin-bottom:var(--s2)}
.tile-fill{height:100%;border-radius:999px;background:var(--navy)}
.tile-fill.k-ok{background:var(--green)} .tile-fill.k-warn{background:var(--amber-ink)} .tile-fill.k-bad{background:var(--red)}
.tile.t-done{background:#F2F9F3;border-color:#CBE2D0}
.tile.t-done b{color:var(--ok-ink)}

/* ---- GUIDE prose (VS 2026-08-03): rendered SOP markdown, read-measure typography ---- */
.guide h2{font-family:var(--f-head);font-size:var(--t-title);color:var(--navy);margin:0 0 var(--s3)}
.guide h3{font-family:var(--f-data);font-size:var(--t-mini);font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--navy);margin:var(--s6) 0 var(--s2);padding-bottom:var(--s1);border-bottom:2px solid rgba(26,45,90,.14)}
.guide p{margin:var(--s2) 0;max-width:78ch}
.guide ul,.guide ol{margin:var(--s2) 0;padding-left:1.4em;max-width:78ch}
.guide li{margin:var(--s2) 0}
.guide li.g-check::marker{content:"☐  ";color:var(--muted)}
.guide hr{border:0;border-top:1px solid var(--line);margin:var(--s5) 0}
.guide table{width:100%;border-collapse:collapse;font-size:var(--t-tight);margin:var(--s3) 0}
.guide th{text-align:left;font-family:var(--f-data);font-size:var(--t-micro);text-transform:uppercase;letter-spacing:.06em;color:var(--navy);padding:var(--s1) var(--s2);border-bottom:2px solid rgba(26,45,90,.14)}
.guide td{padding:var(--s2);border-bottom:1px solid var(--line-s);vertical-align:top}
.guide blockquote{margin:var(--s3) 0;padding:var(--s2) var(--s3);background:#F2F4F8;border:1px solid #CFD7E4;border-radius:8px;max-width:78ch}
.guide code{font-family:var(--f-data);background:rgba(26,45,90,.06);padding:0 4px;border-radius:4px}

/* ---- ASK THE GUIDE (VS 2026-08-03): grounded chat under the SOP. Teal = machine intelligence. */
.gc-log{display:flex;flex-direction:column;gap:var(--s2);max-height:340px;overflow-y:auto;margin:var(--s3) 0;-webkit-overflow-scrolling:touch}
.gc-log:empty{display:none}
.gc-msg{max-width:80%;padding:var(--s2) var(--s3);border-radius:12px;font-size:var(--t-body);white-space:pre-wrap}
.gc-user{align-self:flex-end;background:rgba(26,45,90,.08);border:1px solid rgba(26,45,90,.14);border-bottom-right-radius:4px}
.gc-bot{align-self:flex-start;background:var(--teal-soft);border:1px solid var(--teal-bar);border-bottom-left-radius:4px}
.gc-form{display:flex;gap:var(--s2);align-items:center}
.gc-form input{flex:1;margin:0}
.gc-form button.primary{width:auto;margin:0;padding:var(--s3) var(--s5);white-space:nowrap}

/* ---- RECORD HEADER v2 (VS 2026-08-03): identity + owner cluster + facts strip ---- */
.lh-top{display:flex;gap:var(--s4);align-items:flex-start;flex-wrap:wrap}
.lh-id{flex:1 1 260px;min-width:0}
.lh-ag{font-family:var(--f-data);font-size:var(--t-tight);font-weight:600;color:var(--muted);margin-left:var(--s2);vertical-align:middle}
.lh-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:var(--s2)}
.lh-own{display:flex;flex-direction:column;gap:var(--s2);align-items:flex-end;flex:0 1 auto}
@media(max-width:720px){.lh-own{align-items:flex-start;width:100%}}
/* facts strip: label-over-value figures between hairlines — only real facts render */
.lh-facts{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s6);border-top:1px solid var(--line-s);border-bottom:1px solid var(--line-s);padding:var(--s3) 0;margin:var(--s4) 0 var(--s3)}
.lhf{min-width:84px}
.lhf-wide{flex:1 1 160px;min-width:140px}
.lhf-l{display:block;font-family:var(--f-data);font-size:var(--t-micro);font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--muted)}
.lhf-v{display:block;font-family:var(--f-data);font-variant-numeric:tabular-nums;font-size:var(--t-name);font-weight:600;color:var(--navy);line-height:1.3;white-space:nowrap}
.lhf-v.lhf-txt{font-family:var(--f-body);white-space:normal;font-size:var(--t-body)}
.lhf-v.lhf-bad{color:var(--bad-ink)} .lhf-v.lhf-warm{color:var(--amber-ink)} .lhf-v.lhf-mira{color:var(--teal)}
.lhf-sub{display:block;font-size:var(--t-mini);color:var(--muted)}
@media(max-width:620px){.lh-facts{gap:var(--s3) var(--s4)}.lhf-v{white-space:normal}}

/* header v2.1 (VS 2026-08-03 "negative space"): the owner cluster is ONE wrapping row, not a
   column — the identity band's height is the chips' height, never the cluster's stack. */
.lh-own{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:var(--s2);max-width:100%}
.lh-own .owner-line{margin:0;display:inline-flex;gap:var(--s2);align-items:center}
.lh-own .assignform{margin:0}
.lh-own .assign-sel{width:auto;min-width:9em;margin:0}
.lead-head h1{margin-bottom:0}
.lh-facts{margin-top:var(--s3)}

/* ---- SCRIPT v3 (VS 2026-08-03 night): speakable Devanagari lines + tap-to-open objections ----
   .st-say is THE thing a caller reads mid-call: a white quote card on the tinted briefing panel,
   Devanagari at a read-aloud size. Cues are deliberately small + muted — instructions, not lines.
   Objections use native <details> (zero JS, CSP-clean); the deep bank lives on the Guide shelf. */
.script-v3{margin:var(--s2) 0 var(--s3);padding-left:1.5em;display:flex;flex-direction:column;gap:10px}
.script-v3 li::marker{font-family:var(--f-data);font-weight:600;color:var(--muted)}
.st-k{display:inline-block;font-family:var(--f-data);font-size:11.5px;font-weight:700;letter-spacing:.09em;color:var(--muted)}
.st-say{margin:4px 0 0;padding:8px 12px;background:#fff;border:1px solid #E6E6E6;border-radius:9px;
  font-family:'Noto Sans Devanagari','Nirmala UI','Mangal',var(--f-body);font-size:16.5px;line-height:1.7;color:var(--ink)}
.st-say.st-alt{background:#FDF2EC;border-color:#EAC0B0}
.st-altk{font-weight:700;color:var(--amber-ink)}
.st-cue{margin:3px 0 0;font-size:12.5px;line-height:1.45;color:var(--muted)}
.obj-list{display:flex;flex-direction:column;gap:6px;margin:var(--s2) 0}
.obj{border:1px solid #E6E6E6;border-radius:9px;background:#fff}
.obj summary{cursor:pointer;padding:9px 12px;font-weight:700;font-size:14px}
.obj[open]{padding-bottom:10px}
.obj[open] summary{border-bottom:1px dashed #E6E6E6;margin-bottom:8px}
.obj .st-say{border:0;padding:0 12px;background:transparent}
.obj .st-cue{padding:0 12px}
.obj-more{font-size:13px;color:var(--muted);margin:4px 0 0}
@media (max-width:620px){.script-v3{padding-left:1.2em}}

/* SCRIPT v3.1 (VS 2026-08-04): briefing = fixed Story-so-far + two section folds. VS: "make
   these two feel like a clickable button" — full-width white button rows, hairline + soft shadow,
   pressed state, generous tap target (mobile thumbs mid-call). Caret rotates on open. */
.sec-fold{margin:var(--s2) 0}
/* block layout, absolute caret — flex made text nodes into columns and wrapped titles mid-word */
.sec-fold>summary{display:block;position:relative;cursor:pointer;list-style:none;
  background:#fff;border:1px solid #D8D2C8;border-radius:10px;padding:12px 14px 12px 36px;
  font-size:var(--t-name);font-weight:700;line-height:1.4;box-shadow:0 1px 2px rgba(0,0,0,.05);user-select:none}
.sec-fold>summary::-webkit-details-marker{display:none}
.sec-fold>summary::before{content:'▸';color:var(--muted);position:absolute;left:15px;top:12px}
/* subtitle inside a fold summary (italic in the .md) reads as the muted sub-line, not bold title */
.sec-fold>summary i{font-style:normal;font-weight:500;font-size:var(--t-tight);color:var(--muted)}
.sec-fold>summary:hover{background:#FBF9F5;border-color:#C7BFB2}
.sec-fold>summary:active{background:#F4F1EA;box-shadow:none}
.sec-fold[open]>summary::before{content:'▾'}
.sec-fold[open]>summary{border-radius:10px 10px 0 0;border-bottom-style:dashed;box-shadow:none}
.sec-fold[open]{background:#fff;border:1px solid #D8D2C8;border-top:0;border-radius:10px;box-shadow:0 1px 2px rgba(0,0,0,.05)}
.sec-fold[open]>summary{border-left:0;border-right:0;border-top:0}
.sec-fold>.script-v3,.sec-fold>.obj-list,.sec-fold>.obj-more{margin-left:14px;margin-right:14px}
.sec-fold>.obj-more{padding-bottom:12px}
.sec-fold>.script-v3{margin-top:10px;padding-bottom:12px}
.sec-fold>.obj-list{margin-top:10px}
/* inside the open fold the panel is white — quote cards take a warm paper tint to stay readable */
.sec-fold .st-say:not(.st-alt){background:#FAF7F1;border-color:#E9E3D8}
.sec-fold .obj .st-say:not(.st-alt){background:transparent;border:0}
/* Guide-page folds (<<< syntax in shelf .md files): same button rows; rendered content indents
   inside the open card, and the speak-lines (bold in the .md) keep their reading size */
.guide .sec-fold>:not(summary){margin-left:14px;margin-right:14px}
.guide .sec-fold[open]{padding-bottom:12px}
/* step headings inside a script fold read as the briefing's step labels — small caps, data font */
.guide .sec-fold h4{font-family:var(--f-data);font-size:12.5px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);margin:14px 14px 4px}
/* speak-line quote cards in Guide docs (full-bold paragraphs) — same reading surface as .st-say */
.g-say{margin:6px 0;padding:8px 12px;background:#FAF7F1;border:1px solid #E9E3D8;border-radius:9px;
  font-family:'Noto Sans Devanagari','Nirmala UI','Mangal',var(--f-body);font-size:16.5px;line-height:1.7;color:var(--ink)}
.g-say b{font-weight:600}

/* ---- TERMINAL TEAM LAYER v2 (impeccable pass, VS 2026-08-06): one-screen app shell ----
   The page never scrolls; only the message log does. Sidebar and shell each own their overflow.
   Register: product. Laws honored: no side-stripes, no modals, tokens only, 3-transition budget
   untouched (hover states only), teal = machine voice, orange = self. */
body:has(.tm-wrap){overflow:hidden}
body:has(.tm-wrap) .wrap{padding-bottom:var(--s2)}
.tm-wrap{display:flex;gap:12px;align-items:stretch;height:calc(100dvh - 76px)}
.signed-in .tm-wrap{height:calc(100dvh - 108px)}
.tm-side{flex:0 0 198px;overflow-y:auto;min-height:0;padding-right:2px}
.tm-side-title{font-family:var(--f-data);font-size:var(--t-mini);font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);margin:2px 0 8px}
.tm-side-h{font-family:var(--f-data);font-size:11px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);margin:12px 0 3px}
.tm-chan{display:flex;justify-content:space-between;align-items:center;gap:6px;padding:5px 9px;border-radius:8px;color:var(--ink);text-decoration:none;font-size:14px;line-height:1.35}
.tm-chan:hover{background:rgba(0,0,0,.05)}
.tm-chan.on{background:rgba(0,0,0,.06);font-weight:700}
.tm-unread{font-family:var(--f-data);font-size:11px;font-weight:700;background:var(--orange);color:#fff;border-radius:9px;padding:1px 6px}
.tm-dm-form{display:flex;gap:6px;margin-top:6px}
.tm-dm-form select{flex:1;min-width:0;font-size:13px}
.tm-main{flex:1;min-width:0;height:100%;display:flex;flex-direction:column;padding:0;margin:0}
.tm-head{display:flex;align-items:baseline;gap:8px;padding:10px 16px;border-bottom:1px solid #E6E6E6}
/* message log: warm canvas so the white message cards pop (VS 2026-08-07: "wall of text") */
.tm-log{flex:1;min-height:0;overflow-y:auto;padding:12px 16px;display:flex;flex-direction:column;gap:8px;overscroll-behavior:contain;background:#F6F3ED}
.tm-empty{margin:20px 0;text-align:center}
/* one message = one card: avatar chip + content column */
.tm-msg{display:flex;gap:10px;align-items:flex-start;padding:9px 12px;border-radius:12px;background:#fff;border:1px solid #E9E4DA}
.tm-msg:hover{border-color:#D9D2C4;box-shadow:0 1px 3px rgba(15,27,56,.06)}
.tm-av{flex:0 0 32px;width:32px;height:32px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--f-data);font-size:12.5px;font-weight:700;color:#fff;letter-spacing:.02em;user-select:none;margin-top:1px}
.tm-av.av0{background:#3D5A80}.tm-av.av1{background:#6D4C7D}.tm-av.av2{background:#2F6B4F}
.tm-av.av3{background:#7A5230}.tm-av.av4{background:#545E75}.tm-av.av5{background:#8C3B4A}
.tm-av.avm{background:var(--orange)}.tm-av.avg{background:#0D8F8F}.tm-av.avs{background:#8A94A2}
.tm-c{flex:1;min-width:0}
.tm-meta{display:flex;gap:8px;align-items:baseline}
.tm-author{font-size:14px}
.tm-msg.mine .tm-author{color:var(--orange)}
.tm-msg.system .tm-author,.tm-msg.guide .tm-author{color:#0D8F8F}
/* MIRA speaks in one card whether she answers or announces (VS 2026-09-02) */
.tm-msg.system{background:#F4FAF9;border-color:#D3E7E4}
.tm-msg.guide{background:#F4FAF9;border-color:#D3E7E4}
.tm-when{font-family:var(--f-data);font-size:11px;color:var(--muted)}
.tm-body{margin:2px 0 0;font-size:15px;line-height:1.55;white-space:pre-wrap;word-break:break-word;max-width:76ch}
/* retracted: the card ghosts out — record stays, weight goes */
.tm-msg.gone{opacity:.55;background:transparent;border-style:dashed}
.tm-msg.gone:hover{box-shadow:none;border-color:#E9E4DA}
.tm-retracted{color:var(--muted);font-style:italic;font-size:13.5px}
.tm-msg.announce{background:#FDF2EC;border-color:#EAC0B0}
.tm-ack{display:flex;gap:10px;align-items:center;margin-top:6px;flex-wrap:wrap}
.tm-ack-n{font-size:12.5px;color:var(--muted)}
.tm-ack-btn{font-size:12.5px;font-weight:600;padding:4px 12px;border:1px solid #D8A38E;border-radius:999px;background:#fff;cursor:pointer}
.tm-ack-btn:hover{background:var(--navy);border-color:var(--navy);color:#fff}
.tm-att-img{display:block;max-width:340px;max-height:240px;border-radius:8px;border:1px solid #E6E6E6;margin-top:6px}
.tm-att-file{display:inline-flex;align-items:center;gap:6px;margin-top:6px;padding:6px 10px;border:1px solid #D8D2C8;border-radius:8px;background:#fff;font-size:13px;text-decoration:none;color:var(--ink)}
.tm-att-file:hover{background:#FBF9F5}
/* DOCUMENT CARD (VS 2026-09-03): page one on top, then the name and what it weighs. The preview is
   clipped to a band rather than shown whole — a card is a promise about a document, not the
   document. max-width keeps a portrait A4 from becoming a column of paper in a narrow panel. */
.tm-att-doc{display:block;max-width:330px;margin-top:7px;border:1px solid #E1DCD2;border-radius:12px;
  overflow:hidden;background:#fff;text-decoration:none;color:var(--ink)}
.tm-att-doc:hover{border-color:#CFC7B8;box-shadow:0 1px 4px rgba(15,27,56,.08)}
.tm-att-prev{display:block;width:100%;height:150px;object-fit:cover;object-position:top center;
  background:#F6F3ED;border-bottom:1px solid #EDE8DE}
.tm-att-row{display:flex;align-items:center;gap:9px;padding:9px 11px}
.tm-att-kind{flex:0 0 auto;font-family:var(--f-data);font-size:10.5px;font-weight:700;letter-spacing:.04em;
  color:#fff;background:#8A94A2;border-radius:5px;padding:4px 6px;line-height:1}
.tm-att-kind.k-pdf{background:#C0392B}
.tm-att-kind.k-xlsx,.tm-att-kind.k-csv{background:#1E7A4F}
.tm-att-kind.k-docx{background:#2B5EA8}
.tm-att-txt{min-width:0;display:flex;flex-direction:column;gap:2px}
.tm-att-name{font-size:13.5px;font-weight:600;line-height:1.3;word-break:break-word}
.tm-att-sub{font-family:var(--f-data);font-size:11.5px;color:var(--muted)}
/* actions: a real pill button, not a text whisper (VS 2026-08-07) */
.tm-more{margin-top:7px}
.tm-more>summary{display:inline-flex;align-items:center;cursor:pointer;list-style:none;width:max-content;
  font-family:var(--f-data);font-size:12px;font-weight:700;color:var(--ink);
  border:1px solid #D8D2C8;border-radius:999px;background:#FAF8F4;padding:4px 12px;user-select:none}
.tm-more>summary::-webkit-details-marker{display:none}
.tm-more>summary:hover,.tm-more[open]>summary{background:var(--navy);border-color:var(--navy);color:#fff}
.tm-more-body{display:flex;flex-direction:column;gap:6px;padding:10px;background:#FBF9F5;border:1px solid #E6E1D6;border-radius:10px;margin-top:6px}
.tm-inline{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.tm-inline input[name="title"],.tm-inline input[name="body"],.tm-inline input[name="note"]{flex:1;min-width:160px}
.tm-edit-box{flex:1;min-width:200px;font:inherit;font-size:13.5px;line-height:1.45;resize:vertical;border:1px solid #D8D2C8;border-radius:8px;padding:6px 8px}
.tm-danger{color:var(--bad-ink)}
/* THE TWO ACTS, PLAIN (VS 2026-08-29): no fold and no menu word — Edit and Delete sit under the
   message the way they do in WhatsApp and Slack. Quiet until looked for, one press when needed.
   `form{display:contents}` keeps the Delete form from becoming a second box in the row: the
   button itself becomes the flex child, so the two words sit level and evenly spaced. */
.tm-acts{display:flex;gap:12px;align-items:center;margin-top:5px;min-height:22px}
.tm-act{background:none;border:0;padding:0;font:inherit;font-size:12px;font-weight:600;color:var(--muted);cursor:pointer}
.tm-act:hover{color:var(--navy);text-decoration:underline}
/* Delete: an icon, pushed to the far corner of the card and away from Edit (VS 2026-08-29,
   "not liable to be clicked by mistake"). Distance is the first guard, the confirm the second,
   and the retract route behind it is reversible by nature — the row is struck, never dropped.
   Faded until touched, so it never competes with the message it sits under. */
.tm-del-f{margin-left:auto;display:flex}
.tm-del{background:none;border:0;padding:4px;line-height:0;color:var(--muted);opacity:.5;cursor:pointer;border-radius:6px}
.tm-del:hover,.tm-del:focus-visible{color:var(--bad-ink);background:#FBEDEA;opacity:1}
.tm-del .ic-i{width:15px;height:15px}
.tm-editf{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-top:6px}
/* composer: ONE height (44px), ONE radius (10px), ONE hairline — four controls, one family.
   Buttons stay bottom-aligned when the textarea grows. */
/* align-items:center + every control an exact 44px block = one straight line at rest, no
   baseline quirks; when the box grows the buttons stay vertically centered beside it */
.tm-compose{border-top:1px solid #E6E6E6;padding:10px 12px;display:flex;gap:8px;align-items:center}
.tm-compose textarea{flex:1;display:block;margin:0;resize:none;font:inherit;font-size:14.5px;line-height:20px;
  box-sizing:border-box;height:44px;min-height:44px;max-height:110px;padding:11px 12px;
  border:1px solid #D8D2C8;border-radius:10px;overflow-y:hidden;scrollbar-width:thin}
.tm-compose textarea.scrolls{overflow-y:auto}
.tm-compose textarea:focus{outline:none;border-color:var(--navy)}
.tm-tools{display:flex;gap:8px;align-items:center;flex:none}
.tm-attach-btn,.tm-announce{box-sizing:border-box;height:44px;display:inline-flex;align-items:center;gap:7px;
  border:1px solid #D8D2C8;border-radius:10px;background:#fff;padding:0 14px;cursor:pointer;
  font:inherit;font-size:13.5px;line-height:1;color:var(--muted);user-select:none}
.tm-attach-btn:hover,.tm-announce:hover{background:#FBF9F5;color:var(--ink)}
.tm-attach-btn.has-file{color:var(--navy);border-color:var(--orange)}
.tm-announce input{margin:0;width:15px;height:15px;accent-color:var(--navy)}
.tm-compose .primary{box-sizing:border-box;height:44px;display:inline-flex;align-items:center;
  border-radius:10px;padding:0 20px;font-size:14.5px;line-height:1;border:1px solid transparent}
.tm-file-hidden{display:none}
.tm-taskform{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.tm-taskform input[name="title"],.tm-taskform input[name="body"]{flex:1;min-width:220px}
.tm-task{display:flex;justify-content:space-between;gap:10px;align-items:flex-start;padding:9px 4px;border-bottom:1px solid #F0EDE7}
.tm-task:last-child{border-bottom:0}
.tm-task.overdue{background:#FDF2EC;border-radius:8px;padding:9px 10px}
.tm-task.done{opacity:.75}
.tm-task-main{min-width:0}
.tm-task-meta{display:block;font-size:12.5px;color:var(--muted);margin-top:2px}
.tm-od{color:var(--bad-ink)}
.tm-decision{display:flex;gap:12px;align-items:flex-start;padding:10px 4px;border-bottom:1px solid #F0EDE7}
.tm-decision:last-child{border-bottom:0}
.tm-dnum{font-family:var(--f-data);font-weight:700;font-size:13px;color:var(--muted);flex:none;padding-top:2px}
.tm-dbody{margin:0;font-size:14.5px}
@media (max-width:760px){
  body:has(.tm-wrap){overflow:auto}
  .tm-wrap{flex-direction:column;height:auto}
  .tm-side{flex:none;width:100%;overflow:visible}
  .tm-main{height:auto}
  .tm-log{max-height:56dvh}
  .tm-att-img{max-width:100%}
}

/* ---- P3 MAIL (admin-only): inbox rows + plain-text thread ---- */
.ml-search{display:flex;gap:8px;margin-bottom:10px}
.ml-search input{flex:1}
.ml-row{display:grid;grid-template-columns:180px 1fr 90px;grid-template-areas:'from subj date' 'from snip date';
  gap:2px 12px;padding:9px 6px;border-bottom:1px solid #F0EDE7;text-decoration:none;color:var(--ink);border-radius:6px}
.ml-row:hover{background:#FBF9F5}
.ml-row:last-child{border-bottom:0}
.ml-from{grid-area:from;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ml-subj{grid-area:subj;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ml-snip{grid-area:snip;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ml-date{grid-area:date;font-family:var(--f-data);font-size:11.5px;color:var(--muted);text-align:right}
.ml-row.unread .ml-from,.ml-row.unread .ml-subj{font-weight:700}
.ml-msg-head{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;margin-bottom:8px}
.ml-body{font:inherit;font-size:14px;line-height:1.55;white-space:pre-wrap;word-break:break-word;margin:0;max-width:78ch}
.ml-atts{margin:8px 0 0;font-size:12.5px}
.ml-compose{display:flex;flex-direction:column;gap:8px;margin-top:8px}
.ml-compose input,.ml-compose textarea{font:inherit}
.ml-compose button{align-self:flex-end}
.ok-t{color:var(--ok-ink);font-weight:600}
@media (max-width:680px){.ml-row{grid-template-columns:1fr 70px;grid-template-areas:'from date' 'subj date' 'snip snip'}}

/* ---- gap-filler approval desk (owner-only) ---- */
.gap-item{padding:14px 4px;border-bottom:1px solid #F0EDE7}
.gap-item:last-child{border-bottom:0}
.gap-q{margin:0 0 2px;font-size:15px;font-weight:700}
.gap-form{display:flex;flex-direction:column;gap:8px;margin-top:8px}
.gap-form textarea{font:inherit;font-size:14px;line-height:1.5}
.gap-actions{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap}
.gap-hint{font-size:12.5px}
.gap-dismiss{margin-top:6px}
.gap-dismiss button{font-size:12.5px;background:none;border:0;cursor:pointer;padding:0}

/* rail: staff-view lens */
  color:var(--orange);margin:14px 0 2px;padding:0 9px}
  border-radius:9px;background:transparent;color:var(--muted);cursor:pointer}
/* the role picker is select + Go on one line: the select takes the space, Go takes what it needs */
.lens-row select.side-lens-btn{flex:1 1 auto}
.lens-row button.side-lens-btn{flex:0 0 auto}

/* ---- DEPARTMENT BAR (Phase 2, VS 2026-08-08) -------------------------------------------
   A breadcrumb + sibling chips at the top of every departmental page. Owner-only; it exists
   so the rail never has to carry twenty review links. Quiet by default: it is orientation,
   not a call to action, so nothing here competes with the page's own headline. */
.dept-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 14px;padding-bottom:10px;
  border-bottom:1px solid #EDE9E1}

.dept-sep{color:#C9C3B8;font-size:12px}

.dept-links{display:flex;gap:6px;flex-wrap:wrap;margin-left:6px}
.dept-chip{font-size:12.5px;line-height:1;padding:5px 11px;border:1px solid #E6E1D6;border-radius:999px;
  background:#fff;color:var(--muted);text-decoration:none;white-space:nowrap}
.dept-chip:hover{background:#FBF9F5;color:var(--ink);border-color:#D8D2C8}
.dept-chip.on{background:var(--navy);border-color:var(--navy);color:#fff}
@media (max-width:760px){.dept-bar{gap:6px}.dept-links{margin-left:0;width:100%}}
.dept-blurb{font-size:12.5px;color:var(--muted);margin-left:auto;text-align:right}
@media (max-width:900px){.dept-blurb{display:none}}

/* ROLE LENS banner (VS 2026-08-10) — the owner viewing the Terminal as another role. Deliberately
   loud and full-width: being unsure which identity you are looking through is the one failure this
   feature must not have. Orange (the action accent) because it is a state that must be exited. */
.lens-banner { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1rem;
  margin: 0 0 1rem; padding: .7rem 1rem; border-radius: 10px;
  background: color-mix(in srgb, var(--orange, #E7882F) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--orange, #E7882F) 45%, transparent);
  font-size: .92rem; line-height: 1.45; }
.lens-banner form { margin: 0; }
.lens-banner button { border: 1px solid color-mix(in srgb, var(--orange, #E7882F) 60%, transparent);
  background: var(--card, #fff); border-radius: 8px; padding: .35rem .8rem; cursor: pointer;
  font-weight: 600; white-space: nowrap; }
.lens-banner button:hover { background: color-mix(in srgb, var(--orange, #E7882F) 18%, transparent); }

/* ---- Levey-Jennings (Sprint F) ---------------------------------------------------------------
   Server-rendered SVG: the CSP is defaultSrc 'self', so there is no charting library on the page.
   The +/-4SD window is FIXED in the renderer, which is what lets one week be compared with the
   next by eye — a chart that rescales around its worst point compares nothing. */
.lj { width: 100%; height: auto; max-width: 760px; display: block; margin: .4rem 0 .2rem; overflow: visible; }
.lj line { stroke-width: 1; }
.lj .lj-mean { stroke: var(--navy, #1A2D5A); stroke-width: 1.4; }
.lj .lj-1s { stroke: var(--line, #E4E7EE); }
.lj .lj-2s { stroke: #E7B23F; stroke-dasharray: 4 3; }
.lj .lj-3s { stroke: #C4553D; stroke-dasharray: 2 3; }
.lj .lj-lab { font-family: var(--f-data, monospace); font-size: 9px; fill: var(--muted, #7A8296); }
.lj .lj-line { fill: none; stroke: var(--navy, #1A2D5A); stroke-width: 1.4; stroke-opacity: .55; }
.lj .lj-pt { fill: var(--navy, #1A2D5A); }
.lj .lj-pt.lj-warn { fill: #E7B23F; }
.lj .lj-pt.lj-rej { fill: #C4553D; r: 4.5; }
@media (prefers-color-scheme: dark) {
  .lj .lj-1s { stroke: rgba(255,255,255,.14); }
}

/* ---- The round (VS 2026-08-11) ----------------------------------------------------------------
   A visit card is read standing on a doorstep, on a phone, one-handed. So: the name and the time
   are the only things that need to be legible at arm's length, the address is a block of its own,
   and the three actions sit on one row that never needs a scroll to reach. */
.visit { padding: var(--s4); }
.visit .lead { border: 0; padding: 0; margin-bottom: var(--s2); background: transparent; }
.visit p { margin: .3rem 0; }
/* late is a state, not a decoration: the top border is the one edge a thumb never covers */
.visit-late { border-top: 2px solid var(--orange, #E7882F); }
.visit-addr { display: flex; flex-wrap: wrap; gap: var(--s2); margin: var(--s3) 0 var(--s2); }
.visit-addr input { flex: 1 1 12rem; min-width: 0; }
.visit-addr input[name="landmark"], .visit-addr input[name="locality"],
.visit-addr input[name="gps"] { flex: 1 1 8rem; }
.visit-acts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); margin-top: var(--s2); }
.visit-acts .inlineform { display: flex; gap: var(--s2); align-items: center; }
.visit-acts input[name="reason"] { flex: 1 1 14rem; min-width: 0; }
.visit-acts .warn { flex: 1 1 100%; }
@media (max-width: 640px) {
  /* on a phone the primary action goes full width — Collected is pressed with a thumb, in a hurry */
  .visit-acts { gap: var(--s2); }
  .visit-acts > form:first-of-type, .visit-acts .btn.primary { width: 100%; }
  .visit-acts .btn.primary { min-height: 44px; }
}

/* ---- Rail order (VS 2026-08-11) ---------------------------------------------------------------
   Field, CRM, Lab, then the rest, Terminal last — the order of the day rather than the org chart.
   Done with flex `order` so the markup keeps ONE copy of each group: the alternative was emitting
   the Field block twice and gating each copy, which is how a nav starts disagreeing with itself.

   The one deviation, and it is deliberate: a login whose only camp-adjacent right is Camp Day (a
   lab technician who runs the occasional camp) is not a field login. Putting one occasional link
   above her call queue would cost her a scroll every morning to save one a month. `.rail-camponly`
   drops that group below CRM; a real Field Sales login is unaffected and leads the rail.

   Camp became its OWN group on 2026-08-14 (VS): a camp is an occasional event, not part of the
   daily beat, so it sits below Field and above CRM instead of hanging off the Field list. */
.side-nav > .nav-group { order: 50; }
.side-nav > .ng-field   { order: 10; }
.side-nav > .ng-camp    { order: 15; }
.side-nav > .ng-crm     { order: 20; }
.side-nav > .ng-lab     { order: 30; }
.side-nav > .ng-terminal{ order: 90; }
.side-nav > .ng-camp.rail-camponly { order: 25; }

/* ---- Team slide-over (VS 2026-08-11) -----------------------------------------------------------
   Chat is what you need WHILE doing something else, so it arrives over the page and leaves without
   taking it. Right-hand sheet on desktop, bottom sheet on a phone — the two places a thumb and a
   mouse each expect. Transform/opacity only: the panel must never reflow the page behind it. */
/* THE LAUNCHER. 56px, bottom-right, exactly where WhatsApp/Slack/Intercom have trained the thumb.
   Off the rail entirely, so it costs no vertical space and is in the same place on every page.
   It sits BELOW the panel's z-index and hides while the panel is open — a launcher that stays lit
   under its own sheet reads as a second, broken button. */
.team-fab { position:fixed; right:20px; bottom:20px; z-index:69;
  width:56px; height:56px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:var(--navy,#1A2D5A); color:#fff; text-decoration:none;
  box-shadow:0 10px 26px -8px rgba(26,45,90,.55), 0 2px 6px rgba(26,45,90,.18);
  transition:transform .16s cubic-bezier(.22,1,.36,1), box-shadow .16s ease-out, opacity .16s;
  right:calc(20px + env(safe-area-inset-right));
  bottom:calc(20px + env(safe-area-inset-bottom)); }
.team-fab:hover { transform:translateY(-2px) scale(1.03);
  box-shadow:0 16px 32px -10px rgba(26,45,90,.6), 0 2px 6px rgba(26,45,90,.2); }
.team-fab:active { transform:translateY(0) scale(.97); }
.team-fab:focus-visible { outline:3px solid var(--orange,#E7882F); outline-offset:3px; }
.team-fab-i { width:28px; height:28px; display:block; }
/* the pip rides the rim, like every unread count people already read without thinking */
.team-fab .team-dot { position:absolute; top:-2px; right:-2px;
  min-width:20px; height:20px; padding:0 var(--s1); border-radius:10px;
  background:var(--orange,#E7882F); color:#fff; border:2px solid var(--card,#fff);
  font:700 var(--t-mini)/16px var(--f-data,monospace); text-align:center; }
body.tp-open .team-fab { opacity:0; pointer-events:none; transform:scale(.9); }
@media (max-width:640px) {
  /* clear of the mobile nav toggle and of a thumb resting on the bottom edge */
  .team-fab { width:52px; height:52px; right:calc(14px + env(safe-area-inset-right));
    bottom:calc(14px + env(safe-area-inset-bottom)); }
  .team-fab-i { width:26px; height:26px; }
}
@media print { .team-fab, .tp, .tp-scrim { display:none !important; } }

.tp-scrim { position:fixed; inset:0; background:rgba(26,45,90,.38); opacity:0;
  transition:opacity .18s ease-out; z-index:70; }
.tp-scrim.on { opacity:1; }

.tp { position:fixed; top:0; right:0; height:100dvh; width:min(420px,100vw);
  background:var(--card,#fff); border-left:1px solid var(--line,#E4E7EE);
  display:flex; flex-direction:column; z-index:71;
  transform:translateX(100%); transition:transform .22s cubic-bezier(.22,1,.36,1);
  box-shadow:-18px 0 48px -24px rgba(26,45,90,.45); }
.tp.on { transform:translateX(0); }

.tp-head { display:flex; align-items:center; gap:var(--s2); padding:var(--s4) var(--s4);
  border-bottom:1px solid var(--line,#E4E7EE); flex:0 0 auto; }
.tp-chan { flex:1 1 auto; min-width:0; font-weight:600; }
.tp-full { font-size:var(--t-mini); color:var(--muted,#7A8296); white-space:nowrap; }
.tp-x { background:none; border:0; font-size:var(--fig-m); line-height:1; cursor:pointer;
  color:var(--muted,#7A8296); padding:0 var(--s1); }

.tp-body { flex:1 1 auto; overflow-y:auto; overscroll-behavior:contain; padding:var(--s4) var(--s4); }
.tp-body .msg { margin-bottom:var(--s3); }

.tp-send { display:flex; flex-wrap:wrap; gap:var(--s2); align-items:flex-end; padding:var(--s4) var(--s4);
  border-top:1px solid var(--line,#E4E7EE); flex:0 0 auto;
  padding-bottom:calc(10px + env(safe-area-inset-bottom)); }
.tp-send textarea { flex:1 1 auto; min-width:0; resize:none; max-height:120px;
  font:inherit; line-height:1.35; padding:var(--s3) var(--s3); }
.tp-go { flex:0 0 auto; }

@media (max-width:640px) {
  /* bottom sheet: a right-hand drawer on a phone is a full-screen takeover with extra steps */
  .tp { top:auto; bottom:0; right:0; left:0; width:100%; height:min(78dvh,640px);
    border-left:0; border-top:1px solid var(--line,#E4E7EE);
    border-radius:16px 16px 0 0; transform:translateY(100%);
    box-shadow:0 -18px 48px -24px rgba(26,45,90,.45); }
  .tp.on { transform:translateY(0); }
  .tp-send textarea { min-height:44px; }   /* thumb target */
  .tp-go { min-height:44px; }
}
@media (prefers-reduced-motion:reduce) {
  .tp, .tp-scrim, .team-fab { transition:none; }
  .team-fab:hover, .team-fab:active { transform:none; }
}

/* ---- Panel tabs + boards (VS 2026-08-11) -------------------------------------------------------
   Tasks and Decisions were the last two rows of a sidebar on a page nobody opens mid-shift. As
   tabs they are one thumb-width from the chat, and they carry the only number that matters: what
   you owe. */
.tp-tabs { display:flex; gap:var(--s0); padding:var(--s2) var(--s3) 0; flex:0 0 auto;
  border-bottom:1px solid var(--line,#E4E7EE); }
.tp-tab { flex:1 1 0; min-width:0; background:none; border:0; cursor:pointer;
  /* -1px is a LAYOUT OFFSET, not rhythm: it pulls the active tab's 2px rule over the
     container hairline so the two do not stack into a 3px edge. Same carve-out class as
     the rail's documented -17.1px logo alignment — never snap it to the scale. */
  padding:var(--s3) var(--s2) var(--s3); border-bottom:2px solid transparent; margin-bottom:-1px;
  font:600 var(--t-mini)/1.2 inherit; color:var(--muted,#7A8296);
  display:flex; align-items:center; justify-content:center; gap:var(--s1); }
.tp-tab:hover { color:var(--navy,#1A2D5A); }
.tp-tab.on { color:var(--navy,#1A2D5A); border-bottom-color:var(--orange,#E7882F); }
.tp-tab-n { min-width:17px; height:17px; padding:0 var(--s1); border-radius:9px;
  background:var(--line,#E4E7EE); color:var(--navy,#1A2D5A);
  font:700 var(--t-micro)/17px var(--f-data,monospace); }
/* your own overdue work is the one number allowed to shout */
.tp-tab-n.mine { background:var(--orange,#E7882F); color:#fff; }

/* the composer and channel picker belong to the chat tab only */
.tp.tp-board .tp-send, .tp.tp-board .tp-chan { display:none; }

.tp-task, .tp-decision { padding:var(--s3) var(--s0); border-bottom:1px solid var(--line,#E4E7EE); }
.tp-task:last-child, .tp-decision:last-child { border-bottom:0; }
.tp-task.mine { border-left:0; background:rgba(231,136,47,.06); border-radius:8px;
  padding-left:var(--s3); padding-right:var(--s3); }
.tp-task.overdue .tm-od { color:#C4553D; }
.tp-task-main b { font-family:var(--f-data,monospace); color:var(--muted,#7A8296);
  margin-right:var(--s1); font-size:var(--t-mini); }
.tp-task-meta { display:block; margin-top:var(--s0); color:var(--muted,#7A8296);
  font-size:var(--t-mini); }
.tp-close summary { cursor:pointer; color:var(--muted,#7A8296); font-size:var(--t-mini);
  margin-top:var(--s1); }
.tp-close-f { display:flex; flex-wrap:wrap; gap:var(--s2); margin-top:var(--s2); }
.tp-close-f input { flex:1 1 10rem; min-width:0; }
.tp-decision { display:flex; gap:var(--s3); }
.tp-decision .tm-dnum { flex:0 0 auto; font:700 var(--t-mini)/1.6 var(--f-data,monospace);
  color:var(--amber-ink); }
.tp-decision .tm-dbody { margin:0; }
.tp-add { display:flex; flex-wrap:wrap; gap:var(--s2); margin:var(--s0) 0 var(--s3); }
.tp-add input[name="title"] { flex:1 1 11rem; min-width:0; }
.tp-add select { flex:0 1 8rem; min-width:0; }

/* ---- Composer + picker repair (VS 2026-08-11) --------------------------------------------------
   "Cant see the msg being typed, space needs to be fixed to write the msg."
   Cause: a GLOBAL `button.primary{width:100%}`. Inside the flex composer that made Send claim the
   whole row and starve the textarea to a sliver — the same trap .sendbox already had to undo.
   The textarea now also has a real minimum height: one line of type is not a message box. */
.tp-send button.primary { width: auto; margin: 0; padding: var(--s3) var(--s5);
  font-size: var(--t-ui); border-radius: 10px; flex: 0 0 auto; }
.tp-send textarea { flex: 1 1 auto; min-width: 0; min-height: 46px; }
/* focus is deliberately NOT restyled here: input/textarea:focus already resolves to a navy
   border app-wide, and :focus-visible to an orange ring. A local ring made this the one
   control in the Terminal that focuses differently from every other. */
/* the picker: optgroups need room to read as groups */
.tp-chan { padding: var(--s2) var(--s3); border-radius: 8px; }
.tp-chan optgroup { font-weight: 700; color: var(--muted,#7A8296); }
.tp-chan option { font-weight: 400; color: var(--navy,#1A2D5A); padding: var(--s0) 0; }

/* composer controls — Attach / Announce / Send (VS 2026-08-11, justified + symmetrical).
   The first pass bunched them left at three different heights: `margin-left:auto` on Send lost on
   specificity to an earlier `.tp-send button.primary{margin:0}`, so nothing pushed it right.
   Fixed by weight, not by !important — and the row is now a deliberate shape rather than three
   controls in a line: two equal anchors at the ends, the checkbox taking the slack between them. */
.tp-send textarea { flex: 1 1 100%; }
.tp-send-r { display: flex; align-items: stretch; gap: var(--s3); width: 100%; }
.tp-file-hidden { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* the two ends match: same width, same height, same radius — that is the symmetry */
.tp-send .tp-send-r .tp-attach,
.tp-send .tp-send-r .tp-go {
  flex: 0 0 104px; height: 40px; margin: 0; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 10px; font: 600 var(--t-ui)/1 inherit; cursor: pointer;
}
.tp-send .tp-send-r .tp-attach { background: #fff; color: var(--navy,#1A2D5A);
  border: 1.5px solid var(--line,#E4E7EE); }
.tp-send .tp-send-r .tp-attach:hover { border-color: var(--navy,#1A2D5A); }
/* an attached file must be visible BEFORE Send, not discovered after */
.tp-send .tp-send-r .tp-attach.has { border-color: var(--orange,#E7882F); color: var(--navy,#1A2D5A); }
.tp-send .tp-send-r .tp-go { background: var(--navy,#1A2D5A); color: #fff; border: 1.5px solid var(--navy,#1A2D5A); }

/* Announce sits at its natural width beside Attach; the SPACER below takes the slack, so the two
   ends stay pinned however wide the panel is. Letting the checkbox grow instead stretched a dashed
   box across half the composer, which read as an input rather than a toggle. */
.tp-send .tp-send-r .tp-announce {
  flex: 0 0 auto; min-width: 0; height: 40px; margin: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  border: 1.5px dashed var(--line,#E4E7EE); border-radius: 10px;
  font-size: var(--t-mini); color: var(--muted,#7A8296); white-space: nowrap; cursor: pointer;
}
.tp-send .tp-send-r .tp-announce:hover { border-color: var(--orange,#E7882F); color: var(--navy,#1A2D5A); }
.tp-send .tp-send-r .tp-announce input { margin: 0; }
/* the one flexible thing in the row — present whether or not Announce renders, so a caller's
   composer is the same shape as the owner's */
.tp-send-r::before { content: ""; flex: 1 1 auto; order: 1; }
.tp-send .tp-send-r .tp-announce { order: 0; }
.tp-send .tp-send-r .tp-go { order: 2; }
.tp-send .tp-send-r .tp-attach { order: -1; }

/* amber-ink, not orange: PRODUCT.md forbids orange as text (3.1:1), and this line is read
   in Dehradun sun by somebody checking their attachment went with the message */
.sec-act { float: none; margin-left: auto; }
.tp-file-name { flex: 1 1 100%; margin: var(--s1) 0 0; font-size: var(--t-mini); color: var(--amber-ink); }
@media (max-width: 640px) {
  /* every control in the sheet clears 44px — the tabs were ~33 and are pressed with a thumb
     standing at a doorstep, which is the whole reason this panel exists */
  .tp-tab { min-height: 44px; }
  .tp-close summary { min-height: 44px; display: flex; align-items: center; }
  .tp-send .tp-send-r .tp-attach, .tp-send .tp-send-r .tp-go,
  .tp-send .tp-send-r .tp-announce { height: 44px; }
  .tp-send .tp-send-r .tp-attach, .tp-send .tp-send-r .tp-go { flex-basis: 92px; }
}
/* a section heading that carries an action on its right — flex, not float: a floated control
   beside a heading escapes its line box and lands on whatever follows when the panel narrows */
h2.sec.sec-row { display: flex; align-items: center; gap: var(--s3); }

/* Computed parameters (036). A derived value must LOOK derived — a tech who cannot tell
   arithmetic from their own typing will eventually try to correct the arithmetic. */
input.fx-out{background:var(--paper-2,#f4f1ec);color:var(--ink);font-weight:600;cursor:not-allowed}
input.fx-out::placeholder{font-weight:500;color:var(--muted)}
input.fx-abn{border-color:var(--bad-ink);color:var(--bad-ink);font-weight:700}

/* ---- Trend popup (Phase 1 item 5) — the patient's own history for one parameter ---- */
/* .chip was written for a <span>; used as a button it needs the browser's own chrome removed. */
button.chip{border:1px solid transparent;cursor:pointer;font-family:inherit;line-height:1.4;margin-left:var(--s2)}
button.chip:hover{background:#dfe5f2}
.trendrow > td{padding:0 0 var(--s3);border-top:0}
.tr-card{margin:0;background:#FBFAF8}
.tr-card h3{margin:0 0 var(--s2);font-size:var(--t-name)}
.tr-svg{width:100%;height:auto;display:block;margin:var(--s2) 0 var(--s3)}
/* The reference band is the whole point of the chart: a line of numbers says nothing, a line
   leaving this patient's own normal range says the thing a clinician reads for. */
.tr-band{fill:var(--ok-ink);opacity:.10}
.tr-line{stroke:var(--navy);stroke-width:2;vector-effect:non-scaling-stroke}
.tr-dot{fill:var(--navy)}
.tr-dot.tr-abn{fill:var(--bad-ink)}
.tr-dot.tr-now{stroke:var(--navy);stroke-width:2;fill:#fff}
.tr-dot.tr-now.tr-abn{stroke:var(--bad-ink)}

/* ============================================================================================
   PAGE GRAMMAR (VS 2026-08-15) — "our forms feel generic".
   Flabs' screens are consistent because they have a grammar: a toolbar row, a right-hand drawer,
   a two-column field grid, a required-field mark. These are those primitives, defined once so the
   next Lab Management page inherits them instead of inventing its own layout again.
   ============================================================================================ */

/* THE CONTROL RESET THIS GRAMMAR DEPENDS ON.
   app.css sets `input,select,textarea{width:100%;margin-top:var(--s1);padding:var(--s4)}` globally
   — right for a stacked form, fatal in a toolbar: the search box and the role filter each took the
   full card width and stacked into a column three rows tall. Every control inside these components
   is sized by its container instead. */
.tbar :is(input,select),.dfield :is(input,select,textarea){width:auto;margin-top:0}
.tbar :is(input,select){height:var(--ctrl-h);padding:4px 11px;font-size:var(--t-ui);border:1px solid var(--line-input);border-radius:6px}
.tbar select{padding-right:var(--s5)}

/* Toolbar: title left, controls right, on ONE row. Wraps only on a phone. */
/* Measured on the reference 2026-08-25: the card toolbar is 16px padding with 16px between the
   search and the action group, and the group itself runs at 8px. Ours ran at 8px/8px/6px, which
   is why our toolbar read as a strip of controls and theirs reads as a band. */
.tbar{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s5);align-items:center;justify-content:space-between;
  padding:var(--s5);border-bottom:1px solid var(--line)}
/* The card title must outrank the table header beside it. At --t-name (17px) it read as
   another column heading; the reference sets it a clear step above. */
.tbar-title,.drawer-head h2,.modal-panel h2{font-family:var(--f-body);letter-spacing:0}
.tbar-title{margin:0;font-size:19px;line-height:1.3;font-weight:600;color:var(--ink);white-space:nowrap}
.tbar-actions{display:flex;flex-wrap:wrap;gap:var(--s3);align-items:center;margin:0;min-width:0}
.tbar .btn{height:32px;min-height:32px;padding:0 var(--s4)}
.tbar form{margin:0}
/* A TOOLBAR SELECT IS NOT A FIELD. A native <select> sizes itself to its widest OPTION, so the
   Referral List's centre filter measured 604px on a 1054px toolbar — one control eating 57% of
   the bar and pushing Add onto a third row. Their equivalent is a fixed 200px. Patient List had
   already learned this and fixed it for one select by name (.pl-actions select[name=gpanel]);
   106 makes it the rule for every toolbar select there will ever be. */
.tbar select{max-width:220px;text-overflow:ellipsis}
/* Toolbar search (Referral List). The reference leads its tabs with this and leads Manage User
   with nothing — so it is a component, used where that screen uses it, not a global. */
.tbar-search{position:relative;display:flex;align-items:center;flex:0 1 340px;min-width:220px}
.tbar-search svg{position:absolute;left:var(--s3);width:16px;height:16px;color:var(--muted);pointer-events:none}
.tbar-search input[type=search]{width:100%;padding-left:34px}
/* On a toolbar that already carries a segmented control, the search takes only what it needs
   instead of claiming a 340px basis and wrapping the buttons onto a second row. */
.tbar-search-sm{flex:0 1 220px;min-width:150px}
@media(max-width:820px){
  .tbar{flex-direction:column;align-items:stretch}
  .tbar-actions{width:100%}
  .tbar-search{flex:1 1 auto}
}

/* ---- TAB STRIP -------------------------------------------------------------------------------
   The reference's Referral List sits under six text tabs with a 2px underline on the active one —
   not pills, not buttons. .owner-tabs above is the pill treatment and is a different control; this
   one had to be its own, and conflating them is how a clone starts looking like a cousin. */
/* NO overflow-x HERE (106). One axis set to anything but `visible` forces the OTHER axis to
   compute `auto` — so `overflow-x:auto` on a strip whose tabs carry a -1px bottom margin gave
   every tab strip in the Terminal a 10-15px VERTICAL scrollbar, permanently, over content 1px
   taller than its box. It is the little grey slider sitting at the right of the tab row in VS's
   screenshots. The strip wraps; it never needed to scroll. Row gap is tight so a second line of
   tabs reads as the same strip continuing, not as a second control. */
.dtabs{display:flex;flex-wrap:wrap;gap:var(--s2) var(--s6);align-items:center;
  margin:0 0 var(--s5);border-bottom:1px solid var(--line);overflow-x:visible}
/* Measured on the reference: padding 0 0 8px, 24px between tabs, a 2px ink bar that hugs the LABEL
   (53px under a 53px "Test List", not the tab box), and BOTH states at the same weight — the active
   tab is marked by colour and the bar, never by going bold. Ours went 500 -> 600, which read as a
   different font on the same row. */
.dtab{position:relative;display:inline-flex;align-items:center;gap:var(--s2);
  padding:0 0 var(--s3);font-size:var(--t-ui);font-weight:500;color:var(--ink);
  text-decoration:none;white-space:nowrap;border-bottom:2px solid transparent;margin-bottom:-1px}
.dtab:hover{color:var(--navy)}
.dtab.on{color:var(--navy);border-bottom-color:var(--navy)}
.dtab-n{font-size:var(--t-mini);font-weight:600;color:var(--muted);
  background:#F1F0EC;border-radius:999px;padding:1px 6px}
.dtab.on .dtab-n{background:#E8ECF6;color:var(--navy)}

/* ---- SEGMENTED PILLS -------------------------------------------------------------------------
   The reference's Mapping sub-screen switches its four lists with a SEGMENTED CONTROL — one grey
   trough, the active choice a raised white pill — not the underlined .dtab strip the page above
   uses. Two different controls doing two different jobs: .dtab switches what the screen is about,
   .pill-tab filters within one thing.

   THIS BLOCK IS THE FIX FOR A REAL DEFECT (VS 2026-08-15): the markup shipped naming .pills and
   .pill-tab and neither rule existed, so the four tabs rendered as the bare words
   "B2B Doctor Hospital Phlebotomist" run together. Inventing a class name is not styling it, and
   the render tests passed because they assert text, which was present the whole time. */
.pills{display:inline-flex;align-items:center;gap:2px;padding:3px;margin:0;
  background:#F1F0EC;border-radius:10px}
.pill-tab{display:inline-flex;align-items:center;padding:var(--s2) var(--s4);border-radius:8px;
  font-size:var(--t-ui);font-weight:500;color:var(--muted);text-decoration:none;white-space:nowrap}
.pill-tab:hover{color:var(--ink)}
.pill-tab.on{background:#fff;color:var(--ink);font-weight:600;box-shadow:0 1px 2px rgba(38,48,63,.12)}

/* A wide table inside a card scrolls itself. The page body never scrolls sideways — nine columns
   on the doctor tab is past a laptop's width and the row must not push the rail off screen. */
.dscroll{overflow-x:auto}

/* THE EMPTY STATE LIVES INSIDE THE TABLE, under the headers — as it does on the reference, whose
   "No data" tray always sits below a full header row. Swapping the whole table out for a bare tray
   loses the column names, which are the only thing telling somebody what an empty list would even
   contain. */
.dempty-cell{padding:0}
.dempty-cell .dempty{border:0}

/* A form wrapping one control inside a table cell. Without this it is a block element and the row
   grows a line of its own height around every toggle. */
.switch-form{margin:0;display:inline-flex}

/* STATUS BADGES — the bulk-upload preview's Ready / Skipped, and anywhere a row states a binary
   outcome. Colour carries the meaning, but the WORD is what is read; these are never colour alone. */
.pill{display:inline-block;padding:2px var(--s3);border-radius:999px;
  font-size:var(--t-mini);font-weight:600;line-height:1.6}
.pill-on{background:#E8F4EC;color:var(--ok-ink,#1E6B3A)}
.pill-off{background:#F1F0EC;color:var(--muted)}

/* ---- ROW KEBAB --------------------------------------------------------------------------------
   The reference tucks Edit and Delete behind a ⋮ on the row. Built on <details> so it opens with
   no JavaScript under a CSP that refuses inline script; erp-marketing.js only closes the others.

   THIS BLOCK, AND .pills ABOVE, ARE THE SAME DEFECT VS CAUGHT: the markup shipped naming these
   classes and none of the rules existed. The kebab was worse than the pills because their account
   had no rows, so nothing rendered it and the screenshot could not show it. */
.kebab{position:relative;display:inline-block}
.kebab > summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;
  justify-content:center;width:32px;height:32px;border:1px solid var(--line);border-radius:8px;
  color:var(--muted);background:#fff}
.kebab > summary::-webkit-details-marker{display:none}
.kebab > summary:hover{border-color:var(--line-input);color:var(--ink)}
.kebab[open] > summary{border-color:var(--navy);color:var(--navy)}
.kebab-pop{position:absolute;right:0;top:calc(100% + 4px);z-index:30;min-width:150px;
  display:flex;flex-direction:column;padding:var(--s2);background:#fff;
  border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 24px rgba(38,48,63,.16)}
.kebab-pop form{margin:0}
.kebab-item{display:flex;align-items:center;gap:var(--s3);width:100%;padding:var(--s2) var(--s3);
  border:0;border-radius:6px;background:none;text-align:left;cursor:pointer;
  font:inherit;font-size:var(--t-ui);color:var(--ink)}
.kebab-item:hover{background:#F6F5F2}
.kebab-danger{color:var(--bad-ink)}
.kebab-danger:hover{background:#FDF5F5}
/* The price grid scrolls VERTICALLY inside the dialog, under a header that stays put. A catalogue
   of 200 tests whose column headings scroll away is 200 rows of unlabelled boxes. */
.dscroll-tall{overflow-y:auto;max-height:min(52vh,460px);border:1px solid var(--line);border-radius:8px}
.dscroll-tall .dtable thead th{position:sticky;top:0;z-index:1}

/* Tabs and a toolbar INSIDE a dialog: same grammar, no outer margin of their own. */
.dtabs-inset{margin:0;padding:0 var(--s5);gap:var(--s5)}
.tbar-inset{padding:var(--s4) var(--s5);border-bottom:0}
.modal-note{margin:0 var(--s5) var(--s4)}
/* The dialog's form is a flex column too, or the grid inside it cannot own the scroll — the same
   trap that stopped the Manage Users drawer scrolling: a plain block between a flex container and
   the overflow child defeats it, and min-height:auto stops it shrinking. */
.modal-panel > form{display:flex;flex-direction:column;flex:1;min-height:0}

/* ---- PRICE GRID -------------------------------------------------------------------------------
   Every row carries two editable cells. They are sized by the column, never by the global control
   reset, and they show their unit — the reference puts a rupee inside the price box and a percent
   sign after the commission box, which is the only thing telling you which of the two a bare "60"
   is about to become. */
.dtable-grid td{padding:var(--s2) var(--s4)}
/* The master price and what the cut is worth: read-outs, not inputs. Tabular figures so a column
   of money lines up, and quieter than the boxes between them — they are context, not the task. */
/* The commission column the mode does NOT store is still editable — typing in it fills its
   partner — but it is a consequence, not the agreement, and is drawn as one. */
.cell-derived{background:#FAFAF8}
.cell-derived input{color:var(--muted)}
.dtable-grid th .t-sub{display:inline;margin-left:var(--s2);font-weight:500;text-transform:none}
.cell-in{display:inline-flex;align-items:center;width:100%;max-width:260px;
  border:1px solid var(--line-input);border-radius:8px;background:#fff;overflow:hidden}
.cell-in:focus-within{border-color:var(--navy);box-shadow:0 0 0 2px rgba(38,48,63,.08)}
.cell-in input{width:100%;margin:0;border:0;height:36px;padding:0 var(--s3);
  font-size:var(--t-ui);background:transparent;font-variant-numeric:tabular-nums}
.cell-in input:focus{outline:none}
.cell-in::before,.cell-in::after{font-size:var(--t-mini);color:var(--muted);font-weight:600;
  background:#FAFAF8;align-self:stretch;display:flex;align-items:center;padding:0 var(--s3)}
.cell-rupee::before{content:"\20B9";border-right:1px solid var(--line-input)}
.cell-pct::after{content:"%";border-left:1px solid var(--line-input)}

/* The mode radio sits at the far left of the commit row, as on theirs. */
.drawer-foot-split{justify-content:space-between;align-items:center;flex-wrap:wrap;gap:var(--s4)}
.hint{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;
  border-radius:50%;border:1px solid var(--line-input);color:var(--muted);
  font-size:10px;font-weight:700;cursor:help;margin-left:2px}

/* Partner-login permission rows: label left, switch right, as on their dialog. */
.toggle-row{display:flex;align-items:center;gap:var(--s3);margin:0 0 var(--s4);font-size:var(--t-ui)}
.counter{display:block;text-align:right;font-size:var(--t-mini);font-variant-numeric:tabular-nums}

.upload-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3);
  padding:var(--s4) var(--s5);border-top:1px solid var(--line);background:#FAFAF8}
.upload-row input[type=file]{width:auto;margin:0}

/* Settlement, on the B2B board. Reference field and its commit on one line inside a table cell. */
.inline-settle{display:flex;gap:var(--s2);align-items:center;margin:0}
.inline-settle input{width:auto;margin:0;height:32px;padding:0 var(--s3);font-size:var(--t-mini);
  border:1px solid var(--line-input);border-radius:6px}

/* Pagination, bottom-right of the card — their control, and the honest place to say the list is
   longer than what is on screen. */
.dpager{display:flex;justify-content:flex-end;align-items:center;gap:var(--s2);
  padding:var(--s4) var(--s5)}
.dpager a,.dpager span{min-width:32px;height:32px;display:inline-flex;align-items:center;
  justify-content:center;border:1px solid var(--line);border-radius:6px;font-size:var(--t-mini);
  color:var(--ink);text-decoration:none}
.dpager .on{border-color:var(--navy);color:var(--navy);font-weight:700}
.dpager .off{color:var(--muted);border-color:var(--line-s);pointer-events:none}

/* ---- FORM GRAMMAR ---------------------------------------------------------------------------
   Matched field by field against the reference: the required mark sits BEFORE the label, labels are
   regular weight rather than bold, and no control is ever allowed to wrap its own text. Our first
   pass got all three wrong and the drawer read as a different product. */
/* THE THREE GAPS ARE MEASURED, not chosen. Flabs' form row is a flex at gap 20px/20px on both
   Lab Details and Doctor Details (read off getComputedStyle 2026-08-22), each field item 66px
   tall with a 24px margin under it, and 8px between a label and its control. The density pass
   had guessed 12/16 and 4, which is why our rows read as cramped beside theirs at the same
   control size: the boxes were right and the air between them was not. */
.fgrid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s6) 20px;margin-bottom:var(--s6)}
.fgrid > label,.dfield > label{display:flex;flex-direction:column;gap:8px;
  font-weight:400;font-size:var(--t-ui);color:var(--ink)}
/* VS 2026-09-04: every cell of the counter starts at the row's top — the base label rule's 8px
   top margin sat a labelled cell 8px below a div cell (Age / Gender / Dispatch), so no row read
   as one line. Address fills the line beside Dispatch Methods. */
.qk-card .fgrid label{margin-top:0}
.qk-card .fgrid > .f-addr{grid-column:2 / -1}
/* VS 2026-09-04: a doctor price above the Green Card member price on the rate-card grid */
.over-member{display:inline-block;margin-left:4px;vertical-align:middle;color:var(--warn,#b45309)}
/* VS 2026-09-04: a label in a split cell (the counter's first row, an .fpair) wears the same face */
.fgrid .qk-row1 > label,.fgrid .fpair > label{display:flex;flex-direction:column;gap:8px;
  font-weight:400;font-size:var(--t-ui);color:var(--ink)}
.fgrid :is(input,select),.dfield :is(input,select){width:100%;margin-top:0;height:var(--ctrl-h);
  padding:4px 11px;font-size:var(--t-ui);border:1px solid var(--line-input);border-radius:6px;
  background:#fff;color:var(--ink)}
.fgrid :is(input,select):focus,.dfield :is(input,select):focus{outline:none;border-color:var(--navy);
  box-shadow:0 0 0 3px rgba(26,45,90,.10)}
.fgrid input::placeholder,.dfield input::placeholder{color:#9AA4B0}
.fgrid select,.dfield select{padding-right:var(--s6);appearance:none;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%235A6B7D' stroke-width='1.6'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right var(--s4) center}
@media(max-width:720px){.fgrid{grid-template-columns:1fr}}

/* The required mark PRECEDES the label. */
.req-mark{color:var(--bad-ink);font-weight:700;margin-right:2px}

/* Checkbox and radio rows never wrap their own text — a three-line "Allow user to change password"
   beside a lone checkbox was the single most obvious tell that this was not a clone. */
.radios{display:flex;flex-wrap:wrap;gap:var(--s6);align-items:center;margin:0}
.rr{display:inline-flex;align-items:center;gap:var(--s3);font-weight:500;font-size:var(--t-ui);
  color:var(--ink);white-space:nowrap;cursor:pointer}
.rr input{margin:0;width:auto;height:auto;flex:0 0 auto;accent-color:var(--navy)}
.check-row{margin:0 0 var(--s4)}

/* Phone: a real country selector, not a static prefix. */
.phone{display:flex}
/* VS 2026-09-04: the fixed +91 prefix wears the old picker's seat */
.phone .phone-cc{display:flex;align-items:center;padding:0 12px;border:1px solid var(--line);border-right:0;border-radius:8px 0 0 8px;background:#F4F2EE;color:var(--muted);font-weight:600;white-space:nowrap}
.phone select{width:auto;flex:0 0 auto;border-radius:8px 0 0 8px;border-right:0;background-color:#F4F2EE;
  color:var(--ink);font-weight:600;padding-left:var(--s4);padding-right:var(--s6)}
.phone input{border-radius:0 8px 8px 0;flex:1;min-width:0}
.pw{display:flex;position:relative}
.pw input{flex:1;padding-right:2.6em}
.pw-eye{position:absolute;right:var(--s3);top:50%;transform:translateY(-50%);background:none;border:0;
  cursor:pointer;padding:var(--s1);display:flex;color:var(--muted);line-height:0}
input.locked{background:#F4F2EE;color:var(--muted)}

/* Section rule between drawer sections. */
.drawer-body .sec{margin:0 0 var(--s5);font-size:var(--t-name);font-weight:600;
  color:var(--ink);text-transform:none;letter-spacing:0;font-family:var(--f-body)}
.drawer-body .sec-split{border-top:1px solid var(--line);margin:var(--s6) calc(var(--s5) * -1) var(--s5);
  padding-top:var(--s6);padding-left:var(--s5);padding-right:var(--s5)}

/* TEST MASTERS (053) — the row controls their Test List has.
   The specimen swatch is the TUBE, which is the thing a phlebotomist reaches for; the colours are
   the real cap colours, so the cell is readable before the word is. */
.sw{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:var(--s2);
  vertical-align:-1px;border:1px solid rgba(0,0,0,.14)}
.sw-gold{background:#D9A441} .sw-lav{background:#B9A7DA} .sw-grey{background:#9AA4B0}
.sw-blue{background:#6E93D6} .sw-red{background:#C96A5E} .sw-amber{background:#E3C05A}
.sw-none{background:transparent;border-style:dashed}

/* Price edits in place. The rupee sits inside the box so the number starts where every other
   number in the column starts — a prefix outside the field pushes each row's digits to a
   different x-position as soon as one price is four figures. */
/* inline-flex, and specific enough to beat `.dtable form{display:inline}` further down the file.
   It did not: the form fell back to inline, max-width stopped applying to it, and the 100%-wide
   input wrapped onto a second line under the rupee sign. Every price cell in the catalogue has
   been two lines tall, which is most of why our rows measured 85 against their 61. */
/* WIDTH, not max-width. As an inline-flex item with only a max, the cell shrank to whatever the
   tightened column gave it -- 66px -- and every single price in the catalogue rendered clipped:
   "2000" needed 46px of a 44px box. Theirs is a ~124px cell around an 83px input; this matches. */
.pricecell,.dtable .pricecell{display:inline-flex;align-items:center;gap:0;width:124px}
.dtable .pricecell input{margin:0}
.pricecell .rs{padding:0 var(--s1) 0 var(--s3);color:var(--muted);font-size:var(--t-ui);
  border:1px solid var(--line-input);border-right:0;border-radius:6px 0 0 6px;height:32px;
  display:flex;align-items:center;background:#fff}
.pricecell input{height:32px;flex:1;width:auto;min-width:0;border:1px solid var(--line-input);border-left:0;
  border-radius:0 6px 6px 0;padding:0 var(--s2);font-size:var(--t-ui);font-variant-numeric:tabular-nums;
  text-align:right;background:#fff;color:var(--ink)}
.pricecell input:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 3px rgba(26,45,90,.10)}

/* Interpretation is a checkbox on their screen, and a checkbox that posts is a button here — the
   CSP forbids the inline handler that would submit a real <input type=checkbox>. */
.chk{width:18px;height:18px;border:1.5px solid var(--line-input);border-radius:4px;background:#fff;
  cursor:pointer;padding:0;display:inline-block;position:relative}
.chk:hover{border-color:var(--navy)}
.chk.on{background:var(--navy);border-color:var(--navy)}
.chk.on::after{content:'';position:absolute;left:5px;top:1px;width:4px;height:9px;
  border:solid #fff;border-width:0 2px 2px 0;transform:rotate(43deg)}
.chk:focus-visible{outline:2px solid var(--navy);outline-offset:2px}

/* Pager — their footer control: arrows, a window of pages, an ellipsis, first and last. */
.pager{display:flex;gap:var(--s2);align-items:center;justify-content:flex-end;
  padding:var(--s4) 0 0;flex-wrap:wrap}
.pg{min-width:32px;height:32px;padding:0 var(--s2);display:inline-flex;align-items:center;
  justify-content:center;border:1px solid var(--line);border-radius:6px;background:#fff;
  color:var(--ink);text-decoration:none;font-size:var(--t-ui);font-variant-numeric:tabular-nums}
.pg:hover{border-color:var(--navy);color:var(--navy)}
.pg.on{background:var(--navy);border-color:var(--navy);color:#fff;font-weight:600}
.pg.off{opacity:.4;pointer-events:none}
.pg-gap{color:var(--muted);padding:0 var(--s1)}

/* Permission checklist (051, Roles). Grouped so the reader scans a department at a time rather
   than one flat column of twenty-eight boxes, and two-up because every label is short. The group
   heading is quiet on purpose — it names a section, it is not a field. */
.permgroup{margin:0 0 var(--s5)}
.permgroup-h{margin:0 0 var(--s3);font-size:var(--t-mini);font-weight:700;color:var(--muted);
  text-transform:uppercase;letter-spacing:.04em}
.permgrid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3) var(--s5)}
/* .rr sets white-space:nowrap so a checkbox never orphans its text; inside this grid the cell is
   the width limit instead, so the label wraps rather than overflowing the panel. */
.permgrid .rr{white-space:normal;align-items:flex-start}
@media(max-width:720px){.permgrid{grid-template-columns:1fr}}

/* ---- ONE TABLE SKIN — their proportions, our ink -----------------------------------------------
   106 (VS: "copy the style of all the tables everywhere in our terminal"). Until now the Terminal
   shipped THREE table grammars: .dtable (71 tables, this skin), .atable (69 tables, 13px with
   uppercase Space Grotesk heads and no column rules) and .tbl (18 tables in Workforce — a class
   name with NO CSS RULE AT ALL, so every one of them rendered as a browser-default table). Same
   screen family, three different products. They are one skin now; .tbl is retired in the views.

   MEASURED on the reference 2026-08-25 (lab.flabslis.com/organisation, one row of real data):
     th  #FAFAFA, padding 12px 8px, 14px/22 w500, border-bottom AND border-right 1px #F0F0F0
     td  padding 8px all round, 14px/22 w400, border-bottom AND border-right 1px #F0F0F0,
         and the LAST row keeps its bottom rule — the table closes with a line, it does not fade out
   THE COLUMN RULE IS THE POINT (VS: "rows are not seperated by a line like in flabs ... it is
   easier to read data like that"). A cell that touches its neighbour with nothing between them
   makes the eye do the column-finding; one hairline does it for free. Ours are warm (--line-s)
   rather than their neutral grey, and the header keeps the heavier --line beneath it so the head
   still reads as the boundary it is. */
.card.card-flush{padding:0;overflow:hidden}
.dtable,.atable{width:100%;border-collapse:collapse;font-size:var(--t-ui);
  font-family:var(--f-body);letter-spacing:0}
/* Measured: their header is 14px/500 with 12px 8px padding, cells 8px all round, and a two-line
   row lands at 61px. Ours was 700 with 8px/16px padding and rows at 85 — a third taller, which is
   what made our table look like a different product beside theirs. */
/* 106d — 12px OF HORIZONTAL PADDING, not 8. Measured on the reference's REGISTER (not its referral
   list, which runs at 8): cells are 10px 12px. Once a column has a rule down its side, 8px puts
   the text within a hair of it and eleven columns read as one block — VS: "congested and crammed,
   give every column their space to breathe". The 4px per side is what separates the ink from the
   rule, and it is the cheapest legibility there is. */
.dtable thead th,.atable thead th{text-align:left;font-family:var(--f-body);font-weight:500;
  font-size:var(--t-ui);color:var(--ink);background:#FAFAF8;
  padding:var(--s4);border-bottom:1px solid var(--line);border-right:1px solid var(--line-s);
  white-space:nowrap;text-transform:none;letter-spacing:0}
.dtable td,.atable td{padding:10px var(--s4);border-bottom:1px solid var(--line-s);
  border-right:1px solid var(--line-s);vertical-align:middle}
/* The rule on the last cell of a row would double the card's own edge in a flush card and float
   free of anything in a padded one. The grid is bounded by the card, as it is on theirs. */
.dtable thead th:last-child,.atable thead th:last-child,
.dtable td:last-child,.atable td:last-child{border-right:0}
.dtable tbody tr:hover,.atable tbody tr:hover{background:#FBFAF8}
/* Their two-line name cell is 14px/22 on BOTH lines — the code is not a caption, it is the same
   size in grey. Both lines at lh 22 + 8px padding top and bottom is exactly the 61px row. */
.dtable td b,.atable td b{font-weight:500}
.dtable td,.atable td{line-height:22px}
/* A <th> used as a ROW label (books-reports, books-gst: label/value grids with no thead) is not a
   column head — it keeps the head's weight and loses its fill, or a two-column grid reads as one
   long header. */
.dtable tbody th,.atable tbody th{text-align:left;font-weight:500;color:var(--ink);
  padding:10px var(--s4);border-bottom:1px solid var(--line-s);border-right:1px solid var(--line-s)}
.dtable .t-sub{display:block;color:var(--muted);font-size:var(--t-ui);font-weight:400;line-height:22px}
.dtable .t-inline{color:var(--muted);font-size:var(--t-mini);font-weight:500;margin-left:var(--s2);white-space:nowrap}
.dtable .t-act{display:flex;gap:var(--s2);align-items:center;white-space:nowrap}
.dtable form{display:inline;margin:0}

/* Row actions are OUTLINE BUTTONS with icons, and Delete is red — not neutral chips. */
/* Their row Edit measures 62x28 with a 4px radius — smaller radius than the toolbar, not the same. */
.btn-sm{height:28px;min-height:28px;padding:0 var(--s3);font-size:var(--t-tight);gap:var(--s2);border-radius:4px}
.btn-danger{color:var(--bad-ink);border-color:#E9C4C4}
.btn-danger:hover{border-color:var(--bad-ink);background:#FDF5F5}
/* Icon-only row controls. The reference's Edit and Delete are square glyph buttons; ours carried
   the words and pushed the nine-column doctor row past the card. */
.btn-icon{padding:0;width:32px;min-width:32px;height:32px;min-height:32px;
  display:inline-flex;align-items:center;justify-content:center}
/* The Commission column's [+ Add] — an outline button, quieter than the primary Login beside it. */
.btn-add{gap:var(--s2)}
/* Bulk Price Edit: outlined in the brand navy on the reference, between the plain Export and the
   solid Add. It is the loudest thing on that toolbar that is not the primary action. */
.btn-outline{color:var(--navy);border-color:var(--navy)}
.btn-outline:hover{background:#F2F4FA}
/* A close control that has to POST (it clears server-held wizard state) still sits as one glyph. */
.drawer-x-form{margin:0;display:flex}

/* LOGIN ACCESS TOGGLE. Their control is a switch, not a word — the state is the affordance. */
.switch{display:inline-flex;align-items:center;border:0;background:none;padding:0;cursor:pointer}
.switch-track{width:40px;height:22px;border-radius:999px;background:#CBD2DA;position:relative;
  transition:background .15s ease;display:inline-block}
.switch-track::after{content:"";position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;
  background:#fff;transition:transform .15s ease;box-shadow:0 1px 2px rgba(0,0,0,.25)}
.switch[aria-checked="true"] .switch-track{background:var(--navy)}
.switch[aria-checked="true"] .switch-track::after{transform:translateX(18px)}

/* Empty state — their centred tray, our grey. */
.dempty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s2);
  padding:var(--s8) var(--s5);color:var(--muted)}
.dempty svg{opacity:.35}
.radios{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s4);align-items:center;margin:0}
.rr{display:inline-flex;align-items:center;gap:var(--s2);font-weight:500}
.rr input{margin:0}

/* Phone field with a fixed country prefix, as on every Flabs form. */
.phone{display:flex}
/* VS 2026-09-04: the fixed +91 prefix wears the old picker's seat */
.phone .phone-cc{display:flex;align-items:center;padding:0 12px;border:1px solid var(--line);border-right:0;border-radius:8px 0 0 8px;background:#F4F2EE;color:var(--muted);font-weight:600;white-space:nowrap}
.phone-cc{display:flex;align-items:center;padding:0 var(--s3);border:1px solid var(--line-input);
  border-right:0;border-radius:8px 0 0 8px;background:#F4F2EE;color:var(--muted);font-size:var(--t-tight);white-space:nowrap}
.phone input{border-radius:0 8px 8px 0}
.pw{display:flex;position:relative}
.pw input{flex:1;padding-right:2.4em}
.pw-eye{position:absolute;right:.3em;top:50%;transform:translateY(-50%);background:none;border:0;
  cursor:pointer;font-size:1rem;line-height:1;padding:.2em .3em}
input.locked{background:#F4F2EE;color:var(--muted)}

/* RIGHT-HAND DRAWER. Flabs uses one for Add User rather than a centred modal, and it is the right
   shape for a long two-section form: the list stays visible behind it. Full width on a phone. */
.drawer{position:fixed;inset:0;background:rgba(38,48,63,.38);z-index:60;display:flex;justify-content:flex-end}
.drawer[hidden]{display:none}
body.drawer-open{overflow:hidden}
.drawer-panel{background:#fff;width:min(46rem,100%);height:100%;display:flex;flex-direction:column;
  box-shadow:-8px 0 32px rgba(38,48,63,.18)}
.drawer-head{display:flex;align-items:center;gap:var(--s3);padding:var(--s4) var(--s5);border-bottom:1px solid var(--line)}
.drawer-head h2{margin:0;font-size:var(--t-name)}
.drawer-x{background:none;border:0;font-size:1.5rem;line-height:1;cursor:pointer;color:var(--muted);padding:0 .2em}
.drawer-body{padding:var(--s4) var(--s5);overflow-y:auto;flex:1}
.drawer-foot{display:flex;justify-content:flex-end;gap:var(--s2);padding:var(--s4) var(--s5);border-top:1px solid var(--line)}
.btn-primary{background:var(--navy);color:#fff;border-color:var(--navy)}

/* SUB-RAIL, DESKTOP ONLY (VS 2026-08-15). Flabs' rail expands a group into its pages; ours may do
   the same for the lab surfaces, which are workstation work. It must not reach a phone: the field,
   camp and phlebo logins navigate section-first, and that was the whole reason for the 08-14
   rail-to-page change. Both shapes are in the markup; this picks one, so no script is involved. */
.nav-sub .side-link{padding-left:var(--s6)}
@media(max-width:820px){
  /* The Lab Management group's children are desktop-only (VS 2026-08-15). Its phone fallback link
     was removed on 08-15, so below this width the group renders nothing at all — deliberate while
     these are workstation screens, and the reason the phlebo/sales app is a separate build. */
  .nav-desk{display:none}
}

/* CENTRED MODAL — Flabs uses one for every Add dialog and for the bulk wizard; the drawer is
   reserved for Add User, which is the only form long enough to need it. Same backdrop, so both
   dismiss identically. */
.drawer.modal{align-items:center;justify-content:center;padding:var(--s4)}
.modal-panel{background:#fff;border-radius:12px;width:min(46rem,100%);max-height:90vh;
  display:flex;flex-direction:column;box-shadow:0 12px 40px rgba(38,48,63,.24)}
.modal-panel .drawer-head{justify-content:space-between}
.modal-panel .drawer-body{padding:var(--s5)}
/* A single-column form is a NARROW modal on the reference — roughly 33rem, not the 46rem the bulk
   wizard needs for its preview table. At the wider size the labels sit a third of a screen from
   their inputs and the dialog reads as a page, which is the difference we were called on. */
.modal-narrow .modal-panel{width:min(33rem,100%)}
/* The price grid is a four-column table over the whole catalogue — it gets the room theirs has. */
.modal-wide .modal-panel{width:min(72rem,100%)}
.dfield select[multiple]{width:100%;margin-top:0;padding:var(--s2);height:auto;min-height:110px;
  max-height:150px;border:1px solid var(--line-input);border-radius:6px;background-image:none;
  font-size:var(--t-ui)}
.dfield select[multiple] option{padding:var(--s2) var(--s3);border-radius:6px}

/* Wizard step rail. */
.steps{display:flex;list-style:none;margin:0 0 var(--s5);padding:0;gap:var(--s3);align-items:center}
.steps li{display:flex;align-items:center;gap:var(--s2);color:var(--muted);font-size:var(--t-tight);
  font-weight:600;flex:1}
.steps li::after{content:"";flex:1;height:1px;background:var(--line)}
.steps li:last-child::after{display:none}
.steps li span{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  border-radius:999px;background:var(--line-s);color:var(--muted);font-weight:700;flex:0 0 auto}
.steps li.on{color:var(--navy)} .steps li.on span{background:var(--navy);color:#fff}
.steps li.done span{background:var(--ok-ink);color:#fff}

.dropzone{border:2px dashed var(--line-input);border-radius:12px;padding:var(--s6) var(--s5);
  text-align:center;background:#FBFAF8;margin-bottom:var(--s4)}
.dropzone p{margin:0 0 var(--s2)}
.dropzone input[type=file]{width:auto;margin:var(--s2) auto;display:block}
.tmpl{display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  background:#F4F6FB;border-radius:10px;padding:var(--s4);margin-bottom:var(--s4)}
@media(max-width:640px){.tmpl{flex-direction:column;align-items:flex-start}}

/* ==============================================================================================
   PERMANENT TOP BAR (VS 2026-08-15) — the reference's fixed header, cloned to its metrics.
   64px tall, full width, above everything, present on every page. The rail and the content both
   start beneath it, which is the structural difference from what we had: our rail used to own the
   full height and carry the mark.
   ============================================================================================== */
:root{--topbar-h:64px}
.topbar{position:fixed;top:0;left:0;right:0;height:var(--topbar-h);z-index:60;display:flex;
  align-items:center;gap:var(--s4);padding:0 var(--s5);background:#fff;border-bottom:1px solid var(--line)}
.topbar :is(input,select){margin-top:0}

.tb-burger,.tb-icon{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;
  border-radius:8px;border:1px solid transparent;background:none;color:var(--ink);cursor:pointer;
  flex:0 0 auto;position:relative;text-decoration:none;padding:0}
.tb-burger svg,.tb-icon svg{width:20px;height:20px}
.tb-icon{border-color:var(--line)}
.tb-burger:hover,.tb-icon:hover{background:#F4F2EE}

.tb-brand{display:flex;align-items:center;flex:0 0 auto;height:100%}
.tb-brand img{height:26px;width:auto;display:block}

/* Their search is the widest thing on the bar and it anchors the whole layout. */
.tb-search{position:relative;flex:1 1 auto;max-width:560px;margin:0}
.tb-search svg{position:absolute;left:var(--s4);top:50%;transform:translateY(-50%);
  width:17px;height:17px;color:var(--muted);pointer-events:none}
.tb-search input{width:100%;height:40px;padding:0 var(--s4) 0 42px;border:1px solid var(--line-input);
  border-radius:8px;font-size:var(--t-ui);background:#fff}
.tb-search input:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 3px rgba(26,45,90,.10)}

.tb-right{display:flex;align-items:center;gap:var(--s3);margin-left:auto;flex:0 0 auto}
.tb-centre select{height:40px;padding:0 var(--s6) 0 var(--s4);border:1px solid var(--line-input);
  border-radius:8px;font-size:var(--t-ui);background:#fff;color:var(--ink);appearance:none;width:auto;
  max-width:15rem;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%235A6B7D' stroke-width='1.6'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right var(--s4) center}

.tb-who{display:flex;align-items:center;gap:var(--s2);white-space:nowrap}
.tb-avatar{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;
  border-radius:50%;background:var(--navy);color:#fff;font-size:var(--t-mini);font-weight:700;flex:0 0 auto}
.tb-name{font-size:var(--t-tight);font-weight:600;color:var(--ink)}
.tb-sep{width:1px;height:24px;background:var(--line);flex:0 0 auto}

/* Their Help sits in a tinted pill rather than as a bare icon — it is the one control on the bar
   aimed at somebody who is stuck, and it reads as available rather than as chrome. */
.tb-pill{display:inline-flex;align-items:center;gap:var(--s2);height:38px;padding:0 var(--s4);
  border-radius:8px;font-size:var(--t-tight);font-weight:600;text-decoration:none;border:1px solid transparent}
.tb-pill svg{width:17px;height:17px}
.tb-help{background:#EEF1F8;color:var(--navy)}
.tb-help:hover{background:#E3E8F4}
.tb-dot{position:absolute;top:-4px;right:-4px;min-width:17px;height:17px;padding:0 4px;border-radius:999px;
  background:var(--orange);color:#fff;font-size:10px;font-weight:700;display:flex;align-items:center;
  justify-content:center;line-height:1}
.tb-out{margin:0;display:flex}

/* Everything sits BELOW the bar now. */
.signed-in .sidebar{top:var(--topbar-h)}
.signed-in .content{padding-top:var(--topbar-h)}
.signed-in .drawer{top:0}

/* On a phone the bar keeps the burger, the mark and the essential controls; the search and the
   centre selector drop rather than shrink into unusable slivers. */
@media(max-width:820px){
  :root{--topbar-h:56px}
  .tb-search,.tb-centre,.tb-name,.tb-sep{display:none}
  .topbar{padding:0 var(--s3);gap:var(--s2)}
  .tb-brand img{height:22px}
}

/* The rail's top band went with the mark and the collapse chevron (2026-08-15). Its first group
   starts under the bar, and the logo lives above in the header — the reference's arrangement. */
.side-nav{padding-top:var(--s4)}
.topbar .tb-brand img{height:45px}

/* PROFILE MENU on the top bar — the reference's avatar dropdown. Built on <details>, so it needs
   no script and cannot be broken by the CSP that already refuses inline JS. */
.tb-menu{position:relative}
.tb-menu>summary{display:flex;align-items:center;gap:var(--s2);height:40px;padding:0 var(--s2);
  border-radius:8px;cursor:pointer;list-style:none;white-space:nowrap}
.tb-menu>summary::-webkit-details-marker{display:none}
.tb-menu>summary:hover{background:#F4F2EE}
.tb-chev{width:11px;height:8px;color:var(--muted);flex:0 0 auto;transition:transform .15s ease}
.tb-menu[open] .tb-chev{transform:rotate(180deg)}
.tb-pop{position:absolute;right:0;top:calc(100% + 8px);z-index:70;min-width:19rem;background:#fff;
  border:1px solid var(--line);border-radius:12px;box-shadow:0 10px 30px rgba(38,48,63,.16);overflow:hidden}
.tb-pop-id{padding:var(--s4) var(--s5);border-bottom:1px solid var(--line-s);display:flex;flex-direction:column;gap:2px}
.tb-pop-id b{font-size:var(--t-ui);color:var(--ink)}
.tb-pop-id span{font-size:var(--t-mini);color:var(--muted)}
.tb-pop-row{margin:0;border-bottom:1px solid var(--line-s)}
.tb-pop-row:last-child{border-bottom:0}
.tb-pop-lens{display:flex;gap:var(--s2);align-items:center;padding:var(--s3) var(--s4)}
.tb-pop-lens select{flex:1;min-width:0;height:36px;margin-top:0;padding:0 var(--s3);font-size:var(--t-tight);
  border:1px solid var(--line-input);border-radius:8px;background:#fff}
.tb-pop-btn{display:flex;align-items:center;gap:var(--s3);width:100%;padding:var(--s4) var(--s5);
  background:none;border:0;font:inherit;font-size:var(--t-ui);color:var(--ink);text-align:left;cursor:pointer}
.tb-pop-btn svg{width:17px;height:17px;color:var(--muted);flex:0 0 auto}
.tb-pop-btn:hover{background:#F4F2EE}
@media(max-width:820px){.tb-menu>summary .tb-chev{display:none}}

/* THE DRAWER'S FORM MUST BE PART OF THE FLEX COLUMN, not a plain block sitting between the panel
   and its body. The panel is a flex column and .drawer-body carries flex:1 + overflow-y:auto — but
   the <form> in between defaulted to display:block, so the body had no constrained height to
   overflow against and simply grew past the bottom of the screen with no scrollbar. Anything below
   Role & Permissions was unreachable.
   min-height:0 is the other half: a flex child's default min-height:auto refuses to shrink below
   its content, which silently defeats overflow on both the form and the body. */
.drawer-panel > form{display:flex;flex-direction:column;flex:1;min-height:0}
.drawer-body{min-height:0}
.modal-panel > .drawer-body{min-height:0}
.drawer-foot{flex:0 0 auto}

/* ================================================================================================
   PROCESSING LAB and COLLECTION CENTRES (049)

   Every class name below is used by views/erp/labs.ejs, views/erp/centres.ejs or
   views/erp/centre-form.ejs. That is not a coincidence and it is not decoration: the Mapping
   screen shipped naming .pills and .pill-tab with neither rule written, so four tabs rendered as
   run-together words. tests/css-classes-exist.test.js now fails the build for exactly that, and
   these three views are inside its scope.
   ============================================================================================= */

/* The Exports dropdown. It is a <details> like the row kebab, but its summary is a full button
   rather than three dots, so the kebab's own summary border and padding have to give way. */
/* flex:0 0 auto is the whole fix for a real defect: .tbar-actions is a flex row and .kebab is a
   plain inline-block, so this item shrank below the width of its own summary and the Add button
   next to it sat on top of the word "Exports". Nothing errored, every class existed, and the
   class guard passed — a wrong RULE is invisible to a spelling check. Only the live browser
   showed it. white-space:nowrap keeps the label and its chevron on one line at any width. */
.kebab-menu{flex:0 0 auto}
/* width:auto IS THE FIX. The base .kebab > summary is a 32px SQUARE — it was built for three dots,
   and a fixed width is exactly right for that. Overriding padding and height but not width left
   the word "Exports" overflowing a 32px box, so the Add button beside it rendered on top. The
   class existed, the rule existed, and the class guard passed: what was wrong was an inherited
   value, which no static check can see. The browser found it; measuring the box, not guessing at
   it, found the cause. */
.kebab-menu > summary{gap:var(--s2);padding:0 var(--s4);width:auto;height:38px;border-radius:8px;
  white-space:nowrap;color:var(--ink);font-weight:500;font-size:var(--t-ui)}
.kebab-menu[open] > summary{background:#F6F5F2}
.kebab-menu .kebab-pop{min-width:170px}

/* ---- THE FULL-PAGE FORM. Their add-collection-center is a page of stacked fieldsets, not a
   dialog, so it gets page furniture rather than drawer furniture. ---- */
.formpage{margin:0 0 var(--s6)}
.fsec{margin-bottom:var(--s5)}
.fsec-head{margin:0 0 var(--s5);font-family:var(--f-body);font-size:var(--t-name);font-weight:600;
  letter-spacing:0;color:var(--ink)}
.fsec .fgrid:last-of-type{margin-bottom:0}

/* .fgrid is two columns by default. Their detail rows are four across and their credentials row
   is three, and a four-across grid on a laptop is the single biggest difference between a form
   that looks cloned and one that looks like a questionnaire. */
.fgrid-3{grid-template-columns:repeat(3,1fr)}
/* minmax(0,1fr), not 1fr. A bare 1fr is minmax(auto,1fr), so one cell with a wide
   min-content steals width from the other three — the registration row rendered with a
   490px First Name beside a 167px Gender until this was pinned. */
.fgrid-4{grid-template-columns:repeat(4,minmax(0,1fr))}
@media(max-width:1100px){.fgrid-4{grid-template-columns:repeat(2,1fr)}}
@media(max-width:860px){.fgrid-3{grid-template-columns:repeat(2,1fr)}}
@media(max-width:720px){.fgrid-3,.fgrid-4{grid-template-columns:1fr}}

/* A textarea inside .fgrid must not inherit the 44px height every input gets. */
/* A TEXTAREA IS A CONTROL, and took none of the control's measurements: 8px/12px padding and an
   8px corner beside every input's 4px/11px and 6px, and a blanket 84px floor that beat the rows=
   the view asked for. Flabs' own Degree box measures 297x54 -- two rows at the input's padding.
   So the rows attribute governs the height now, with a two-line floor under it, and the padding
   and corner are the ones measured off their controls. (Found in the browser: the Add Doctor
   Degree box rendered 84 tall at 8px padding while its neighbour input was 32 at 4px 11px.) */
.fgrid textarea{width:100%;min-height:54px;padding:4px 11px;font:inherit;
  font-size:var(--t-ui);border:1px solid var(--line-input);border-radius:6px;background:#fff;
  color:var(--ink);resize:vertical}
.fgrid textarea:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 3px rgba(26,45,90,.10)}
.fgrid textarea::placeholder{color:#9AA4B0}
.fgrid input[readonly]{background:#F6F5F2;color:var(--muted)}

/* The quiet line under a field that explains a rule rather than labelling a control. */
.fhint{font-size:var(--t-mini);color:var(--muted);font-weight:500;line-height:1.45}
/* A label for a control that is not a single input — a slider pair, a file button, a picker. */
.flabel{font-weight:500;font-size:var(--t-ui);color:var(--ink)}

/* ACTIVE STATE. Their form's switch is a form FIELD, not the post-on-click button the list rows
   use, so it is a checkbox wearing the same track. Sharing .switch-track markup was tempting and
   wrong: that track is positioned by a button's aria-checked, and a checkbox has no such thing. */
.fswitch{gap:var(--s3);align-items:flex-start}
.switch-check{appearance:none;-webkit-appearance:none;width:40px;height:22px;flex:0 0 auto;
  border-radius:999px;background:#CBD2DA;border:0;position:relative;cursor:pointer;
  transition:background .15s ease;margin:0}
.fgrid .switch-check{width:40px;height:22px;padding:0}
.switch-check::after{content:"";position:absolute;top:2px;left:2px;width:18px;height:18px;
  border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .15s ease}
.switch-check:checked{background:var(--navy)}
.switch-check:checked::after{transform:translateX(18px)}
.switch-check:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(26,45,90,.18)}

/* A checkbox and its text on one line, never wrapping under the box. */
.checkrow{display:inline-flex;align-items:center;gap:var(--s3);font-weight:500;
  font-size:var(--t-ui);color:var(--ink);cursor:pointer;margin:0}
.checkrow input[type=checkbox]{width:18px;height:18px;flex:0 0 auto;margin:0;accent-color:var(--navy)}
.fsec > .checkrow{margin-top:var(--s2)}

/* ---- THE LETTERHEAD BLOCK, revealed by its checkbox. ---- */
.lhblock{margin-top:var(--s5);padding-top:var(--s5);border-top:1px solid var(--line)}
.lhblock[hidden]{display:none}
.lhfile{display:flex;flex-direction:column;gap:var(--s2)}
.lhfile-row{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap}

/* "Click to Upload" is a label wrapping a hidden file input, so the whole button is the target
   and no script is needed to make it one. */
.upbtn{position:relative;overflow:hidden;cursor:pointer}
.upbtn input[type=file]{position:absolute;inset:0;opacity:0;width:100%;cursor:pointer}
.upbtn-name{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--muted);font-weight:500}

/* The stored file, shown as their form shows it: a bordered row with a thumbnail glyph and a bin. */
.upchip{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s4);
  border:1px solid var(--line-input);border-radius:8px;background:#fff;font-size:var(--t-ui);
  color:var(--ink);max-width:320px}
.upchip svg{color:var(--navy);flex:0 0 auto}
.upchip span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.upchip-x{background:none;border:0;padding:var(--s1);cursor:pointer;color:var(--muted);
  display:inline-flex;border-radius:6px}
.upchip-x:hover{color:var(--bad-ink);background:#FDF5F5}

/* Margin: a track and a number box that move together. The number box carries the field name, so
   the value posts whether or not the script that links them ever ran. */
.sliderfield{display:flex;flex-direction:column;gap:var(--s2)}
.sliderrow{display:flex;align-items:center;gap:var(--s4)}
.sliderrow input[type=range]{flex:1;min-width:0;height:22px;padding:0;accent-color:var(--navy);
  background:none;border:0}
.sliderrow input[type=number]{width:72px;flex:0 0 auto}

/* The Referral Doctors picker: All, then the named list it disables. */
.scopefield{display:flex;flex-direction:column;gap:var(--s3)}
.scopefield select[multiple]{width:100%;height:auto;padding:var(--s2);font-size:var(--t-ui);
  border:1px solid var(--line-input);border-radius:8px;background:#fff;color:var(--ink);
  appearance:none;background-image:none}
.scopefield select[multiple]:disabled{background:#F6F5F2;color:var(--muted)}
.scopefield select[multiple] option{padding:var(--s2) var(--s3)}

/* Save alone at the bottom right, as on their page. */
.formfoot{display:flex;justify-content:flex-end;gap:var(--s2);margin-bottom:var(--s6)}

/* ---- THE CENTRE LEDGER (049, rebuilt) and the Preview Report modal ---------------------------- */

/* A page title with its subtitle, outside a card — the ledger opens on the record's identity
   rather than straight into a form, the way the cloned screens open on their toolbar. */
.pagehead{margin:0 0 var(--s5)}
.pagehead .tbar-title{white-space:normal}
.pagehead .fhint{margin-top:var(--s2)}
/* A code, a UTR, a date range: an identifier standing beside a name, never competing with it. */
.t-code{font-size:var(--t-mini);font-weight:500;color:var(--muted);letter-spacing:.2px}

/* A button that has to sit on the baseline of a grid of labelled fields. Without this it aligns to
   the top of the row and floats level with the labels instead of the inputs. */
.fswitch-end{display:flex;align-items:flex-end}

/* Mark-paid is a field and a button on one line inside a table cell, and it must not wrap: the
   Action column is the narrowest on the widest table in the ERP. */
/* `.dtable .paidform` as well as the bare class, the .pricecell precedent. This form sits in a
   settlement row and at (0,1,0) it lost to `.dtable form{display:inline}` — the reference input
   wrapped under the button, exactly as the price cell did. Found by the guard in
   css-classes-exist.test.js while it was being written for the same bug in 062. */
.paidform,.dtable .paidform{display:flex;gap:var(--s2);align-items:center;margin:0}
.paidform input{width:8.5em;height:32px;margin-top:0;padding:0 var(--s3);font-size:var(--t-tight);
  border:1px solid var(--line-input);border-radius:8px;background:#fff;color:var(--ink)}
.paidform input:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 3px rgba(26,45,90,.10)}

/* THE PREVIEW REPORT MODAL. The sheet is 595pt wide and 842 tall, so the frame is sized to show a
   whole A4 page at once on a laptop and to scroll on anything shorter. Sealed in an iframe: the
   report carries its own stylesheet and must not inherit this one, nor leak into it. */
.lhframe{flex:1;min-height:0;display:flex;background:#525659}
.lhframe iframe{flex:1;width:100%;height:min(78vh,900px);border:0;display:block}

/* Preview Report is its own column at the right of the letterhead row, level with Click to Upload
   — on theirs it stands apart from the upload control rather than crowding it. Bottom-aligned so
   it lines up with the buttons beside it, not with the labels above them. */
.lhpreview{display:flex;align-items:flex-end;justify-content:flex-end}

/* A hint that follows a flush table needs the padding the card itself gave up. */
.pad-fhint{padding:var(--s4) var(--s5) var(--s5)}

/* A WIDE TABLE MUST SCROLL, NOT COMPRESS.
   .dtable is width:100% and .dscroll is overflow-x:auto, which between them do nothing for an
   eleven-column table: the table obediently fits the container by crushing its first column, so
   the network board rendered "Test fixture 2066596 — erp-network test run, cannot be removed"
   down a six-line ribbon while numeric columns sat half empty. min-width gives the table a floor
   to refuse below, and only then does the scroller have anything to scroll. Applied by opt-in,
   because the five-column screens are correct as they are. */
.dtable-wide{min-width:1080px}
.dtable-wide td:first-child,.dtable-wide th:first-child{min-width:230px}
/* Numbers are read by comparison down a column, so they get no more room than they need and the
   name column keeps what is left. */
.dtable-wide td:not(:first-child):not(:nth-child(2)):not(:last-child){white-space:nowrap}

/* A record's identifying facts under its title: values, separated, in the record's own words.
   Not a sentence about the record — see the prose sweep of 2026-08-15. */
.metaline{margin:var(--s2) 0 0;font-size:var(--t-mini);color:var(--muted);font-weight:500}
.metasep{opacity:.55;margin:0 var(--s1)}
.pagehead-act{margin:var(--s3) 0 0}

/* ================================================================================================
   A CENTRE'S DASHBOARD (050) — stat cards, donuts and bars, drawn without a charting library.
   The CSP is script-src 'self' with no unsafe-inline, so every chart here is SVG or CSS rendered
   from the same numbers the tables print. It cannot disagree with them, and it prints.
   ============================================================================================= */

.pagehead-split{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s5);flex-wrap:wrap}
.daterange{display:flex;align-items:center;gap:var(--s2);margin:0;flex:0 0 auto}
.daterange input[type=date]{height:38px;margin-top:0;padding:0 var(--s3);font-size:var(--t-tight);
  border:1px solid var(--line-input);border-radius:8px;background:#fff;color:var(--ink)}
.daterange input[type=date]:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 3px rgba(26,45,90,.10)}
.daterange-sep{color:var(--muted)}

/* Six cards across, wrapping to three and then two. auto-fit rather than a fixed count: at six
   columns on a laptop the money values were wrapping inside their own card. */
/* SIX ACROSS, as on theirs. auto-fit with a 180px floor gave five and orphaned Due Cleared onto
   a second row, which reads as a different kind of card rather than the sixth of six. */
.statrow{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--s3);margin-bottom:var(--s5)}
@media(max-width:1400px){.statrow{grid-template-columns:repeat(3,1fr)}}
@media(max-width:760px){.statrow{grid-template-columns:repeat(2,1fr)}}
.statcard{background:#fff;border:1px solid var(--line);border-radius:12px;padding:var(--s4);min-width:0}
.statcard-h{font-size:var(--t-mini);font-weight:600;color:var(--muted);letter-spacing:.3px}
.statcard-v{font-size:24px;line-height:1.2;font-weight:700;color:var(--navy);margin:var(--s2) 0 var(--s3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.statcard-s{display:flex;justify-content:space-between;gap:var(--s3);font-size:var(--t-mini);
  color:var(--muted);padding:2px 0}
.statcard-s b{color:var(--ink);font-weight:600}

/* Two panels side by side, stacking on a narrow screen. */
.panelrow{display:grid;grid-template-columns:1fr 1fr;gap:var(--s4);margin-bottom:var(--s5)}
@media(max-width:940px){.panelrow{grid-template-columns:1fr}}

/* ---- the donut. One <circle> per slice, dashed to its share. ---- */
.donutrow{display:flex;align-items:center;gap:var(--s6);flex-wrap:wrap}
.donut{width:140px;height:140px;flex:0 0 auto;transform:rotate(-90deg)}
.dn-track{fill:none;stroke:#EEF0F3;stroke-width:16}
.dn-slice{fill:none;stroke-width:16}
.dn-total{transform:rotate(90deg);transform-origin:70px 70px;font:700 22px/1 var(--f-body,inherit);
  fill:var(--navy)}
.dn-a{stroke:#1A2D5A} .dn-b{stroke:#2E6FBF} .dn-c{stroke:#0D8F8F} .dn-d{stroke:#E3A008}

.legend{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--s2);min-width:150px}
.legend-row{flex-direction:row;gap:var(--s6);margin-top:var(--s4)}
.legend li{display:flex;align-items:center;gap:var(--s3);font-size:var(--t-ui);color:var(--ink)}
.legend .lg-l{flex:1;color:var(--muted)}
.legend b{font-weight:600}
.lg-dot{width:10px;height:10px;border-radius:50%;flex:0 0 auto}
.lg-a{background:#1A2D5A} .lg-b{background:#2E6FBF} .lg-c{background:#0D8F8F} .lg-d{background:#E3A008}
.lg-paid{background:#2E9E5B} .lg-due{background:#D64545} .lg-test{background:#1A2D5A}

/* ---- the bar charts. Flex columns, heights as percentages of the tallest bar. ---- */
.bars{display:flex;align-items:flex-end;gap:var(--s2);height:180px;padding-top:var(--s3)}
.bar-col{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;gap:var(--s2);height:100%}
.bar-stack{flex:1;width:100%;display:flex;align-items:flex-end;justify-content:center;gap:3px}
/* A zero bar still gets a sliver: an empty day must read as measured-and-nothing, not as missing. */
.bar{width:42%;max-width:22px;min-height:2px;border-radius:3px 3px 0 0;display:block}
.bar-paid{background:#2E9E5B} .bar-due{background:#D64545} .bar-test{background:#1A2D5A}
.bar-x{font-size:var(--t-micro);color:var(--muted);white-space:nowrap}

/* The totals row on a dashboard table reads as a sum, not as one more row. */
.dtable tr.dtotal td,.atable tr.dtotal td{border-top:1.5px solid var(--line-input);font-weight:600;background:#FAFAF8}

/* The date range as its own row above the panels, right-aligned — on the network board and the
   centre dashboard both, since they share one partial. */
.daterange-bar{justify-content:flex-end;margin-bottom:var(--s4)}

/* Nine sample states, not four — the donut legend covers the whole status domain (see the note in
   centredash.js). Distinct enough to tell apart at 10px, and the two exception states are greyed
   and red rather than joining the pipeline's colour run. */
.dn-e{stroke:#7A5FBF} .dn-f{stroke:#0D8F8F} .dn-g{stroke:#2E9E5B}
.dn-x{stroke:#D64545} .dn-y{stroke:#9AA4B0}
.lg-e{background:#7A5FBF} .lg-f{background:#0D8F8F} .lg-g{background:#2E9E5B}
.lg-x{background:#D64545} .lg-y{background:#9AA4B0}

/* Three cards, not six — the ledger's Earnings answers a narrower question than the dashboard. */
.statrow-3{grid-template-columns:repeat(3,1fr)}
@media(max-width:760px){.statrow-3{grid-template-columns:1fr}}
/* A liability that is not zero. The only card on any of these screens that changes colour: an
   activity figure is neither good nor bad, but money owed and not yet settled is a state. */
.statcard-warn{border-color:rgba(227,160,8,.55);background:#FFFCF5}
.statcard-warn .statcard-v{color:var(--amber-ink,#A15E08)}

/* TEST SEQUENCE (054) — the reference's two-pane ordering modal. Spec: erp/TEST-MASTERS-CLONE-SPEC.md */
/* MEASURED OFF THE LIVE REFERENCE, 2026-08-16 at a 1440px viewport — every number below was read
   off their DOM, not judged from a screenshot:
     panel 880x562, radius 8, mask rgba(0,0,0,.45), 24px inset
     header: NO rule under it, title 16px/600 (ours was 22/700 — half again too big)
     footer: NO rule over it
     rows 63px pitch, checkbox 16, number box 72x30, name 14px/22
   Ours was 1180 wide, which at VS's window width hit the 100% branch and went full-bleed. A fixed
   880 cannot do that. */
.seqmodal{position:fixed;inset:0;background:rgba(0,0,0,.45);display:flex;align-items:center;
  justify-content:center;z-index:60;padding:var(--s5)}
.seqpanel{background:#fff;border-radius:8px;
  box-shadow:0 6px 16px rgba(0,0,0,.08),0 3px 6px -4px rgba(0,0,0,.12),0 9px 28px 8px rgba(0,0,0,.05);
  width:min(880px,100%);max-height:min(562px,90vh);display:flex;flex-direction:column;overflow:hidden}
.seqhead{display:flex;align-items:center;justify-content:space-between;padding:var(--s6) var(--s6) var(--s5)}
.seqhead h2{margin:0;font-size:16px;font-weight:600;letter-spacing:0}
.seqx{font-size:26px;line-height:1;color:var(--muted);text-decoration:none;padding:0 var(--s2)}
.seqx:hover{color:var(--ink)}
/* Two panes, split by a hairline. Each scrolls on its own — the reference scrolls the department
   column past 23 rows while the test column stays where it was. */
.seqbody{display:grid;grid-template-columns:46fr 54fr;flex:1;min-height:0}
.seqcol{overflow-y:auto;padding:0 var(--s6)}
.seqcol-r{border-left:1px solid var(--line);display:flex;flex-direction:column;padding:0}
/* PINNED, as on theirs: the rows scroll underneath this, it does not scroll away. Their search box
   is the same 32px control as every other input on the screen, not the 48px one we drew. */
.seqsearch{position:sticky;top:0;background:#fff;padding:0 var(--s6) var(--s4);z-index:1}
.seqsearch input{width:100%;height:32px;border:1px solid var(--line-input);border-radius:6px;
  padding:0 var(--s3);font-size:var(--t-ui);background:#fff;color:var(--ink)}
.seqlist{overflow-y:auto;padding:0 var(--s6) var(--s4);flex:1}
.seqempty{color:var(--muted);padding:var(--s6) 0;text-align:center}
/* 63px pitch: a 30px control with 16px above and below plus the hairline. */
.seqrow{display:flex;align-items:center;gap:var(--s4);padding:var(--s5) 0;border-bottom:1px solid var(--line-soft)}
.seqrow:last-child{border-bottom:0}
.seqrow:hover,.seqrow.on{background:#FAFAF8}
/* Six dots in a 2x3 grid — the drag affordance. Ordering is by number today; the handle is drawn
   because the row reads wrong without it, and it is not wired to a drag it cannot yet perform. */
.grip{flex:0 0 auto;width:10px;height:16px;background-image:radial-gradient(currentColor 1.4px,transparent 1.5px);
  background-size:5px 5px;color:#B7BDC7;opacity:.9}
.seqpick{flex:0 0 auto;width:16px;height:16px;border:1px solid var(--line-input);border-radius:4px;
  background:#fff;display:inline-block;position:relative}
.seqpick.on{background:var(--navy);border-color:var(--navy)}
.seqpick.on::after{content:'';position:absolute;left:5px;top:1px;width:4px;height:8px;
  border:solid #fff;border-width:0 2px 2px 0;transform:rotate(43deg)}
.seqname{flex:1;min-width:0;font-size:var(--t-ui);line-height:22px}
/* Number and tick read as ONE control split in two — shared height, touching borders. 72x30 total,
   matching their box exactly. */
.seqset{display:flex;align-items:center;flex:0 0 auto}
.seqset input{width:44px;height:30px;text-align:center;font-variant-numeric:tabular-nums;
  border:1px solid var(--line-input);border-radius:6px 0 0 6px;border-right:0;font-size:var(--t-ui);
  background:#fff;color:var(--ink);padding:0;margin:0}
.seqset input:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 2px rgba(26,45,90,.10)}
.seqok{width:28px;height:30px;border:1px solid var(--line-input);border-radius:0 6px 6px 0;
  background:#fff;color:var(--navy);cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}
.seqok svg{width:16px;height:16px}
.seqok:hover{background:#F4F6FB}
.seqfoot{display:flex;justify-content:flex-end;padding:var(--s5) var(--s6) var(--s6)}
/* Thin scrollbars — theirs are unobtrusive; ours were the full native bar with arrows. */
.seqcol::-webkit-scrollbar,.seqlist::-webkit-scrollbar{width:6px}
.seqcol::-webkit-scrollbar-thumb,.seqlist::-webkit-scrollbar-thumb{background:#D6D2CA;border-radius:3px}
.seqcol::-webkit-scrollbar-track,.seqlist::-webkit-scrollbar-track{background:transparent}
.seqcol,.seqlist{scrollbar-width:thin;scrollbar-color:#D6D2CA transparent}
@media(max-width:820px){.seqbody{grid-template-columns:1fr}.seqcol-r{border-left:0;border-top:1px solid var(--line)}}

/* MASS UPDATE PRICE (055) — their "Edit Test Price". Measured on the live reference 2026-08-16:
   panel 420x271 radius 8, 24px inset, title 16px/600, body text 14px/22 in #595959, and two
   170x32 buttons stacked and centred — Download outlined in the accent at radius 6, Upload a
   DASHED #b2b2b2 at radius 4. The dashed border is the affordance that says "drop a file here",
   so it is cloned rather than tidied into a second solid button. */
.masspanel{width:min(420px,100%);max-height:none}
.masshead{padding:var(--s6) var(--s6) var(--s4);border-bottom:1px solid var(--line)}
.massbody{padding:var(--s5) var(--s6) var(--s6);display:flex;flex-direction:column;align-items:center;
  gap:var(--s4);overflow-y:auto}
.massinfo{display:flex;gap:var(--s3);align-items:flex-start;margin:0 0 var(--s2);font-size:var(--t-ui);
  line-height:22px;color:#595959;text-align:left}
.massinfo svg{flex:0 0 auto;margin-top:2px;color:#8C8C8C}
.masswide{display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  width:170px;height:32px;font-size:var(--t-ui);font-weight:500;text-decoration:none;cursor:pointer;
  background:#fff;line-height:1.2}
.massdl{border:1px solid var(--navy);border-radius:6px;color:var(--navy)}
.massdl:hover{background:#F2F4FA}
.massupl{border:1px dashed var(--line-input);border-radius:4px;color:var(--ink);position:relative}
.massupl:hover{border-color:var(--navy);color:var(--navy)}
.massupl input[type=file]{position:absolute;inset:0;opacity:0;width:100%;cursor:pointer}
.massup{display:flex;flex-direction:column;align-items:center;gap:var(--s3);margin:0}
.massgo{width:170px}   /* the <noscript> fallback submit — same width as the two real buttons */

/* Step two is a different shape from step one — it carries a table, so the panel grows. */
.masspanel-wide{width:min(880px,100%);max-height:min(640px,90vh)}
.masspanel-wide .massbody{align-items:stretch;text-align:left}
.masssum{margin:0;font-size:var(--t-ui);line-height:22px}
.masscounts{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:var(--s2) var(--s5);
  font-size:var(--t-ui);color:var(--muted)}
.masscounts b{color:var(--ink);font-weight:600}
.mc-go b{color:var(--navy)}
.mc-warn b{color:var(--bad-ink,#A23A3A)}
.massscroll{overflow:auto;max-height:320px;border:1px solid var(--line);border-radius:6px}
.massscroll::-webkit-scrollbar{width:6px;height:6px}
.massscroll::-webkit-scrollbar-thumb{background:#D6D2CA;border-radius:3px}
.massnum{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.massnew{font-weight:600;color:var(--navy)}
.massskip summary{cursor:pointer;font-size:var(--t-ui);color:var(--muted);padding:var(--s2) 0}
.massskip[open] summary{margin-bottom:var(--s3)}
.massfoot{gap:var(--s3)}
.massfoot form{margin:0}

/* DEPARTMENT MASTER (062) — the Department List tab.
   The tab's own toolbar sits in .tbar-actions beside the others, so it inherits their 32px control
   height and gaps rather than inventing a second bar grammar two tabs along. Only the Add form
   needs a rule of its own: it is a POST among links, so it must not stack. */
.dmAdd{display:flex;align-items:center;gap:var(--s2);margin:0}
.dmAdd input{width:190px;margin:0}
/* The editor is the modal this screen already opens twice. Two forms, one act each.
   NARROWER THAN .seqpanel's 880px default: two short fields stretched across it gave a department
   name a 760px box, which reads as a paragraph field and puts the Rename button a screen away from
   the text it renames. */
.dmEdPanel{width:min(520px,100%)}
.dmEd{padding:var(--s5);display:flex;flex-direction:column;gap:var(--s4)}
.dmEdRow{display:flex;align-items:flex-end;gap:var(--s3);margin:0}
.dmEdRow label{flex:1;margin:0}
/* 32px, the height .teF gives every control on this screen. A button left at the default sits a
   step proud of the box beside it on an align-items:flex-end row. */
.dmEdRow .btn{flex:0 0 auto;height:32px;min-height:32px}
.dmEdStat{margin:0;padding-top:var(--s3);border-top:1px solid var(--line);color:var(--muted);
  font-size:var(--t-tight)}
.dmEdStat b{color:var(--ink);font-weight:600}
/* The assign screen's per-row picker. Same 32px control as the rest of the clone; without this it
   inherits the global input rule and every row is 70px tall. */
.dmAssign select{width:100%;max-width:260px;height:32px;margin:0;padding:0 var(--s2);
  font-size:var(--t-ui);border:1px solid var(--line-input);border-radius:6px}
.dmAssign select:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 2px rgba(26,45,90,.10)}

/* TEST MAPPING (063) — their three toolbar checkboxes, and the alias chips.
   The count rides inside the label so the operator knows what a filter will show before ticking
   it; theirs makes you tick to find out. */
.mfChk{display:inline-flex;align-items:center;gap:var(--s2);margin:0;height:40px;padding:0 var(--s3);
  border:1px solid var(--line-input);border-radius:8px;background:#fff;font-size:var(--t-ui);
  font-weight:500;color:var(--ink);white-space:nowrap;cursor:pointer}
.mfChk input{width:15px;height:15px;margin:0;accent-color:var(--navy);flex:0 0 auto}
.mfChk:has(input:checked){border-color:var(--navy);background:#F4F6FB}
.mfN{color:var(--muted);font-variant-numeric:tabular-nums}
/* An alias is a chip with its own remove form — inline-flex so the × sits beside the word rather
   than under it, and scoped nowhere near a .dtable, which is where that goes wrong. */
.mapAliases{display:flex;flex-wrap:wrap;gap:var(--s2);align-items:center;min-height:32px}
.mapChip{display:inline-flex;align-items:center;gap:var(--s1);margin:0;background:#eef1f8;
  border-radius:999px;padding:var(--s0) var(--s1) var(--s0) var(--s3);font-size:var(--t-mini);
  font-weight:700;color:var(--navy)}
.mapX{border:0;background:transparent;color:var(--navy);font-size:16px;line-height:1;
  padding:0 var(--s2);cursor:pointer;opacity:.55}
.mapX:hover{opacity:1;color:var(--red)}
/* An alias that only repeats the test's own name. Shown, because hiding it would leave an operator
   asking why a test with visible chips still reads "not mapped" — but never mistaken for one that
   maps something. */
.chip-dim,.mapChip.chip-dim{background:#F2F1EE;color:var(--muted);font-weight:500}
.mapChip.chip-dim .mapX{color:var(--muted)}

/* TEST EDIT (055) — their Edit screen. Same 32px controls and 14px/22 type as the rest of the
   clone; what is specific here is the field GRID, which on the reference is a flowing row of
   labelled controls rather than a two-column form, and the two-pane parameter block below it. */
.teCard{padding:0}
.teHead{display:flex;align-items:center;justify-content:space-between;gap:var(--s4);flex-wrap:wrap;
  padding:var(--s5) var(--s5) var(--s4);border-bottom:1px solid var(--line)}
.teName{margin:0;font-size:18px;font-weight:600;letter-spacing:-.01em}
.teActs{display:flex;gap:var(--s2);flex-wrap:wrap}
/* auto-fit rather than a fixed column count: their grid reflows and the field widths are driven
   by the controls, not by a 12-column skeleton. */
.teGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:var(--s4) var(--s4);
  padding:var(--s5);margin:0;align-items:start}
.teF{display:flex;flex-direction:column;gap:var(--s2);min-width:0;margin:0;border:0;padding:0}
.teF>span,.teF>legend,.teLbl{font-size:var(--t-ui);color:var(--ink);font-weight:500;padding:0}
.teF .req::after,.req::after{content:' *';color:var(--bad-ink,#A23A3A)}
.teF input,.teF select,.teF textarea{height:32px;border:1px solid var(--line-input);border-radius:6px;
  padding:0 var(--s3);font-size:var(--t-ui);background:#fff;color:var(--ink);width:100%;margin:0}
.teF textarea{height:auto;padding:var(--s2) var(--s3);line-height:22px;resize:vertical}
.teF input:focus,.teF select:focus,.teF textarea:focus{outline:none;border-color:var(--navy);
  box-shadow:0 0 0 2px rgba(26,45,90,.10)}
.teF-wide{grid-column:span 2}
/* display:block, not flex. `.teF` sets flex-direction:column, and a modifier that only re-declares
   `display:flex` inherits that column — which is why the gender radios and the flag checkboxes
   rendered as a stacked list instead of the reference's single inline row. A legend is a block and
   the controls are inline, so block is what this actually wants. */
.teF-gender,.teF-req{display:block}
.teF-gender>legend,.teF-req>legend{font-size:var(--t-ui);font-weight:500;margin-bottom:var(--s2);padding:0}
.teRadio,.teCk{display:inline-flex;align-items:center;gap:var(--s2);font-size:var(--t-ui);
  line-height:22px;white-space:nowrap;cursor:pointer;margin:0 var(--s4) var(--s2) 0}
.teRadio input,.teCk input{margin:0;width:16px;height:16px;accent-color:var(--navy)}
.teF-req{grid-column:span 2}
/* the loose flags are one row across the whole grid, as on theirs */
.teF-flags{grid-column:1/-1;display:block}
.teF-pre{display:flex;flex-direction:column;gap:var(--s2);align-items:flex-start}
.teF-pre .btn{white-space:normal;height:auto;min-height:32px;text-align:left}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---- the parameter block: their table left, their field editor right ---- */
.teFields{padding:0;margin-top:var(--s5)}
/* ---- COMPARTMENTS (VS 2026-08-16) -----------------------------------------------------------
   Native <details>, so the disclosure needs no script the CSP would refuse. A closed section
   still states what is in it, which is the whole point: folded, not hidden. */
.teSec{border-top:1px solid var(--line)}
.teSec:first-of-type{border-top:0}
.teSec>summary{display:flex;align-items:baseline;gap:var(--s3);flex-wrap:wrap;cursor:pointer;
  padding:var(--s4) var(--s5);list-style:none;user-select:none}
.teSec>summary::-webkit-details-marker{display:none}
/* The caret is drawn rather than left to the browser's default marker, which differs per engine
   and cannot be positioned. It turns on open, so the state is legible without reading the text. */
.teSec>summary::before{content:"";width:0;height:0;flex:none;align-self:center;
  border-left:5px solid var(--muted);border-top:4px solid transparent;border-bottom:4px solid transparent;
  transition:transform .12s ease}
.teSec[open]>summary::before{transform:rotate(90deg)}
.teSec>summary:hover{background:#FAFAF8}
.teSec>summary:focus-visible{outline:2px solid var(--navy);outline-offset:-2px}
.teSecName{font-size:var(--t-ui);font-weight:600;color:var(--navy)}
.teSecMeta{font-size:var(--t-mini);color:var(--muted);font-variant-numeric:tabular-nums}
.teSec>.teGrid,.teSec>.teEdGrid{padding:0 var(--s5) var(--s5)}
.teForm{margin:0}

/* What this test still needs, in four chips. State, not description. */
.teReady{display:flex;gap:var(--s2);flex-wrap:wrap;margin:0 0 var(--s3)}
.teChip{font-size:var(--t-mini);font-weight:600;border-radius:999px;padding:2px var(--s3);
  border:1px solid var(--line);background:#fff;color:var(--muted)}
.teChip.ok{background:rgba(46,158,91,.10);border-color:rgba(46,158,91,.45);color:#1e7a44}
.teChip.warn{background:#FFFCF5;border-color:rgba(227,160,8,.45);color:#A15E08}
.teChip.bad{background:rgba(214,69,69,.10);border-color:rgba(214,69,69,.45);color:#b03535}

/* The field editor's own compartments and its pinned footer. */
.teEdHead{display:flex;flex-direction:column;gap:var(--s3);padding:var(--s4) var(--s5) var(--s4)}
.teEdTitle{margin:0;font-size:var(--t-body);font-weight:600}
.teEdGrid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3)}
.teEdGrid .teSpan{grid-column:1/-1}
.teCkList{display:flex;flex-direction:column;gap:var(--s2)}
.teEdFoot{position:sticky;bottom:0;background:#fff;border-top:1px solid var(--line);
  display:flex;justify-content:flex-end;gap:var(--s2);padding:var(--s3) var(--s5);margin-top:0}

.teCols{display:grid;grid-template-columns:minmax(0,1fr) 380px;align-items:start}
.teTable{min-width:0;padding:var(--s4)}
.teEditor{border-left:1px solid var(--line);padding:0}
.teEd{display:flex;flex-direction:column;gap:0;margin:0}
.teEditor{position:sticky;top:var(--s4)}
.teRow2{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3)}
.teEdFoot{display:flex;justify-content:flex-end;gap:var(--s2);margin-top:var(--s2)}
.teOff{opacity:.45;pointer-events:none}
.teOn td{background:#F4F6FB}
.teMove{white-space:nowrap;display:flex;gap:2px}
.teOrd{display:inline;margin:0}
.teArrow{width:24px;height:24px;border:1px solid var(--line-input);border-radius:4px;background:#fff;
  color:var(--navy);cursor:pointer;font-size:12px;line-height:1;padding:0}
.teArrow:disabled{opacity:.35;cursor:not-allowed}
.teArrow:hover:not(:disabled){background:#F4F6FB}
.teDel{width:28px;height:28px;border:1px solid #E9C4C4;border-radius:4px;background:#fff;
  color:var(--bad-ink,#A23A3A);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0}
.teDel:hover{background:#FDF5F5}

/* ---- the two modals this screen opens ---- */
.teTextPanel{width:min(720px,100%);max-height:min(560px,90vh)}
.teTextForm{display:flex;flex-direction:column;flex:1;min-height:0;margin:0}
.teTextForm textarea{flex:1;margin:0 var(--s6);border:1px solid var(--line-input);border-radius:6px;
  padding:var(--s3);font:inherit;font-size:var(--t-ui);line-height:22px;resize:vertical;color:var(--ink)}
.teRangePanel{width:min(980px,100%);max-height:min(620px,90vh)}
.teBand{display:flex;flex-direction:column;gap:var(--s3);margin:var(--s5) 0 0;
  border-top:1px solid var(--line);padding-top:var(--s4)}
.teBandRow{display:flex;flex-wrap:wrap;gap:var(--s2);align-items:center}
.teBandRow input,.teBandRow select{height:32px;border:1px solid var(--line-input);border-radius:6px;
  padding:0 var(--s3);font-size:var(--t-ui);width:104px;background:#fff;color:var(--ink);margin:0}
.teBandRow input[name=range_text]{width:200px}
.teBandLbl{font-size:var(--t-ui);color:var(--muted);min-width:44px}

.teNote{grid-column:1/-1;margin:0;font-size:var(--t-ui);color:var(--muted);line-height:22px}

/* Copy from existing test — their header search, rendered as a GET plus a POST per row. */
.teCopy{display:flex;gap:var(--s2);align-items:center;margin:0;flex:1 1 260px;max-width:420px}
.teCopy input{flex:1;min-width:0;height:32px;border:1px solid var(--line-input);border-radius:6px;
  padding:0 var(--s3);font-size:var(--t-ui);background:#fff;color:var(--ink);margin:0}
.teCopyHits{padding:var(--s4) var(--s5) 0;display:flex;flex-direction:column;gap:var(--s2)}
.teCopyHits>p{margin:0}
.teCopyRow{display:flex;align-items:center;gap:var(--s4);margin:0;padding:var(--s2) var(--s3);
  border:1px solid var(--line);border-radius:6px;background:#fff}
.teCopyRow:hover{border-color:var(--navy);background:#FAFAF8}
.teCopyName{flex:1;min-width:0;font-size:var(--t-ui);line-height:20px}
.teCopyName .t-sub{display:block;color:var(--muted);font-size:var(--t-mini)}
.teCopyN{font-size:var(--t-ui);color:var(--muted);white-space:nowrap}

/* Create a new test — their chooser. Cards are equal-width and centred under the heading. */
.tcWrap{max-width:1040px;margin:0 auto;text-align:center;padding:var(--s7) 0 var(--s8)}
.tcTitle{margin:0;font-size:28px;font-weight:600;letter-spacing:-.02em}
.tcSub{margin:var(--s2) 0 var(--s7);color:var(--muted);font-size:var(--t-body)}
.tcCards{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:var(--s5);text-align:center}
.tcCard{border:1px solid var(--line);border-radius:10px;background:#fff;padding:var(--s6) var(--s5);
  display:flex;flex-direction:column;align-items:center;gap:var(--s3)}
.tcCard:hover{border-color:var(--navy);box-shadow:var(--sh-s)}
.tcIcon{width:56px;height:56px;border-radius:50%;background:#EEF1F9;color:var(--navy);
  display:flex;align-items:center;justify-content:center;margin-bottom:var(--s2)}
.tcName{margin:0;font-size:19px;font-weight:600}
.tcBlurb{margin:0;color:var(--muted);font-size:var(--t-ui);line-height:22px}
.tcNote{margin:var(--s2) 0 0;background:#FFFCF5;border:1px solid rgba(227,160,8,.45);border-radius:6px;
  padding:var(--s3);font-size:var(--t-ui);line-height:20px;color:var(--amber-ink,#A15E08);text-align:left}
.tcGo{margin-top:auto;padding-top:var(--s4);color:var(--navy);font-weight:500;font-size:var(--t-ui);
  text-decoration:none}
.tcGo:hover{text-decoration:underline}
.tcOff{color:var(--muted);cursor:not-allowed;text-decoration:none}
.tcOff:hover{text-decoration:none}

/* Create from PDF — their three-step wizard. The stepper is the only chrome; each step is one
   card so the operator's eye lands on the one decision that step is asking for. */
.pdfWrap{max-width:1040px;margin:0 auto;padding:var(--s6) 0 var(--s8);text-align:center}
.pdfSteps{list-style:none;margin:var(--s5) 0 var(--s6);padding:0;display:flex;justify-content:center;
  gap:var(--s6);flex-wrap:wrap}
.pdfStep{display:flex;align-items:center;gap:var(--s2);font-size:var(--t-ui);color:var(--muted)}
.pdfStep span{width:22px;height:22px;border-radius:50%;border:1px solid var(--line-input);
  display:inline-flex;align-items:center;justify-content:center;font-size:var(--t-mini);font-weight:600}
.pdfStep.on{color:var(--navy)}
.pdfStep.on span{border-color:var(--navy);background:var(--navy);color:#fff}
.pdfStep.did span{background:#EEF1F9;color:var(--navy)}
.pdfCard{max-width:760px;margin:0 auto;text-align:left;padding:var(--s6)}
.pdfCard .dtable{margin-top:var(--s4)}

/* The file control IS the drop zone — a separate styled button next to a native input is two
   controls for one action, and the second one always drifts out of step with the first. */
.pdfDrop{display:flex;flex-direction:column;align-items:center;gap:var(--s3);cursor:pointer;
  border:1px dashed var(--line-input);border-radius:8px;padding:var(--s7) var(--s5);background:#FCFCFB}
.pdfDrop:hover{border-color:var(--navy);background:#FAFAFF}
.pdfDropIcon{width:56px;height:56px;border-radius:50%;background:#EEF1F9;color:var(--navy);
  display:flex;align-items:center;justify-content:center}
.pdfDropLabel{font-size:var(--t-body);font-weight:500;color:var(--navy)}
.pdfDrop input[type=file]{font-size:var(--t-ui);max-width:100%}
.pdfMeta{margin:var(--s3) 0 0;text-align:center;font-size:var(--t-mini);color:var(--muted)}
.pdfRules{margin:var(--s5) 0 0;padding-left:var(--s5);color:var(--muted);font-size:var(--t-ui);
  line-height:22px}
.pdfActs{display:flex;gap:var(--s3);justify-content:flex-end;margin-top:var(--s5)}
.pdfActs-end{max-width:1040px;margin-left:auto;margin-right:auto}
.pdfFile{margin:0;font-size:var(--t-ui);font-weight:500;display:flex;align-items:center;gap:var(--s2)}
.pdfPick .pdfTick,.pdfTick{width:34px}
.pdfNum{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.pdfPick label{cursor:pointer}
.pdfReview{text-align:left}
.pdfTest{padding:var(--s5);margin-bottom:var(--s5)}
.pdfTestHead{display:flex;gap:var(--s4);align-items:flex-end;flex-wrap:wrap}
.pdfTestHead .teF-wide{flex:1 1 320px}
.pdfState{margin:0 0 var(--s2)}
.pdfFields{margin-top:var(--s4)}
/* A row that will not be written is dimmed, never hidden: a field silently dropped between the
   review and the save is the one thing this screen must not do. */
.pdfOff td{color:var(--muted);background:#FBFBFA}

/* Preview Report — the masters row seen the way a patient will. */
.tpCard{max-width:900px}
.tpTitle{margin:0;font-size:20px;font-weight:600}
.tpMeta{margin:var(--s1) 0 var(--s5);color:var(--muted);font-size:var(--t-ui)}
.tpTable{margin-top:var(--s3)}
.tpVal{color:var(--muted)}

/* Layout rows (057). Each one is drawn as the thing it does, not as a labelled placeholder —
   a separator line IS a line, a space IS a gap. The page break is the exception: it has no
   appearance of its own on a scrolling screen, so it is named. */
.tpHead td{font-weight:600;color:var(--navy);padding-top:var(--s4);background:#FAFAF8}
.tpHeadRule td{border-bottom:1px solid var(--navy)}
.tpHeadMid td{text-align:center}
.tpRule td{padding:0;height:1px;border-bottom:1px solid var(--line)}
.tpSpace td{padding:0;height:14px;border:0}
.tpBreak td{padding:var(--s2) var(--s3);font-size:var(--t-mini);color:var(--muted);
  border-top:1px dashed var(--line-input);border-bottom:1px dashed var(--line-input);text-align:center}
/* On the Edit screen a layout row takes the three analyte columns as one cell — it has no field
   type, no unit and no range to put in them. */
.teLayout{color:var(--muted);font-size:var(--t-tight)}
/* Linked parameters (058). The chip says which way the link runs — a mirror names its source, a
   master says how many it feeds — because that decides where an edit lands. */
.teLink{background:#EEF1F9;color:var(--navy);border-radius:999px;padding:1px var(--s2);
  font-size:var(--t-micro);font-weight:600;white-space:nowrap}
.teLinked{border-top:1px solid var(--line);margin-top:var(--s4);padding-top:var(--s4);
  display:flex;align-items:center;justify-content:space-between;gap:var(--s3)}
.teLinkedAt{margin:0;font-size:var(--t-ui);color:var(--muted)}
.teFieldOnly{display:contents}
.teFieldOnly[hidden]{display:none}
.tpText{white-space:pre-wrap;font-size:var(--t-ui);line-height:22px;margin:var(--s2) 0 0}

@media(max-width:900px){.teCols{grid-template-columns:1fr}
  /* The editor stops following the scroll once it is stacked under the table — a sticky panel in
     a single column pins itself over the rows it is meant to sit beside. */
  .teEditor{border-left:0;border-top:1px solid var(--line);position:static}
  .teF-wide,.teF-req,.teF-flags{grid-column:span 1}
  .teEdGrid{grid-template-columns:1fr}
  .rxAdd{flex-direction:column;align-items:stretch}}

/* Audit Trail (059). A log is read down the left edge — the timestamp column is fixed-width and
   tabular so the eye can scan it, and the note column takes whatever is left. */
.taCard{padding:var(--s5)}
.taWho{font-size:var(--t-ui);color:var(--muted)}
.taTable{margin-top:var(--s4)}
.taWhen{white-space:nowrap;font-variant-numeric:tabular-nums;color:var(--muted)}

/* Reflex rules (060). A rule reads as a sentence across the row — when this field is flagged,
   propose that — so the add form lays out on one line at width and stacks below it. */
.rxHead{padding:var(--s4) var(--s5) 0}
.rxTable{margin:var(--s3) 0 0}
.rxAdd{display:flex;flex-wrap:wrap;gap:var(--s4);align-items:flex-end;padding:var(--s5)}
.rxAdd .teF{flex:1 1 180px;min-width:0}
.rxAdd .teF-wide{flex:2 1 320px}
/* The flag boxes read across, not down — five of them stacked turned the add-rule row into a
   ladder and pushed every control beside it out of alignment. */
.rxFlags{display:flex;flex-flow:row wrap;gap:var(--s3);align-items:center;flex:0 0 auto;
  border:0;padding:0;margin:0}
.rxFlags legend{font-size:var(--t-mini);color:var(--muted);padding:0;float:left;width:100%}
.rxFlags .teCk{white-space:nowrap}
.rxFoot{flex:0 0 auto}

/* PACKAGE MASTERS (2026-08-17). No tokens of its own: the page is built from card / tbar / btn /
   dtable / teF, the classes Test Masters and Referral List already use. The Flabs-token layer that
   stood here (Flabs blue, Roboto, AntD radii, a segmented view toggle) put Package Masters in a
   different design language from the screen beside it under MASTERS and was deleted whole —
   VS: "clone flabs exactly excluding the fonts and brand colors … just keep our fonts/brand kit".
   Two padding helpers only, for the footer actions and the verified-by line under a flush card. */
.teFootActs{padding:var(--s4) var(--s5);align-items:center}
.teFootActs form{margin:0}
.teFootNote{padding:0 var(--s5) var(--s4);margin:0}

/* A form on the tabs row, hard right — where Flabs' Outsource keeps "Enter Lab Name / Add Lab". The
   8px bottom margin matches .dtab's padding so the control sits on the tab baseline, not below it. */
.dtabs-act{margin-left:auto;display:flex;gap:var(--s2);align-items:center;margin-bottom:8px}
.dtabs-act input{height:32px;padding:0 var(--s3);border:1px solid var(--line-input);border-radius:6px;font-size:var(--t-ui);width:220px}

/* Outsource add-row typeahead: a full-width text input over a datalist of the whole test master */
.dtable input.osTest{width:100%;min-width:260px;height:32px;padding:0 var(--s3);border:1px solid var(--line-input);border-radius:6px;font-size:var(--t-ui)}

/* Test wise > Lab List: a two-column grid inside the cell. Each lab on its own line, prices in a
   right-aligned column, tabular figures so 60 and 100 line up on the digit. */
/* Test wise > Lab List / Lab Price: two real columns, one line per lab in each. Same line-height in
   both cells so lab N and its price sit on the same baseline. */
.osLines div{line-height:22px;white-space:nowrap}
.osNum{font-variant-numeric:tabular-nums}
.dtabs-act input[list]{width:280px}

/* ---- NAVIGATION PROGRESS (VS 2026-08-18: "keep the hairline, remove the page transitions") --------
   A hairline on the top edge appears 150ms after any click that leaves the page (nav-progress.js)
   and creeps until the new page lands — a slow Airtable page is visibly coming, never a dead click.
   The cross-document view transitions and the eased controls that shipped beside it the same night
   were REMOVED at VS's word ("uneasy to the eye"); the constellation-logo motion replaces this later. */
.nav-progress{position:fixed;top:0;left:0;height:2px;width:0;background:var(--red,#D64545);z-index:100;opacity:0;pointer-events:none;
  transition:width 8s cubic-bezier(.1,.7,.2,1),opacity 150ms linear}
html.nav-busy .nav-progress{opacity:1;width:82%}
@media (prefers-reduced-motion:reduce){.nav-progress{transition:none}}

/* ---- LOGIN (VS 2026-08-18: the Terminal's first impact; staff only, one door) ---------------------
   Two panes: the form on a white ground, the brand on navy. Standalone document (views/login.ejs),
   so nothing here leans on the rail or the sprite. Fonts and tokens are the house ones. */
.lg-body{margin:0;min-height:100vh;background:#fff}
.lg{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);min-height:100vh}
.lg-form{display:flex;flex-direction:column;padding:40px 48px;min-height:100vh;box-sizing:border-box}
.lg-brand{display:inline-block;width:150px;line-height:0}
.lg-brand img{width:100%;height:auto}
.lg-formwrap{margin:auto 0;padding:56px 0;width:100%;max-width:400px;align-self:center}
.lg-kicker{margin:0 0 10px;font-family:var(--f-data);font-weight:500;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.lg-formwrap h1{font-family:var(--f-display);font-weight:700;font-size:34px;line-height:1.1;letter-spacing:0;color:var(--navy);margin:0 0 10px}
.lg-sub{margin:0 0 28px;color:var(--muted);font-size:15px;line-height:1.5}
.lg-fields label{display:block;font-size:13px;font-weight:600;color:var(--ink);margin:0 0 6px}
.lg-fields input{display:block;width:100%;box-sizing:border-box;margin:0 0 18px;padding:0 14px;height:48px;border:1px solid var(--line-input);border-radius:10px;font-size:16px;font-family:inherit;background:#fff;color:var(--ink)}
.lg-fields input:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 3px rgba(26,45,90,.12)}
.lg-go{display:block;width:100%;height:50px;margin-top:6px;border:0;border-radius:10px;background:var(--navy);color:#fff;font-family:var(--f-body);font-weight:700;font-size:16px;letter-spacing:.01em;cursor:pointer}
.lg-go:hover{background:var(--navy-d)}
.lg-go:focus-visible{outline:3px solid rgba(26,45,90,.35);outline-offset:2px}
.lg-err{margin:0 0 18px;font-size:14px}
.lg-foot{display:flex;align-items:center;gap:10px;color:var(--muted);font-size:12.5px;letter-spacing:.01em}
.lg-dot{width:3px;height:3px;border-radius:50%;background:var(--line-input);display:inline-block}
/* the brand pane: navy, with a faint dot field — the constellation, at rest, until its motion arrives */
.lg-panel{position:relative;background:linear-gradient(160deg,var(--navy) 0%,var(--navy-d) 100%);color:#fff;display:flex;align-items:center;justify-content:center;overflow:hidden}
.lg-panel::before{content:"";position:absolute;inset:0;background-image:radial-gradient(rgba(255,255,255,.14) 1px,transparent 1.2px);background-size:26px 26px;opacity:.55;
  mask-image:radial-gradient(ellipse at 50% 45%,#000 0%,transparent 72%);-webkit-mask-image:radial-gradient(ellipse at 50% 45%,#000 0%,transparent 72%)}
.lg-panelin{position:relative;width:min(420px,78%);text-align:left}
.lg-panelmark{width:100%;height:auto;display:block;margin-bottom:28px}
.lg-panelline{margin:0 0 22px;padding-top:22px;border-top:1px solid rgba(255,255,255,.18);font-family:var(--f-display);font-weight:500;font-size:20px;line-height:1.35;color:#fff;letter-spacing:.01em}
.lg-panelrow{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.lg-panelrow li{font-family:var(--f-data);font-weight:500;font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:rgba(255,255,255,.82);border:1px solid rgba(255,255,255,.28);border-radius:999px;padding:6px 12px}
@media (max-width:900px){
  .lg{grid-template-columns:1fr;grid-template-rows:auto 1fr}
  .lg-panel{order:-1;min-height:120px;padding:26px 24px;align-items:flex-start;justify-content:flex-start}
  .lg-panelin{width:auto;max-width:520px}
  .lg-panelmark{width:150px;margin-bottom:0}
  .lg-panelline,.lg-panelrow{display:none}
  .lg-form{min-height:0;padding:28px 24px 32px}
  .lg-brand{display:none}
  .lg-formwrap{margin:0 auto;padding:8px 0 28px}
}

/* ---- LAB PROFILE PAGES (070/071) --------------------------------------------------------------------
   Flabs' settings page measured in the browser 2026-08-21: a main column of stacked section cards
   beside a 180px rail carrying Preview Report and Save. The rail STICKS because those two are the
   only things an operator does here, and on a page this tall they would otherwise be a scroll away.
   The first cut of this screen had no rail at all and a two-column grid; theirs is three. */
.lp-page{display:grid;grid-template-columns:minmax(0,1fr) 180px;gap:var(--s4);align-items:start}
.lp-main{min-width:0}
/* The topbar is position:fixed at 64px, so a rail sticking at the viewport top slides UNDER it
   (caught in the browser: the Save button was clipped in half). Clear it by the bar's own height. */
.lp-rail{position:sticky;top:calc(var(--topbar-h) + var(--s3));display:flex;flex-direction:column;
  gap:var(--s2)}
.lp-rail-btn{width:100%;justify-content:center;text-align:center}
/* card-flush zeroes the card's padding so the header bar can span it; the body puts it back.
   Flabs runs a tighter body than we did -- 12px, not 16 -- and the cards sit closer together. */
.lp-body{padding:var(--s4) var(--s5)}
.lp-page .card{margin-bottom:var(--s3)}
/* Flabs tints each section's header bar (#FAFAFA) and sets its title at 14px/500. Ours were
   transparent at the 19px card-title step, so seven stacked sections read as seven page titles
   instead of one page with seven sections. The FIRST card keeps the page title; the sections
   under it step down. Scoped to this page — .tbar elsewhere is unchanged. */
.lp-main > .card:not(:first-child) > .tbar{background:#FAFAFA}
.lp-main > .card:not(:first-child) > .tbar > .tbar-title{font-size:var(--t-name);font-weight:600}
.lp-body .fgrid:last-child,.lp-body .check-row:last-child{margin-bottom:0}
/* Twelve print switches read as a block of rows, not a form grid: each is one word and a box. */
.lp-checks{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s3) var(--s4);
  margin-bottom:var(--s5)}
/* Flabs shows an outlined "Click to Upload" control, not a raw file input sitting in a box that
   looks like a text field. The native control is kept (it is the accessible one) and its button
   half is dressed as a house button. */
.lp-art .t-act{gap:var(--s2);align-items:center;flex-wrap:wrap}
.lp-art input[type=file]{font-size:var(--t-tight);color:var(--muted);max-width:100%}
.lp-art input[type=file]::file-selector-button{font:inherit;font-weight:600;color:var(--navy);
  background:#fff;border:1px solid var(--line-input);border-radius:8px;padding:6px var(--s4);
  margin-right:var(--s3);cursor:pointer}
.lp-art input[type=file]::file-selector-button:hover{background:#F6F8FB;border-color:var(--navy)}
.lp-art-img{max-width:100%;max-height:90px;border:1px solid var(--line);border-radius:6px}
@media(max-width:1100px){
  .lp-page{grid-template-columns:1fr}
  .lp-rail{position:static;flex-direction:row;justify-content:flex-end}
  .lp-rail-btn{width:auto}
  .lp-checks{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:720px){.lp-checks{grid-template-columns:1fr}}

/* ---- ADD DOCTOR (076) ------------------------------------------------------------------------
   Measured off Flabs' Doctor Details tab, 2026-08-22, not off a screenshot. Their card here is
   982 wide with 24px of its OWN padding -- not the 0-padding section cards of Report Details,
   which is why .lp-body is overridden on this block alone rather than globally. Content 932,
   three columns of 297 at a 20px gap. */
.docblk .lp-body{padding:var(--s6)}
/* Two named sections on one card need more air between them than .lp-sub's 12px, which was set
   for sub-blocks INSIDE one section on Report Details. The first heading keeps its zero, from
   the .lp-body > .lp-sub:first-child rule above. */
.docblk .lp-sub{margin-top:var(--s6)}
/* Address runs the full width, as it does on the reference: a street line in a 258px box wraps
   out of sight, and the three fields under it are what get read at a glance. */
.docblk .fgrid > label.fw{grid-column:1 / -1}
.docblk + .docblk{margin-top:var(--s4)}
.docblk-off{opacity:.62}
/* A field whose control is not a single <input> still needs the label's own type and rhythm:
   .fgrid > label carries it for the rest, this carries it for the three that are assemblies. */
.dlabel{display:block;font-size:var(--t-ui);font-weight:400;color:var(--ink);margin-bottom:8px}

/* Signature: their outlined "Click to Upload" over a bordered preview well with a bin in it. */
.doc-sig .doc-up{display:flex;gap:var(--s2);align-items:center;margin:0}
.doc-up-btn{position:relative;overflow:hidden;gap:var(--s2);height:var(--ctrl-h);
  padding:0 var(--s4);border-radius:6px}
.erp .doc-up-btn input[type=file]{position:absolute;inset:0;width:100%;height:100%;opacity:0;
  cursor:pointer}
.doc-sig-box{position:relative;margin-top:var(--s3);min-height:90px;display:flex;
  align-items:center;justify-content:center;background:#fff;border:1px solid var(--line-input);
  border-radius:6px}
.doc-sig-box img{max-width:calc(100% - var(--s6));max-height:80px}
.doc-sig-empty{color:#9FB3D6;line-height:0}
.doc-sig-del{position:absolute;right:var(--s3);top:50%;transform:translateY(-50%);padding:4px;
  border:0;background:none;color:var(--muted);cursor:pointer;line-height:0}
.doc-sig-del:hover{color:var(--bad-ink)}

/* Position: a native range so the control needs no script to work, dressed as their slider --
   4px rail, 10px handle -- with the three marks CENTRED ON THEIR STOPS, which is why they are
   absolutely placed and not grid cells (theirs overhang both ends by half a word). */
.doc-posrow{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--s5)}
.doc-pos{flex:0 1 446px;min-width:0}
.erp input.doc-slider{width:100%;height:12px;margin:var(--s1) 0 0;padding:0;border:0;
  background:none;border-radius:0;-webkit-appearance:none;appearance:none;cursor:pointer}
.erp input.doc-slider:focus{outline:none;box-shadow:none}
.doc-slider::-webkit-slider-runnable-track{height:4px;border-radius:2px;background:rgba(0,0,0,.06)}
.doc-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:10px;height:10px;
  margin-top:-3px;border-radius:50%;background:#fff;border:2px solid var(--navy)}
.doc-slider::-moz-range-track{height:4px;border-radius:2px;background:rgba(0,0,0,.06)}
.doc-slider::-moz-range-thumb{width:10px;height:10px;border-radius:50%;background:#fff;
  border:2px solid var(--navy)}
.doc-marks{position:relative;height:22px;margin-top:var(--s2);font-size:var(--t-ui);
  color:var(--muted)}
.doc-marks span{position:absolute;transform:translateX(-50%);white-space:nowrap}
.doc-marks span:nth-child(1){left:0}
.doc-marks span:nth-child(2){left:50%}
.doc-marks span:nth-child(3){left:100%}
.doc-marks[data-pos="0"] span:nth-child(1),
.doc-marks[data-pos="1"] span:nth-child(2),
.doc-marks[data-pos="2"] span:nth-child(3){color:var(--ink)}
/* Theirs is their primary blue; ours is the house navy -- VS: keep the colours, clone the rest. */
.doc-remove{height:var(--ctrl-h);padding:0 var(--s4);color:var(--navy);border-color:var(--navy);
  background:#fff;white-space:nowrap}
.doc-remove:hover{background:#F6F8FB}
.doc-rule{border:0;border-top:1px solid var(--line-s);margin:var(--s7) 0 var(--s6)}

/* Alignment: a segmented control, 2px of padding on a #D9D9D9 bed, 63x36 cells, the chosen one
   white. The radios are the state; they are visually removed, never display:none, so the group
   stays keyboard-reachable. */
.dseg{display:inline-flex;padding:2px;background:#D9D9D9;border-radius:8px}
.erp .dseg input[type=radio]{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
/* margin:0 is load-bearing. The house `label` rule carries margin-top:8px, and a flex item's
   margin counts toward the line's cross size -- the group measured 48 tall against Flabs' 40
   until this line existed. Caught in the browser, not by the suite. */
.dseg label{display:flex;align-items:center;justify-content:center;width:63px;height:36px;
  margin:0;border-radius:6px;color:var(--muted);cursor:pointer}
.dseg input:checked + label{background:#fff;color:var(--ink);box-shadow:0 1px 2px rgba(16,24,40,.08)}
.dseg input:focus-visible + label{outline:2px solid var(--navy);outline-offset:-2px}

/* Signature Setting. The bound login shows only under Select, which is the only setting where it
   means anything -- :has() rather than script, so it is right on first paint. */
.doc-set{display:flex;align-items:center;gap:var(--s6);flex-wrap:wrap;margin:var(--s6) 0}
.doc-set .dlabel{margin:0}
.doc-user{display:none;align-items:center;gap:var(--s3)}
.docblk:has(.sigmode-select:checked) .doc-user{display:flex}
.erp .doc-user select{width:200px}

/* Department: a 32px control that opens a checkbox list, which is what their tag multi-select is
   underneath. <details> carries the open state, so this needs no script either. */
.doc-dept .dlabel{margin-bottom:8px}
.msel{position:relative;width:466px;max-width:100%}
.msel > summary{display:flex;align-items:center;height:var(--ctrl-h);padding:4px 11px;
  border:1px solid var(--line-input);border-radius:6px;background:#fff;font-size:var(--t-ui);
  color:var(--ink);cursor:pointer;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
  list-style:none}
.msel > summary::-webkit-details-marker{display:none}
.msel-none > summary{color:#9AA4B0}
.msel[open] > summary{border-color:var(--navy)}
.msel-pop{position:absolute;z-index:20;left:0;right:0;top:calc(var(--ctrl-h) + 4px);
  max-height:220px;overflow:auto;padding:var(--s2);background:#fff;border:1px solid var(--line);
  border-radius:6px;box-shadow:0 6px 20px rgba(16,24,40,.12)}
.msel-pop .rr{display:flex;padding:var(--s1) var(--s2);border-radius:4px}
.msel-pop .rr:hover{background:#F6F8FB}
.doc-add{margin-top:var(--s4)}

/* ---- REFERRAL LIST > More info (079) ---------------------------------------------------------
   The reference keeps its extra doctor fields behind a "Show More Info" expander, and so does
   this: the eight fields above it are what an operator fills in every time, and a drawer that
   opens twenty controls tall is a drawer nobody reads to the bottom of. */
.ref-more{margin:var(--s4) 0 0;border-top:1px solid var(--line-s);padding-top:var(--s4)}
.ref-more > summary{list-style:none;cursor:pointer;font-size:var(--t-ui);font-weight:600;
  color:var(--navy);display:flex;align-items:center;gap:var(--s2)}
.ref-more > summary::-webkit-details-marker{display:none}
.ref-more > summary::after{content:'';width:8px;height:8px;border-right:1.6px solid currentColor;
  border-bottom:1.6px solid currentColor;transform:rotate(45deg) translate(-2px,-2px)}
.ref-more[open] > summary::after{transform:rotate(-135deg) translate(-3px,-3px)}
.ref-more-body{margin-top:var(--s4)}
@media(max-width:860px){
  .doc-posrow{flex-direction:column;align-items:stretch;gap:var(--s4)}
  .doc-pos{flex:1 1 auto}
}

/* ---- REPORT DETAILS, the eleven-section clone (072) -------------------------------------------
   Flabs breaks a long section into named sub-blocks ("Position", "Design", "Spacing", "Age
   Format") set smaller than the card title. Same job here, one step under the section bar. */
.lp-sub{margin:var(--s4) 0 var(--s2);font-size:var(--t-ui);font-weight:600;color:var(--ink)}
.lp-body > .lp-sub:first-child{margin-top:0}
/* Their patient-block gallery is a grid of pickable layouts. Ours names each one, because a
   thumbnail of a layout nobody can read is decoration; the name is what an operator chooses by. */
.pd-gallery{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s3)}
.pd-tile{display:flex;flex-direction:column;gap:2px;text-align:left;cursor:pointer;
  padding:var(--s3) var(--s4);border:1px solid var(--line-input);border-radius:8px;background:#fff}
.pd-tile:hover{border-color:var(--navy);background:#F6F8FB}
.pd-tile.on{border-color:var(--navy);background:#F1F5FC;box-shadow:0 0 0 2px rgba(26,45,90,.12)}
.pd-tile-art{display:block;background:#fff;border:1px solid var(--line);border-radius:4px;
  padding:4px;margin-bottom:var(--s2)}
.pd-tile-n{font-weight:600;font-size:var(--t-ui);color:var(--ink)}
/* the chosen design, shown on the card so the drawer is not the only place it is visible */
.pd-current{max-width:320px;background:#fff;border:1px solid var(--line);border-radius:6px;
  padding:6px;margin:0 0 var(--s4)}
.pd-tile-d{font-size:var(--t-tight);color:var(--muted)}
/* A colour swatch is a control, not a text box: it gets the height of one, not the width. */
.lp-body input[type=color]{width:64px;padding:2px;cursor:pointer}
@media(max-width:720px){.pd-gallery{grid-template-columns:1fr}}

/* ---- BILL DETAILS (075) -----------------------------------------------------------------
   Flabs runs their thirteen bill ticks in a 3-column grid, and opens the tab with a
   Default | switch | Custom line. Controls we cannot honour are drawn DISABLED with the
   reason beside them rather than left out, so an operator can see it was considered. */
.bill-flags{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s3) var(--s4);
  margin:var(--s4) 0 var(--s5)}
/* House .rr is nowrap so a lone checkbox never gets a three-line label. These rows carry a
   REASON after the label, which overflowed into the next column at nowrap — caught in the
   browser. Inside this grid they wrap, and the box stays pinned to the first line. */
.bill-flags .rr{white-space:normal;align-items:flex-start;line-height:1.45}
.bill-flags .rr input{margin-top:2px;flex:0 0 auto;width:15px;height:15px}
.gst-lock input,.rr-off input{flex:0 0 auto;width:15px;height:15px}
.bill-mode{display:flex;align-items:center;gap:var(--s3);margin:0 0 var(--s5)}
.rr-off{opacity:.62;cursor:default}
/* it is a <label> inside .fgrid, and that rule sets flex-direction:column — which stacked the
   box above its own text. The direction is stated here, not inherited. */
.fgrid > label.gst-lock{display:flex;flex-direction:row;align-items:center;gap:var(--s2);
  white-space:normal;line-height:1.45;align-self:end;padding-bottom:11px;font-weight:500}
.gst-lock input{margin-top:3px}
.rr-off input{cursor:default}
@media(max-width:1100px){.bill-flags{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:720px){.bill-flags{grid-template-columns:1fr}}

/* ---- NEW REGISTRATION (081) -------------------------------------------------------------------
   The reference's registration row is FOUR columns of 269px with a 22px gutter, measured off the
   live form 2026-08-22 — and two of those columns are split in half (Patient ID beside
   Designation, Age beside Age Type) into 122px cells with the same gutter. .fgrid-4 already draws
   the four; .fpair splits one of them and inherits the gutter rather than restating it, so the
   half-cells line up with the whole ones by construction and not by a matching pair of numbers. */
.fpair{display:grid;grid-template-columns:1fr 1fr;gap:20px;align-items:start}
/* VS 2026-09-04: the counter's first row — five controls on one line, short ones at their value's width */
.qk-card .qk-row1{display:grid;grid-template-columns:.62fr .62fr .8fr 1.25fr 1.25fr;gap:20px;align-items:start}
@media(max-width:1100px){.qk-card .qk-row1{grid-template-columns:1fr 1fr 1fr;}}

@media(max-width:1100px){.fpair{gap:var(--s4)}}

/* A label for a control that is not one input — the radio row, the dispatch picker. `.fgrid >
   label` is a flex column with an 8px gap, which a <span> heading cannot inherit by sitting next
   to a <p>, so the two spacings are stated here once instead of drifting apart. */
.flab{display:block;margin-bottom:8px;font-size:var(--t-ui);font-weight:400;color:var(--ink)}
.fgrid > div > .radios{min-height:var(--ctrl-h);align-items:center}

/* A select with an Add button welded to its right. The button is a fixed 32 square so the select
   keeps the column's full width minus exactly that, and both sit on the control line. */
.withadd{display:flex;gap:var(--s2);align-items:center}
.withadd select{flex:1;min-width:0}
.withadd .btn{flex:0 0 auto;width:32px;height:var(--ctrl-h);padding:0;justify-content:center}

/* The patient typeahead. Anchored to .tbar-search, which is already position:relative. */
.ta-pop{position:absolute;z-index:30;left:0;right:0;top:calc(var(--ctrl-h) + 4px);
  max-height:280px;overflow:auto;padding:var(--s1);background:#fff;border:1px solid var(--line);
  border-radius:6px;box-shadow:0 6px 20px rgba(16,24,40,.12)}
.ta-row{display:flex;flex-direction:column;gap:2px;width:100%;padding:var(--s2) var(--s3);
  border:0;border-radius:4px;background:none;text-align:left;cursor:pointer;font:inherit}
.ta-row:hover,.ta-row:focus{background:#F6F8FB;outline:none}
.ta-name{font-size:var(--t-ui);font-weight:600;color:var(--ink)}
.ta-sub{font-size:var(--t-mini);color:var(--muted)}

/* Three radios inside one quarter-column of .fgrid-4. The default 24px gap is sized for a
   full-width row and wrapped Other onto a second line, which made the whole grid row
   taller than its neighbours. */
.fgrid-4 .radios{gap:var(--s3) var(--s4)}

/* ---- BILLING (082) -------------------------------------------------------------------------------
   The reference's Billing modal, as a page. Measured 2026-08-23 at a 1512 viewport: modal 1150
   wide, patient rail 260, line table header 47 tall, search row 32-tall controls, Discount column
   ~300 spanning the full money panel, Flags ~215 and Summary beside it with Payment Modes
   UNDER those two, foot 56. ONE SCREEN (VS 2026-08-23: "unnecessary scroll, make it one page
   like flabs"): the page is the viewport minus the header and the wrap's padding; the money
   panel and the foot are fixed; only the line table scrolls. The first cut stacked Payment
   Modes full-width below the panel and rendered search results as a table in the flow — 1144px
   tall on a 768px viewport. */
.bill{background:#fff;border:1px solid var(--line);border-radius:12px;overflow:hidden;
  box-shadow:0 12px 40px rgba(38,48,63,.10);
  display:flex;flex-direction:column;height:calc(100vh - var(--topbar-h) - 2 * var(--s4));min-height:560px}
.bill-head{display:flex;align-items:center;gap:var(--s4);padding:var(--s3) var(--s5);
  border-bottom:1px solid var(--line);flex:0 0 auto}
.bill-head .tbar-title{font-size:17px;margin:0}
.bill-x{display:inline-flex;width:32px;height:32px;align-items:center;justify-content:center;
  border-radius:6px;color:var(--muted);margin-left:auto}
.bill-x:hover{background:#F3F4F6;color:var(--ink)}
.bill-err{margin:0;padding:2px var(--s3);font-size:var(--t-ui);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bill-body{display:grid;grid-template-columns:260px minmax(0,1fr);margin:0;flex:1 1 auto;min-height:0}
.bill-rail{border-right:1px solid var(--line);overflow:auto;min-height:0}
.bill-rail-sec{padding:var(--s4) var(--s5);border-bottom:1px solid var(--line)}
.bill-rail-sec:last-child{border-bottom:0}
.bill-link{font-size:var(--t-ui);color:var(--muted);text-decoration:underline}
.bill-name{margin:var(--s3) 0 0;font-weight:600;font-size:var(--t-ui)}
.bill-id{margin:2px 0 var(--s3);font-size:var(--t-ui)}
.bill-kv{display:grid;grid-template-columns:1fr 1fr;gap:var(--s2) var(--s4);margin-top:var(--s3)}
.bill-kv.one{grid-template-columns:1fr}
.bill-kv .k{display:block;color:var(--muted);font-size:var(--t-ui)}
.bill-kv .v{display:block;font-size:var(--t-ui)}
.bill-lbl{display:flex;flex-direction:column;gap:6px;font-size:var(--t-ui);color:var(--ink);margin:0 0 var(--s3)}
.bill-lbl .opt{color:var(--muted)}
.bill-lbl :is(input,select,textarea){width:100%;margin:0;height:var(--ctrl-h);padding:4px 11px;
  font-size:var(--t-ui);border:1px solid var(--line-input);border-radius:6px;background:#fff}
.bill-lbl textarea{height:auto;min-height:64px;padding:6px 11px;resize:vertical}
.bill-note > summary{list-style:none;cursor:pointer;width:100%;justify-content:center}
.bill-note > summary::-webkit-details-marker{display:none}
.bill-note textarea{width:100%;margin-top:var(--s3);min-height:72px;padding:6px 11px;
  border:1px solid var(--line-input);border-radius:6px;font-size:var(--t-ui)}
.bill-main{min-width:0;display:flex;flex-direction:column;min-height:0}

/* the line table — the ONE region that scrolls */
.bill-lines-wrap{flex:1 1 auto;min-height:96px;overflow:auto}
.bill-lines{margin:0}
.bill-lines thead th{position:sticky;top:0;background:#fff;z-index:1;padding-top:12px;padding-bottom:12px}
.bill-lines .c-sr{width:64px;text-align:center}
.bill-lines .c-price,.bill-lines .c-disc{width:120px}
.bill-lines .c-urg{width:100px;text-align:center}
.bill-lines .c-act{width:104px}
.bill-lines td{padding-top:8px;padding-bottom:8px}
.bill-empty td{text-align:center;color:var(--muted);padding:var(--s5) 0}
.bill-empty-ic{display:block;margin:0 auto var(--s2);width:36px;height:36px;color:#C9CED6}
.bill-empty-ic .ic{width:36px;height:36px}
.t-gc{color:#1E7A43}
.money{position:relative;display:inline-flex;align-items:center;width:100%}
.money::before{content:'₹';position:absolute;left:10px;color:var(--ink);font-size:var(--t-ui);pointer-events:none}
.money input{width:100%;margin:0;height:var(--ctrl-h);padding:4px 8px 4px 22px;font-size:var(--t-ui);
  border:1px solid var(--line-input);border-radius:6px;-moz-appearance:textfield}
.money input::-webkit-outer-spin-button,.money input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}

/* the search row; the picker drops OVER the money panel, never into the flow */
.bill-search{display:flex;gap:var(--s3);align-items:center;justify-content:center;padding:var(--s3) var(--s4);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);background:#FAFAFA;flex:0 0 auto;position:relative;z-index:2}
.bill-find{display:flex;gap:var(--s2);margin:0}
.bill-find .tbar-search{flex:0 0 320px}
.bill-find select{height:var(--ctrl-h);width:100px;flex:0 0 100px;margin:0;padding:4px 28px 4px 11px;
  border:1px solid var(--line-input);border-radius:6px;font-size:var(--t-ui);background:#fff}
.bill-find .ta-pop{max-height:300px;text-align:left}
.bill-find .ta-row.is-cur{background:#F6F8FB}
.ta-none{margin:0;padding:var(--s3);font-size:var(--t-ui);color:var(--muted)}
.ta-price{color:var(--ink)}
/* .bseg, not .dseg: New Registration owns .dseg as a radio segmented control, and the first cut
   of this row reused the name for a pair of links and restyled the registration's switch. */
.bseg{display:inline-flex;background:#F0F0F0;border-radius:8px;padding:2px;height:32px}
.bseg a{display:inline-flex;align-items:center;padding:0 12px;border-radius:6px;font-size:var(--t-ui);
  color:var(--ink);text-decoration:none;white-space:nowrap}
.bseg a.on{background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.08)}
.bill-other{display:flex;gap:var(--s3);padding:var(--s3) var(--s4);margin:0;align-items:center;flex:0 0 auto;border-bottom:1px solid var(--line)}
.bill-other input[type=text]{flex:1;height:var(--ctrl-h);margin:0;padding:4px 11px;border:1px solid var(--line-input);border-radius:6px}
.bill-other .money{width:160px}

/* discount · flags · summary, with payment modes under flags + summary — the reference's panel */
.bill-money{display:grid;grid-template-columns:minmax(0,300px) minmax(0,215px) minmax(0,1fr);
  grid-template-rows:auto 1fr;flex:0 0 auto}
.bill-col{padding:var(--s4) var(--s4);border-right:1px solid var(--line)}
.bill-disc{grid-row:1 / span 2}
.bill-sum{border-right:0}
/* .bill-flagcol, not .bill-flags: Bill Details (075) owns .bill-flags as a three-column grid, and
   the first cut of this column took that name and laid its checkboxes out in a row. Same
   shared-prefix trap as .seg and .lp- before it. */
.bill-flagcol .rr{display:flex;margin-bottom:var(--s3);white-space:nowrap}
.bill-flagcol .bill-lbl{margin:var(--s3) 0 6px;flex-direction:row;align-items:center;gap:6px;white-space:nowrap}
.bill-flagcol input.locked{width:100%;height:var(--ctrl-h);padding:4px 11px;border:1px solid var(--line-input);
  border-radius:6px;background:#F4F2EE;color:var(--muted)}
.bill-due{margin:var(--s3) 0 0;font-weight:600;font-size:var(--t-ui)}
.due-pill{margin-left:var(--s3);padding:2px 8px;border-radius:4px;background:#FDE8E8;color:#C0392B;font-weight:600}
.due-pill.due-zero{background:#EAF6EE;color:#1E7A43}
.due-pill.due-over{background:#FFF4E5;color:#A55A00}
.bill-sum h3,.bill-pay h3{margin:0 0 var(--s3);font-size:var(--t-ui);font-weight:600}
.bill-sum .row{display:flex;justify-content:space-between;padding:var(--s2) 0;border-bottom:1px solid var(--line-s);font-size:var(--t-ui)}
.bill-sum .row.total{border-bottom:0;font-weight:700}

/* payment modes: second row, under flags and summary */
.bill-pay{grid-column:2 / span 2;padding:var(--s3) var(--s4) var(--s4);border-top:1px solid var(--line)}
.bill-pay .radios{gap:var(--s5);margin:0 0 var(--s2)}
.bill-modes{margin:0}
.bill-modes .c-mode{width:70px}
.bill-modes th{padding-top:8px;padding-bottom:8px}
.bill-modes td{padding-top:6px;padding-bottom:6px}
.bill-modes .money{max-width:240px}
.bill-modes input[type=text]{height:var(--ctrl-h);margin:0;padding:4px 11px;border:1px solid var(--line-input);border-radius:6px;width:220px}

/* foot */
/* the team launcher is fixed 20px from the bottom-right corner; at a 1366 laptop it sat on top of
   Register & Print Bill. The foot keeps the button clear of it (56px launcher + its 20px margin). */
.bill-foot{display:flex;justify-content:space-between;align-items:center;padding:var(--s3) calc(var(--s5) + 76px) var(--s3) var(--s5);
  border-top:1px solid var(--line);flex:0 0 auto}
.bill-discard{margin:0}
@media(max-width:1000px){.bill{height:auto}.bill-body{grid-template-columns:1fr}.bill-rail{border-right:0;border-bottom:1px solid var(--line)}
  .bill-lines-wrap{flex:0 0 auto;overflow:visible}
  .bill-money{grid-template-columns:1fr;grid-template-rows:none}.bill-disc{grid-row:auto}.bill-pay{grid-column:auto}
  .bill-col{border-right:0;border-bottom:1px solid var(--line)}}

/* ---- PATIENT LIST (083) ------------------------------------------------------------------------
   The reference's register, measured 2026-08-23 on a 1568-wide capture: count-left tabs on a
   hairline; the card's toolbar with the search left and range · Filters · Worksheet · More ·
   Export right; nine columns (66 · 102 · 102 · 129 · 167 · 257 · 103 · 129 · 235) on 67px two-line
   rows; test pills with a letter badge (P blue, C green), pink for an outsourced test; the row
   kebab. Prefix pl- throughout: .kebab, .dtab and .dtable are the house primitives it rides on. */
/* 105: the count sits AFTER the label, in the markup AND on the screen. This rule used to
   force it visually first with order:-1, which is why flipping the markup changed nothing
   the eye could see — the DOM read label-first while the pixels read count-first. */
.pl-tabs .dtab-off{color:var(--muted);cursor:default}
.pl-tabs .dtab-off:hover{color:var(--muted)}
.pl-card{padding-bottom:var(--s3)}
/* ONE LINE, like the reference (096b, VS's strip pair): the search absorbs the squeeze and the
   actions never wrap; only a genuinely narrow screen (the 2818 media rule) stacks the bar */
.pl-tbar{padding:var(--s5);border-bottom:1px solid var(--line);flex-wrap:nowrap}
.pl-search{flex:1 1 220px;min-width:170px;max-width:370px}
.pl-actions{margin-left:auto;flex-wrap:nowrap;flex:0 0 auto}
.pl-actions select[name=gpanel]{max-width:190px;text-overflow:ellipsis}
.pl-range{display:inline-flex;align-items:center;gap:var(--s2);padding:0 var(--s2);height:var(--ctrl-h);
  border:1px solid var(--line-input);border-radius:6px;background:#fff}
/* 118px stays. 106 fits the row better and CLIPS THE YEAR — a date input does not scroll, it
   truncates its own segments, so scrollWidth === clientWidth reports no overflow while the screen
   shows "08/25/202". Read the pixels, not the property. The register's search gives up the 24px
   instead; a placeholder can be read short, a date cannot. */
.pl-range input[type=date]{height:26px;border:0;padding:0 4px;font-size:var(--t-ui);width:118px}
.pl-arrow{color:var(--muted)}
.pl-go{height:24px;min-height:24px}
.pl-table{margin:0}
.pl-table thead th{padding-top:14px;padding-bottom:14px;white-space:nowrap}
.pl-table td{padding-top:10px;padding-bottom:10px}
.pl-table .c-x{width:66px;text-align:center}
.pl-table .c-date{width:112px;white-space:nowrap}
.pl-table .c-id{width:102px}
.pl-table .c-pat{width:129px}
.pl-table .c-ref{width:167px}
.pl-table .c-tests{min-width:200px}
.pl-table .c-amt{width:103px;white-space:nowrap}
.pl-table .c-st{width:129px}
.pl-table .c-act{width:235px;white-space:nowrap}
.pl-x{display:inline-flex;width:22px;height:22px;align-items:center;justify-content:center;border:1px solid var(--line-input);
  border-radius:4px;color:var(--ink);text-decoration:none;font-size:15px;line-height:1}
.pl-x:hover{border-color:var(--navy);color:var(--navy)}
.pl-sub{display:block;font-size:var(--t-mini);color:var(--muted);line-height:18px}
.pl-name{color:var(--ink);text-decoration:none;font-weight:500}
.pl-name:hover{color:var(--navy);text-decoration:underline}
.pl-empty td{text-align:center;color:var(--muted);padding:var(--s7) 0}
/* tests: one pill per line, badge beside it, link icon for an outsourced test */
.pl-test{display:inline-flex;align-items:center;gap:var(--s2);margin:2px var(--s2) 2px 0;max-width:100%}
.pl-tname{display:inline-block;padding:3px 8px;border-radius:4px;background:#F5F5F5;color:var(--ink);font-size:var(--t-tight);line-height:18px;
  max-width:190px;white-space:normal}
.pl-out .pl-tname{background:#FDF0F5;color:#9C2B63}
.pl-letter{display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;border-radius:4px;
  font-size:11px;font-weight:600;font-family:var(--f-data)}
.pl-l-p{background:rgba(26,45,90,.07);color:var(--navy)}
.pl-l-c{background:#EAF6EE;color:#1E7A43}
.pl-l-x{background:#F1F0EC;color:var(--muted)}
.pl-ext{display:inline-flex;color:var(--navy)}
.pl-ext .ic-i{width:14px;height:14px}
/* status: the report's, not the money's */
.pl-status{display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:4px;font-size:var(--t-tight);white-space:nowrap}
.pl-pend{background:rgba(26,45,90,.07);color:var(--navy);border:1px solid rgba(26,45,90,.18)}
.pl-done{background:#EAF6EE;color:#1E7A43;border:1px solid #C9E8D3}
.pl-draft{background:#F4F2EE;color:var(--muted);border:1px solid var(--line)}
.pl-status .ic-i{width:13px;height:13px}
/* action cell: Bill · Report · kebab */
.c-act .btn-sm{vertical-align:middle}
.pl-bill{color:var(--navy);border-color:var(--navy)}
.pl-kebab{vertical-align:middle}
.pl-kebab > summary{height:28px;min-height:28px;width:32px;padding:0;justify-content:center}
.pl-kebab .kebab-pop{min-width:176px}
.pl-kebab .kebab-item{border:0;background:none;font:inherit;text-align:left;cursor:pointer;color:var(--ink);text-decoration:none}
.pl-kebab .kebab-item:disabled{color:var(--muted);cursor:not-allowed}
.pl-kebab .kebab-item:disabled:hover{background:none}
.pl-detail td{background:#FAFAFA;padding:var(--s4) var(--s5)}
.pl-dgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s3) var(--s6);max-width:760px}
.pl-dgrid .k{display:block;color:var(--muted);font-size:var(--t-ui)}
.pl-dgrid .v{display:block;font-weight:600;font-size:var(--t-ui);overflow-wrap:anywhere}
.pl-pager{display:flex;justify-content:flex-end;align-items:center;gap:var(--s2);padding:var(--s4) var(--s5) var(--s2)}
.pl-page{display:inline-flex;min-width:28px;height:28px;align-items:center;justify-content:center;border:1px solid var(--navy);
  border-radius:4px;color:var(--navy);font-family:var(--f-data);font-size:var(--t-tight)}
.pl-pager .btn[aria-disabled]{color:var(--muted);pointer-events:none}
.ok-line{display:flex;align-items:center;gap:var(--s2);margin:var(--s3) var(--s5) 0;color:#1E7A43;font-size:var(--t-ui)}
/* Pending Dispatch / Dispatched (084): the tick column, the Dispatched Mode chips (amber (i) =
   the contact is missing; plain = ready; on the Dispatched tab, what went out and when), Send */
.pl-table .c-mode{width:150px}
.pl-table .c-x input[type=checkbox]{width:15px;height:15px;margin:0}
.pl-mode{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;border-radius:4px;margin:2px 0;font-size:var(--t-tight);
  background:#F5F5F5;color:var(--ink);white-space:nowrap}
.pl-mode{display:flex;width:max-content;max-width:100%}
.pl-mode-missing,.pl-mode-manual{background:#FFF8E1;color:#A56A00}
.pl-mode .ic-i{width:13px;height:13px}
.pl-mode-sent{flex-direction:column;align-items:flex-start;gap:0;padding:3px 8px}
.pl-mode-sent .pl-sub{line-height:16px}
.pl-send{margin-left:var(--s2)}
.pl-send:disabled{opacity:.55;cursor:not-allowed}
.pl-row:has([data-pick]:checked){background:rgba(26,45,90,.07)}
/* Due (085): the Due cell, and the Clear Due page — the ticked bills over the Billing screen's payment block */
.pl-due{color:#C0392B;font-weight:600}
/* Outsource (086): the partner column and the Upload Reports page */
.pl-table .c-lab{width:160px}
.pu-card{padding:var(--s5);max-width:760px}
.pu-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--s4)}
.pu-head .tbar-title{margin:0;font-size:17px}
.pu-who{margin:0 0 var(--s4);font-size:var(--t-ui)}
.pu-table{margin:0}
.pu-table .c-act{width:300px}
/* `.dtable .pu-form` AS WELL AS THE BARE CLASS (106) — the .pricecell / .paidform precedent, for
   the third time. At (0,1,0) this lost to `.dtable form{display:inline}` (0,1,1), so the upload
   row's file box and its button were laid out inline and wrapped instead of sitting in a row. */
.pu-form,.dtable .pu-form{display:flex;gap:var(--s2);align-items:center;margin:0}
.pu-form input[type=file]{width:auto;margin:0;padding:0;font-size:var(--t-tight);max-width:180px}
.pu-why{display:block;margin-top:4px;color:var(--muted);font-size:var(--t-tight)}
.pd-card{padding:var(--s5);max-width:960px}
.pd-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--s4)}
.pd-head .tbar-title{margin:0;font-size:17px}
.pd-table{margin:0 0 var(--s5)}
.pd-table tfoot td{font-weight:700;border-top:2px solid var(--line)}
.pd-pay{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s5);align-items:start}
.pd-pay .bill-pay{padding:0;border:0}
.pd-h3{margin:0 0 var(--s3);font-size:var(--t-ui);font-weight:600}
.pd-sum .row{display:flex;justify-content:space-between;padding:var(--s2) 0;border-bottom:1px solid var(--line-s);font-size:var(--t-ui)}
.pd-sum .row.total{border-bottom:0;font-weight:700}
.pd-foot{display:flex;justify-content:flex-end;gap:var(--s3);margin-top:var(--s5);padding-top:var(--s4);border-top:1px solid var(--line)}
@media(max-width:800px){.pd-pay{grid-template-columns:1fr}}
/* Filters (089): the reference's right drawer — 396px, full height, its own scroll, the list
   dimmed behind it (body.pl-drawer-on) */
.pl-drawer{position:fixed;top:0;right:0;bottom:0;width:396px;max-width:92vw;background:var(--card,#fff);border-left:1px solid var(--line);box-shadow:-12px 0 32px rgba(15,20,40,.12);z-index:80;display:flex;flex-direction:column}
.pl-drawer-head{display:flex;align-items:center;justify-content:space-between;padding:var(--s4) var(--s5);border-bottom:1px solid var(--line-s)}
.pl-drawer-head h2{margin:0;font-size:16px}
.pl-drawer-body{flex:1;overflow-y:auto;padding:var(--s4) var(--s5);display:flex;flex-direction:column;gap:var(--s3)}
.pl-f{display:block;font-size:var(--t-ui)}
.pl-f input,.pl-f select{width:100%;margin-top:4px}
.pl-f-off,.pl-f-off select{color:var(--muted)}
.pl-f-ticks{display:grid;grid-template-columns:1fr 1fr;gap:var(--s2) var(--s3);padding-top:var(--s2)}
.pl-f-ticks .rr{font-size:var(--t-ui)}
.pl-drawer-foot{display:flex;justify-content:flex-end;gap:var(--s3);padding:var(--s3) 0 0;border-top:1px solid var(--line);position:sticky;bottom:0;background:var(--card,#fff)}
body.pl-drawer-on .pl-card{opacity:.55}
.pl-filters.on{border-color:var(--navy);color:var(--navy)}

/* Worksheet (090): the Print Worksheet page — the dialog's bar and its register table */
.pw-card{padding:var(--s5)}
.pw-bar{margin-bottom:var(--s4);gap:var(--s3);flex-wrap:wrap}
.pw-bar select{max-width:220px}
.pw-bar input[type=date]{width:auto}
.pw-search{max-width:340px}
.pw-table .c-dept{width:170px}
.pw-table .c-gp{width:150px;color:var(--muted)}

/* More (091): the toolbar menu and the Bulk Download / Consolidated pages */
.pl-more,.pl-export{position:relative}
.pl-more .kebab-pop,.pl-export .kebab-pop{right:0;left:auto;min-width:220px}
.pm-note{margin:0 0 var(--s3);color:var(--muted);font-size:var(--t-ui)}
.pm-bar select{max-width:180px}
.pm-machine{white-space:nowrap;font-size:var(--t-ui)}
.pm-table .c-st{width:140px}

/* Export (092): the dropdown shares the More menu's skin */
.pl-export .kebab-pop{min-width:140px}

/* Documents (094): the card's picker form and the folder page */
.ph-docs{display:flex;gap:var(--s2);flex-wrap:wrap;align-items:center}
.ph-upform{display:inline-flex;gap:var(--s2);align-items:center;margin:0}
.pdc-card{padding:var(--s5);max-width:900px}
.pdc-up{display:flex;gap:var(--s3);align-items:center;margin-bottom:var(--s4);flex-wrap:wrap}
.pdc-up input[type=file]{width:auto;max-width:320px}
.pdc-table .c-act{width:110px}

/* Refunded (087): the tab's stacked refunds and the Refund Invoice page — measured on the
   reference 2026-08-23: a 644px dialog, the who-block in two columns, the lines table, then the
   reason + mode on the left and the three totals on the right */
.pl-table .c-by{width:130px}
.pl-table .c-rem{min-width:200px}
.pl-rf{display:block}
.pl-rf+.pl-rf{margin-top:var(--s2);padding-top:var(--s2);border-top:1px dashed var(--line-s)}
.pl-rf .pl-sub{display:block}
.pr-card{padding:var(--s5);max-width:760px}
.pr-who{display:grid;grid-template-columns:1fr 1fr;gap:var(--s4) var(--s6);margin:0 0 var(--s4);font-size:var(--t-ui)}
.pr-who .k{display:block;color:var(--muted)}
.pr-who .v{display:block;font-weight:600;margin-top:2px}
.pr-who .v .pl-sub{display:block;font-weight:400}
.pr-table{margin:0 0 var(--s5)}
.pr-table .c-x{width:40px}
.pr-table tr.pr-done td{color:var(--muted)}
.pr-table .pl-sub{display:block;font-size:var(--t-tight)}
.pr-body{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s5);align-items:start}
.pr-form{display:flex;flex-direction:column;gap:var(--s2)}
.pr-lab{font-size:var(--t-ui)}
.pr-form textarea,.pr-form select,.pr-form input{width:100%;margin:0}
.pr-sum .row{display:flex;justify-content:space-between;padding:var(--s2) 0;border-bottom:1px solid var(--line-s);font-size:var(--t-ui)}
.pr-sum .row.total{border-bottom:0;font-weight:700;font-size:15px}
.pr-sum .row.pr-split{color:var(--muted);font-size:var(--t-tight);border-bottom:0;padding:2px 0}
@media(max-width:800px){.pr-body,.pr-who{grid-template-columns:1fr}}
/* Discount (088): the given-away column carries how it was given under the figure */
.pl-table .pl-disc .pl-sub{display:block;white-space:nowrap}

/* ---- PATIENT HISTORY (083) — the reference's View Details page ------------------------------ */
.ph-title{font-size:17px;margin:var(--s2) 0 var(--s4)}
.ph-card{padding:var(--s5)}
.ph-grid{display:grid;grid-template-columns:minmax(0,1.4fr) repeat(3,minmax(0,1fr));gap:var(--s4) var(--s6);align-items:start}
.ph-grid .k{display:block;color:var(--muted);font-size:var(--t-ui)}
.ph-grid .v{display:block;font-size:var(--t-ui);margin-top:2px;overflow-wrap:anywhere}
.ph-who{display:flex;align-items:center;gap:var(--s4)}
.ph-avatar{display:inline-flex;width:48px;height:48px;align-items:center;justify-content:center;border-radius:50%;background:#F1F0EC;color:var(--muted)}
.ph-avatar .ic{width:24px;height:24px}
.ph-name{display:block;font-size:var(--t-ui)}
.ph-id{display:block;color:var(--muted);font-size:var(--t-ui);font-family:var(--f-data)}
.ph-docs{display:flex;gap:var(--s2)}
.ph-merge{margin:var(--s4) 0 0}
.ph-merge > summary{list-style:none;cursor:pointer;display:inline-flex}
.ph-merge > summary::-webkit-details-marker{display:none}
/* the Merge Patient IDs dialog: a <details> body styled as the reference's modal */
.ph-modal{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);width:min(560px,calc(100vw - 40px));z-index:60;
  background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:0 16px 48px rgba(16,24,40,.22);padding:var(--s5)}
.ph-merge[open]::before{content:'';position:fixed;inset:0;background:rgba(16,24,40,.35);z-index:59}
.ph-mhead{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--s4)}
.ph-mx{display:inline-flex;width:28px;height:28px;align-items:center;justify-content:center;border-radius:6px;color:var(--muted)}
.ph-mx:hover{background:#F3F4F6;color:var(--ink)}
.ph-msearch{margin:0 0 var(--s4)}
.ph-msearch .tbar-search{flex:1 1 auto;width:100%}
.ph-mform{margin:0}
.ph-mlbl{display:flex;align-items:center;gap:var(--s2);margin:0 0 var(--s3);color:var(--muted);font-size:var(--t-ui)}
.ph-mrow{display:flex;align-items:flex-start;gap:var(--s3);padding:var(--s2) 0;white-space:normal;font-size:var(--t-ui)}
.ph-mrow input{margin-top:3px}
.ph-mnone{margin:var(--s3) 0}
.ph-mfoot{display:flex;justify-content:flex-end;margin-top:var(--s4);padding-top:var(--s4);border-top:1px solid var(--line)}
.ph-h2{font-size:17px;margin:var(--s6) 0 var(--s4)}
.ph-table .c-amt{width:100px}

/* ---- REPORT TRACKING (083) ---------------------------------------------------------------- */
.pt-card{padding:var(--s5);max-width:900px}
.pt-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--s4)}
.pt-head .tbar-title{margin:0;font-size:17px}
.pt-who{margin:0 0 var(--s4);font-size:var(--t-ui)}
.pt-test{border:1px solid var(--line);border-radius:8px;margin:0 0 var(--s3)}
.pt-test > summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s4);background:#FAFAFA;border-radius:8px;font-size:var(--t-ui)}
.pt-test > summary::-webkit-details-marker{display:none}
.pt-test[open] > summary{border-bottom:1px solid var(--line);border-radius:8px 8px 0 0}
.pt-test > summary .ic-i{transition:transform .15s}
.pt-test:not([open]) > summary .ic-i:first-child{transform:rotate(-90deg)}
.pt-bar{margin-left:auto;color:var(--muted);font-family:var(--f-data);font-size:var(--t-tight)}
.pt-line{list-style:none;margin:0;padding:var(--s4) var(--s5)}
.pt-line li{display:flex;gap:var(--s3);align-items:flex-start;padding:0 0 var(--s4);position:relative;font-size:var(--t-ui)}
.pt-line li::before{content:'';position:absolute;left:5px;top:14px;bottom:-2px;width:2px;background:var(--line)}
.pt-line li:last-child::before{display:none}
.pt-dot{flex:0 0 12px;width:12px;height:12px;margin-top:4px;border-radius:50%;border:2px solid var(--navy);background:#fff;position:relative;z-index:1}
.pt-dot.pt-now{background:var(--navy)}

/* ---- NEW REGISTRATION (081c) — the last of the old shapes off this screen ------------------ */
/* Server-rendered candidates use the SAME dropdown the typeahead paints, so a search with script
   blocked looks like the search with script running. */
.ta-static{position:static;margin:var(--s2) 0 var(--s4);max-width:466px}
/* The Add-doctor dialog: the reference's modal, opened by a <details> so it needs no script. */
.ref-modal{margin:0}
.ref-modal > summary{list-style:none;display:none}
.ref-modal[open] > .modal-wrap{position:fixed;inset:0;z-index:60;background:rgba(16,24,40,.45);
  display:flex;align-items:center;justify-content:center;padding:var(--s4)}
.ref-modal .modal-panel{width:min(40rem,100%)}
.ref-modal .drawer-x{background:none;border:0;font-size:22px;line-height:1;cursor:pointer;color:var(--muted)}
.reg-foot{display:flex;justify-content:flex-end;gap:var(--s3);margin:var(--s5) 0 0}

/* ---- 099 BOOKINGS (Flabs clone, section 1): the head bar and the status pills ------------- */
/* The reference's page head: title + blurb left, view toggle · refresh · Export · New Booking
   right. The register itself reuses the patient list's skin — one table language per Terminal. */
.bk-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s4);margin:0 0 var(--s4)}
.bk-head h1{margin:0}
.bk-sub{margin:4px 0 0}
.bk-head-actions{display:flex;align-items:center;gap:8px;flex-wrap:nowrap}
.bk-viewtoggle{display:inline-flex;border:1px solid var(--line);border-radius:6px;overflow:hidden}
.bk-viewtoggle .btn{border:0;border-radius:0}
.bk-viewtoggle .on{background:rgba(26,45,90,.07);color:var(--navy)}
/* the ladder's colours, one pill class per stop; In Progress covers its four inner states */
.bk-sched{background:#FFF4E5;color:#B25E09;border:1px solid #F5DFC0}
.bk-conf{background:#E7F0FE;color:#1D5CC8;border:1px solid #C9DCF8}
.bk-phlebo{background:#F1EAFB;color:#6B3FBF;border:1px solid #E0D2F5}
.bk-prog{background:rgba(26,45,90,.07);color:var(--navy);border:1px solid rgba(26,45,90,.18)}
.bk-resch{background:#FDF3D7;color:#8A6D1A;border:1px solid #F0E2B0}
.bk-cancel{background:#FDEBEC;color:#B3261E;border:1px solid #F5CFCC}
.bk-unmapped{color:var(--muted)}

/* ---- 100 NEW BOOKING (Flabs clone, section 2): the six-step wizard ------------------------- */
/* One form; the steps render stacked for a no-script page and erp-bookings.js shows one at a
   time. The chips are the reference's numbered stepper: current, done, and locked-until-valid. */
.bw{max-width:1080px}
.bw-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s4);margin:0 0 var(--s4)}
.bw-head h1{margin:0}
.bw-sub{margin:4px 0 0}
.bw-err{margin:0 0 var(--s4)}
.bw-chips{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:0 0 var(--s5);padding:0}
.bw-chip{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;border:1px solid var(--line);
  border-radius:999px;font-size:var(--t-ui);color:var(--muted);cursor:pointer;background:#fff;user-select:none}
.bw-chip-n{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;
  border-radius:50%;background:rgba(26,45,90,.07);color:var(--navy);font-size:12px;font-weight:600}
.bw-chip.on{border-color:var(--navy);color:var(--ink);background:rgba(26,45,90,.07)}
.bw-chip.on .bw-chip-n{background:var(--navy);color:#fff}
.bw-chip.done .bw-chip-n{background:#E6F4EA;color:#1E7A3C}
.bw-chip.locked{opacity:.5;cursor:not-allowed}
.bw-step{border:1px solid var(--line);border-radius:10px;background:#fff;padding:var(--s5);margin:0 0 var(--s5)}
.bw-step legend{padding:0 8px;font-weight:600}
.bw-wide{grid-column:1/-1}
.bw-ratechip{margin:var(--s3) 0 0;font-size:var(--t-ui)}
.bw-ratechip b{background:rgba(26,45,90,.07);color:var(--navy);border-radius:6px;padding:2px 8px}
.bw-ladder{margin:6px 0 0;font-size:var(--t-tight)}
/* step 3: the picker row, the numbered lines, the money strip */
.bw-find{display:flex;gap:var(--s3);align-items:flex-start;margin:0 0 var(--s4)}
.bw-find .tbar-search{flex:1;position:relative;max-width:520px}
.bw-find select{height:36px}
.bw-lines{width:100%}
.bw-lines .c-sr{width:44px}
.bw-lines .c-price{width:120px;text-align:right}
.bw-lines .c-act{width:56px;text-align:right}
.bw-empty td{color:var(--muted);text-align:center;padding:var(--s5)}
.bw-money{max-width:380px;margin:var(--s4) 0 0 auto;display:grid;gap:8px}
.bw-money .row{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);font-size:var(--t-ui)}
.bw-money .total{border-top:1px solid var(--line);padding-top:8px;font-size:var(--t-body)}
.bw-discbox{display:inline-flex;gap:6px;margin-left:auto}
.bw-discbox select{width:56px}
.bw-discbox input{width:96px}
/* step 4: the slot grid — three windows of half-hourly chips, plus Custom */
.bw-slotwrap{margin-top:var(--s2)}
.bw-slotgrp h4{margin:var(--s4) 0 6px;font-size:var(--t-ui);letter-spacing:.04em}
.bw-slotgrp h4 .muted{font-weight:400;letter-spacing:0}
.bw-slots{display:flex;flex-wrap:wrap;gap:8px;margin:0}
.bw-slot{display:inline-flex;cursor:pointer}
.bw-slot input{position:absolute;opacity:0;pointer-events:none}
.bw-slot span{display:inline-block;padding:6px 12px;border:1px solid var(--line);border-radius:6px;
  font-size:var(--t-ui);font-family:var(--f-data);background:#fff}
.bw-slot input:checked + span{background:var(--navy);border-color:var(--navy);color:#fff}
.bw-slot input:focus-visible + span{outline:2px solid var(--navy);outline-offset:1px}
.bw-custom{align-items:center;margin-top:var(--s4)}
.bw-custom input[type="time"]{height:34px}
/* steps 5-6: the choice cards (collection type, payment mode) */
.bw-cards{display:flex;flex-wrap:wrap;gap:var(--s4);margin:0 0 var(--s5)}
.bw-card{flex:1 1 220px;max-width:320px;display:block;border:1px solid var(--line);border-radius:10px;
  padding:var(--s4);cursor:pointer;background:#fff}
.bw-card input{position:absolute;opacity:0;pointer-events:none}
.bw-card-t{display:block;font-weight:600}
.bw-card-b{display:block;margin-top:4px;font-size:var(--t-ui)}
.bw-card:has(input:checked){border-color:var(--navy);background:rgba(26,45,90,.07);box-shadow:0 0 0 1px var(--navy) inset}
.bw-nocustom{margin:var(--s2) 0 0}
/* step 6: the summary */
.bw-sum{max-width:460px;border:1px solid var(--line);border-radius:10px;padding:var(--s4) var(--s5);display:grid;gap:8px}
.bw-sum h3{margin:0 0 4px}
.bw-sum .row{display:flex;justify-content:space-between;gap:var(--s4);font-size:var(--t-ui)}
.bw-sum .row > span:first-child{color:var(--muted)}
.bw-sum .total{border-top:1px solid var(--line);padding-top:8px;font-size:var(--t-body)}
.bw-nav{display:flex;align-items:center;gap:var(--s3);margin:var(--s5) 0}
.bw-nav-gap{flex:1}

/* ---- 101 BOOKING DETAIL + KEBAB (Flabs clone, section 3) ----------------------------------- */
/* The detail: head with the gated buttons, the five-stop ladder, then Patient / Schedule /
   Tests / Notes / Activity as cards. The row kebab reuses the patient list's menu skin, with
   the reference's group headers; actions follow the status. */
.bd{max-width:1080px}
.bd-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s4);margin:0 0 var(--s4)}
.bd-head h1{margin:2px 0}
.bd-crumb{margin:0;font-size:var(--t-ui)}
.bd-crumb a{color:var(--muted);text-decoration:none;display:inline-flex;align-items:center;gap:4px}
.bd-crumb a:hover{color:var(--ink)}
.bd-who{margin:2px 0 0;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.bd-actions{display:flex;gap:8px;flex-wrap:wrap}
.bd-err{margin:0 0 var(--s4)}
.bd-cancelled{display:flex;align-items:center;gap:8px;margin:0 0 var(--s5);padding:10px 14px;
  background:#FDEBEC;color:#B3261E;border:1px solid #F5CFCC;border-radius:8px}
.bd-ladder{display:flex;gap:0;list-style:none;margin:0 0 var(--s5);padding:0}
.bd-ladder li{flex:1;position:relative;text-align:center;font-size:var(--t-ui);color:var(--muted);padding-top:20px}
.bd-ladder li::before{content:'';position:absolute;top:7px;left:-50%;width:100%;height:2px;background:var(--line)}
.bd-ladder li:first-child::before{display:none}
.bd-dot{position:absolute;top:0;left:50%;transform:translateX(-50%);width:14px;height:14px;
  border-radius:50%;border:2px solid var(--line);background:#fff}
.bd-ladder li.done{color:var(--ink)}
.bd-ladder li.done .bd-dot{border-color:#1E7A3C;background:#1E7A3C}
.bd-ladder li.done::before{background:#1E7A3C}
.bd-ladder li.now{color:var(--ink);font-weight:600}
.bd-ladder li.now .bd-dot{border-color:var(--navy);background:var(--navy)}
.bd-ladder li.now::before{background:#1E7A3C}
.bd-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s4)}
@media(max-width:900px){.bd-grid{grid-template-columns:1fr}}
.bd-sec h3{margin:0 0 var(--s4);display:flex;align-items:center;justify-content:space-between}
.bd-kv{display:flex;gap:var(--s4);padding:5px 0;font-size:var(--t-ui)}
.bd-kv > span:first-child{flex:0 0 130px;color:var(--muted)}
.bd-lines .c-sr{width:36px}
.bd-lines .c-price{width:110px;text-align:right}
.bd-pri{text-transform:capitalize}
.bd-pri-urgent{color:#B3261E;font-weight:600}
.bd-pri-high{color:#B25E09;font-weight:600}
.bd-note{border-top:1px solid var(--line);padding:var(--s3) 0}
.bd-note.pinned{background:#FFFBEB;margin:0 calc(-1 * var(--s3));padding:var(--s3)}
.bd-note-meta{margin:0 0 4px;display:flex;align-items:center;gap:8px;font-size:var(--t-tight)}
.bd-note-body{margin:0;white-space:pre-wrap}
.bd-activity{grid-column:1/-1}
.bd-wide{width:min(52rem,100%)}
/* the kebab's group headers and the register's action column */
.bk-pop{min-width:230px}
.kebab-h{display:block;padding:var(--s2) var(--s3) 2px;font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.kebab-h:not(:first-child){border-top:1px solid var(--line);margin-top:4px;padding-top:8px}
.kebab-item.bk-danger{color:#B3261E}
.c-kebab{width:48px;text-align:right}

/* ---- 102 THE CRM FEED: the Unmapped tab's Resolve door ------------------------------------- */
.bk-resolve{white-space:nowrap;text-align:right}
.bk-resolve .btn{margin-left:6px}

/* ---- 103/105 BOOKINGS CALENDAR: the month as a summary, and the day beside it --------------
   Rebuilt against the reference after VS put the two side by side. Theirs does not list chips
   in a cell — the cell carries a COUNT, a distribution BAR and the day's money, and the day's
   bookings live in a panel to the right with their own chips and search. Ours does that, and
   adds the home/lab split, which is the number a collection round is planned against. */
.bkc-wrap{display:grid;grid-template-columns:minmax(0,1fr) 336px;gap:var(--s4);align-items:start}
@media(max-width:1080px){.bkc-wrap{grid-template-columns:1fr}}
.bkc-main{overflow:hidden}
.bkc-bar{display:flex;align-items:center;justify-content:space-between;gap:var(--s3) var(--s4);
  flex-wrap:wrap;padding:8px var(--s5);border-bottom:1px solid var(--line)}
.bkc-nav{display:inline-flex;align-items:center;gap:8px}
.bkc-label{min-width:132px;text-align:center;font-size:var(--t-body)}
/* the key, read once, above the month */
/* the key is a key, not a paragraph: it must not cost the month a row of its own */
.bkc-legend{display:flex;flex-wrap:wrap;gap:2px 11px;margin:0;font-size:11px;color:var(--muted);line-height:1.5}
.bkc-lg{display:inline-flex;align-items:center;gap:5px;white-space:nowrap}
.bkc-dot{width:8px;height:8px;border-radius:50%;flex:0 0 8px}
.bkc-d-sched{background:#E8A33D}.bkc-d-resch{background:#D9B441}.bkc-d-conf{background:#2FA8A0}
.bkc-d-phlebo{background:#6B3FBF}.bkc-d-prog{background:var(--navy)}.bkc-d-started{background:#3D86D8}
.bkc-d-atloc{background:#B03FBF}.bkc-d-coll{background:#2E8B57}.bkc-d-done{background:#1E7A43}
.bkc-d-cancel{background:#D0453E}

.bkc-grid{width:100%;border-collapse:collapse;table-layout:fixed}
.bkc-grid th{padding:6px 10px;border-bottom:1px solid var(--line);font-size:var(--t-tight);
  color:var(--muted);text-align:left;font-weight:500}
.bkc-grid th abbr{text-decoration:none}
/* A MONTH MUST FIT ONE SCREEN. At 98px the last week fell below the fold on a 1440x765
   window, which turns "how does August look" into a scroll. 76px still holds the number, the
   spread and the money with air. */
.bkc-day{vertical-align:top;height:70px;padding:0;border-bottom:1px solid var(--line);
  border-right:1px solid var(--line)}
.bkc-day:last-child{border-right:0}
.bkc-grid tbody tr:last-child .bkc-day{border-bottom:0}
/* the whole cell is the target — a day is one click, not a hunt for its number */
.bkc-cell{display:flex;flex-direction:column;gap:4px;height:100%;padding:5px 8px;
  text-decoration:none;color:var(--ink)}
.bkc-cell:hover{background:#FAFAFB}
.bkc-out .bkc-cell{color:var(--muted);opacity:.5}
.bkc-out .bkc-cell:hover{background:none}
.bkc-num{display:flex;align-items:center;justify-content:space-between;gap:6px;
  font-family:var(--f-data);font-size:var(--t-ui);line-height:1.3}
.bkc-count{display:inline-flex;min-width:18px;height:18px;padding:0 5px;align-items:center;
  justify-content:center;border-radius:999px;background:rgba(26,45,90,.07);color:var(--navy);
  font-size:11px;font-weight:600}
.bkc-today .bkc-num{color:var(--navy);font-weight:700}
.bkc-today .bkc-count{background:var(--navy);color:#fff}
.bkc-sel{background:#F4F7FE;box-shadow:inset 0 0 0 2px var(--navy)}
.bkc-sel .bkc-cell:hover{background:transparent}
/* the distribution bar is NOT .bkc-bar (that is the toolbar above the grid) — one class, one
   job, the lesson .pl-x taught this codebase twice */
.bkc-spread{display:flex;gap:2px;height:4px;border-radius:2px;overflow:hidden;margin-top:auto}
.bkc-spread i{display:block;min-width:3px;border-radius:2px}
.bkc-money{font-family:var(--f-data);font-size:11px;color:var(--muted);line-height:1}

/* the day panel */
.bkc-panel{position:sticky;top:var(--s4);padding:0;display:flex;flex-direction:column;max-height:calc(100vh - 120px)}
@media(max-width:1080px){.bkc-panel{position:static;max-height:none}}
.bkc-phead{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s3);
  padding:var(--s4) var(--s5) var(--s3)}
.bkc-phead h2{margin:0;font-size:var(--t-body)}
.bkc-phead p{margin:2px 0 0;font-size:var(--t-ui)}
.bkc-mix{display:flex;gap:10px;margin:0;font-size:var(--t-ui);color:var(--muted);white-space:nowrap}
.bkc-mix span{display:inline-flex;align-items:center;gap:4px;font-family:var(--f-data)}
.bkc-chips{display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0 var(--s5) var(--s3)}
.bkc-chip{display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;
  border:1px solid var(--line);background:#fff;color:var(--muted);
  font-size:var(--t-tight);text-decoration:none;white-space:nowrap}
.bkc-chip:hover{border-color:var(--navy);color:var(--ink)}
.bkc-chip.on{outline:2px solid var(--navy);outline-offset:-2px;color:var(--ink)}
.bkc-find{padding:0 var(--s5) var(--s3)}
.bkc-find .tbar-search{width:100%}
.bkc-list{overflow-y:auto;padding:0 var(--s5) var(--s3);display:grid;gap:8px}
.bkc-none{margin:var(--s3) 0;display:flex;flex-direction:column;align-items:flex-start;gap:8px}
.bkc-card{display:grid;gap:5px;padding:9px 11px;border:1px solid var(--line);border-left:3px solid var(--navy);
  border-radius:8px;text-decoration:none;color:var(--ink);background:#fff}
.bkc-card:hover{border-color:var(--navy);border-left-color:var(--navy);background:#FCFCFE}
.bkc-cname{display:flex;justify-content:space-between;gap:8px;font-weight:600;font-size:var(--t-ui)}
.bkc-camt{font-family:var(--f-data);font-weight:500;color:var(--muted)}
.bkc-cmeta{display:flex;flex-wrap:wrap;gap:5px;align-items:center}
.bkc-time,.bkc-ctype{display:inline-flex;align-items:center;gap:4px;padding:2px 7px;border-radius:4px;
  background:#F4F3F0;color:var(--muted);font-size:var(--t-tight);white-space:nowrap}
.bkc-time{font-family:var(--f-data)}
.bkc-cwho{display:inline-flex;align-items:center;gap:4px;font-size:var(--t-tight);color:var(--muted)}
.bkc-pfoot{margin:auto 0 0;padding:var(--s3) var(--s5) var(--s4);border-top:1px solid var(--line)}
.bkc-pfoot a{display:inline-flex;align-items:center;gap:5px;font-size:var(--t-ui);
  color:var(--navy);text-decoration:none}
.bkc-pfoot a:hover{text-decoration:underline}

/* ---- 104 MORE FILTERS + COLUMNS + EXPORT + CONVERT ----------------------------------------- */
.bk-drawer-pop{min-width:280px;padding:var(--s4);display:grid;gap:10px;max-height:70vh;overflow:auto}
.bk-drawer-pop .bill-lbl span{font-size:var(--t-tight)}
.bk-drawer-foot{display:flex;justify-content:flex-end;gap:8px;margin:4px 0 0}
.bk-colpop .kebab-pop{min-width:180px;padding:var(--s3)}
.bk-colopt{display:flex;padding:4px 2px}
.bk-optcell{max-width:180px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bd-convert{display:inline}
/* the register's toolbar carries more than one row's worth at 1280px: let it wrap, and never
   let flex crush a drawer summary to an icon sliver */
#bkf .pl-actions{flex-wrap:wrap;justify-content:flex-end}
#bkf .kebab{flex:0 0 auto}
#bkf .kebab > summary{white-space:nowrap}

/* ---- 105 THE REGISTER, MEASURED AGAINST THE REFERENCE --------------------------------------
   Gaps found by putting the two screens side by side (VS 2026-08-24): the count sat before the
   label, the tests cell borrowed .pl-x (which is the bordered EXPAND button, so "+1" rendered
   in a box), the pills carried no mark, the type read as bare text, the kebab inherited
   .pl-kebab's 176px and wrapped every long verb onto two lines, and the table ended without
   saying how much of it there was. */

/* nine doors do not wrap onto a second line — they scroll, and the strip keeps one height */
.pl-tabs{flex-wrap:nowrap;gap:var(--s5);scrollbar-width:thin}
.pl-tabs .dtab{flex:0 0 auto}

/* the tests cell: a kind letter on the chip (T/P/S, the reference's badge) and a quiet +N that
   is TEXT, not a button — the row has exactly one control and it is the kebab */
.bk-k-t{background:#EAF6EE;color:#1E7A43}
.bk-k-p{background:rgba(26,45,90,.07);color:var(--navy)}
.bk-k-s{background:#F1EAFB;color:#6B3FBF}
.pl-tname .pl-letter{margin-right:2px;vertical-align:-1px}
.bk-more{display:inline-block;margin-left:6px;color:var(--muted);font-size:var(--t-tight);
  font-family:var(--f-data);white-space:nowrap}
/* type and money read as data */
.bk-type{white-space:nowrap}
.bk-type .ic-i{color:var(--muted);vertical-align:-2px;margin-right:4px}
.bk-amt{font-family:var(--f-data);text-align:right;white-space:nowrap}
.bk-when{white-space:nowrap}
.bk-who{display:inline-block;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
/* a cancelled row is history: present, legible, and visibly not live work */
.bk-row-dead td:not(.c-sel):not(.c-kebab){opacity:.62}
/* the Unmapped tab names each gap as a chip, key in bold — the triage IS the list */
.bk-gap{display:inline-block;margin:1px 6px 1px 0;padding:2px 8px;border-radius:4px;
  background:#FFF7E8;color:#8A6D1A;font-size:var(--t-tight);white-space:nowrap}
.bk-gap b{font-weight:600}
.bk-emptyhint{margin-top:4px}

/* selection: the column, and a bar that only lights when it can act */
.pl-table .c-sel{width:38px;text-align:center;padding-right:0}
.pl-table .c-sel input{width:15px;height:15px;accent-color:var(--navy);cursor:pointer;vertical-align:middle}
/* 106e — THE BULK BAR IS A RESPONSE, NOT A BAND. Measured: the register card stood 319px tall and
   61px of that was the booking. Five stacked bands and four full-width rules before you reached a
   row, and one of the bands — 47px of it — existed to tell you that nothing was selected. That is
   the "still crammed" VS is reading: not the columns, the CHROME above them.

   `:has()` and not a class, so it works with script off: the bar answers the checkboxes directly
   rather than waiting for erp-bookings-list.js to notice them. And because it can only be on
   screen when something IS selected, it drops the greyed-out state it used to wear. */
.bk-bulkbar{display:none;align-items:center;gap:var(--s4);flex-wrap:wrap;
  padding:8px var(--s5);border-bottom:1px solid rgba(26,45,90,.18);background:#F4F7FE;
  color:var(--ink);font-size:var(--t-ui)}
.pl-card:has(.bk-table input[name="ids"]:checked) .bk-bulkbar{display:flex}
.bk-bulkn{font-variant-numeric:tabular-nums}
.bk-bulkacts{display:flex;align-items:center;gap:8px;margin-left:auto;flex-wrap:wrap}
.bk-bulkassign{display:inline-flex;gap:6px;align-items:center}
.bk-bulkassign select{height:30px;max-width:190px}
.bk-bulkbar .btn:disabled,.bk-bulkbar select:disabled{opacity:.5;cursor:not-allowed}
/* the count under the table: the reference prints one, and ours also owns up to the 500 ceiling */
.bk-foot{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s4);
  margin:0;padding:var(--s4) var(--s5);border-top:1px solid var(--line);
  color:var(--ink);font-size:var(--t-ui)}
.bk-foot .pl-sub{display:inline}

/* the kebab: a tinted tile per verb, and a width that never breaks a label in half.
   .pl-kebab .kebab-pop{min-width:176px} out-specifies a lone .bk-pop — this must carry BOTH
   classes to win, which is the whole reason the menu was wrapping. */
.pl-kebab.bk-kebab .kebab-pop{min-width:258px}
.bk-kebab .kebab-item{white-space:nowrap;gap:10px;padding:6px var(--s3)}
.kb-ic{display:inline-flex;align-items:center;justify-content:center;flex:0 0 24px;
  width:24px;height:24px;border-radius:7px}
.kb-ic .ic-i{width:14px;height:14px}
.kb-ok{background:#EAF6EE;color:#1E7A43}
.kb-info{background:rgba(26,45,90,.07);color:var(--navy)}
.kb-warn{background:#FFF4E5;color:#B25E09}
.kb-bad{background:#FDEBEC;color:#B3261E}
.kb-vio{background:#F1EAFB;color:#6B3FBF}
.kb-navy{background:#E8ECF6;color:var(--navy)}
.kb-grey{background:#F1F0EC;color:var(--muted)}
/* a held action keeps its shape and loses its colour — visibly present, visibly not yet */
.kebab-item:disabled .kb-ic{background:#F4F3F0;color:#C2BFB6}

/* ---- 105 THE WIZARD, measured against the reference ---------------------------------------
   Their stepper marks each step with an ICON and gives it a sentence; ours had numbers and a
   bare legend, which made every step look the same until you read the fields. */
/* EVERY step wears its icon, as the reference does; the number is the fallback for a step
   that has none, and a finished step swaps the icon for a tick. */
.bw-chip{gap:7px}
.bw-chip-n{display:none}
.bw-chip-ic,.bw-chip-ok{display:inline-flex;align-items:center;justify-content:center;
  width:20px;height:20px;border-radius:50%;background:#F1F0EC;color:var(--muted);flex:0 0 20px}
.bw-chip-ok{display:none}
.bw-chip .ic-i{width:12px;height:12px}
.bw-chip.on .bw-chip-ic{background:var(--navy);color:#fff}
.bw-chip.done .bw-chip-ic{display:none}
.bw-chip.done .bw-chip-ok{display:inline-flex;background:#E6F4EA;color:#1E7A3C}
.bw-legendsub{margin:-4px 0 var(--s5);color:var(--muted);font-size:var(--t-ui);max-width:74ch}
.bw-note{display:flex;align-items:center;gap:8px;margin:var(--s2) 0 0;padding:9px 13px;
  border:1px solid rgba(26,45,90,.18);background:#F4F7FE;border-radius:8px;color:var(--ink);font-size:var(--t-ui)}
.bw-note .ic-i{color:var(--navy);flex:0 0 auto}

/* ---- 105 DISPATCH METHODS as chips (New Registration) --------------------------------------
   The reference shows each chosen method as its own chip and lets the box grow to hold them.
   The popup must follow the box's real height, not a fixed control height, or it lands on top
   of the second row of chips. */
.msel > summary{height:auto;min-height:var(--ctrl-h);flex-wrap:wrap;gap:5px}
.msel-pop{top:calc(100% + 4px)}
.msel-chips{display:flex;flex-wrap:wrap;gap:5px;padding:2px 0}
.msel-chip{display:inline-flex;align-items:center;padding:2px 9px;border-radius:999px;
  background:rgba(26,45,90,.07);color:var(--navy);border:1px solid rgba(26,45,90,.18);font-size:var(--t-tight);white-space:nowrap}
/* a carried line: on the booking, priced as booked, and the only thing that can be done to it
   is take it off — the wizard has no rate to re-read for it */
.bw-kept td{background:#FFFDF6}
.bw-asbooked{background:#FFF4E5;color:#8A6D1A}

/* ---- 105b: what only the pixels showed --------------------------------------------------
   Measured on the live register beside the reference: a long test name wrapped to THREE lines
   and made one row 87px against its neighbours' 69, which reads as a broken grid; and the
   Assigned To / Booking Created headers ended up 2px apart, so they scanned as one phrase. */
.bk-table .pl-tname{display:-webkit-box;-webkit-line-clamp:2;-webkit-line-clamp:2;line-clamp:2;
  -webkit-box-orient:vertical;overflow:hidden;max-width:210px}
/* 106d: the register's rows keep the house 10px. They used to squeeze to 8 to claw back height
   from cells that were wrapping; the columns are wide enough now that nothing wraps. */
.bk-table td{padding-top:10px;padding-bottom:10px}
/* the two date columns and the assignee need their own room, or their headings collide */
.bk-table .c-asg{min-width:124px}
.bk-table .c-when{min-width:104px}

/* THE ACTIONS ARE ALWAYS REACHABLE. With the select column and the optional columns the table
   is wider than the card, so the kebab scrolled off the right edge — on the reference too. A
   row's own menu must never be something you have to go looking for: it stays pinned to the
   right, over a hairline shadow that shows there is more table underneath. */
.bk-table .c-kebab,.bk-table thead th:last-child{position:sticky;right:0;z-index:2;background:#fff}
.bk-table thead th:last-child{background:#FAFAF8}
.bk-table tbody tr:hover .c-kebab{background:#FBFAF8}
.bk-table .c-kebab::before{content:'';position:absolute;left:0;top:0;bottom:0;width:6px;
  transform:translateX(-100%);pointer-events:none;
  background:linear-gradient(to right,rgba(16,24,40,0),rgba(16,24,40,.06))}
/* the open menu must sit ABOVE the pinned column's neighbours, not be clipped by them */
.bk-table .c-kebab .kebab[open]{z-index:40}
/* the range presets: a named range beats two typed dates, and the button SAYS which one is on */
.bk-rangepop .kebab-pop{min-width:170px}
.bk-rangepop .kebab-item.on{background:rgba(26,45,90,.07);color:var(--navy);font-weight:500}
/* 106 — ONE CONTINUOUS LEFT-PACKED ROW, which is what the reference's is. Measured on theirs:
   search 280px then All Types, the date range, More Filters and Columns following it at a 10px
   gap, everything hard against the left. Ours split the bar in two — search pinned left, the rest
   pinned right by `.pl-actions{margin-left:auto}` — with 300px of nothing in the middle, and then
   wrapped onto a second row anyway because the group would not shrink.

   Now: the ACTIONS never wrap (flex-wrap:nowrap) and never shrink (flex:0 0 auto), so the search
   absorbs the squeeze — it is the one control that still works at any width. All eight controls
   sit on one line at 1440 with the search at 227px; below that the search gives ground first and
   the row still holds. Verified against the live register, not against a fixture. */
#bkf{justify-content:flex-start}
#bkf .tbar-search{flex:1 1 auto;min-width:170px;max-width:300px}
#bkf .pl-actions{margin-left:0;min-width:0;flex:0 0 auto;flex-wrap:nowrap;justify-content:flex-start;row-gap:8px}
/* their Type dropdown is 200px; ours sizes itself to "Home Collection" and would take 157 */
#bkf select[name=btype]{max-width:134px}
.bk-tools{display:inline-flex;align-items:center;gap:8px;flex:0 0 auto}
/* the ladder as a timeline: each stop that has happened says when */
.bd-ladder .bd-when{display:block;margin-top:2px;font-size:11px;color:var(--muted);
  font-family:var(--f-data);line-height:1.3}

/* ==== 106 — ONE TABLE SKIN, ONE KEBAB, AND THE STRIP THAT SCROLLED FOR NO REASON ==============
   VS 2026-08-25, comparing our screens against the reference side by side. Everything in this
   block is a measured gap, not a preference. */

/* A TABLE CLOSES WITH A LINE. Removing `tbody tr:last-child td{border-bottom:0}` is what makes
   the last row look like a row instead of a paragraph fading out — but the closing rule should be
   the weight of the OPENING one, not an interior hairline, so the table reads as a bounded object:
   --line above and below, --line-s between. */
.dtable tbody tr:last-child td,.atable tbody tr:last-child td{border-bottom:1px solid var(--line)}
/* ...and then the count strip under the table must not draw a SECOND line 1px below the first. */
.bk-foot{border-top:0}

/* TOTALS ROW. Eleven tables in Books, Packages and Patient Due close on a <tfoot>; before 106 the
   only rule for one was .pd-table's, so the other ten rendered as browser-default bold. */
.dtable tfoot th,.dtable tfoot td,.atable tfoot th,.atable tfoot td{
  text-align:left;font-weight:600;color:var(--ink);background:#FAFAF8;
  padding:var(--s3);border-top:1.5px solid var(--line-input);
  border-right:1px solid var(--line-s)}
.dtable tfoot th:last-child,.dtable tfoot td:last-child,
.atable tfoot th:last-child,.atable tfoot td:last-child{border-right:0}

/* The register's strip lived INSIDE its card until W23k (2026-08-30) — white A1 tiles on the
   white card lost the ribbon, so it moved to the canvas above, uniform with Dispatch. */
/* nine tabs on one line inside a card 114px narrower than theirs (our rail is wider). Their strip
   runs at a 24px gap and fits; measured, ours needs 18 — the label text is identical, our count
   badge is the wider element. Below 1440 it wraps, and the tight row gap above keeps the second
   line reading as the same strip. */
.pl-tabs{column-gap:18px}

/* THE MENU IS LAID OUT AGAINST THE VIEWPORT (public/kebab.js), which frees it from .dscroll's
   overflow and the card's clipped corners. Two consequences for the CSS:
     · it needs a z-index that clears the sticky table furniture it now floats over, and
     · the sticky action column is a stacking context of its own (position:sticky + z-index:2), so
       while its menu is open the CELL has to be lifted too or the menu is trapped at z-index 2. */
.kebab-pop{z-index:60}
.bk-table td.c-kebab:has(.kebab[open]),
.bk-table th:last-child:has(.kebab[open]){z-index:41}

/* A NUMBER COLUMN RIGHT-ALIGNS. The B2B ageing table asked for this with `class="n"` — a
   one-letter name no rule had ever heard of, so five columns of rupees sat left-aligned against
   their headings. Renamed into the .t- family the tables already use, and given the rule the
   print views have always had in their own <style>. */
.dtable td.t-num,.dtable th.t-num,.atable td.t-num,.atable th.t-num{
  text-align:right;font-variant-numeric:tabular-nums lining-nums}

/* A TABLE IN A PADDED CARD NEEDS ITS OWN EDGE. In a flush card the card supplies it — the grid
   runs to the card's border and the object is closed. In a padded card there is nothing at the
   ends, so the same grid reads as an open field of lines. One hairline ring closes it, and
   border-collapse merges the ring with the header's and the last row's rules rather than
   doubling them. */
.card:not(.card-flush) .dtable,.card:not(.card-flush) .atable{border:1px solid var(--line)}

/* ==== 106d — THE REGISTER'S COLUMN WIDTHS ======================================================
   VS 2026-08-25: "this portion feels a little congested and crammed, give every column their
   space to breathe". Measured, ours against theirs, at 1440:

     column          theirs   ours was   ours now
     select            48        24         44
     #                 50        27         44
     Patient          190        78        190     <- the name was wrapping onto two lines
     Tests & Packages 220       130        220     <- the package chip was wrapping too
     Type             150       146        150
     Status           160       121        150
     Payment          100       106        112
     Amount           110        71        104
     Scheduled        140       104        128
     Assigned To      150       124        140
     Booking Created  160       126        128
     action            60        49         56

   Six of the twelve carried no class, so the browser distributed the space by content and gave
   Patient 78px while "Home Collection" took 146. Every column is named now and sized to what it
   actually holds.

   AND YES, IT SCROLLS. Their register is 1554px in a 1176px holder — 378px, a quarter of the
   table, off screen at all times. Ours is narrower still because our rail is wider, so cramming
   twelve columns into 1054 was never going to be readable; the choice was a table you cannot read
   or a table you scroll, and the reference already made it. What we add on top: the action column
   is pinned, so a row's menu never scrolls away, and the Columns control drops any of the six
   optional columns for a desk that does not want them. */
.bk-table .c-sel{width:44px}
.bk-table .c-num{width:44px}
.bk-table .c-pat{width:190px;min-width:190px}
.bk-table .c-tests{width:220px;min-width:220px}
.bk-table .c-gap{min-width:220px}
.bk-table .c-type{width:150px;min-width:150px}
.bk-table .c-st{width:150px;min-width:150px}
.bk-table .c-pay{width:112px;min-width:112px}
.bk-table .c-amt{width:104px;min-width:104px}
.bk-table .c-when{width:128px;min-width:128px}
.bk-table .c-asg{width:140px;min-width:140px}
.bk-table .c-kebab,.bk-table thead th:last-child{width:56px;min-width:56px}
/* the two-line cells are two REAL lines now, not a clamped one-and-a-bit */
.bk-table .pl-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
/* THE FLOOR. Sum of the twelve columns above; the six optional ones push past it when switched on.
   Without it the table compresses every `width` back down to fit and the sizing above does nothing
   — measured: Patient rendered 121px under a 190px rule. */
.bk-wide{min-width:1466px}

/* A ROW'S OWN CONTROLS ARE NEVER SOMETHING YOU SCROLL TO FIND (106d). The register proved the
   pattern with its kebab column; .c-stick is the same thing as a house primitive, for any table
   whose last column is what you act with. The ::before is a 6px gradient that sits OUTSIDE the
   cell, so the pinned column reads as floating over the scroll rather than glued to the edge. */
.dtable .c-stick,.atable .c-stick{position:sticky;right:0;z-index:2;background:#fff}
.dtable thead th.c-stick,.atable thead th.c-stick{background:#FAFAF8}
.dtable tbody tr:hover .c-stick,.atable tbody tr:hover .c-stick{background:#FBFAF8}
.dtable .c-stick::before,.atable .c-stick::before{content:'';position:absolute;left:0;top:0;bottom:0;
  width:6px;transform:translateX(-100%);pointer-events:none;
  background:linear-gradient(to right,rgba(16,24,40,0),rgba(16,24,40,.06))}
/* a sticky cell is its own stacking context: lift it while its menu is open */
.dtable td.c-stick:has(.kebab[open]){z-index:41}
/* the six switchable columns. 120 is enough for a pincode, a rate list or a priority; address and
   location clamp at .bk-optcell's 180 and ellipsise rather than growing the table by an address. */
.bk-table .c-opt{min-width:120px}

/* THE SCROLLBAR UNDER A WIDE TABLE. Windows draws the default one as a 15px slab of mid-grey, and
   on a card holding one booking it is the loudest thing in the lower half — VS's screenshot is
   mostly that bar. Thin, warm, and on the card's own ground: an affordance, not a fixture. */
.dscroll,.dscroll-tall{scrollbar-width:thin;scrollbar-color:#CFC8BC transparent}
.dscroll::-webkit-scrollbar,.dscroll-tall::-webkit-scrollbar{width:10px;height:10px}
.dscroll::-webkit-scrollbar-track,.dscroll-tall::-webkit-scrollbar-track{background:transparent}
.dscroll::-webkit-scrollbar-thumb,.dscroll-tall::-webkit-scrollbar-thumb{
  background:#DCD6CB;border-radius:99px;border:3px solid #fff;background-clip:padding-box}
.dscroll:hover::-webkit-scrollbar-thumb,.dscroll-tall:hover::-webkit-scrollbar-thumb{background:#C4BCAE}

/* A count that changes without a page load has to be ANNOUNCED, and the bar it used to live in
   now disappears when the selection empties — a hidden element announces nothing. This one is
   always in the tree and never on the screen. */
.sr-live{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* ==== 106f — THE SELECT AND # COLUMNS ==========================================================
   VS: "only this needs proper spacing so that it looks designed not adjusted." Measured, and he
   is reading a real asymmetry rather than a feeling:

     cell 36px wide (a 44px rule, compressed — see below)
     padding 10px 0 10px 12px      <- padding-right:0, inherited from the patient list
     checkbox 15px, sitting 16px from the left edge and 5px from the right

   `text-align:center` was already on the cell and doing nothing, because centring happens inside
   the CONTENT box — and the content box had been pushed 12px right and flush to the cell's edge.
   A box centred inside an off-centre frame is exactly what "adjusted, not designed" looks like.

   And the width: these two were the only columns in 106d given a `width` with no `min-width`, so
   they were the two the auto-layout compressed — 44 asked, 36 and 40 delivered.

   Now: 48px each (the reference's own), symmetric, with the content centred in the whole cell. A
   16px box in a 48px cell leaves exactly 16 on each side. The row number is centred too — an
   ordinal and a tick are POSITION, not values, and a value left-aligned in a box three times its
   width reads as a leftover. (Their # is left-aligned; ours is not. Deliberate — recorded.) */
.bk-table .c-sel,.bk-table thead th.c-sel{width:48px;min-width:48px;
  padding-left:0;padding-right:0;text-align:center}
.bk-table .c-num,.bk-table thead th.c-num{width:48px;min-width:48px;
  padding-left:0;padding-right:0;text-align:center}
/* display:block drops the inline baseline the input was riding — it sat 24px from the top of the
   row and 22px from the bottom. Centred by its own margins, in the middle of the line box. */
.bk-table .c-sel input[type=checkbox]{display:block;margin:0 auto;width:16px;height:16px}
/* tabular figures so a column of 1..99 does not shuffle sideways as the digits change */
.bk-table .c-num{font-variant-numeric:tabular-nums lining-nums;color:var(--muted)}

/* ---- 107 · ENTER & VERIFY, THE PATHOLOGY WORKLIST -------------------------------------------
   The register reuses the Patient List's skin whole — .pl-table, .pl-test/.pl-tname/.pl-letter,
   .pl-status, .pl-drawer — because it IS that register read for the bench. Only the column set
   differs, so only the column set is declared here.

   EVERY NUMBER BELOW WAS MEASURED ON THE LIVE SCREEN AT 1440, NOT ESTIMATED. The first cut was
   estimated, and it shipped a visible defect: a 1136px floor inside a 1054px scrollport left 82px
   of overflow, so `position:sticky; right:0` pinned the Action column 82px to the left of its own
   place and sat on top of Status — permanently, at rest, because there was too little scroll to
   move it off. The browser spec passed: it asserted the pinned cell was inside the viewport,
   which it was. It never asked whether the cell was on top of its neighbour.

   The scrollport is 1054 at 1440. The content, cell padding (12px a side) included:
     Bill Date 86+24 · ID 80+24 · name 102+24 · Status pill 89+24 · Enter Results 117+24
   So both grains are sized to FIT, and the register does not scroll at the width VS reads it at.
   .c-stick stays for narrower windows, where the pin earns its keep. */
.vf-table .c-date{width:110px;min-width:110px}
.vf-table .c-id{width:104px;min-width:104px}
.vf-table .c-pat{width:165px;min-width:165px}
.vf-table .c-ref{width:120px;min-width:120px}
.vf-table .c-tests{min-width:240px}
.vf-table .c-st{width:113px;min-width:113px}
.vf-table .c-act{width:141px;min-width:141px;white-space:nowrap}
.vf-table{min-width:993px}
/* Test wise carries Department as an eighth column, so every other one gives up a little rather
   than the table growing past the scrollport and putting Action back on top of Status. */
.vf-test .c-pat{width:150px;min-width:150px}
/* REBALANCED 2026-08-28 after measuring the FULL August range rather than the default day. The
   Status floor above was measured at 89+24 from a range whose widest pill said "Pending"; over a
   real month the widest is "Complete" at 101+24 = 125, and those 12px were the last of the
   overflow that put Action on top of Status. Referral gives them up: its widest content on this
   register is 46px against a 110px floor, the most slack of any column here. Measure over a
   month, never over a day — a column floor is only as good as the widest row you looked at. */
/* 102, not 104: the browser rounds each column up, so a floor total that EQUALS the scrollport
   still overflows by a pixel. Leave the rounding somewhere to land. */
.vf-test .c-ref{width:102px;min-width:102px}
.vf-test .c-st{width:125px;min-width:125px}
.vf-test .c-dept{width:135px;min-width:135px}
.vf-test .c-tests{min-width:185px}
.vf-test{min-width:1048px}
/* The accession under a test pill reads as the pill's caption, not as a second value. */
.vf-table .c-tests .pl-sub{margin-top:2px;font-family:var(--f-data)}

/* ---- 107 · ENTER & VERIFY, THE ENTRY SCREEN -------------------------------------------------
   Their /doctor_report/<id>, RE-MEASURED in the browser on 2026-08-25 rather than read off my own
   notes, and the notes were wrong about the shape. What the reference actually builds:

     page header    full width, h 76, padding 16, white, position STATIC (it scrolls away)
     Report Entry   one card, x16 w1392, radius 8; its title row pads 0 0 16 and draws NO rule
       test block   its OWN card — 1px #D9D9D9, radius 8, w1358, 16px between blocks
         header     bg #FAFAFA, padding 16, h 65, radius 8 8 0 0, space-between
         param row  h 53, padding 10px 16px, border-bottom 1px #D9D9D9
         footer     h 52, space-between: attachments LEFT, the verdict RIGHT
     bill footer    full width, h 65, pinned to the bottom, space-between

   The first cut made each test a BAND inside one card with a border-top. Five tests then read as
   one long table with headings in it, which is exactly what a per-test verdict must not read as:
   the operator is signing one test at a time and the page has to say so. */
.ve-top{display:flex;align-items:flex-start;gap:var(--s4);flex-wrap:wrap;
  padding:0 0 var(--s4);border-bottom:1px solid var(--line);margin-bottom:var(--s5)}
.ve-who{display:flex;align-items:center;gap:var(--s4);flex-wrap:wrap;min-width:0}
.ve-id{font-size:var(--t-ui);color:var(--ink);min-width:0}
.ve-id b{font-family:var(--f-data)}
/* their header row, measured 2026-08-27: Report Preview | Save | kebab, all 32 tall, 8px apart */
.ve-top-act{margin-left:auto;display:flex;align-items:center;gap:8px}
.ve-of{font-size:var(--t-tight);white-space:nowrap}
/* A CRITICAL VALUE IS NOT A TOAST. enterResults writes it to the custody chain; the screen says
   it in red, above the fold, and names the analyte — a toast that fades is the wrong instrument
   for a potassium of 7.2. */
.ve-crit{display:flex;align-items:center;gap:var(--s3);margin:0 0 var(--s4);
  padding:var(--s3) var(--s4);border:1px solid #E9C4C4;border-left:3px solid var(--bad-ink);
  border-radius:6px;background:#FDF5F5;color:var(--bad-ink);font-weight:600;font-size:var(--t-ui)}
/* .card-flush zeroes the padding (it exists for edge-to-edge tables) and sets overflow:hidden —
   so the first cut's `.ve-card{padding}` lost the cascade and the Apply button was CLIPPED 27px
   off the right edge. Measured, not guessed: card 308..1364, actions 777..1363, Apply 1337..1391.
   The reference insets its blocks 17px from the card edge; ours takes 16. */
.card.ve-card{padding:var(--s5);margin-bottom:var(--s5)}
/* their title row: no rule under it, because each test below is a card with its own edge */
.ve-panel{display:flex;align-items:center;gap:var(--s3) var(--s5);flex-wrap:wrap;
  padding:0 0 var(--s5)}
/* ONE ROW, as the reference's is. Measured on ours after the first deploy: the actions group
   summed to 698px starting at x=794 inside a 1054 card, so Apply wrapped to a second line and
   left "Report Entry" floating against a two-line block. The selects give up the width instead —
   they carry a name, not a paragraph. (Their selects need no Apply at all: theirs fire on change
   in React. Ours submits, because this screen works with script off.) */
/* flex:0 0 auto on the GROUP, not just on its children. With min-width:0 the flex algorithm
   shrank the group to 586 while its children (590 + 24 of gaps = 614) refused to shrink with it,
   so Apply hung 27px past the card's overflow:hidden edge and vanished. Three deploys chasing
   that one button, all of it visible in one measurement of the two boxes. */
/* min-width:max-content, and nothing subtler. .tbar-actions ships min-width:0 (it is built to
   shrink inside a toolbar), and with the group's own children at flex:0 0 auto that produced a
   586px BOX holding 614px of buttons — Apply hung 27px past the card's overflow:hidden edge and
   simply was not there. flex:0 0 auto on the group did not fix it; declaring the floor did.
   Measured each time rather than reasoned about, which is the only reason it took three tries
   and not thirty. */
/* THE MEASUREMENT, AND WHAT IT TOOK. The group's box computes to 586px here while its four
   controls plus three 8px gaps want 614 — and .card-flush sets overflow:hidden, so Apply did not
   wrap, it simply WAS NOT THERE. flex:0 0 auto did not move it and neither did
   min-width:max-content, so the content gives up the 28px instead of the box being argued with:
   the two selects take 164 rather than 180. They carry a name, not a paragraph.
   And the row WRAPS rather than clips, so a narrower window loses a line and never a control. */
.ve-panel .tbar-actions{margin-left:auto;flex-wrap:wrap;justify-content:flex-end}
/* nowrap on the ROW is not enough: flex then shrinks each item to min-content and a long label
   wraps INSIDE its own button — "Show Abnormal / Values" on two lines, which is the same defect
   one level down. The four controls sum to 742 in a 1054 card, so none of them needs to shrink. */
.ve-panel .tbar-actions > *{flex:0 0 auto}
.ve-panel .tbar-actions .btn{white-space:nowrap}
.ve-h{font-size:var(--t-ui);font-weight:600}
.ve-sel{width:164px;max-width:164px;flex:0 0 auto;text-overflow:ellipsis}
.ve-sel-sm{height:28px;min-height:28px;max-width:132px;font-size:var(--t-tight)}
.ve-none{padding:var(--s6) var(--s5);color:var(--muted);text-align:center}
.ve-hidden{display:none}
.ve-inline{display:inline;margin:0}
.ve-spacer{flex:1 1 auto;min-width:0}

/* ONE TEST = ONE CARD, 16px apart, as the reference draws it */
.ve-test{border:1px solid var(--line);border-radius:8px;margin:0 0 var(--s5);overflow:hidden}
.ve-test:last-of-type{margin-bottom:0}
.ve-thead{display:flex;align-items:center;gap:var(--s4);flex-wrap:wrap;
  padding:var(--s5);background:#FAFAF8;border-bottom:1px solid var(--line)}
.ve-tname{font-weight:600;font-size:var(--t-ui);color:var(--ink)}
.ve-dept{font-size:var(--t-mini);color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
.ve-acc{font-family:var(--f-data)}
.ve-two{display:inline-flex;align-items:center;gap:4px;font-size:var(--t-tight);color:var(--navy)}
/* the Versions pop rides the house kebab, so it escapes a scroll box the same way every other
   row menu does (public/kebab.js) — no second implementation. */
.ve-vers{margin-left:0}
.ve-verspop{min-width:280px;max-width:360px;padding:var(--s3)}
.ve-ver{display:block;padding:var(--s2) var(--s3);font-size:var(--t-tight);color:var(--ink);
  border-bottom:1px solid var(--line-s)}
.ve-ver:last-child{border-bottom:0}
.ve-note{margin:0;padding:var(--s5);color:var(--muted);font-size:var(--t-ui);
  display:flex;align-items:flex-start;gap:var(--s3)}
/* a signed test is not editable and must not look editable */
.ve-locked .ve-grid input,.ve-locked .ve-grid select{background:#F7F6F3;color:var(--muted)}

/* the grid is a TABLE, not their flex rows: our ONE table skin already aligns columns across
   rows, which is the whole job. Their proportions on it — 53px rows, 10px 16px cells. */
.ve-grid td,.ve-grid th,.ve-grid thead th{padding:10px var(--s5)}
.ve-grid tbody tr{height:53px}
.ve-grid .c-pname{width:280px;min-width:280px;text-align:left;font-weight:400}
.ve-grid .c-val{width:200px;min-width:200px}
.ve-grid .c-unit{width:110px;min-width:110px}
.ve-grid .c-range{width:170px;min-width:170px}
.ve-grid .c-flag{width:96px;min-width:96px}
.ve-grid{min-width:856px}
.ve-grid input[type=text],.ve-grid select{width:100%;max-width:180px;height:28px;min-height:28px}
.ve-out{display:inline-block;min-width:80px;font-family:var(--f-data);color:var(--muted)}
.ve-abn td,.ve-abn th{background:#FFFCF5}
.ve-crit-row td,.ve-crit-row th{background:#FDF5F5}
.ve-f{display:inline-flex;min-width:26px;height:20px;align-items:center;justify-content:center;
  padding:0 5px;border-radius:4px;font-size:11px;font-weight:600;font-family:var(--f-data)}
.ve-f-h,.ve-f-l,.ve-f-a{background:#FDF3E3;color:#8A5A11}
.ve-f-ch,.ve-f-cl{background:#FBE6E6;color:var(--bad-ink)}
.ve-f-d{background:rgba(26,45,90,.07);color:var(--navy);margin-left:4px}

/* attachments left, the verdict right — their split, and their meaning */
.ve-foot{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;
  padding:var(--s4) var(--s5);border-top:1px solid var(--line)}
.ve-sent{display:inline-flex;align-items:center;gap:4px}
.ve-bad{background:#FBE6E6;color:var(--bad-ink);border:1px solid #E9C4C4}

/* the bill footer travels with the page rather than sitting under five screens of grid */
.ve-bottom{position:sticky;bottom:0;z-index:20;display:flex;align-items:center;gap:var(--s3);
  flex-wrap:wrap;padding:var(--s4) var(--s5);border-top:1px solid var(--line);
  background:var(--card,#fff);box-shadow:0 -6px 16px -12px rgba(16,24,40,.35)}
.ve-off{opacity:.45;pointer-events:none}
/* 107 section 3 — machine values. The select and Re-run sit in the block header, on a READINGS
   block only: measured on the reference, its upload-mode block carries neither. */
.ve-mv{display:inline-flex;align-items:center;gap:var(--s2);margin:0}
.ve-rerun{margin:0;padding:var(--s3) var(--s5);background:#FDF3E3;color:#8A5A11;
  font-size:var(--t-ui);display:flex;align-items:center;gap:var(--s3);
  border-bottom:1px solid var(--line-s)}
/* 107 section 4 — Upload Report | Enter Readings. Measured on the reference: a 231x32 segmented
   control on a 2px #D9D9D9 track, the selected half white on a 4px radius with a hairline shadow.
   Two real buttons rather than a scripted segment, so the toggle works with script off. */
.ve-seg{display:inline-flex;gap:2px;padding:2px;background:#EAE7E1;border-radius:6px}
.ve-seg-on,.ve-seg-off{height:28px;display:inline-flex;align-items:center;padding:0 var(--s4);
  border-radius:4px;font-size:var(--t-ui);font-family:var(--f-body);white-space:nowrap;border:0}
.ve-seg-on{background:#fff;color:var(--ink);box-shadow:0 1px 2px rgba(16,24,40,.06)}
.ve-seg-off{background:transparent;color:var(--muted);cursor:pointer}
.ve-seg-off:hover{color:var(--ink)}
/* the upload body sits where their grid would be, centred, with the reason named above it */
.ve-up{padding:var(--s6) var(--s5);display:flex;flex-direction:column;align-items:center;
  gap:var(--s4);text-align:center}
.ve-up-why{margin:0;color:var(--muted);font-size:var(--t-ui);max-width:70ch;
  display:flex;align-items:flex-start;gap:var(--s3)}
.ve-up-has{margin:0;color:#1E7A43;font-size:var(--t-ui);display:flex;align-items:center;gap:var(--s2)}
.ve-up-act{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;justify-content:center}
.ve-up-act input[type=file]{font-size:var(--t-tight);max-width:230px}
/* an amendment reason is only asked for when the database will demand one (report v2 onwards) */
.ve-amend{height:28px;min-height:28px;width:220px;font-size:var(--t-tight)}

/* ---- 107 section 5 · comments and issues ----------------------------------------------------
   FOUR GRAINS, three of which print and one of which must never. The reference opens a modal for
   each; this screen has to work with script off, so each is a native <details> whose body posts —
   the parameter footnote and the test's working copy ride the page's own Save, and the library,
   the issue and the bill note post their own one-control forms. */
.ve-grid .c-note{width:44px;min-width:44px;padding-left:0;padding-right:var(--s3)}
.ve-pc{position:relative}
.ve-pc > summary{list-style:none;cursor:pointer;display:inline-flex;width:28px;height:28px;
  align-items:center;justify-content:center;border-radius:4px;color:var(--muted)}
.ve-pc > summary::-webkit-details-marker{display:none}
.ve-pc > summary:hover{background:#F2F0EC;color:var(--ink)}
.ve-pc[open] > summary{background:rgba(26,45,90,.07);color:var(--navy)}
.ve-pc textarea{position:absolute;right:0;top:30px;z-index:30;width:320px;
  border:1px solid var(--line-input);border-radius:6px;padding:var(--s3);font-size:var(--t-ui);
  background:#fff;box-shadow:0 8px 24px -12px rgba(16,24,40,.4)}
/* THE PER-REPORT RANGE OVERRIDE (093, section 6).
   Their pencil lives INSIDE the reference cell, right of the range text (measured 2026-08-26:
   cell x1109 w265, pencil at x1244, bubble at x1279 — ours keeps the bubble in its own column,
   the deviation section 5 already shipped). The editor is the same disclosure primitive as the
   footnote so the two behave identically under keyboard and with script off. */
.c-range{white-space:nowrap}
.ve-rg{vertical-align:middle}
/* An overridden band must not look like the catalogue's. No badge and no colour — a dotted rule
   under the text, which reads as "somebody set this" without shouting on a page of numbers. */
.ve-rg-ov{border-bottom:1px dotted var(--navy);cursor:help}
.ve-ro{position:relative;display:inline-block;vertical-align:middle;margin-left:var(--s1)}
.ve-ro > summary{list-style:none;cursor:pointer;display:inline-flex;width:24px;height:24px;
  align-items:center;justify-content:center;border-radius:4px;color:var(--muted)}
.ve-ro > summary::-webkit-details-marker{display:none}
.ve-ro > summary:hover{background:#F2F0EC;color:var(--ink)}
.ve-ro[open] > summary{background:rgba(26,45,90,.07);color:var(--navy)}
/* .ve-grid input[type="text"] is (0,2,1) and sets width:100%, which on an absolutely
   positioned box means 100% of the 24px pencil — measured live at 24px wide before this
   selector was raised above it. Specificity, not source order: the grid rule would win the
   tie either way. */
.ve-grid .ve-ro input, .ve-ro input{position:absolute;left:0;top:28px;z-index:30;width:200px;height:var(--ctrl-h);
  border:1px solid var(--line-input);border-radius:6px;padding:0 var(--s3);font-size:var(--t-ui);
  background:#fff;box-shadow:0 8px 24px -12px rgba(16,24,40,.4)}
/* SHOW INTERPRETATION (094). First item in the test footer's left group, as on the reference. */
.ve-ip{display:inline-flex;align-items:center;gap:var(--s2);cursor:pointer;
  font-size:var(--t-ui);color:var(--ink);white-space:nowrap}
.ve-ip input[type=checkbox]{width:16px;height:16px;margin:0;flex:0 0 auto}
.ve-ip-off{display:inline-flex;align-items:center;gap:var(--s2);white-space:nowrap}

.ve-cm,.ve-is{border-top:1px solid var(--line-s)}
.ve-cm > summary,.ve-is > summary{cursor:pointer;padding:var(--s3) var(--s5);font-size:var(--t-ui);
  color:var(--ink);display:flex;align-items:center;gap:var(--s2)}
.ve-cm > summary:hover,.ve-is > summary:hover{background:#FAFAF8}
.ve-cm-body,.ve-is-body{padding:0 var(--s5) var(--s5);display:flex;flex-direction:column;gap:var(--s3)}
.ve-cm-pick{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap}
.ve-cm-body textarea{width:100%;border:1px solid var(--line-input);border-radius:6px;
  padding:var(--s3);font-size:var(--t-ui);font-family:var(--f-body)}
.ve-cm-ro{margin:0;padding:var(--s3) var(--s5);color:var(--muted);font-size:var(--t-ui);
  border-top:1px solid var(--line-s);display:flex;gap:var(--s3)}
.ve-is-row{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap}
.ve-is-txt{font-size:var(--t-ui);color:var(--ink)}
.ve-is-done .ve-is-txt{color:var(--muted);text-decoration:line-through}
.ve-is-in{flex:1 1 220px;min-width:180px;height:28px;min-height:28px}
/* Note on Report rides the house kebab, so kebab.js lifts it clear of any scroll box */
.ve-rn{margin-right:auto}
.ve-rn-pop{min-width:420px;padding:var(--s4)}
.ve-rn-pop textarea{width:100%;border:1px solid var(--line-input);border-radius:6px;
  padding:var(--s3);font-size:var(--t-ui);font-family:var(--f-body)}
.ve-rn-act{display:flex;justify-content:flex-end;gap:var(--s3);margin-top:var(--s3)}

/* REPORT PREVIEW (107 section 8). Three panes, no gaps — theirs measured 264 | 708 | 296 in a
   1268-wide overlay; ours keeps the proportions inside the content column. The PDF pane is dark
   because the browser's own viewer chrome is; the empty state paints the same ground so the pane
   does not flash white when nothing renders. */
.vp-wrap{display:flex;align-items:stretch;border:1px solid var(--line);border-radius:8px;
  overflow:hidden;background:#fff;height:calc(100vh - 170px);min-height:420px}
.vp-tests{width:264px;flex:0 0 auto;border-right:1px solid var(--line-s);padding:var(--s5);
  overflow-y:auto;display:flex;flex-direction:column}
.vp-set{width:296px;flex:0 0 auto;border-left:1px solid var(--line-s);padding:var(--s5);
  overflow-y:auto}
.vp-pdf{flex:1 1 auto;background:#2B2B31;min-width:0}
.vp-frame{width:100%;height:100%;border:0;display:block}
.vp-h{font-size:16px;font-weight:600;margin:0 0 var(--s4)}
.vp-row{display:flex;align-items:center;gap:var(--s2);font-size:var(--t-ui);color:var(--ink);
  padding:var(--s2) var(--s3);border-radius:6px;cursor:pointer;margin-bottom:var(--s2)}
.vp-row:hover{background:#F5F3EF}
.vp-row input[type=checkbox]{width:16px;height:16px;margin:0;flex:0 0 auto}
.vp-all{font-weight:600}
.vp-off{color:var(--muted);cursor:not-allowed;background:#F7F5F2}
.vp-apply{margin-top:auto}
.vp-none{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;
  color:#D6D2CB;text-align:center;padding:var(--s6)}
.vp-none b{color:#fff}
.vp-none .pl-sub{color:#B9B4AC;max-width:360px}
.vp-note{margin-top:var(--s3)}

/* THE WORKLIST STRIP, as the reference draws it (walked 2026-08-26): count-first chips above the
   card, grain toggle at the right end of the same row, active tab = navy text + navy chip +
   ink-bar underline. Nine tabs must fit beside the toggle, so the strip may scroll sideways on a
   narrow window rather than wrap into a second row the reference does not have. */
.vf-strip{display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  margin:0 0 var(--s4)}
.vf-tabs{display:flex;align-items:center;gap:var(--s6);overflow-x:auto;scrollbar-width:none}
.vf-tabs::-webkit-scrollbar{display:none}
.vf-tab{display:inline-flex;align-items:center;gap:var(--s2);white-space:nowrap;
  padding:var(--s2) 0 var(--s3);font-size:var(--t-ui);color:var(--muted);text-decoration:none;
  border-bottom:2px solid transparent}
.vf-tab:hover{color:var(--ink)}
.vf-tab.on{color:var(--navy);border-bottom-color:var(--navy);font-weight:600}
.vf-n{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;
  padding:0 var(--s2);border-radius:10px;background:#EFECE7;color:var(--muted);
  font-size:12px;font-weight:600;font-variant-numeric:tabular-nums}
.vf-tab.on .vf-n{background:var(--navy);color:#fff}

/* the grain toggle shares a tight row with nine tabs; its labels must not wrap */
.vf-strip .bk-viewtoggle{display:inline-flex;flex:0 0 auto}
.vf-strip .bk-viewtoggle .btn{white-space:nowrap}

/* the machine column (re-walk 2026-08-26): what the analyzer said, beside what was typed */
.ve-grid .c-mach{width:120px;color:var(--muted);font-variant-numeric:tabular-nums}
/* comment/issue footer popovers: same kebab primitive as Note on Report, sized for a library */
.ve-cm .kebab-pop,.ve-is .kebab-pop{width:560px;padding:var(--s4)}
.ve-cm .kebab-pop textarea{width:100%;margin-top:var(--s3)}
.ve-is .kebab-pop .ve-is-row{display:flex;flex-wrap:wrap;gap:var(--s2);align-items:center;margin-bottom:var(--s3)}
.ve-is .kebab-pop .ve-is-in{flex:1 1 200px}

/* 095 (clone-all-four re-walk): the per-row mark, the header kebab, the multi filters */
.ve-more{flex:0 0 auto}
/* their trigger, measured: 32x32 icon-only, 16x16 glyph centered (VS 2026-08-27: "i want pixel too") */
.ve-more > summary.btn{width:32px;height:32px;min-height:32px;padding:0;
  display:inline-flex;align-items:center;justify-content:center}
.ve-more > summary.btn .ic-i{width:16px;height:16px}
.ve-msel{flex:0 0 auto}
.ve-grid td.c-val{white-space:nowrap}
/* .erp input[type=checkbox] (0,2,1) resets checkboxes to width:auto — a bare .ve-mk (0,1,0)
   loses to it on specificity and the box rendered the browser's 13px. Matched and outweighed. */
.ve-grid input.ve-mk{width:16px;height:16px;vertical-align:middle;margin:0 var(--s2) 0 0;flex:0 0 auto}
.ve-grid .c-val input[type=text],.ve-grid .c-val select{max-width:156px;vertical-align:middle}
.ve-more-pop{min-width:116px;padding:var(--s1)}
.ve-msel-sum{max-width:200px;min-width:148px;display:inline-block;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;text-align:left;color:var(--muted)}
.ve-msel-sum.on{color:var(--ink)}
.ve-msel-pop{min-width:230px;max-height:300px;overflow:auto;display:flex;flex-direction:column;
  gap:2px;padding:var(--s2)}
.ve-msel-opt{display:flex;align-items:center;gap:var(--s2);padding:4px var(--s2);
  border-radius:6px;cursor:pointer;white-space:nowrap}
.ve-msel-opt:hover{background:#F6F5F2}

/* ================================================================================================
   LABONE TINT — the Terminal design system (FROZEN 2026-08-27, VS; SSOT labone-design-system.md).
   Chosen by OPERATING the living prototype. ADDITIVE layer: live screens are untouched until a
   view opts in with these lt- classes; Pulse and the E&V pilot wear them first. All values are
   the brand tokens already at :root — nothing invented. */
:root{
  --lt-ground:#F7F6F3;--lt-card:#FFFFFF;--lt-r:16px;--lt-rs:12px;
  --lt-shadow:0 1px 3px rgba(26,45,90,.05);
  --lt-wash-money:#EAF0F8;--lt-wash-grow:#E7F3EE;--lt-wash-warn:#FAF0E1;--lt-wash-plain:#F2F2F5;
}
.lt-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.lt-tile{background:var(--lt-card);border-radius:var(--lt-r);padding:12px 14px;box-shadow:var(--lt-shadow)}
.lt-tile.lt-w-money{background:var(--lt-wash-money)}
.lt-tile.lt-w-grow{background:var(--lt-wash-grow)}
.lt-tile.lt-w-warn{background:var(--lt-wash-warn)}
.lt-tile.lt-w-plain{background:var(--lt-wash-plain)}
.lt-tile .k{font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:600}
.lt-tile .v{font-family:var(--f-data);font-size:25px;font-weight:700;margin-top:3px;
  font-variant-numeric:tabular-nums lining-nums}
.lt-tile .d{font-size:11.5px;color:var(--muted);margin-top:2px}
.lt-tile .v a{color:inherit;text-decoration:none}
.lt-meter{height:7px;border-radius:999px;background:#ECE9E3;overflow:hidden;margin-top:7px}
.lt-meter i{display:block;height:100%;background:var(--teal);border-radius:999px;
  transition:width .6s cubic-bezier(.2,.8,.2,1)}
/* THE ONE ALERT LANGUAGE: severity insight card — left bar, eyebrow, plain-English headline */
.lt-ins{border-left:3px solid;border-radius:var(--lt-rs);padding:10px 13px;margin-top:8px;font-size:13px}
/* display:block because the eyebrow is a <span> inside the lt-flash partial's <p>: a <div> there
   would be invalid (a paragraph cannot contain one) and the views-wellformed guard would say so.
   The <div> form on Pulse blocks on its own and is unaffected. */
.lt-ins .eb{display:block;font-size:10px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;opacity:.6}
.lt-ins b{display:block;margin-top:1px;font-size:13px}
.lt-ins a{color:inherit}
.lt-in-bad{background:#FBEDEC;border-color:var(--red)}
.lt-in-due{background:#FAF3E3;border-color:var(--orange)}
.lt-in-ok{background:#EAF4EE;border-color:var(--green)}
/* THE GAME ANSWERS BACK */
.lt-bump{animation:lt-bump .45s cubic-bezier(.2,.8,.2,1)}
@keyframes lt-bump{30%{transform:scale(1.12);color:var(--teal)}}
.lt-pop{animation:lt-pop .5s cubic-bezier(.2,.8,.2,1)}
@keyframes lt-pop{25%{transform:scale(1.012);box-shadow:0 4px 20px rgba(13,143,143,.22)}}
@media (prefers-reduced-motion:reduce){.lt-bump,.lt-pop{animation:none}.lt-meter i{transition:none}}
.lt-h{font-family:var(--f-display);font-size:15px;font-weight:700;margin:24px 0 9px;color:var(--ink)}
.lt-h .q{color:var(--muted);font-weight:600;font-size:12.5px}

/* 098: the Report-a-problem button — fixed bottom-right on every screen */
/* stacked ABOVE the team-panel bubble (.team-fab, right:20 bottom:20) — VS 2026-08-27:
   the two float together, chat below, report above, neither covering the other */
.fb-root{position:fixed;right:20px;bottom:84px;z-index:70}
/* THE FLOATS MUST NOT SIT ON A CONTROL. Playwright found this at the end of the Tint sprint: the
   Bookings wizard's Continue button is at the bottom right of its card, exactly where the
   Report-a-problem button and the chat bubble live, so the click hit the float instead —
   "subtree intercepts pointer events", real browser, real booking. VS had already reported the
   two floats covering EACH OTHER; this is the same defect pointed at the page.

   THE FIRST FIX WAS WRONG AND THE SUITE SAID SO. Reserving the stack's height on every `.wrap`
   made the DESK BILLING page scroll, and that page is pinned by
   tests/smoke/registration.spec.js to fit a 1366x768 laptop without scrolling — the reference's
   own "one screen" rule for a receptionist. It fits with 12px to spare, so no global clearance of
   any useful size can exist. A terminal-wide fix for a two-screen problem was the wrong shape.

   So the clearance goes where the collision is: a long wizard whose primary action sits in the
   bottom-right corner. Both of these already scroll, so the space costs nothing. */
.bw-nav{padding-bottom:96px}
.fb-root summary{list-style:none}
.fb-root summary::-webkit-details-marker{display:none}
.fb-btn{display:inline-flex;gap:7px;align-items:center;background:var(--lt-card);color:var(--muted);
  border:1px solid var(--line);border-radius:999px;padding:9px 15px;font:600 12.5px var(--f-body);
  cursor:pointer;box-shadow:var(--sh-m)}
.fb-root[open] .fb-btn{background:var(--navy);border-color:var(--navy);color:#fff}
.fb-pop{position:absolute;right:0;bottom:46px;width:min(320px,calc(100vw - 32px));
  background:var(--lt-card);border:1px solid var(--line);border-radius:var(--lt-rs);
  box-shadow:var(--sh-l);padding:12px}
.fb-pop textarea{width:100%;margin-top:4px}
.fb-l{font-size:12px;font-weight:600;color:var(--ink)}
.fb-row{display:flex;align-items:center;gap:8px;margin-top:8px}
.fb-scr{font-size:11px;color:var(--muted);margin-right:auto;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;max-width:200px}
@media (max-width:700px){.fb-btn .fb-lbl{display:none}.fb-btn{padding:11px}}
.fbd{max-width:420px;margin:80px auto;text-align:center;display:flex;flex-direction:column;gap:12px;
  align-items:center}
.fbd-ok{font-family:var(--f-display);font-size:19px;font-weight:700;margin:0}
.fb-item .fb-meta{display:flex;align-items:center;gap:10px;margin-top:6px}
.fb-item{margin:10px 14px}

/* Pulse zones A+B in Tint — the complete switch (VS 2026-08-27); the cmd- skin is retired here */
.lt-mast{display:flex;align-items:baseline;gap:12px;margin:2px 0 14px;flex-wrap:wrap}
.lt-mast h1{font-family:var(--f-display);font-size:22px;font-weight:700;margin:0;letter-spacing:.005em}
.lt-mast-sub{font-size:12.5px;color:var(--muted)}
.lt-mast-go{margin-left:auto}
/* only the FIRST action takes the pushing margin — with auto on every pill the free space split
   between them and "This week" floated mid-masthead (VS's screenshot, 2026-08-28). Siblings sit
   together at the flex gap, aligned as one cluster against the right edge. */
.lt-mast-go~.lt-mast-go{margin-left:0}
.lt-quiet{font-size:13px;color:var(--muted);background:var(--lt-wash-plain);border-radius:var(--lt-rs);
  padding:12px 14px;margin:8px 0 0}
/* an <a> is inline by default — block children fragment its background into shards
   (the broken pen card, VS 2026-08-27). Every severity card that is a link is a block. */
a.lt-ins{display:block;text-decoration:none;color:inherit}
.lt-pen{position:relative;display:block;padding-right:74px}
.lt-sub{display:block;font-size:11.5px;color:var(--muted);font-weight:400;margin-top:2px}
/* THE FROZEN "GO" AFFORDANCE (VS 2026-08-27, holding the two side by side on Pulse: "I like the
   top one better, so that stands frozen"). The white pill IS the way the Terminal says "this
   opens something". `.lt-open` is that shape, reusable anywhere; `.lt-go` is the same pill parked
   in a card's right margin, and nothing else may invent a third form. */
.lt-open{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;
  color:var(--navy);background:#fff;border:1px solid var(--line);border-radius:999px;padding:5px 13px;
  text-decoration:none;white-space:nowrap}
.lt-go{position:absolute;right:12px;top:50%;transform:translateY(-50%);font-size:12px;font-weight:700;
  color:var(--navy);background:#fff;border:1px solid var(--line);border-radius:999px;padding:5px 13px}
.lt-park{margin-top:10px}
.lt-park>summary{display:inline-block;font-size:12.5px;font-weight:600;color:var(--muted);cursor:pointer;
  background:var(--lt-wash-plain);border-radius:999px;padding:7px 14px}
.lt-park-row{display:flex;align-items:center;gap:10px;justify-content:space-between;
  background:var(--lt-wash-plain);border-radius:var(--lt-rs);
  padding:10px 13px;margin-top:8px;font-size:13px}
.lt-park-add{display:flex;gap:8px;margin-top:8px}
.lt-park-add input{flex:1}
.lt-strips{display:grid;grid-template-columns:repeat(auto-fit,minmax(290px,1fr));gap:12px;margin-top:4px}
/* the terminal canvas is PURE WHITE (owner ruling) — a white card on it has no edge, which
   is how the strips lost their card-ness (VS 2026-08-27). The wash IS the containment,
   exactly as the Zone-0 tiles above: one card language, top to bottom. */
.lt-strip{background:var(--lt-wash-plain);border-radius:var(--lt-r);padding:14px 16px}
.lt-strip-h{display:flex;align-items:center;gap:8px;margin-bottom:9px}
.lt-strip-h b{font-family:var(--f-display);font-size:14.5px;font-weight:700;color:var(--ink)}
.lt-strip-go{margin-left:auto;font-size:12px;font-weight:700;color:var(--navy);text-decoration:none}
.lt-dot{width:9px;height:9px;padding:0;border:0;border-radius:999px;background:#CBD2DC;flex:0 0 auto}
.lt-dot.d-ok{background:var(--green)}.lt-dot.d-warn{background:var(--orange)}.lt-dot.d-bad{background:var(--red)}
.lt-nums{display:flex;flex-wrap:wrap;gap:10px 20px}
.lt-n{display:flex;flex-direction:column}
.lt-n .nv{font-family:var(--f-data);font-size:22px;font-weight:700;
  font-variant-numeric:tabular-nums lining-nums}
.lt-n.bad .nv{color:#9E3A24}
/* W6: Pulse's own residue drained. `.lt-of` was an inline font-size+opacity on every tile that
   carries a target; `.lt-note-tiles` replaces two inline margins. `pl-sub` — the patient
   register's class — was borrowed for a line on Pulse, which is how one screen's tweak silently
   moves another; it uses this layer's own quiet line now. */
.lt-of{font-size:12px;opacity:.55}
.lt-note-tiles{margin:8px 2px 0}
.lt-n .nof{font-size:12px;color:var(--muted);font-weight:500}
.lt-n .nk{font-size:11.5px;color:var(--muted)}
.lt-delta{display:inline-block;margin-left:5px;font-family:var(--f-data);font-size:10.5px;font-weight:700;
  padding:1px 6px;border-radius:999px}
.lt-delta.good{color:#1F6B45;background:#E7F3EC}
.lt-delta.bad{color:#9E3A24;background:#FBEAE4}
.lt-delta.flat{color:var(--muted);background:var(--lt-wash-plain)}
/* ---- PULSE, SECOND CUT (VS 2026-08-27: "the card feel less informative ... make this dashboard
   speak up and help me run my entire business from here at a glance").
   THE DIAGNOSIS was hierarchy, not content. Every strip showed six numbers at one weight, and six
   numbers at one weight is a wall — the eye finds no entry point, so it reads none of them. Each
   strip now leads with the one number that decides whether that department won today. */

/* THE HERO BAND — the month against the number the business is run to. Nothing else on this page
   is allowed to be this size, because nothing else answers the owner's first question. */
.lt-hero{display:block;text-decoration:none;color:inherit;background:var(--lt-wash-money);
  border-radius:var(--lt-r);padding:16px 18px;margin:0 0 12px;box-shadow:var(--lt-shadow)}
.lt-hero-k{font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:600}
.lt-hero-v{font-family:var(--f-data);font-size:38px;font-weight:700;line-height:1.1;margin-top:2px;
  color:var(--navy);font-variant-numeric:tabular-nums lining-nums}
.lt-hero-of{font-size:16px;font-weight:600;color:var(--muted)}
.lt-hero-meter{margin-top:10px;height:9px}
.lt-hero-d{font-size:12.5px;color:var(--muted);margin-top:7px}
.lt-hero-pace{font-family:var(--f-data);font-weight:700;font-variant-numeric:tabular-nums lining-nums}
.lt-hero-pace.good{color:var(--ok-ink)}
.lt-hero-pace.bad{color:var(--bad-ink)}
.lt-hero-ok{background:var(--lt-wash-grow)}
.lt-hero-ok .lt-meter i{background:var(--green)}

/* THE VERDICT IS A WORD, not only a colour. A dot alone asks the reader to remember a legend, and
   an owner scanning five strips at midnight should not have to. */
.lt-verdict{font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  padding:2px 8px;border-radius:999px}
.lt-verdict.v-bad{background:#FBEDEC;color:#9E3A24}
.lt-verdict.v-warn{background:var(--lt-wash-warn);color:var(--amber-ink)}
.lt-verdict.v-ok{background:var(--lt-wash-grow);color:var(--ok-ink)}

/* THE STRIP'S OWN HERO — one number, its target, and a meter under it. */
.lt-hn{display:flex;align-items:baseline;gap:9px;margin:2px 0 0;flex-wrap:wrap}
.lt-hn-v{font-family:var(--f-data);font-size:32px;font-weight:700;line-height:1.1;
  font-variant-numeric:tabular-nums lining-nums;color:var(--navy)}
.lt-hn.bad .lt-hn-v{color:#9E3A24}
.lt-hn-k{font-size:12px;color:var(--muted);font-weight:600}
.lt-hn-meter{margin-top:8px}
.lt-strip .lt-nums{margin-top:11px}

.lt-spark{margin-top:9px;color:var(--teal)}
/* the area under the line — the chart reads as a QUANTITY, not only a direction */
.lt-spark-area{fill:currentColor;opacity:.10}
/* the live endpoint. VS: "there is no motion in the cards graph, which should add accent to it" —
   the draw-on runs once and is over before anyone looks, so the last point keeps a slow pulse and
   the chart reads as live at any moment. 2.6s is a resting heart rate, not a blink. */
.lt-spark-end{fill:currentColor}
.lt-spark svg{overflow:visible}
.lt-spark svg{display:block;width:100%;max-width:230px;height:26px}
.lt-spark-k{font-size:10.5px;color:var(--muted)}
.lt-worst{margin:9px 0 0}
.lt-worst b{font-weight:600}
.lt-note{font-size:12px;color:var(--muted);margin:8px 0 0}

/* ================================================================================================
   W1 · THE SHARED SKIN — LABONE TINT at the family selectors (Raksha Bandhan sprint, 2026-08-27).
   VS: "Time to make the entire terminal look like this."

   HOW THIS BLOCK IS ALLOWED TO EXIST. Roughly 110 screens share five families — .card, .dtable/
   .atable, .tbar, .btn, the tab strip — so the skin flips here, once, instead of in 110 views.
   Two rules govern every line below, and breaking either is how a sprint like this wrecks a
   working product:

     1. PAINT PROPERTIES ONLY: colour, background, border-COLOUR, radius, shadow, transition.
        Never a padding, height, width, margin or font-size. The geometry in this file was
        MEASURED off the reference (53px rows, 10px/12px cells, 32px controls, column floors)
        and is pinned by tests and by smoke specs that read getComputedStyle in a browser. A
        skin that moves a pixel is not a skin, it is a regression.
     2. APPEND, NEVER REWRITE. Several rules above are pinned by their SOURCE TEXT
        (erp-table-skin, erp-density, erp-verify-entry read app.css as a string). Their bodies
        stay byte-identical; where Tint supersedes one, the successor sits here at equal
        specificity and wins by order. The pinned line stays as the record of what was measured.

   WHAT IS DELIBERATELY NOT HERE. Zebra striping was in the plan and is dropped: E&V marks
   abnormal and critical rows by painting the <tr>, and any nth-child rule landing later in this
   file would silently outrank a panic-limit tint. Column rules plus row separators already do
   the column-finding — that is what the reference was measured to do. A stripe is not worth a
   silenced critical. Bare classes (.warn/.ok/.money) are still never restyled: they are
   load-bearing in compounds across 170 views, and markup converts to lt- instead.
   ================================================================================================ */

/* ---- CARDS. White on the warm ground; the ground IS the edge, so the hairline recedes and the
   shadow is a whisper. --lt-r everywhere: the 08-22 split (ERP 8px / CRM 12px) predates the
   design system and the frozen system is one terminal, one corner. The 8px rule above is kept
   verbatim because erp-density pins its text; this is its Tint successor at equal specificity. */
.card,.adherence{background:var(--lt-card);border-color:var(--line-s);border-radius:var(--lt-r);
  box-shadow:var(--lt-shadow)}
.lp-page .card,.derp .card{border-radius:var(--lt-r)}
.card.card-flush{overflow:hidden}

/* ---- TABLES. Structure is Flabs and stays Flabs — this changes only what the pixels are made
   of. The head is the warm instrument band (the terminal's own canvas colour, one step up from
   the card it sits in) with navy ink, so a column heading reads as an instrument label rather
   than as another row of data. Hover carries the brand's teal at its faintest usable strength:
   the row answers the pointer, quietly. */
/* THE WEIGHT IS NOT OURS TO CHANGE. The first cut of this rule also said font-weight:600 and
   tests/smoke/ui-shell.spec.js failed it in a real browser on two screens: the head weight is 500
   because that is what the reference measures, and "structure is Flabs" covers the weight of a
   column heading as surely as it covers its position. Navy ink on the warm band is the whole
   Tint change here, and it is enough — a heading reads as an instrument label by its COLOUR. */
.dtable thead th,.atable thead th{background:var(--lt-ground);color:var(--navy)}
.dtable tbody tr:hover,.atable tbody tr:hover{background:rgba(13,143,143,.045)}
.dtable tbody th,.atable tbody th{background:var(--lt-ground)}

/* ---- TOOLBAR. The band above a register: the canvas colour again, closing on the table head
   below it so the card reads head-body-foot instead of three loose strips. */
.tbar,.pl-tbar{background:var(--lt-ground);border-bottom-color:var(--line-s)}

/* ---- CONTROLS. 12px is the frozen control radius; .btn-sm keeps the reference's smaller-than-
   the-toolbar relationship at 8. The press is the quietest possible "answers back" — one pixel
   of travel, killed under reduced-motion. */
.btn{border-radius:var(--lt-rs);transition:background .12s ease,border-color .12s ease,box-shadow .12s ease}
.btn-sm{border-radius:8px}
.btn:hover{border-color:var(--navy)}
.btn:active{transform:translateY(1px)}
.btn-primary{box-shadow:var(--lt-shadow)}
.btn-primary:hover{background:var(--navy-d);border-color:var(--navy-d)}
.tbar :is(input,select),.pl-range,.tbar-search input[type=search]{border-radius:var(--lt-rs)}
/* teal is the brand's focus colour in the frozen system (progress, meters, focus rings) */
:focus-visible{outline-color:var(--teal)}
@media (prefers-reduced-motion:reduce){.btn{transition:none}.btn:active{transform:none}}

/* ---- STATUS PILLS. The report's state, re-cut on the Tint washes: money for in-flight, grow
   for finished, plain for a draft. Same three states, same places, one palette. */
.pl-status{border-radius:999px;font-weight:600}
.pl-pend{background:var(--lt-wash-money);color:var(--navy);border-color:#D7E1F1}
.pl-done{background:var(--lt-wash-grow);color:var(--ok-ink);border-color:#CBE5D7}
.pl-draft{background:var(--lt-wash-plain);color:var(--muted);border-color:var(--line-s)}

/* ---- TAB STRIP. The underline stays (it is the reference's control); only the count chip
   changes hands — plain wash at rest, money wash when its tab is the live one. */
.dtab-n{background:var(--lt-wash-plain)}
.dtab.on .dtab-n{background:var(--lt-wash-money);color:var(--navy)}

/* ---- TOAST. Card radius, so the one floating surface matches every anchored one. */
.toast{border-radius:var(--lt-r)}

/* ---- W3 · THE FIELD PHONES ----------------------------------------------------------------------
   The rep's screen is the one Terminal surface that is only ever seen on a phone, in daylight, one
   handed, between two clinics. Everything here serves that: bigger targets stay untouched (the 28px
   floor is law), the KPI strip stops being its own little product, and the numbers that have a
   TARGET get a meter, because a number without its target is trivia.

   THE KPI FAMILY JOINS THE TILE FAMILY rather than being deleted view by view. The plan said retire
   .kpi; what actually serves the terminal is ONE rule set wearing two class names, so a future
   change lands in one place and no markup had to be rewritten to get there. Deleting the name would
   have meant editing eight divs and a delta helper on a live screen for no visible gain — the sort
   of churn that breaks a working product on a sprint day. */
.kpi-row{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.kpi{background:var(--lt-card);border:0;border-radius:var(--lt-r);box-shadow:var(--lt-shadow);
  padding:12px 14px;text-align:left}
.kpi b{font-size:25px;font-weight:700;font-variant-numeric:tabular-nums lining-nums}
.kpi span{display:block;font-size:10.5px;font-weight:600;letter-spacing:.08em;margin-top:1px}
.kpi-bad{background:var(--lt-wash-warn)}
.kpi-good{background:var(--lt-wash-grow)}
/* the rank card and the new-comment flag are ALERTS, so they speak the one alert language */
.rank-card,.rem-alert{border-radius:var(--lt-r);box-shadow:none}
.rem-alert{border:0;border-left:3px solid var(--orange);background:var(--lt-wash-warn)}
.rank-card{border:0;border-left:3px solid var(--teal);background:var(--lt-wash-money)}
/* the outcome bars: the brand's teal, on the plain wash, at the tile's corner */
.pipe-bar{background:var(--lt-wash-plain);border-radius:999px}
.pipe-fill{border-radius:999px}
/* W3 drains: the idioms that were repeated as inline style= on the field views. Each carries the
   value it replaces, so nothing moved by more than the spacing scale's own rounding. */
.f-tight{padding:var(--s2) var(--s3)}          /* was style="padding:.4rem .5rem" x8 */
.f-cardp{padding:11px 14px}                    /* was .6rem .8rem and .7rem .9rem, now one card */
.f-ch{margin:0 0 var(--s3);font-size:var(--t-name);font-weight:700;color:var(--ink)}
.f-ch.f-ch0{margin:0}
.f-row{display:flex;flex-wrap:wrap;gap:10px;align-items:center}
.f-right{margin-left:auto}
.f-bad{color:var(--bad-ink);font-weight:600}
.f-hint{font-size:var(--t-tight)}
.f-num{text-align:right}
.f-left{text-align:left}
.f-mt{margin-top:var(--s3)}                    /* was .4rem/.5rem/.55rem margin-top, x11 */
.f-mb{margin:var(--s1) 0 var(--s3)}
.f-my{margin:var(--s1) 0}
.f-p8{padding:var(--s3)}
.f-w6{font-weight:600}
.f-w7{font-weight:700}
/* THE BEAT-PLANNER DATE. This was a whole control skin written inline, twice, including a
   `rgba(128,128,128,.4)` border — a grey the brand palette does not contain and no token could
   ever change. It is the terminal's own control now. */
.f-date{height:var(--ctrl-h);padding:4px 11px;border:1px solid var(--line-input);
  border-radius:var(--lt-rs);font:inherit;background:var(--card);color:inherit;width:auto;margin-top:0}
/* the check-in state, as a severity card: the rep must read "am I on the clock" in one glance */
.f-ci{margin:var(--s3) 0}
.f-ci .f-ci-b{display:flex;flex-wrap:wrap;gap:var(--s3);align-items:center;margin-top:var(--s2)}
.f-ci .f-ci-b .muted{font-size:var(--t-tight)}

/* ---- W4 · THE TELECALLER ------------------------------------------------------------------------
   VS named these screens when he named the problem: "the ui feels confusing for the ones i have
   built myself, like telecaller, b2b sales." The confusion was never the colours. It was that the
   belt card offered FOUR actions in two rows, all of them the same white button, so a caller had
   to read four labels to find the one that moves the work. Tint's law is one primary per zone:
   Call is the verb of the job, Record outcome is what advances the belt, and everything else steps
   back to being available rather than shouted.

   The tile families join the tile family here, the same way .kpi did in W3: one rule set, several
   class names, so the terminal has ONE figure card and the next change lands in one place. */
.tiles{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.tile{background:var(--lt-card);border:0;border-radius:var(--lt-r);box-shadow:var(--lt-shadow);
  padding:12px 14px;text-align:left}
.tile b{font-size:25px;font-weight:700;font-variant-numeric:tabular-nums lining-nums}
.tile span{display:block;font-size:10.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase}
.tile.red{background:#FBEDEC}.tile.t-money{background:var(--lt-wash-money)}
.tile.hot{background:#E6F4F4}.tile.warm{background:var(--lt-wash-warn)}
/* the belt card: the SLA is the wash, so "how late is this" is read before any word on the card */
.belt-card{border:0;border-radius:var(--lt-r);box-shadow:var(--lt-shadow)}
.belt-card.belt-red{background:#FBEDEC}
.belt-card.belt-amber{background:var(--lt-wash-warn)}
.belt-next{border-radius:var(--lt-r)}
/* THE PRIMARY HAS TO BE RE-ASSERTED INSIDE THE CARD, and this cost a live white-on-white button
   before it was caught in the browser. `.belt-card .btn{background:#fff}` — the old "all-white
   actions" rule — scores (0,2,0) and beats a bare `.btn-primary` at (0,1,0). The primary kept its
   white TEXT from .btn-primary and lost its navy GROUND to the card rule, so both primaries
   rendered as blank boxes with fourteen invisible characters in them. A global class is only
   global until something scopes over it: when promoting a control inside a component, promote it
   AT THE COMPONENT'S OWN SPECIFICITY. */
.belt-card .btn-primary{background:var(--navy);color:#fff;border-color:var(--navy)}
.belt-card .btn-primary:hover{background:var(--navy-d);border-color:var(--navy-d)}
.belt-card .btn-outline{background:var(--lt-card);color:var(--navy);border-color:var(--navy)}
.belt-card .btn-outline:hover{background:#F2F4FA}
/* NO LAYOUT HERE. The first cut set `.belt-grid{display:flex}`, which collided with the existing
   `.belt-grid .btn{width:100%}` and stacked two side-by-side buttons into two full-width rows.
   The grid was already right; W4 changes which button is loud, never where it sits. */

/* ---- W5 · MASTERS, COMMERCIAL, ADMIN ------------------------------------------------------------
   The bulk of this wave landed in W1: these eighty-odd screens are built from .card, .dtable,
   .tbar and .btn, so they took the skin the moment those families changed. What is left is the
   page banner — now views/partials/lt-flash.ejs across 75 views — and the last tile family.

   .statcard is the fifth and final one (after .tile, .kpi, .pf-tiles and .lt-tile). It joins the
   others rather than being deleted: the class name is fine, it was the second visual grammar that
   was the problem. One figure card in the Terminal, five names for it, one rule set. */
.statcard{background:var(--lt-card);border:0;border-radius:var(--lt-r);box-shadow:var(--lt-shadow);
  padding:12px 14px}
.statcard-h{font-size:10.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase}
.statcard-v{font-size:25px;font-variant-numeric:tabular-nums lining-nums}
.statcard-warn{border:0;background:var(--lt-wash-warn)}

/* ---- W2 · THE ALIVE LAYER on Enter & Verify -----------------------------------------------------
   A previewed flag must be legible as UNSAVED, and it must not move the row by a pixel — a
   verifier reading down a column of values cannot have the column reflow under the cursor. Both
   effects are therefore non-layout: an outline (which paints outside the box and reserves no
   space) and a border colour. The row tint itself is the EXISTING ve-abn / ve-crit-row language:
   one visual grammar for abnormal, whether the server said it or the preview did. */
.lt-ve-pre{outline:1px dashed rgba(26,45,90,.45);outline-offset:1px}
.lt-ve-dirty td.c-val input,.lt-ve-dirty td.c-val select{border-color:var(--teal)}
/* the block that moved, on the way back from a ladder press — a rise, not a bounce (QUIET) */
.lt-ve-pop{animation:lt-ve-pop .5s cubic-bezier(.2,.8,.2,1)}
@keyframes lt-ve-pop{30%{transform:translateY(-2px);box-shadow:0 6px 22px rgba(13,143,143,.20)}}
@media (prefers-reduced-motion:reduce){.lt-ve-pop{animation:none}}

/* ==================================================================================================
   W7 · THE HAND — one hover language, one "go" affordance, and data that arrives moving.
   VS 2026-08-27, holding two Open controls side by side on Pulse: "Use two different time-of-click
   options for the same thing. Use it uniformly for the same. I like the top one better, so that
   stands frozen. Gaps like this are to be noticed and fixed in the entire terminal." Then: highlight
   what is clickable, keep it uniform, add hover animation everywhere a pointer can go, and "the
   graphs and the charts: make them all move and have motion."

   THREE RESPONSES, AND EVERY CLICKABLE THING PICKS EXACTLY ONE:
     LIFT   a card, tile, strip or severity card that opens something — rises 1px, shadow deepens
     TINT   a row or a rail link — the surface warms, nothing moves (a table must not jitter)
     PRESS  a button or a pill — border sharpens on hover, travels 1px on the press
   A fourth response would be a fourth thing to learn, which is the defect VS pointed at.

   NOTHING HERE MOVES LAYOUT. Every effect is transform, box-shadow, border-color or background —
   composited, reversible, and incapable of reflowing a table under a verifier's cursor. The whole
   block is switched off under prefers-reduced-motion at the end, in one place.
   ================================================================================================== */

/* ---- LIFT ---------------------------------------------------------------------------------- */
.lt-tile,.lt-strip,.lt-ins,.kpi,.tile,.statcard,.card{transition:box-shadow .16s ease,transform .16s ease,border-color .16s ease}
a.lt-ins:hover,.lt-strip:hover,.lt-tile:hover{transform:translateY(-1px);box-shadow:0 4px 14px rgba(26,45,90,.10)}
/* a tile is only a LIFT when its number is a door — Pulse's are, and they say so with an <a> */
.lt-tile:hover .v a{text-decoration:underline;text-underline-offset:3px}

/* ---- TINT ---------------------------------------------------------------------------------- */
.dtable tbody tr,.atable tbody tr,.side-link,.frow,.beltrow,.lead,.convrow{transition:background-color .13s ease,color .13s ease}
.frow:hover,.beltrow:hover,.lead:hover,.convrow:hover{background:rgba(13,143,143,.045)}

/* ---- PRESS + THE FROZEN PILL ---------------------------------------------------------------- */
.lt-open,.lt-go,.pl-x,.dtab,.pill-tab,.vf-tab{transition:background-color .14s ease,border-color .14s ease,box-shadow .14s ease,transform .14s ease,color .14s ease}
.lt-open:hover,.lt-go:hover{border-color:var(--navy);box-shadow:0 2px 8px rgba(26,45,90,.12)}
.lt-open:hover{transform:translateY(-1px)}
/* .lt-go is already centred by a transform, so its hover has to carry the centring with it —
   a bare translateY here would drop the pill to the bottom of the card. */
.lt-go:hover{transform:translateY(calc(-50% - 1px))}
.lt-open:active,.lt-go:active{box-shadow:none}
.lt-open:active{transform:translateY(1px)}
.lt-go:active{transform:translateY(calc(-50% + 1px))}
/* the card lifts and its pill answers at the same moment — one gesture, not two */
a.lt-ins:hover .lt-go{border-color:var(--navy);background:var(--navy);color:#fff}

/* ---- WHAT CANNOT BE CLICKED MUST NOT LOOK LIKE WHAT CAN ------------------------------------- */
/* The audit found eight <span class="btn"> — every one legitimate: a current tab, a disabled
   Previous. They are correct markup and were the wrong PIXELS: identical to a live control, so a
   person learns the skin means nothing. A state is flat, muted and takes no pointer. */
span.btn,.btn[disabled],.btn.ve-off{cursor:default;box-shadow:none}
span.btn:not(.on):not(.pill-tab){color:var(--muted);background:var(--lt-wash-plain);border-color:transparent}
span.btn:hover{border-color:var(--line-input);transform:none}
/* A PLACEHOLDER HREF IS NOT A LINK YET. camp.ejs's "Send link on WhatsApp" carries href="#" until
   a valid ten-digit number is typed, so for most of that form's life it is a live-looking button
   that does nothing — precisely the class of gap VS asked to be found terminal-wide. The rule is
   general, so any future placeholder is honest by default, and camp.js already swaps in the real
   wa.me URL the moment the number is valid: the control lights up exactly when it starts working. */
a[href="#"]{color:var(--muted);background:var(--lt-wash-plain);border-color:transparent;
  cursor:not-allowed;box-shadow:none}
a[href="#"]:hover{transform:none;border-color:transparent;box-shadow:none}
/* and everything that IS clickable says so under the pointer */
a[href],button,summary,.lt-open,.lt-go,label.rr,.switch{cursor:pointer}
a[href]:focus-visible,button:focus-visible{outline-offset:2px}

/* ---- THE CHARTS MOVE ------------------------------------------------------------------------
   Every bar in the Terminal is drawn by the SERVER, as an inline width or height computed from a
   real number — that is the honest way and it is not changing. So the motion is an ENTRANCE: the
   element scales in from nothing to the size the server gave it. Because it is a transform, the
   final geometry is exactly the server's number, the layout never reflows, and with script off
   (or animation off) the bar simply is its full size, which is what it was before.
   A horizontal bar grows from its left edge; a column grows from its baseline, like a real one. */
.lt-meter i,.pipe-fill,.tile-fill,.pf-fbar,.pf-mbar{transform-origin:left center;animation:lt-grow-x .55s cubic-bezier(.2,.8,.2,1)}
.trend-bar,.pf-bar{transform-origin:bottom center;animation:lt-grow-y .5s cubic-bezier(.2,.8,.2,1)}
@keyframes lt-grow-x{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes lt-grow-y{from{transform:scaleY(0)}to{transform:scaleY(1)}}
/* the sparkline DRAWS itself, left to right. pathLength="1" on the polyline normalises every
   line to the same dash budget, so a 14-point series and a 3-point one take the same time. */
.lt-spark polyline{stroke-dasharray:1;stroke-dashoffset:1;animation:lt-draw 1.1s cubic-bezier(.3,.7,.4,1) forwards}
@keyframes lt-draw{to{stroke-dashoffset:0}}
/* the area rises with the line, and the endpoint keeps beating after both have arrived */
.lt-spark-area{animation:lt-fade .9s .4s ease both}
@keyframes lt-fade{from{opacity:0}to{opacity:.10}}
.lt-spark-end{animation:lt-fade-in .3s 1s ease both,lt-beat 2.6s 1.3s ease-in-out infinite}
@keyframes lt-fade-in{from{opacity:0}to{opacity:1}}
@keyframes lt-beat{0%,100%{r:2.4;opacity:1}50%{r:3.6;opacity:.55}}
/* a column chart reads better if the bars do not all arrive at once — 14 days, 25ms apart */
.pf-spark .pf-bar:nth-child(2n){animation-delay:.05s}
.pf-spark .pf-bar:nth-child(3n){animation-delay:.1s}

/* ---- ONE SWITCH ----------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  .lt-tile,.lt-strip,.lt-ins,.kpi,.tile,.statcard,.card,.lt-open,.lt-go,
  .dtable tbody tr,.atable tbody tr,.side-link,.frow,.beltrow,.lead,.convrow{transition:none}
  a.lt-ins:hover,.lt-strip:hover,.lt-tile:hover,.lt-open:hover,.lt-open:active,
  .lt-go:hover,.lt-go:active{transform:none}
  .lt-meter i,.pipe-fill,.tile-fill,.pf-fbar,.pf-mbar,.trend-bar,.pf-bar{animation:none}
  .lt-spark polyline{animation:none;stroke-dasharray:none;stroke-dashoffset:0}
  /* the area and the endpoint must be RESTORED, not merely stopped: a paused fade is an invisible
     chart, and a paused beat can rest at half opacity. */
  .lt-spark-area{animation:none;opacity:.10}
  .lt-spark-end{animation:none;opacity:1}
}

/* ==================================================================================================
   W8 · THE CARD EDGE — every card gets a hairline, terminal-wide.
   VS 2026-08-28: "the cards are not visible and are difficult to differentiate from the background.
   We can use a hairline border, a soft border around all such cards in the entire terminal, so that
   we can differentiate the cards, isolate and read the information separately."

   THIS OVERTURNS A CALL I MADE IN W1, and the comment there is worth quoting because it names the
   error exactly: "White on the warm ground; the ground IS the edge, so the hairline recedes and the
   shadow is a whisper." That reasoning holds for ONE card on an empty page. It fails for a grid of
   six tiles and five strips, which is what this terminal actually renders: at 1-2% luminance
   difference the eye cannot find where one card stops and the next begins, so it stops reading them
   as separate things and reads the whole block as texture. A whisper shadow is not an edge; it is a
   suggestion of one, and at these sizes the suggestion did not land.

   TWO SURFACES ALSO GO WHITE. `.lt-strip` and the plain tile wore the neutral wash (#F2F2F5, cool)
   on the warm ground (#F7F6F3) — a 1% difference in the wrong direction, which is the worst of both:
   not white enough to read as a card, not dark enough to read as a zone. The semantic washes stay,
   because money/growth/attention are MEANING and worth their colour; "plain" was never meaning, only
   the absence of it, and the honest rendering of that is a white card with an edge.

   The edge is navy at low alpha rather than a warm grey: it darkens whatever sits under it, so one
   token reads correctly on white AND on all four washes, and it keeps the brand's rule that every
   shadow and line on this product is navy-tinted, never black.
   ================================================================================================== */
/* THE RULES THAT STOOD HERE FOR NINE HOURS ARE GONE, and the header above is kept as the record
   of why they existed. VS 2026-08-28 morning, operating the live terminal: "that started to make
   my UI feel cheaper and compartmentalized. I want to go back to the previous cards... the
   version with tint. Remove the hairline completely."

   THE RULING OF RECORD IS NOW: A CARD IS A TINT, NEVER A LINE. Zones separate by their wash —
   money / grow / warn / plain — and by the soft navy shadow on the warm ground, exactly the
   LABONE TINT language as frozen. W8 was a pure append, so deleting its rules restores every
   base rule untouched: .lt-strip and the plain tile wear --lt-wash-plain again, severity cards
   keep their own 3px bar (base .lt-ins), and W1's shadow carries the depth. Do not re-add a card
   border anywhere in the app skin without VS's word in writing — this is the second reversal on
   this exact question in one day, and tint-card-edge.test.js now pins THIS direction. */

/* ==================================================================================================
   W9 · THE GAPS VS FOUND BY EYE (2026-08-28).
   "I think you are just going superficially and not watching the gaps by eye." Correct. Four
   defects he screenshotted that every structural test in this repo was blind to, because each one
   is a COLLISION or a DEFAULT — the markup is right, the classes exist, the links resolve, the
   suite is green, and the pixels are still wrong.
   ================================================================================================== */

/* 1 · A GROUPED BUTTON IS PART OF ITS GROUP. `.pl-range` is a bordered pill holding two dates and
   Go. Go carried its own full button border INSIDE that border, so the screen showed two nested
   rounded rectangles a few pixels apart and read as a rendering fault. It becomes the group's
   right-hand segment: no box of its own, a hairline to divide it, the group's own corner. */
.pl-range{overflow:hidden;padding-right:0}
.pl-range .pl-go{border:0;border-left:1px solid var(--line-input);border-radius:0;
  height:100%;min-height:0;padding:0 12px;background:transparent;color:var(--navy);font-weight:700}
.pl-range .pl-go:hover{background:var(--lt-wash-money);box-shadow:none;transform:none}

/* 2 · THE BACK LINK WAS STILL PRE-TINT — grey text with an arrow, on screens whose every other
   control had been re-cut. It is a control, so it wears the control language: the frozen pill,
   quieter, because going back is never the primary thing on a page. */
.back{display:inline-flex;align-items:center;gap:6px;color:var(--muted);background:var(--lt-card);
  border:1px solid var(--line-input);border-radius:999px;padding:5px 13px;font-size:12px;font-weight:700;
  margin-bottom:var(--s4);transition:border-color .14s ease,color .14s ease,box-shadow .14s ease,transform .14s ease}
.back:hover{color:var(--navy);border-color:var(--navy);box-shadow:0 2px 8px rgba(26,45,90,.12);
  transform:translateY(-1px)}
.back:active{transform:translateY(1px);box-shadow:none}

/* 3 · THE TICK BOX WAS THE BROWSER'S. Every checkbox in the terminal rendered as the OS default —
   a grey square belonging to no design system. `accent-color` re-colours the native control
   without touching its box, so every checkbox and radio across 158 views becomes the brand navy at
   ZERO layout risk: the sizes pinned by the register, the bench grid and the worksheet specs are
   untouched, because the element is still the native one. */
input[type=checkbox],input[type=radio]{accent-color:var(--navy)}

/* and a MODE toggle is not a tick box. "Default [ ] Custom" asked a person to read a checkbox as a
   switch. This is a real switch that is still a checkbox underneath — it posts in a plain form and
   works with script off, which the button-based .switch cannot. */
/* `input[type=checkbox].lt-sw` and not a bare `.lt-sw`, and this is the SECOND time this exact
   trap has been paid for: `.erp input[type=checkbox]` scores (0,2,1) and resets every box to
   width:auto, which on an appearance:none element means ZERO. The first cut of this switch
   rendered 0x0 — an invisible control on a live settings screen — and the comment fixing it for
   .ve-mk was already twelve lines up in this same file. Matched and outweighed. */
input[type=checkbox].lt-sw{appearance:none;-webkit-appearance:none;position:relative;flex:0 0 auto;
  width:38px;height:22px;border-radius:999px;background:#CBD2DA;border:0;cursor:pointer;margin:0;
  transition:background-color .16s ease}
input[type=checkbox].lt-sw::after{content:"";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;
  background:#fff;box-shadow:0 1px 2px rgba(26,45,90,.3);transition:transform .16s cubic-bezier(.2,.8,.2,1)}
input[type=checkbox].lt-sw:checked{background:var(--navy)}
input[type=checkbox].lt-sw:checked::after{transform:translateX(16px)}
input[type=checkbox].lt-sw:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
input[type=checkbox].lt-sw:disabled{opacity:.5;cursor:not-allowed}
@media (prefers-reduced-motion:reduce){input[type=checkbox].lt-sw,input[type=checkbox].lt-sw::after{transition:none}}

/* ==================================================================================================
   W10 · NOTHING WEARS THE OPERATING SYSTEM (VS 2026-08-28).
   "The calendar buttons somewhere are from the Windows 10 model and are ancient ... and so are all
   the buttons, like 'Choose File' and 'Save Photo'. Everything. All the buttons."

   An audit that asked the STYLESHEET — for every class a button wears, does any rule give it a
   background, border or padding? — found 24 buttons that no rule skins at all, including the Search
   button on Mail. They rendered as the browser's grey box on a terminal where everything else had
   been re-cut.

   THE FIX IS A BASELINE, NOT 24 EDITS. `button` is an ELEMENT selector at (0,0,1), so it loses to
   every class rule in this file: the toast's transparent close, the kebab summary, the switch, the
   pill — all keep their own skin untouched. What it catches is the button nobody dressed, today and
   every future one, which is the actual complaint.
   ================================================================================================== */
/* SIZE GOES ONLY TO THE GENUINELY UNDRESSED, and that distinction was worth measuring for. A flat
   `button{min-height:32px;padding:0 16px}` looked right and would have broken two things quietly:
   `.sr` is a VISUALLY-HIDDEN submit at 1x1 (a 32px floor makes it a visible box in the middle of a
   form), and `.chip`, `.mini`, `.teDel`, `.modebtn` and friends set no height of their own, so
   every small inline button in every table would have grown to 32px. `:not([class])` is exactly
   the population the audit found: a button nobody dressed. */
button:not([class]),input[type=submit]:not([class]),input[type=reset]:not([class]),
button[class=""],input[type=submit][class=""]{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  min-height:var(--ctrl-h);padding:0 var(--s4)}
/* the PAINT is safe for every button, because each of these loses to any class rule at (0,1,0) */
button,input[type=submit],input[type=reset]{
  font-family:var(--f-body);font-size:var(--t-ui);font-weight:500;line-height:1.2;
  background:#fff;color:var(--navy);border:1px solid var(--line-input);border-radius:var(--lt-rs);
  cursor:pointer;transition:background-color .14s ease,border-color .14s ease,box-shadow .14s ease,transform .14s ease}
button:hover,input[type=submit]:hover{border-color:var(--navy)}
button:active,input[type=submit]:active{transform:translateY(1px)}
button[disabled],input[type=submit][disabled]{opacity:.55;cursor:not-allowed;transform:none}
/* and the one hidden control must stay hidden whatever the baseline says */
.sr{min-height:0;padding:0;border:0;background:none}
/* a button that names itself dangerous should look it — `tm-danger` was one of the 24 with a name
   and no rule behind it */
.tm-danger{color:var(--bad-ink);border-color:#E9C4C4;background:#fff;
  min-height:var(--ctrl-h);padding:0 var(--s4)}
.tm-danger:hover{border-color:var(--bad-ink);background:#FDF5F5}

/* CHOOSE FILE. ::file-selector-button is the one part of a file input CSS can reach, and it had
   never been touched — so every upload on the terminal offered an OS-grey "Choose file". */
input[type=file]{font-family:var(--f-body);font-size:var(--t-ui);color:var(--muted);
  border:1px solid var(--line-input);border-radius:var(--lt-rs);background:#fff;
  padding:0;height:var(--ctrl-h);width:auto;max-width:100%}
input[type=file]::file-selector-button{
  font-family:var(--f-body);font-size:var(--t-ui);font-weight:600;
  margin:0 var(--s3) 0 0;height:calc(var(--ctrl-h) - 2px);padding:0 var(--s4);
  background:var(--lt-wash-money);color:var(--navy);
  border:0;border-right:1px solid var(--line-input);
  border-radius:calc(var(--lt-rs) - 1px) 0 0 calc(var(--lt-rs) - 1px);
  cursor:pointer;transition:background-color .14s ease}
input[type=file]::file-selector-button:hover{background:#DCE6F5}

/* THE DATE FIELD. Its picker ICON is styleable and now matches the terminal; the CALENDAR POPUP is
   browser chrome drawn outside the document and CSS cannot reach it at all — that is a real limit,
   not an oversight, and replacing it means a scripted picker that stops working with script off.
   What is fixed here is everything the page actually owns. */
input[type=date],input[type=time],input[type=datetime-local],input[type=month]{
  font-family:var(--f-body);font-size:var(--t-ui);color:var(--ink);
  border:1px solid var(--line-input);border-radius:var(--lt-rs);background:#fff}
input[type=date]::-webkit-calendar-picker-indicator,
input[type=time]::-webkit-calendar-picker-indicator,
input[type=datetime-local]::-webkit-calendar-picker-indicator{
  cursor:pointer;opacity:.55;padding:2px;border-radius:6px;transition:opacity .14s ease,background-color .14s ease}
input[type=date]::-webkit-calendar-picker-indicator:hover,
input[type=time]::-webkit-calendar-picker-indicator:hover,
input[type=datetime-local]::-webkit-calendar-picker-indicator:hover{opacity:1;background:var(--lt-wash-money)}
/* the range group draws its own frame, so the dates inside it keep none */
.pl-range input[type=date]{border:0;border-radius:0;background:transparent}
@media (prefers-reduced-motion:reduce){
  button,input[type=submit],input[type=reset],input[type=file]::file-selector-button{transition:none}
  button:active,input[type=submit]:active{transform:none}
}

/* ==================================================================================================
   W11 · THE OPERATOR'S HANDS (VS 2026-08-28, approved upgrades 1/3/4/5/6/8 + the search ruling).
   Everything here dresses an enhancement layer over pages that already work script-off. Namespaced
   lt- throughout; the global reduced-motion block above already silences every transition below.
   ================================================================================================== */

/* ---- 1 · THE COMMAND PALETTE (Ctrl+K, lt-palette.js). The scrim is the terminal's own navy at
   depth, the box a plain card — the palette is an instrument, not a feature to admire. ---------- */
.lt-pal-scrim{position:fixed;inset:0;z-index:240;display:none;background:rgba(15,27,56,.42);
  padding:11vh 16px 0;justify-content:center;align-items:flex-start}
.lt-pal-scrim.on{display:flex}
.lt-pal{width:min(560px,100%);background:var(--lt-card);border-radius:var(--lt-r);
  box-shadow:0 18px 50px rgba(15,27,56,.30);overflow:hidden}
.lt-pal-in{width:100%;border:0;border-bottom:1px solid var(--line-input);border-radius:0;
  padding:15px 18px;font-family:var(--f-body);font-size:15px;color:var(--ink);background:var(--lt-card)}
.lt-pal-in:focus{outline:none;border-bottom-color:var(--teal)}
.lt-pal-list{list-style:none;margin:0;padding:6px;max-height:46vh;overflow-y:auto}
.lt-pal-row{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:var(--lt-rs);
  font-size:var(--t-ui);color:var(--ink);cursor:pointer}
.lt-pal-row.on{background:var(--lt-wash-money);color:var(--navy)}
.lt-pal-l{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}
.lt-pal-k{flex:0 0 auto;font-size:var(--t-mini);font-weight:700;color:var(--muted);
  letter-spacing:.04em;text-transform:uppercase}
.lt-pal-row.on .lt-pal-k{color:var(--teal)}
.lt-pal-none{padding:14px 12px;font-size:var(--t-ui);color:var(--muted)}
.lt-pal-hint{margin:0;padding:8px 14px;border-top:1px solid var(--line-s,#EAE6DF);
  font-size:var(--t-mini);color:var(--muted);background:var(--lt-ground)}
.lt-pal-hint kbd{font-family:var(--f-data);font-size:10.5px;font-weight:600;color:var(--navy);
  background:var(--lt-card);border:1px solid var(--line-input);border-radius:4px;padding:1px 5px}

/* ---- 4 · TAT — a waiting row wears its age (E&V board). Text in the date cell's own sub-line,
   so the 53px row geometry is untouched; the ramp turns at 6 and 24 hours. ---------------------- */
.lt-tat{font-family:var(--f-data);font-weight:600;letter-spacing:.02em;color:var(--muted)}
.lt-tat-warn{color:var(--amber-ink)}
.lt-tat-bad{color:var(--bad-ink)}

/* ---- 6 · THE DELTA GRAMMAR on the E&V strip — each tab count carries its move against the
   previous period. Judged by direction: a waiting bucket up is bad, a finished bucket up is good,
   volume (All) is neutral muted. --------------------------------------------------------------- */
.lt-dl{margin-left:5px;font-family:var(--f-data);font-size:var(--t-mini);font-weight:700;color:var(--muted)}
.lt-dl-ok{color:var(--ok-ink)}
.lt-dl-bad{color:var(--bad-ink)}

/* ---- the search ruling · LIVE FILTER — hidden rows and the honest note (lt-livefilter.js).
   display:none is the point: filtering IS the layout change; the note names what Enter still has. */
.dtable tbody tr.lt-lf-off,.atable tbody tr.lt-lf-off{display:none}
.dtable tbody tr.lt-lf-note td,.atable tbody tr.lt-lf-note td{padding:9px var(--s5);
  font-size:var(--t-tight);color:var(--muted);background:var(--lt-ground);text-align:center}

/* ---- 8 · DRAFT SAFETY — a restored draft says so quietly until the person types again -------- */
textarea.lt-draft-back{border-left:3px solid var(--teal);
  box-shadow:inset 3px 0 0 0 rgba(13,143,143,.10)}

/* ==================================================================================================
   W12 · THE COLOR VOICE (VS 2026-08-28: "I love colors... color density, not to look cheap but to
   look premium. The whole system should speak out for itself.")

   THE DOCTRINE THAT KEEPS DENSITY PREMIUM — colour is meaning, at two sizes:
     LARGE (a card's whole ground)  takes only the soft washes, and only as a VERDICT (on plan /
                                    watch / breach) or a ZONE (money / growth) the view computed.
     SMALL (an icon, a count, a monogram)  may take full-strength brand hues, and only to NAME
                                    something — a person, a queue, a state.
   Decoration — colour that answers no question — stays banned. That is the whole line between
   premium and carnival, and every rule below cites which question its colour answers.
   ================================================================================================== */
:root{--lt-wash-bad:#F9E8E6;
  --av0-g:#E4EAF5;--av0-i:#1A2D5A;--av1-g:#DCEFEF;--av1-i:#0A6E6E;
  --av2-g:#FBEBD9;--av2-i:#9C5A12;--av3-g:#E1F1E7;--av3-i:#1F6B40;
  --av4-g:#E7ECF2;--av4-i:#3D5578;--av5-g:#F8E7E4;--av5-i:#A03B30;
  --av6-g:#F6EFDB;--av6-i:#84691C;--av7-g:#E0EDF3;--av7-i:#20618E}

/* WHO — the person hue. Eight brand-derived pastels, hashed from the name in lib/ui.js mono();
   the same person wears the same colour on every screen. Semantic monograms (mira / won / rival /
   cust) never take one — a judgment always outranks an identity. */
.mono-h0{background:var(--av0-g);color:var(--av0-i)} .mono-h1{background:var(--av1-g);color:var(--av1-i)}
.mono-h2{background:var(--av2-g);color:var(--av2-i)} .mono-h3{background:var(--av3-g);color:var(--av3-i)}
.mono-h4{background:var(--av4-g);color:var(--av4-i)} .mono-h5{background:var(--av5-g);color:var(--av5-i)}
.mono-h6{background:var(--av6-g);color:var(--av6-i)} .mono-h7{background:var(--av7-g);color:var(--av7-i)}

/* HOW AM I DOING — the scorecard tile's ground is its verdict. The k-* / t-done classes come from
   the view's own target math (kst/tdone in performance.ejs); CSS adds no judgment of its own.
   A washed tile drops its hairline: a card is a tint, never a line (W8R). */
.tile.k-ok,.tile.t-done{background:var(--lt-wash-grow);border-color:transparent}
.tile.k-warn{background:var(--lt-wash-warn);border-color:transparent}
.tile.k-bad{background:var(--lt-wash-bad);border-color:transparent}
.tile.t-money{background:var(--lt-wash-money);border-color:transparent}

/* WHERE DOES THE BUSINESS STAND — a Pulse department on watch stands on the warn wash, a breach
   on the bad wash; on-plan stays the quiet plain wash. Class from s.light in command.ejs. */
.lt-strip.lt-sv-warn{background:var(--lt-wash-warn)}
.lt-strip.lt-sv-bad{background:var(--lt-wash-bad)}

/* WHICH QUEUE IS THIS — the lead lenses and the CRM strip. The icon and the count wear the
   queue's colour; the pill stays white so twelve chips read as a quiet row with twelve named
   doors, not twelve buttons shouting. The active chip (.on / .lane-on) keeps the navy fill —
   selection outranks naming. */
.qchip .ic{color:var(--muted)}
.qchip:not(.on).q-due .ic,.qchip:not(.on).q-due b{color:var(--orange)}
.qchip:not(.on).q-hot .ic,.qchip:not(.on).q-hot b{color:var(--orange-d)}
.qchip:not(.on).q-new .ic,.qchip:not(.on).q-new b{color:var(--av7-i)}
.qchip:not(.on).q-rep .ic,.qchip:not(.on).q-rep b{color:var(--teal)}
.qchip:not(.on).q-done b,.qchip:not(.on).q-done{color:var(--ok-ink)}
.qchip:not(.on).q-gc .ic,.qchip:not(.on).q-gc b{color:var(--ok-ink)}
.qchip:not(.on).q-stop .ic,.qchip:not(.on).q-stop b{color:var(--bad-ink)}
.qchip:not(.on).q-stall .ic,.qchip:not(.on).q-stall b{color:var(--amber-ink)}
.qchip:not(.on).q-risk{color:var(--bad-ink)}
.belt-lanes a .ic{color:var(--muted)}
.belt-lanes a:not(.lane-on).lane-new .ic,.belt-lanes a:not(.lane-on).lane-new b{color:var(--ok-ink)}
.belt-lanes a:not(.lane-on).lane-chat .ic,.belt-lanes a:not(.lane-on).lane-chat b{color:var(--teal)}
.belt-lanes a:not(.lane-on).lane-due .ic,.belt-lanes a:not(.lane-on).lane-due b{color:var(--orange)}
.belt-lanes a:not(.lane-on).lane-all .ic{color:var(--navy)}
.belt-lanes a:not(.lane-on).lane-add .ic{color:var(--orange)}
.belt-lanes a:not(.lane-on).lane-score .ic{color:var(--av6-i)}

/* ==================================================================================================
   W13 · THE STAGE CLOCK + THE CLOSED LOOP (approved upgrades 1 and 5, VS 2026-08-28).
   The trail under a bill's header: where did this bill's time go, hop by hop — and a dash on any
   hop nobody stamped, which is the trail teaching the stamp. Chip stage text rides .lt-tat.
   ================================================================================================== */
.lt-trail{display:block;margin-top:3px;font-family:var(--f-data);font-size:var(--t-mini);
  font-weight:600;letter-spacing:.02em;color:var(--muted)}
.lt-trail b{color:var(--navy);font-weight:700}
.lt-hop{white-space:nowrap}
.lt-hop-none{opacity:.55}

/* the week page (WBR): everything rides Pulse's own dialect; only the layout gaps are new */
.lt-wk-money{margin-bottom:var(--s5)}
.lt-wk-money .tile{text-align:left}
.lt-wk-sub{display:block;font-size:var(--t-mini);color:var(--muted);margin-top:2px}
.lt-wk-worst{margin:2px 0 8px;font-size:var(--t-tight);color:var(--bad-ink)}
.lt-wk-nums{flex-wrap:wrap}

/* the andon lamp (approved upgrade 3): an open issue holds the bill, and the bill wears it beside
   its state — red-tinted because a held line is a stopped line, not a warning about one */
.pl-status.lt-held{background:var(--lt-wash-bad);color:var(--bad-ink)}

/* THE WAIT SITS UNDER ITS STATE (2026-08-28). The pill names what the test is waiting in; this
   names how long. On its own line so the Status column grows DOWN, not sideways — sideways is
   what pushed the sticky Action column onto 70px of Status when the age rode the date cell. */
.dtable .c-st .lt-tat,.atable .c-st .lt-tat{display:block;margin-top:3px;margin-left:0}

/* ==================================================================================================
   W17 · THE QUIET RAIL (VS 2026-08-28, Option B of three templates, approved before any code).
   Approved: https://claude.ai/code/artifact/a5d605ca-e571-4848-843f-fa1b65a44220

   MEASURED FIRST, then designed. On the live Terminal at 1440px:
     · rail 232px wide with FIVE pixels of horizontal slack — "Collection Centres" alone needs 171
       of them. The rail was never wide because it was padded; it was wide because of its FONT.
       So narrowing it and shrinking the type are not two changes, they are one, and the width
       follows the type rather than the other way round.
     · eleven rail rows carried no icon at all (fixed in lib/icons.js + lib/depts.js).
     · 72px of a 1440px screen thrown away on the right, because .wrap capped work pages at 1080.
     · three surfaces on one screen: a WHITE rail (#FFFFFF), a WHITE bar with a hard #E2DED7 rule,
       and the warm canvas between them. That is the "clear-cut colour mismatch" VS saw at the
       rail's top and bottom edges — not a bad line, but two panels sitting ON a page.

   OPTION B, in one sentence: ONE GROUND, WHISPER SEAMS. The rail and the bar take the canvas
   colour, so nothing pops out; a single --line-s hairline stays at each join so the eye can find
   the edge when it looks for it and never trips on it when it doesn't. "Distinguishable and yet
   undistinguishable" (VS, verbatim) is a contradiction only until you separate FINDING an edge
   from NOTICING one — this layer keeps the first and removes the second.

   COLOUR IS UNTOUCHED. Every value below is either the frozen Tint ground (--bg) or the frozen
   soft line (--line-s). The LABONE TINT palette is not reopened by this wave — only geometry and
   which surface wears which frozen colour.
   ================================================================================================== */

/* ---- 1 · the ground, and the two seams -------------------------------------------------------- */
/* The rail token inverts back: it went WHITE in the Tint freeze because a white panel beside a warm
   canvas is how the frozen prototype read. VS has now looked at that split on a real screen for a
   day and ruled against the panel. The token moves, not the eighty rules that ask for it. */
:root{--rail:#F7F6F3}
.sidebar{background:var(--bg);border-right:1px solid var(--line-s);box-shadow:none}
.topbar{background:var(--bg);border-bottom:1px solid var(--line-s)}
/* A bordered box on a quiet ground is the loudest thing left, so the bar's icon buttons lose their
   ring and keep only their hover — the control appears under the cursor and is otherwise ground. */
.tb-icon{border-color:transparent}
.tb-burger:hover,.tb-icon:hover{background:rgba(26,45,90,.06)}

/* ---- 2 · the rail, sized and typed like Claude Code's ----------------------------------------
   VS: "the overall width of the rail should be like the Claude Code at present, so that it sits on
   the side quietly with the least empty space. Also, the font size should be the same... We are
   going to add modules, so we don't need a lot of negative space."
   232 -> 206 and 14px -> 12.5px are one decision: at 12.5/500 the longest label measures 152px,
   which clears 206 minus the 15px icon, the 9px gap and two 9px gutters with 4px to spare. The
   rail is no longer at its limit, which is the point — modules are coming.

   ROW HEIGHT AND TYPE ARE TOKENS, NOT LITERALS, because [data-density="comfortable"] is a real
   contract: a rep reading a phone in the sun gets bigger rows, and a flat 30px here would have
   silently revoked that for the one group of people who need it. The mobile floor is independent
   of density for the same reason — a drawer is thumb-driven whoever opens it. */
:root{--rail-w:206px;--rail-row:30px;--rail-t:12.5px}
[data-density="comfortable"]{--rail-row:42px;--rail-t:14px}
.sidebar{width:var(--rail-w)}
.signed-in .content{margin-left:var(--rail-w)}
.side-nav{padding:var(--s3) 7px 0}
.side-link{min-height:var(--rail-row);font-size:var(--rail-t);gap:9px;padding:0 9px;border-radius:7px}
.side-link .ic{width:15px;height:15px}
.side-link.on::before{top:6px;bottom:6px}
/* the two groups that still carry a heading (Masters, Lab Management) come down with their rows —
   a heading typed larger than the list it heads is the panel look all over again, in miniature */
.nav-h,button.nav-h{font-size:var(--t-micro);letter-spacing:.14em;text-transform:uppercase;
  padding:12px 9px 3px;font-weight:700}
.nav-sub .side-link{padding-left:9px}
.nav-badge{font-size:var(--t-micro)}

/* ---- 3 · the bar, 64 -> 52 -------------------------------------------------------------------
   Everything on it comes down to 34px, which leaves 9px of air above and below — the same
   proportion the 38px controls had in the 64px bar, so nothing feels newly cramped. */
:root{--topbar-h:52px}
.topbar{gap:var(--s3)}
.tb-burger,.tb-icon{width:34px;height:34px}
.tb-burger svg,.tb-icon svg{width:18px;height:18px}
.tb-search input,.tb-centre select,.tb-menu>summary,.tb-pill{height:34px}
.tb-avatar{width:26px;height:26px}
/* 560 -> 320: it was over half the bar and read as the page's hero. Its job did not change. */
.tb-search{max-width:320px}
.tb-search input{padding-left:36px;font-size:var(--t-tight)}
.tb-search svg{left:var(--s3);width:15px;height:15px}
.tb-pill{font-size:var(--t-mini)}
.tb-pill svg{width:15px;height:15px}
.tb-sep{height:20px}

/* ---- 4 · Report a problem, relocated ---------------------------------------------------------
   It was position:fixed over the bottom-right corner of all 158 screens, stacked above the chat
   bubble. In the bar it is a 34px icon like the rest; the ONLY thing that changes about the
   feature is which way its popover hangs. The chat bubble stays where it is (VS ruling): a field
   phone reaches it with a thumb, and that was a deliberate placement, not an accident of history. */
.tb-fb{position:relative;right:auto;bottom:auto;z-index:auto;flex:0 0 auto}
.tb-fb .fb-btn{gap:0;padding:0;border:1px solid transparent;background:none;color:var(--ink);
  border-radius:8px;box-shadow:none}
.tb-fb .fb-btn:hover{background:rgba(26,45,90,.06)}
.tb-fb[open] .fb-btn{background:var(--navy);border-color:var(--navy);color:#fff}
.tb-fb .fb-pop{top:calc(100% + 8px);bottom:auto;right:0}

/* ---- 5 · the screen stops throwing space away ------------------------------------------------
   VS: "the screen space for all the screens can be adjusted to utilize the maximum screen space
   when used on a laptop or a desktop", capped at 1560 on his ruling "so a line of text never gets
   unreadably long".
   Only the WORK measure moves. read(760) is the reading measure itself — widening a lead story to
   1560 is the exact failure the cap exists to prevent — and table(1680) already fills a 1440 screen
   edge to edge, so it was never part of the complaint. Loose prose on a wide page keeps its 78ch
   rule, which is the second half of the same protection. */
:root{--w-work:1560px}

/* ---- 6 · mobile keeps its own metrics --------------------------------------------------------
   The rail is a 250px drawer below 820px and is driven by a thumb, so it takes the phone's row
   height whatever density the operator's role was given. The bar keeps 56px for the same reason. */
@media(max-width:820px){
  :root{--topbar-h:56px;--rail-row:40px;--rail-t:14.5px}
  .signed-in .content{margin-left:0}
  .tb-search{max-width:none}
}

/* ---- 7 · the rail's scrollbar was the third line ----------------------------------------------
   Found by LOOKING at the deployed screen, not by reading the stylesheet: 22 rows overflow a 632px
   nav, and Chrome painted its default light track + grey thumb down the last 10px of the rail —
   a second vertical rule sitting directly against the seam we had just softened. Exactly the
   "clear-cut boundary" this wave exists to remove, and no CSS assertion could have seen it.

   Note the mechanism, because the old rules looked like they already handled this: .side-nav has
   carried ::-webkit-scrollbar{width:6px} since Rail D, and Chrome IGNORES it — once the standard
   scrollbar-width property is set (it is, `thin`), the -webkit- pseudo-elements stop applying.
   scrollbar-color is the property that works, so that is the one used.

   The gutter stays reserved at all times and only its COLOUR changes, so nothing reflows when the
   thumb appears — a scrollbar that takes 10px away on hover would shove every label sideways. */
.side-nav{scrollbar-color:transparent transparent}
.sidebar:hover .side-nav,.side-nav:focus-within{scrollbar-color:rgba(26,45,90,.22) transparent}
.side-nav::-webkit-scrollbar-track{background:transparent}
.side-nav::-webkit-scrollbar-thumb{background:transparent}
.sidebar:hover .side-nav::-webkit-scrollbar-thumb{background:rgba(26,45,90,.20)}

/* ==================================================================================================
   W18 · THE BAR READS AS THE PRODUCT'S (VS 2026-08-28, six notes off a screenshot walk).
   Follows W17 and only moves what he named. Colour still untouched.
   ================================================================================================== */

/* ---- the mark: LEFT, and a quarter larger -------------------------------------------------------
   It was centred on 08-28 and reversed on 08-29 after VS looked at it: "I don't like it's there.
   Place it on the left side beside the three lines." So this is deliberately NOT a rule — the base
   .tb-brand puts it second in the flow, and there is nothing here to override that.

   THE SIZE IS THE REAL FIX, and it only became visible once the position stopped being a variable.
   "It's reading off" was never about where the mark sat: at 30px in a 52px bar the DIAGNOSTICS
   line under the wordmark drew about two pixels tall, which is a grey smudge, not a word. 30 -> 38
   is his 0.25x, and it leaves 7px of air above and below in the 52px bar. */
.topbar .tb-brand img{height:38px}

/* CLOSER TO THE BURGER (VS 2026-08-29, twice: "shift it a little bit more towards the left",
   then "maybe 8px more"). The bar's own 8px flex gap sat on TOP of the 8px of padding inside the
   burger button, so the mark read 16px clear of a glyph only 18px wide itself. -8 cancelled the
   gap; -16 goes 8px further and puts the mark flush against the drawn hamburger.

   THE SECOND 8px COSTS SOMETHING, and it is paid for here rather than left to be found later.
   At -16 the brand's box overlaps the burger BUTTON's box by 8px — the empty padding right of
   the glyph — and the brand is later in the DOM, so without this it would paint over that strip
   and swallow presses meant for the menu. The button is raised instead: it keeps every pixel of
   its own 34px hit area, and the brand loses 8px of its left edge, which is the harmless half of
   the trade (the logo link is 130px wide; the menu button is the one a thumb aims at). */
.tb-brand{margin-left:calc(var(--s3) * -2)}
.tb-burger{position:relative;z-index:1}

/* ---- the rail comes in again -------------------------------------------------------------------
   VS: "the left rail can further be shrunken because still there is some negative space, as the
   module names are not so big." Measured after W17: the longest label ("Membership Master") draws
   117px, and 206px was giving it 153 — 36px of air.

   206 -> 184, and the 10px scrollbar gutter comes back as label room. That gutter was holding a
   scrollbar W17 had already made invisible, so the rail was reserving a tenth of itself to display
   nothing. Wheel and trackpad still scroll; on the phone the drawer is 250px and touch-scrolls.
   NET: the rail is 22px narrower AND the longest label has MORE room than before (142 vs 153 is
   less, but it needs 117 — the slack that mattered stays at 25px). */
:root{--rail-w:184px}
.side-nav{scrollbar-width:none}
.side-nav::-webkit-scrollbar{width:0;height:0}

/* ---- the bar's controls -------------------------------------------------------------------------
   Tools keeps the tinted pill (it is a destination, not a utility); the three utilities are bare
   icon buttons in VS's order — Mail, Settings, Bugs. The bug control is the only one with no
   feature behind it, and it must not LOOK cheaper for that. */
.tb-fb .fb-btn .ic-i{width:18px;height:18px}

/* ---- CANCEL BILL (2026-08-29) --------------------------------------------------------------
   The register's kebab gains a control that needs a REASON before it will fire, so it opens in
   place rather than navigating: a <details> nested inside the menu, which needs no script and
   cannot be broken by the CSP. kebab.js already positions the outer menu; this only lays out the
   row that appears inside it. */
.kebab-sub{display:block}
.kebab-sub>summary{list-style:none;cursor:pointer}
.kebab-sub>summary::-webkit-details-marker{display:none}
.dtable .kb-cancel,.atable .kb-cancel{display:flex;gap:var(--s2);align-items:center;
  padding:var(--s2) var(--s4) var(--s3);background:var(--lt-wash-bad,#FDF2EC)}
.dtable .kb-cancel input[type=text],.atable .kb-cancel input[type=text]{flex:1 1 auto;min-width:0;
  height:30px;margin:0;font-size:var(--t-tight);border:1px solid var(--line-input);border-radius:7px;
  padding:0 var(--s3);background:#fff}
.dtable .kb-cancel .btn-danger,.atable .kb-cancel .btn-danger{background:var(--red);
  border-color:var(--red);color:#fff;white-space:nowrap}
.dtable .kb-cancel .btn-danger:hover,.atable .kb-cancel .btn-danger:hover{background:var(--bad-ink);
  border-color:var(--bad-ink)}

/* A VOID BILL MUST NOT READ AS A LIVE ONE. Red ground, not the amber of Pending — the register is
   scanned, and the one thing that must never happen is a cancelled row being worked. */
.pl-status.pl-cancelled{background:var(--lt-wash-bad,#FDF2EC);color:var(--bad-ink)}

/* ==================================================================================================
   W19 · THE PAYMENTS LEDGER (Flabs Billing Management Update, walked live 2026-08-29).
   Their Manage Payments dialog as a page, in the Tint voice. Every class namespaced bp-.
   ================================================================================================== */
.bp-card{max-width:1080px}
.bp-trio{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s4);margin:var(--s4) 0 var(--s5)}
.bp-stat{background:var(--lt-wash-plain,#F2F2F5);border-radius:12px;padding:12px 16px}
.bp-stat span{display:block;font-size:var(--t-mini);color:var(--muted);font-weight:600}
.bp-stat b{display:block;font-family:var(--f-data);font-size:20px;color:var(--ink);margin-top:2px}
.bp-stat b.bp-ok{color:var(--ok-ink)}
.bp-stat b.bp-due,.bp-due{color:var(--bad-ink)}
.bp-ok{color:var(--ok-ink)}
.bp-table .c-idx{width:44px;text-align:center}
.bp-none{color:var(--muted);text-align:center;padding:var(--s6) 0}
.bp-chip{display:inline-block;background:var(--lt-wash-plain,#F2F2F5);border-radius:999px;
  padding:2px 10px;font-size:var(--t-tight);font-weight:600}
.bp-st{display:inline-block;font-size:var(--t-mini);font-weight:700;border-radius:999px;padding:2px 9px}
.bp-st-full{background:var(--lt-wash-grow,#E7F3EE);color:var(--ok-ink)}
.bp-st-partial{background:var(--lt-wash-warn,#FAF0E1);color:var(--amber-ink)}
.bp-void{margin:0;display:inline}
.bp-void-btn{color:var(--bad-ink)}
.bp-add{margin-top:var(--s5)}
.bp-modes{max-width:640px}
.bp-add-h{margin:0 0 var(--s3)}
.bp-more{margin-top:var(--s3);color:var(--navy)}
.bp-now{display:flex;gap:var(--s6);margin-top:var(--s4);font-size:var(--t-tight);color:var(--muted)}
.bp-now b{font-family:var(--f-data);color:var(--ink);margin-left:6px}
.bp-foot{display:flex;align-items:center;justify-content:space-between;margin-top:var(--s5)}
.bp-note{font-size:var(--t-tight);color:var(--muted)}
/* the register's Bill button wears the payments count, exactly as the reference's does */
.pl-paybadge{position:absolute;top:-7px;right:-7px;min-width:17px;height:17px;padding:0 4px;
  border-radius:999px;background:var(--navy);color:#fff;font-size:10px;font-weight:700;
  display:flex;align-items:center;justify-content:center;line-height:1}
.pl-bill{position:relative}

/* the reference draws Clear Due as the DANGER action (slide 4 of the update): filled red beside
   a plain Cancel. Scoped to the due page's own class — .btn-danger's bare form stays the quiet
   outline it has always been elsewhere. */
.pd-foot .pd-clear{background:var(--red);border-color:var(--red);color:#fff}
.pd-foot .pd-clear:hover{background:var(--bad-ink);border-color:var(--bad-ink)}
.pd-foot .pd-clear[disabled]{background:var(--lt-wash-plain,#F2F2F5);border-color:var(--line);color:var(--muted)}

/* ---- W21 · ACCESSION (Register & Accession's landing) ------------------------------------------
   The bill's tubes, ready to collect and label. acc- namespaced; the labels page is PAPER and
   carries its own inline print CSS, none of this. */
.acc-card{max-width:980px}
.acc-no{white-space:nowrap}
.acc-no code{font-size:var(--t-ui);font-weight:700;letter-spacing:.03em}
.acc-form{margin:0;display:inline}
.acc-table .c-act{text-align:right;white-space:nowrap}
.acc-foot{display:flex;align-items:center;justify-content:space-between;margin-top:var(--s5)}
.acc-foot-r{display:flex;gap:var(--s3)}

/* ---- W22 · RECEIVE (the bench's scan box) ------------------------------------------------------
   Lives on the worklist head, outside the clone-pinned toolbar. One box, one button; the input
   is wide enough for LAB-YYMMDD-NNN plus a scanner's suffix keystroke. */
.bk-head .rcv-box{display:flex;align-items:center;gap:var(--s2);margin:0}
.rcv-box .ic-i{color:var(--teal);width:16px;height:16px}
.rcv-box input[type=text]{width:220px;height:32px;margin:0;font-family:var(--f-data);
  font-size:var(--t-tight);letter-spacing:.02em;border:1px solid var(--line-input);
  border-radius:8px;padding:0 var(--s3);background:#fff}
.rcv-box input[type=text]:focus{outline:none;border-color:var(--teal);
  box-shadow:0 0 0 3px rgba(13,143,143,.12)}

/* ---- W23 · THE ONE REGISTRATION PAGE (R1) ------------------------------------------------------
   The desk form's patient search, moved into the wizard's Patient step. The dropdown reuses the
   ta- family; the static (no-script) list renders in flow, not floated over the fields below. */
.bw-pfind{position:relative;max-width:440px;margin:0 0 var(--s5)}
.bw-pfind input[type=search]{width:100%}
.bw-pfind .ta-static{position:static;margin-top:var(--s2)}
.bw-pfind .ta-row{text-decoration:none;color:inherit}
.bw-pfind-none{margin:var(--s2) 0 0}
.bw-pfind .bw-note{margin-top:var(--s2)}

/* ---- W23 · BOOK IN TERMINAL (C1) — the lead card's bridge to the one registration page ------- */
.ldbk-book{margin:0 0 var(--s4)}
.bw-dispatch{grid-column:1/-1}

/* ---- W23c · THE RAIL, TIGHT AND FLAGGED (VS 2026-08-29 evening, off the live rail) ------------
   "Reduce the undue gaps between modules" — the group gap comes down from ~28px of stacked
   margins and head padding to ~12px, rows untouched (34px stays the tap floor). And the stage
   heads wear the house ORANGE so the eye can cut the rail into its stages at a glance — the one
   accent, used for exactly one job here. Paint and margins only; no pinned geometry moves. */
.side-nav .nav-group{margin:2px 0 4px}
.side-nav .nav-h,.side-nav button.nav-h{padding:7px 9px 2px;color:var(--orange)}
.side-collapsed .nav-h{color:var(--muted)}

/* ---- W23f · THE QUICK LANE (Template A) --------------------------------------------------------
   The lane switch is the page's one segmented control, top right; the quick card reuses the
   retired form's own families (fgrid, fpair, msel, ref-modal, reg-foot) which all survived W6. */
/* W23k·5 (VS 2026-08-30): the lane switch matches its two neighbours — .btn geometry (the
   lt-rs radius, 32px line), not a 99px pill; the workflow-rounding exemption is the STEPPER's,
   not this control's. Active keeps the solid navy of .btn.primary. */
.bw-lane{display:inline-flex;border:1px solid var(--line-input);border-radius:var(--lt-rs);overflow:hidden;
  margin-right:var(--s3);flex:0 0 auto}
.bw-lane a{display:inline-flex;align-items:center;padding:0 var(--s4);min-height:30px;font-size:var(--t-ui);font-weight:600;color:var(--muted);text-decoration:none}
.bw-lane a.on{background:var(--navy);color:#fff}
.bw-lane a:not(.on):hover{color:var(--navy)}
.locked.reg-no{background:var(--w-plain, #F2F2F5);color:var(--muted);font-weight:700;letter-spacing:.02em}
.qk-card{max-width:1100px}
.qk-card .reg-foot{display:flex;justify-content:flex-end;gap:var(--s3);margin-top:var(--s5)}

/* ---- W23g · QUOTATIONS ------------------------------------------------------------------------
   The composer and the tracking register ride the shared families (pd-card, dtable, dtabs,
   ta-pop, bw-sum, ref-modal); qt- carries only what is this screen's own. */
.qt-card{max-width:980px}
.qt-meta{margin:0 0 var(--s4)}
.qt-find{max-width:520px;margin:var(--s4) 0}
.qt-disc{align-items:end;max-width:560px}
.qt-disc-go{margin:0}
.qt-sum{max-width:360px;margin-left:auto}
.qt-foot{display:flex;align-items:center;justify-content:space-between;margin-top:var(--s5)}
.qk-quote{order:-2}
/* VS 2026-09-04: Crelio's order on screen — Register before Register And Bill; DOM stays billing-first */
.qk-register{order:-1}

/* ---- W23i · THE PAGE HEAD (T1, VS 2026-08-30) --------------------------------------------------
   One grammar for every screen's top strip: Row 1 the MOTTO — the page name wearing the same
   orange accent the rail heads wear, always the SAME WORD as the rail row that lit it, muted
   meta beside it, at most two actions right — then places (chips), then states (tabs), then
   the card. .ph makes the accent independent of the wrapper: .wrap>h1::after only reached bare
   headings, which is exactly why half the terminal's names had the bar and half did not. */
.ph{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--s3) var(--s4);
  flex-wrap:wrap;margin:var(--s2) 0 var(--s4)}
.ph h1{margin:0;position:relative;padding-bottom:var(--s3)}
.ph h1::after{content:"";position:absolute;left:0;bottom:0;width:34px;height:2px;
  border-radius:1px;background:var(--orange)}
.ph .ph-meta{font-size:var(--t-ui);font-weight:400;color:var(--muted);margin-left:var(--s2)}
.ph-act{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap}

/* ---- W23j·4 · SOFT TILES, COMPACT AND PASTEL (A1 — VS 2026-08-30, templates-first ruling) ----
   The settled ribbon: a place is a compact white tile (~30px), its icon on a 20px wash-tinted
   square; hover lifts; the ACTIVE tile FILLS WITH ITS OWN WASH — amber for waiting, teal for
   the bench, green for done, the soft navy wash for ordinary places. No solid fill anywhere:
   the navy-filled active of the first cut was ruled "too harsh, killing the grace". The
   stepper alone stays a rounded pill (unlock-in-order workflows differentiate by shape).
   THE TINT VOCABULARY (declared, never ad hoc): default records-navy · tint-g inflow/done ·
   tint-o owed/waiting · tint-t lab/machine; the belt's lane-* classes map onto it. */
.belt-lanes{gap:6px}
.belt-lanes a{display:inline-flex;align-items:center;gap:6px;padding:4px 10px 4px 6px;
  border:1px solid var(--line-s);border-radius:8px;background:#fff;color:#3D4757;
  font-weight:600;transition:transform .12s,box-shadow .12s,background .15s,color .15s}
.belt-lanes a svg{width:20px;height:20px;padding:4px;border-radius:6px;
  background:#EAF0F8;color:var(--navy);box-sizing:border-box;flex:0 0 auto;
  transition:background .15s,color .15s}
.belt-lanes a:hover{transform:translateY(-1px);box-shadow:0 2px 8px -4px rgba(26,45,90,.22)}
.belt-lanes a.lane-on{background:#EAF0F8;border-color:transparent;color:var(--navy);font-weight:700}
.belt-lanes a.lane-on svg{background:rgba(255,255,255,.75);color:var(--navy)}
.belt-lanes a:not(:has(svg)){padding-left:10px}

/* the tile as a family any ribbon can wear */
.rchips{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.rchips-bar{margin:0 0 var(--s4)}
.rchip{display:inline-flex;align-items:center;gap:6px;padding:5px 12px;
  border:1px solid var(--line-s);border-radius:8px;background:#fff;color:#3D4757;
  font-weight:600;text-decoration:none;white-space:nowrap;
  transition:transform .12s,box-shadow .12s,background .15s,color .15s}
.rchip:hover{transform:translateY(-1px);box-shadow:0 2px 8px -4px rgba(26,45,90,.22)}
.rchip.on{background:#EAF0F8;border-color:transparent;color:var(--navy);font-weight:700}
.rchip .n{font-size:11.5px;font-weight:700;font-variant-numeric:tabular-nums;margin-left:2px}

/* the tints at rest — the icon square wears the hue, the count follows */
.belt-lanes a.tint-g svg,.belt-lanes a.lane-new svg{background:#E7F3EE;color:#237A48}
.belt-lanes a.tint-o svg,.belt-lanes a.lane-due svg{background:#FAF0E1;color:#A15E08}
.belt-lanes a.tint-t svg,.belt-lanes a.lane-chat svg{background:#E3F1F1;color:#0D8F8F}
.rchip.tint-g:not(.on) .n{color:#237A48}
.rchip.tint-o:not(.on) .n{color:#A15E08}
.rchip.tint-t:not(.on) .n{color:#0D8F8F}

/* the tints lit — the ACTIVE tile fills with its own wash (A1) */
.belt-lanes a.lane-on.tint-g,.belt-lanes a.lane-on.lane-new{background:#E7F3EE;color:#1E5C36}
.belt-lanes a.lane-on.tint-o,.belt-lanes a.lane-on.lane-due{background:#FAF0E1;color:#7A4A06}
.belt-lanes a.lane-on.tint-t,.belt-lanes a.lane-on.lane-chat{background:#E3F1F1;color:#0A6E6E}
.belt-lanes a.lane-on.tint-g svg,.belt-lanes a.lane-on.lane-new svg{color:#1E5C36}
.belt-lanes a.lane-on.tint-o svg,.belt-lanes a.lane-on.lane-due svg{color:#7A4A06}
.belt-lanes a.lane-on.tint-t svg,.belt-lanes a.lane-on.lane-chat svg{color:#0A6E6E}
.rchip.on.tint-g{background:#E7F3EE;color:#1E5C36}
.rchip.on.tint-o{background:#FAF0E1;color:#7A4A06}
.rchip.on.tint-t{background:#E3F1F1;color:#0A6E6E}
.rchip.on.tint-g .n{color:#1E5C36}.rchip.on.tint-o .n{color:#7A4A06}.rchip.on.tint-t .n{color:#0A6E6E}

/* THE STATES JOIN THE FAMILY (VS 2026-08-30: "Masters, Processing and Dispatch still carry
   the old ribbon"). The underline dies: .dtab (every register and masters tab strip — the
   Patient List, Bookings, Test/Package/Outsource/Membership Masters, Referral List, Marketing,
   Lab Profile, Quotation Tracking, the price grid) and .vf-tab (Processing's board) restyle to
   the same compact pastel tile at the CLASS level, so no screen can be missed and none can
   drift. Counts stay quiet inside the tile; Processing's deltas keep their colors. */
.dtabs{gap:6px;border-bottom:0;padding-bottom:0}
.dtab{padding:5px 12px;border:1px solid var(--line-s);border-radius:8px;background:#fff;
  color:#3D4757;font-weight:600;margin-bottom:0;
  transition:transform .12s,box-shadow .12s,background .15s,color .15s}
.dtab:hover{transform:translateY(-1px);box-shadow:0 2px 8px -4px rgba(26,45,90,.22);color:var(--navy)}
.dtab.on{background:#EAF0F8;border-color:transparent;color:var(--navy);font-weight:700}
.dtab .dtab-n{font-size:11.5px}
.dtab.dtab-off{opacity:.55}
.dtab.dtab-off:hover{transform:none;box-shadow:none;color:var(--ink)}
.vf-tabs{gap:6px}
.vf-tab{padding:5px 12px;border:1px solid var(--line-s);border-radius:8px;background:#fff;
  color:#3D4757;font-weight:600;border-bottom-color:var(--line-s);
  transition:transform .12s,box-shadow .12s,background .15s,color .15s}
.vf-tab:hover{transform:translateY(-1px);box-shadow:0 2px 8px -4px rgba(26,45,90,.22);color:var(--navy)}
.vf-tab.on{background:#EAF0F8;border-color:transparent;color:var(--navy)}
.vf-tab .vf-n{font-size:11.5px;font-weight:700}

/* THE ONE EXCEPTION (VS): the wizard stepper KEEPS its rounded pills — a workflow whose steps
   unlock in order is a different creature from a row of places. It wears the corrected navy. */
/* R1 counts: ONE quiet style on every state tab — a muted tabular number, no bubble.
   The Processing deltas (.vf-delta family) and the belt's queue hues stay: signals, not decor. */
.dtab-n{background:transparent;border-radius:0;padding:0;min-width:0;font-weight:700;
  font-variant-numeric:tabular-nums}
.dtab.on .dtab-n{background:transparent;color:var(--navy)}
.vf-n{background:transparent;min-width:0;height:auto;padding:0;font-weight:700;color:var(--muted)}
.vf-tab.on .vf-n{background:transparent;color:var(--navy)}

/* W23k·6: the "grain segment" component that lived here is DEAD. It shipped with W23j wearing
   the bare name .seg — which the field manager's Segment scorecard has owned since the fm
   build (.seg/.seg-sub/.seg-good/.seg-bad, app.css:190) — and, having NO markup consumer of
   its own, its only effect was to re-dress every scorecard row as a bordered tile (VS caught
   it live, 2026-08-30). The 4400 comment already named the .seg shared-prefix trap. If a
   re-cut grain control is ever needed, it gets a NAMESPACED class, never a bare word. */

@media (prefers-reduced-motion: reduce){
  .belt-lanes a,.belt-lanes a svg{transition:none}
}

/* ============ W23k · THE LAPTOP USES ITS WHOLE SCREEN (VS 2026-08-30) ============
   Off five screenshots: Human Resource and the field manager's day wrap their strips to three
   rows beside a half-blank screen; Digital CRM works in a 760px column of a full viewport.
   Ruling: the laptop view is UNIFORM and uses the maximum space possible; mobile is its own
   optimization. So on a desktop viewport every measure goes fluid and the four capped composer
   cards open with the wrap. This supersedes W17's protected read measure ON DESKTOP ONLY — the
   tokens themselves stay (they are the phone-and-tablet law), which is why the override lives
   at the selector, never at :root. Prose alone keeps its reading measure, and a conversation
   bubble never grows past a readable line. */
@media(min-width:1024px){
  .wrap,.wrap.w-work,.wrap.w-table{max-width:none;padding-left:var(--s6);padding-right:var(--s6)}
  .wrap>p,.wrap>.day-sub{max-width:78ch}
  .bw,.acc-card,.qk-card,.qt-card{max-width:none}
  .bubble{max-width:min(82%,700px)}
}
/* a strip that still lives inside a card (the price grid's inset tabs) rests on the canvas
   tint, never white-on-white */
.card .dtab:not(.on){background:var(--bg)}
/* W23k·2 (VS 2026-08-30, off six crops): the belt/dept strips render as <p class="belt-lanes">,
   so the 78ch PROSE measure was catching them — every chip strip wrapped at ~900px while the
   nav-tag strips (Referral List's .dtabs) filled the line. A strip is navigation, not prose:
   it takes the whole line and wraps only when the line is truly full. Same specificity as the
   prose caps (0,2,1), later in the sheet, so it wins on every measure. */
.wrap>p.belt-lanes{max-width:none}

/* ============ W26 · APPOINTMENT SETTINGS (R-3, the Crelio clone) ============
   One small admin card: three windows, a step, and the resulting grid read back. New component,
   new namespace (aps-) — nothing here touches a pinned family. */
.aps-card{max-width:560px;margin-bottom:var(--s5);padding:var(--s5)}
.aps-table input[type="time"]{padding:6px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit}
.aps-step{display:flex;align-items:center;gap:var(--s4);margin:var(--s5) 0 0}
.aps-step select{padding:6px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit}
.aps-h{margin:0 0 var(--s4);font-size:15px}
.aps-win{margin:var(--s4) 0 var(--s2)}
.aps-chips{display:flex;flex-wrap:wrap;gap:var(--s2);margin:0}

/* ============ W27/W28 · CRELIO SUBMENU — T1 GUIDED TREE (R-5 ruled by VS) ============
   The module fold rows (Appointments / Home Collection), corrected to the ruling off the Six
   Rails board: the parent is a BUTTON at the RAIL'S OWN scale — --rail-t/--rail-row, the 6448
   spec; the first cut shipped --t-ui/34px and sat 1.5px oversized, which VS caught by eye.
   Children ride ONE type-step down on a small dot (the W28 guide line was retired in W30 —
   VS: distracting); every row is single-line, ellipsis + title. Folds persist per
   device and NEVER auto-close a sibling — T3's exclusive-open was REJECTED ("staff keep the
   rails as per their convenience"). The two new tokens live HERE so the pinned 6448 line
   stays byte-stable; comfortable density scales them with the rest of the rail contract. */
:root{--rail-ts:11.5px;--rail-rows:26px}
[data-density="comfortable"]{--rail-ts:12.5px;--rail-rows:36px}
.sp-parent{display:flex;align-items:center;width:100%;border:0;background:transparent;cursor:pointer;
  gap:9px;padding:0 9px;min-height:var(--rail-row);font:inherit;font-size:var(--rail-t);font-weight:500;
  color:#3D4757;border-radius:7px;text-align:left;white-space:nowrap}
.sp-parent:hover{background:rgba(26,45,90,.05);color:var(--navy)}
.sp-parent .ic{width:15px;height:15px;flex:0 0 auto;color:#7A8494}
.sp-parent:hover .ic{color:var(--navy)}
.sp-parent .side-label{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis}
.sp-parent .ng-ch{margin-left:auto}
.sp-group{margin:0}
.sp-group.ng-closed .ng-ch{transform:rotate(-90deg)}
/* W31 (VS 09-06): the GUIDE LINE IS BACK. W30 retired it as distracting; with the rail grown it
   is what keeps a module's children read as one group under their parent ("becoming really very
   confusing to sort it mentally"). W28's form, verbatim: the children indent behind a hairline,
   tight rows, no empty air; the small dot rides the line; the active bar sits ON the line. */
.sp-kids{position:relative;margin-left:16px;padding-left:8px}
.sp-kids::before{content:"";position:absolute;left:0;top:3px;bottom:3px;width:1.5px;background:var(--line);border-radius:2px}
.sp-kids .side-link{padding-left:7px;gap:7px;min-height:var(--rail-rows);font-size:var(--rail-ts);white-space:nowrap}
/* W28b (VS): a SMALL dot rides the line — "a little bit more differentiated... just a small
   dot and a little spacing", no extra air. The house 4px ::after shrinks to 3px in-tree. */
.sp-kids .side-sub::after{width:3px;height:3px;opacity:.35}
.sp-kids .side-link.on::before{left:-9.5px;top:5px;bottom:5px} /* the orange bar sits ON the line */
/* W28b: a fold CLOSED over the lit row lights its parent — the map stays honest while the
   operator keeps absolute control of the fold (the force-open law is deleted, sidebar.js) */
.sp-group.ng-closed .sp-parent[data-active="1"]{background:rgba(26,45,90,.08);color:var(--navy);font-weight:600}
.sp-group.ng-closed .sp-parent[data-active="1"] .ic{color:var(--navy)}
/* icons-only rail: the children and the chevron fold away; the module icon remains the door */
.side-collapsed .sp-kids{display:none}
.side-collapsed .sp-parent{justify-content:center;padding:11px 0;cursor:default;pointer-events:none}
.side-collapsed .sp-parent .ng-ch,.side-collapsed .sp-parent .ng-sum{display:none}
/* ---- W28 · THE DRAG GRIP (R-5 standing fix): the rail's width is the operator's ----
   Drag 184–320px, persisted per device (sidebar.js); double-click returns the 184px default
   the tint-rail pin owns. Desktop only — the collapse and the phone drawer keep their widths. */
#rail-grip{position:absolute;top:0;right:-3px;width:7px;height:100%;cursor:col-resize;z-index:41}
#rail-grip:hover,#rail-grip.dragging{background:linear-gradient(90deg,transparent 2px,rgba(26,45,90,.35) 2px,rgba(26,45,90,.35) 4px,transparent 4px)}
.side-collapsed #rail-grip{display:none}
@media(max-width:820px){#rail-grip{display:none}}
/* the field screens' one toolbar: a date (or range/phlebo) picker riding the head cluster */
.hcp-datebar{display:flex;align-items:center;gap:var(--s2)}
.hcp-datebar input[type="date"],.hcp-datebar select{padding:6px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit;max-width:220px}
/* ---- W31 · PATIENT SEARCH (Crelio's finder, walked 2026-09-04): three labelled fields on
   one row, the button at the end; the register below wears the shared table family. */
.ps-card{padding:var(--s3) var(--s4)}
.ps-form{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--s3)}
.ps-field{display:flex;flex-direction:column;gap:4px;flex:1 1 200px;max-width:320px}
.ps-lbl{font-size:var(--t-tight);color:var(--muted);font-weight:500}
.ps-field input{padding:7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit;width:100%}
.ps-actions{display:flex;gap:var(--s2);align-items:center}
.ps-rows{margin:0;padding:var(--s2) var(--s4);font-size:var(--t-tight);color:var(--muted);border-bottom:1px solid var(--line)}
.ps-table .c-act{white-space:nowrap}
.ps-mono{font-family:var(--f-data,monospace);white-space:nowrap} /* NOT .mono — that is the monogram chip */
/* ---- W33 · REGISTRATION PARITY: the address row spans the grid ---- */
.qk-card .f-span{grid-column:1/-1}
/* ---- W34 · ACCESSION LANE: the scan box on the lane, the reject fold, the urgent chip ---- */
.acc-rcv{display:flex;align-items:center;gap:var(--s2);padding:var(--s2) var(--s4);border-bottom:1px solid var(--line)}
.acc-rcv .ic-i{color:var(--teal);width:16px;height:16px}
.acc-rcv input[type="text"]{padding:6px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit;min-width:240px}
.acc-reject{display:inline-block;vertical-align:top;margin-left:6px}
.acc-reject .kb-cancel{display:flex;gap:6px;margin-top:6px;align-items:center}
.acc-reject .kb-cancel input{padding:5px 8px;border:1px solid var(--line);border-radius:6px;font:inherit;min-width:220px}
.t-urg{background:#FDE7E7;color:#8A2626}
.bh-kebab .kb-cancel{display:flex;gap:6px;padding:4px var(--s3) var(--s2);align-items:center}
.bh-kebab .kb-cancel input{padding:5px 8px;border:1px solid var(--line);border-radius:6px;font:inherit;min-width:160px}
/* ---- W37 · REPORT PRINTS: the tray's summary rides the chip ribbon; Print Done is inline ---- */
.rp-sum{margin-left:auto;font-size:var(--t-tight);color:var(--muted);align-self:center}
.rp-done{display:inline-block;margin-left:6px}
.rp-table .c-act{white-space:nowrap}
/* ---- W32 · BILLING HISTORY (Crelio's register, walked 2026-09-04) ---- */
.bh-tbar{gap:var(--s3);flex-wrap:wrap}
.bh-tabs{padding:0 var(--s4);border-bottom:1px solid var(--line)}
.bh-table td{vertical-align:top}
.bh-table .pl-sub,.adv-table .pl-sub{display:block}
.bh-addendum td:first-child{padding-left:calc(var(--s4) + 14px)}
.bh-st{display:inline-block;padding:1px 8px;border-radius:999px;font-size:var(--t-mini);font-weight:600;background:rgba(26,45,90,.08);color:var(--navy)}
.bh-st-pending{background:#FFF3CD;color:#7A5A00}
.bh-st-paid{background:#E3F5E8;color:#1B6B3A}
.bh-st-cancelled{background:#F3E3E3;color:#8A2626}
.bh-st-draft{background:rgba(26,45,90,.06);color:var(--muted)}
.bh-st-addendum{margin-left:6px;vertical-align:middle}
.bh-kebab .kebab-form{margin:0}
.bh-kebab .kebab-form .kebab-item{width:100%;text-align:left;background:transparent;border:0;font:inherit;cursor:pointer}
.kebab-quiet{opacity:.6}
.adv-form{border-top:1px solid var(--line);padding-top:var(--s3);margin-top:var(--s3)}
.adv-who b{display:block}
.adv-form select{padding:7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit}
.bp-adv{margin-bottom:var(--s3)}
.audit-table td{vertical-align:top}

/* STEP 2 PART 3c: the Account Registration form (views/erp/order-new.ejs) */
.reg-block{border:1px solid var(--line-input);border-radius:8px;padding:10px 14px 14px;margin:0 0 12px}
.reg-block legend{font-weight:600;padding:0 6px}
.reg-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px 16px}
.reg-grid label,.reg-row label{display:flex;flex-direction:column;gap:4px;font-size:var(--t-ui)}
.reg-row{display:flex;flex-wrap:wrap;gap:8px 18px;align-items:center;margin-top:10px}
.reg-row .rr{flex-direction:row;align-items:center;gap:6px}
.reg-row .k{font-weight:600}
