/* ============================================================
   The Car Buyers CRM, v5 BRAND (migrated 2026-08-26).
   The office edition of the brand system: white cards on the
   brand soft, violet hairlines, tinted status pills. The ONLY
   dark chrome left is the sidebar (see the SIDEBAR block, which
   carries its own scoped palette and ignores these tokens). The
   mobile tab bar reads these tokens like every other surface.

   TYPE. Two faces, one job each. --font (Manrope) is every
   proportional surface and inherits from body, so family is
   changed in ONE place, never in the 374 font-size rules.
   --font-display (Schibsted Grotesk) is display roles ONLY and
   never appears below 24px; --font never appears above 22px.
   That 2px gap is what keeps two matched grotesks from blurring
   into each other, so do not invent a lower display floor,
   raise the heading instead.

   MONO is for IDENTIFIERS, not for numbers: rego, VIN, bank and
   reference strings, the age column, where telling 0 from O is
   the point. Figures use tabular Manrope, which body turns on
   once with font-variant-numeric:tabular-nums. Do not add that
   property per rule and do not reach for font-feature-settings,
   the file has one mechanism.

   WEIGHT LADDER, four steps:
     400  body and table cell text
     500  secondary and meta
     600  card titles, buttons, emphasis
     700 / 800  display roles only
   Half of that rule holds today and half does not, so read it as
   the direction of travel, not an invariant the file already has.
   What DOES hold: 400, 500, 600, 700 and 800 are the only weights
   in the CRM and in the four portal stylesheets. Nothing sits at
   650, 550 or 750 any more. Those three used to snap up to the
   next Inter instance the page actually loaded, and Manrope ships
   as a variable face, so on the day the family changed they would
   have started rendering as true 650 / 550 / 750 and sixteen CRM
   surfaces plus twenty five portal ones would have quietly gone
   thinner, money figures and paperwork headings among them. They
   were snapped to the step they already rendered at, which is why
   700 is currently on far more than display roles.
   What does NOT hold: the ROLE half. 170 rules sit at 600 and 139
   at 700 against 5 at 400, so weight is not signalling yet. The
   6h audit that pushes table cell and meta text down to 400 / 500
   and pulls 700 back to display roles has NOT been run. It is a
   whole app visual change and it wants its own pass with browser
   evidence, not a line in a typography chunk.

   UPPERCASE TRACKING, two values on the caps micro label layer:
   .07em at 11px and below, .05em above 11px, nothing else. Five
   surfaces still carry a hair of tracking of their own: the avatar
   initials in .user-row .av, the mobile .tab label, .brandtag.sm,
   .age-exact and .wk-chip. None of the five is uppercase, so they
   are a different job, not a breach of this rule.

   THE ACCENT SPLIT. --accent is brand identity and selection
   (violet, and it is everywhere). --action is the apex, the one
   colour that means "tap me", and it belongs on .btn.primary and
   nothing else on a given viewport. --focus is the ring only.
   Do NOT paint --action onto the 90 var(--accent) sites.
   ============================================================ */
:root{
  --bg:#F6F7FB;            /* page background (the brand soft) */
  --bg-deep:#FAF9FD;       /* nested tint (board tiles, table heads, inputs) */
  --surface:#ffffff;       /* cards / panels */
  --surface-2:#F5F3FA;     /* hover surface */
  --surface-3:#ffffff;     /* elevated (popover — pairs with --shadow-pop) */
  --line:#E6E3F1;          /* hairline border (the brand hair) */
  --line-2:#D6D1E6;        /* stronger divider */
  --text:#070611;          /* primary text (the brand ink), 20.13:1 on white */
  --text-2:#3F3B52;        /* secondary, 10.72:1 */
  --muted:#6A6680;         /* muted (labels, meta), 5.49:1 */
  --faint:#9A96AC;         /* 2.86:1, under AA on every ground, so it is not a
                              text colour. Anything an operator has to read
                              takes --muted, and no new readable label may be
                              given this token. The sweep to enforce that is
                              PARTIAL, not finished: the sites named in the
                              brand migration spec 2b plus the operator
                              critical ones (empty state, cockpit hero field
                              keys, paperwork summary, the Form sub line, the
                              stage sort note, the SLA units in Settings)
                              moved on 2026-08-26. Roughly thirty low traffic
                              sites still read it, each to move as its own
                              chunk touches it. Treat this as a direction of
                              travel, not an invariant the file already holds. */
  --accent:#7424E8;        /* brand violet: identity + selection */
  --action:#0765D2;        /* THE action blue. .btn.primary fill only.
                              5.52:1 both ways, where the brand's #087CFF
                              is 3.93:1 and fails as a 13px fill. */
  --action-2:#0857B4;      /* .btn.primary:hover, white on it is 6.92:1 */
  --focus:#087CFF;         /* the focus ring only (3:1 floor applies):
                              3.93:1 on white, 5.12:1 on the ink sidebar */
  --accent-2:#5417B0;      /* deep violet (links, money), 9.88:1 on white */
  --accent-soft:#F3ECFF;   /* violet tint bg */
  --ok:#0D7A55;            /* green, fine / success, 5.34:1 on white */
  --warn:#9a6310;          /* amber, warning, 5.04:1 on white */
  --bad:#b42323;           /* red, overdue / danger, 6.55:1 on white */
  --ok-bg:#e3f5ee; --warn-bg:#faf1dd; --bad-bg:#fdebeb;
  /* Per-stage hues (board bar, stage chip). ONE violet ramp graded by
     lightness along the pipeline, so violet answers "where in the
     pipeline" and green / amber / red keep "healthy, warning, overdue"
     to themselves. Every step clears 3:1 on the --line bar track.
     The NAMES are load-bearing: five call sites build --st-<stage> by
     string interpolation, and a missing token paints transparent
     instead of throwing. Change values, never names. */
  --st-action:#9764DF; --st-contacted:#8A51DB; --st-inspection_booked:#7D3ED8;
  --st-report_in:#702BD4; --st-offer:#6627C1; --st-pending_paperwork:#5C24AE; --st-outcome:#501F96;
  /* brands (The Car Buyers / EV Car Buyers), see server/brands.py */
  --brand-ev:#6A2BE8;      /* EV Car Buyers, the EV site's own on-light violet */
  --brand-tcb:#5F5E5A;     /* The Car Buyers, the CRM's existing neutral */
  --shadow-card:0 1px 2px rgba(7,6,17,.10),0 6px 20px rgba(7,6,17,.06);
  --shadow-pop:0 2px 6px rgba(7,6,17,.14),0 24px 64px rgba(7,6,17,.30);
  --fast:.16s ease-out;    /* state changes: hover, colour, opacity */
  --move:.28s cubic-bezier(.2,.7,.2,1); /* things that travel: drawers, the rail */
  --font:'Manrope','Manrope Fallback',-apple-system,'Helvetica Neue',Arial,sans-serif;
  --font-display:'Schibsted Grotesk','Manrope',-apple-system,'Helvetica Neue',Arial,sans-serif;
  --mono:'JetBrains Mono',ui-monospace,monospace;
  --radius:14px;           /* cards */  --radius-sm:12px; /* controls */
  /* --radius-xs is a deliberate step off the brand ladder: an operator
     control is roughly half a marketing page's, and a 22px tall rego
     plate at 12px reads as a lozenge. Four users, no more:
     .btn.sm, .rego, .user-out and the avatar tile .user-row .av,
     which sits beside .user-out and has to match it. */
  --radius-xs:8px;
  /* Sidebar geometry. The rail values are today's tablet values exactly, so
     the 48px nav target survives the change. ONE definition, read by the
     sidebar block, by the rail block and by .nav-item.on::before, which is
     what stops the active marker drifting off the edge the next time a
     width moves. */
  --sb-w:248px;  --sb-w-rail:64px;
  --sb-pad:12px; --sb-pad-rail:8px;
}
/* The collapsed rail. js/shell.js sets this class before first paint and
   setRail() in js/app.js owns it after that. */
html.rail:not(.peek){--sb-w:var(--sb-w-rail);--sb-pad:var(--sb-pad-rail)}

/* ---- the peeking rail ----------------------------------------------------
   Resting state is the 64px rail. Hovering it floats the full panel out OVER
   the page, the way Eclipse, VS Code, Linear and Gmail all do it, and the
   toggle now pins it open rather than being the only way in.

   The sidebar is taken out of flow the moment the rail is on, and #view
   carries the 64px gutter instead. That is the whole trick: widening a fixed
   element cannot reflow anything, so a fifty row queue does not move a pixel
   while the labels slide over it.

   Hover only, and only where hover is real. On a touch screen there is no
   pointer to leave, so a panel that opened on tap would have no way to close
   without stealing a tap from the nav row underneath. */
html.rail .sidebar{position:fixed;top:0;left:0;bottom:0;height:100vh;z-index:60;
  transition:width var(--move)}
html.rail #view{margin-left:var(--sb-w-rail)}
html.rail.peek .sidebar{box-shadow:0 24px 64px -12px rgba(7,6,17,.55)}
@media(prefers-reduced-motion:reduce){html.rail .sidebar{transition:none}}
@media(hover:none){html.rail.peek .sidebar{width:var(--sb-w-rail)}}
/* Metric matched fallback for the swap window. display=swap means the
   operator reads the fallback on every cold load, and a queue of fifty rows
   must not jump when Manrope lands under a cursor already moving to a row.
   src names Helvetica Neue and Arial so the fallback is never San Francisco,
   whose advance runs 6.3% narrower than Manrope. Measured in Chrome against
   Manrope at 13px: size-adjust 99% is the minimum mean advance error over a
   corpus of real queue strings, and the two overrides reproduce Manrope's
   ascent and descent exactly (426 / 120 at 400px). Re measure if the body
   face ever changes. */
@font-face{
  font-family:'Manrope Fallback';
  src:local('Helvetica Neue'),local('Arial');
  size-adjust:99%;
  ascent-override:107.6%;
  descent-override:30.3%;
  line-gap-override:0%;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{font-family:var(--font);background:var(--bg);color:var(--text);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-size:14px;line-height:1.5;
  font-variant-numeric:tabular-nums}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer;color:inherit}
input,select,textarea{font-family:inherit;font-size:inherit;color:inherit;outline:none}
.mono,.num{font-family:var(--mono)}
.muted{color:var(--muted)} .sp{flex:1}
.ic{width:18px;height:18px;flex:none;stroke:currentColor;stroke-width:1.85;fill:none;
  stroke-linecap:round;stroke-linejoin:round;display:inline-block;vertical-align:middle}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:#CFCBDD;border-radius:8px;border:2px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:#BAB5CC}
::-webkit-scrollbar-track{background:transparent}
::selection{background:color-mix(in srgb,var(--accent) 22%,transparent)}
::placeholder{color:var(--faint)}
@keyframes riseIn{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){*{animation-duration:.01ms!important}}

/* ============================================================ APP SHELL */
#app{display:flex;height:100vh;overflow:hidden}
#view{flex:1;min-width:0;overflow:auto;height:100vh;background:var(--bg);
  /* The gutter is kept whether or not the page scrolls. Without it a queue
     long enough to scroll was 10px narrower than a short one, so the same
     rows took one layout on one tab and the other on the next (stg-rows,
     under STAGE PAGE). A browser that draws its scrollbars over the page
     reserves nothing. */
  scrollbar-gutter:stable}
/* auth (login) hides the shell chrome and keeps the CRM's dark theme. The
   phone rules below still read `body:not(.portal)`: that negation is always
   true now that nothing can set the class, and it is left alone because
   dropping a :not() lowers a live rule's specificity, which is a change to
   the cascade rather than a deletion. */
body.auth #app{display:block;height:auto}
body.auth #view{height:auto;overflow:visible}
body.auth .sidebar{display:none}

/* ============================================================ SIDEBAR
   The one piece of dark chrome (matches the wholesaler page's dark header).
   Self-contained palette, deliberately does NOT use the light tokens.

   The palette below is SCOPED, not :root, so no other surface inherits these
   dark values by accident. .rail-tip shares the selector
   because the tooltip is appended to document.body (the sidebar clips its own
   overflow), so it sits OUTSIDE .sidebar and would otherwise inherit nothing.
   Contrast measured against the ink ground. */
.sidebar,.rail-tip{
  --sb-ink:#070611;                    /* the brand ink */
  --sb-tx:#F6F7FB;                     /* 18.8:1 on ink */
  --sb-idle:#C3C0D0;                   /* idle nav row text, 11.28:1 */
  --sb-tx-2:#9B98AC;                   /* secondary, 7.17:1 */
  --sb-cap:#8E8AA0;                    /* group caption, 6.03:1 */
  --sb-hair:rgba(246,247,251,.14);     /* the kit's hairline on ink */
  --sb-fill:rgba(246,247,251,.06);
  --sb-fill-2:rgba(246,247,251,.10);
  --sb-on:rgba(116,36,232,.34);        /* active row ground */
  --sb-rail:#A97FFF;                   /* active marker, 6.87:1 on ink */
}
.sidebar{width:var(--sb-w);flex:none;height:100vh;background:var(--sb-ink);
  border-right:1px solid var(--sb-hair);
  display:flex;flex-direction:column;padding:14px var(--sb-pad) 12px;
  overflow-y:auto;overflow-x:hidden;color:var(--sb-tx)}
/* Brand row. Both marks stay in the DOM with one display:none, which still
   fetches, so the first collapse is instant with no flash. Do NOT swap them
   with content:url(): that carries no intrinsic size and the row would
   reflow on every toggle. */
.sidebar .brand{display:flex;align-items:center;gap:11px;padding:4px 8px 14px}
.sidebar .brand .mark{height:26px;width:auto;display:block}
.sidebar .brand .mark-sm{height:24px;width:auto;display:none}
html.rail:not(.peek) .sidebar .brand .mark{display:none}
html.rail:not(.peek) .sidebar .brand .mark-sm{display:block}

/* the collapse toggle. A real button: Enter, Space and the focus ring for
   free. Always visible, because an all day tool should not hide its own
   chrome behind hover, and overflow-x:hidden above would clip anything
   overlapping the sidebar edge anyway. */
.rail-t{margin-left:auto;width:30px;height:30px;flex:none;display:flex;align-items:center;
  justify-content:center;border:1px solid var(--sb-hair);border-radius:9px;
  background:transparent;color:var(--sb-tx-2);
  transition:color var(--fast),border-color var(--fast),background var(--fast)}
.rail-t:hover{color:var(--sb-tx);border-color:var(--sb-fill-2);background:var(--sb-fill)}
/* the chevron points the way the panel travels: left to collapse, right to expand */
.rail-t .ic{width:16px;height:16px;transform:rotate(180deg);
  transition:transform var(--move)}

/* group caption */
.nav-cap{font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--sb-cap);
  padding:14px 10px 6px}
.nav-div{height:1px;background:var(--sb-fill);margin:8px 6px}
.sidebar .foot{margin-top:auto}

/* nav item */
.nav-item{display:flex;align-items:center;gap:11px;height:40px;padding:0 10px;border-radius:10px;
  color:var(--sb-idle);font-size:13.5px;font-weight:500;position:relative;
  transition:background var(--fast),color var(--fast)}
.nav-item:hover{background:var(--sb-fill);color:var(--sb-tx)}
.nav-item .ic{width:18px;height:18px;flex:none;opacity:.85}
.nav-item .lb{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nav-item.on{background:var(--sb-on);color:var(--sb-tx)}
.nav-item.on .ic{opacity:1}
/* The marker reads the SAME token the sidebar padding does, so it is flush
   against the edge in both states by construction. Pinned at a literal -12px
   it sat 4px inside the rail's padding box and overflow-x:hidden ate it,
   which is why the icon rail has never shown an active state. */
.nav-item.on::before{content:"";position:absolute;left:calc(var(--sb-pad) * -1);
  top:9px;bottom:9px;width:3px;border-radius:3px;background:var(--sb-rail)}
/* count pill on a nav row */
.nav-item .pill-n{min-width:20px;height:19px;padding:0 6px;border-radius:999px;font-family:var(--mono);
  font-size:11px;font-weight:600;display:inline-flex;align-items:center;justify-content:center;
  background:var(--sb-fill);color:var(--sb-tx-2);border:1px solid transparent}
.nav-item.on .pill-n{background:var(--sb-fill-2);color:var(--sb-tx)}
.nav-item .pill-n.bad{background:rgba(180,35,35,.45);color:#ffb4b4;border-color:transparent}
.nav-item .pill-n.zero{opacity:.45}

/* command center hero item */
.nav-cc{display:flex;align-items:center;gap:12px;padding:11px;border-radius:12px;position:relative;
  background:var(--sb-fill);border:1px solid var(--sb-hair);color:var(--sb-tx);margin-bottom:2px}
.nav-cc:hover{background:var(--sb-fill-2);border-color:var(--sb-hair)}
.nav-cc.on{background:var(--sb-on);border-color:color-mix(in srgb,var(--sb-rail) 50%,transparent)}
.nav-cc .cc-ic{width:34px;height:34px;flex:none;border-radius:10px;background:var(--accent);
  color:var(--sb-tx);display:flex;align-items:center;justify-content:center}
.nav-cc .cc-ic .ic{width:18px;height:18px;stroke-width:2}
.nav-cc.on .cc-ic{background:var(--sb-tx);color:var(--accent)}
.nav-cc .cc-t{flex:1;min-width:0}
.nav-cc .cc-t b{display:block;font-size:13.5px;font-weight:600;line-height:1.2}
.nav-cc .cc-t span{display:block;font-size:11px;color:var(--sb-tx-2);margin-top:1px}
.nav-cc .cc-n{min-width:22px;height:22px;padding:0 7px;border-radius:999px;font-family:var(--mono);
  font-size:11.5px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;
  background:var(--bad);color:var(--sb-tx)}
.nav-cc .cc-n.zero{background:var(--sb-fill);color:var(--sb-tx-2)}

/* user row */
.user-row{display:flex;align-items:center;gap:10px;padding:9px 8px;margin-top:6px;border-radius:10px}
.user-row .av{width:32px;height:32px;flex:none;border-radius:var(--radius-xs);background:var(--sb-fill-2);color:var(--sb-tx);
  display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;letter-spacing:.02em}
.user-row .un{font-size:13px;font-weight:600;line-height:1.2;color:var(--sb-tx)}
.user-row .ur{font-size:11px;color:var(--sb-tx-2);display:flex;align-items:center;gap:5px}
.user-row .ur .od{width:6px;height:6px;border-radius:50%;background:var(--ok);
  box-shadow:0 0 0 2px color-mix(in srgb,var(--ok) 25%,transparent)}
.user-row .user-id{flex:1;min-width:0}
.user-out{flex:none;width:30px;height:30px;display:flex;align-items:center;justify-content:center;
  border:1px solid var(--sb-hair);border-radius:var(--radius-xs);background:transparent;color:var(--sb-tx-2);cursor:pointer}
.user-out:hover{color:var(--sb-tx);border-color:var(--sb-fill-2);background:var(--sb-fill)}
.user-out .ic{width:16px;height:16px}

/* ---------------- RAIL. One definition. js/shell.js and setRail own the class.
   Row height stays 40px in both states: changing height mid transition makes
   the whole column jump. --------------------------------------------------- */
html.rail:not(.peek) .sidebar .brand{flex-direction:column;gap:9px;padding:2px 0 12px}
html.rail:not(.peek) .rail-t{margin-left:0;width:48px;height:28px;border-radius:8px}
html.rail:not(.peek) .rail-t .ic{transform:none}

/* group captions become the hairline they always meant */
html.rail:not(.peek) .nav-cap{height:1px;padding:0;margin:12px 8px;font-size:0;line-height:0;
  color:transparent;background:var(--sb-hair);border-radius:1px}
html.rail:not(.peek) .nav-div{margin:8px 8px}

html.rail:not(.peek) .nav-item{width:48px;margin:0 auto;padding:0;justify-content:center;gap:0}
html.rail:not(.peek) .nav-item .lb{display:none}

/* counts ride the GLYPH's top right corner, not the row's, so the number reads
   as belonging to its icon on rows that have no active background. The icon is
   18px centred in the 48px content box, so top:4px right:6px overlaps its
   corner. That right edge lands at x=50 inside a 64px rail, well clear of
   overflow-x:hidden. Ringed so it reads on the ink ground. */
html.rail:not(.peek) .nav-item .pill-n{position:absolute;top:4px;right:6px;min-width:16px;height:16px;
  padding:0 4px;font-size:9.5px;font-weight:700;border-radius:999px;
  box-shadow:0 0 0 2px var(--sb-ink)}
html.rail:not(.peek) .nav-item .pill-n.zero{display:none}

/* Command Center: the violet tile alone, no outer chrome */
html.rail:not(.peek) .nav-cc{position:relative;width:48px;margin:0 auto 4px;padding:0;
  justify-content:center;background:transparent;border-color:transparent}
html.rail:not(.peek) .nav-cc:hover,html.rail:not(.peek) .nav-cc.on{background:transparent;border-color:transparent}
html.rail:not(.peek) .nav-cc .cc-t{display:none}
html.rail:not(.peek) .nav-cc .cc-ic{width:44px;height:44px;border-radius:12px}
html.rail:not(.peek) .nav-cc .cc-n{position:absolute;top:-2px;right:-2px;min-width:16px;height:16px;
  padding:0 4px;font-size:9.5px;box-shadow:0 0 0 2px var(--sb-ink)}
html.rail:not(.peek) .nav-cc .cc-n.zero{display:none}

/* identity: avatar over sign out, the name moves into the tooltip */
html.rail:not(.peek) .user-row{flex-direction:column;gap:8px;padding:9px 0}
html.rail:not(.peek) .user-row .user-id{display:none}

/* Motion: width and nothing else. Labels are display:none in the rail, which
   cannot be transitioned, and fading them while the column reflows reads as
   lag. Gating on sb-anim means no animation on first paint and none on a
   resize crossing the breakpoint, only on a deliberate toggle, and
   will-change lives only for the 320ms the class is set rather than keeping
   a compositor layer alive for the session.
   The global reduced motion rule only zeroes animation-duration and never
   touches transitions, which is why this needs its own guard, placed below
   the tooltip rules so source order and specificity both land its way. */
html.sb-anim .sidebar{transition:width var(--move);will-change:width}

/* Rail tooltip. Lives on document.body, not in the sidebar, because
   overflow-x:hidden clips anything drawn inside the rail. Decoration only,
   aria-hidden: the accessible name comes from the row's aria-label.
   z-index 70 sits above the mobile tab bar at 60 and below pop menus and
   toasts at 80, so a tip can never cover a menu opened on purpose. */
.rail-tip{position:fixed;z-index:70;display:flex;align-items:center;gap:8px;max-width:220px;
  padding:7px 10px;border-radius:10px;background:#1C1A2B;color:var(--sb-tx);font-size:12.5px;
  font-weight:600;white-space:nowrap;border:1px solid var(--sb-hair);
  box-shadow:var(--shadow-pop);
  opacity:0;transform:translateX(-4px);pointer-events:none;
  transition:opacity var(--fast),transform var(--fast)}
.rail-tip.in{opacity:1;transform:none}
.rail-tip .n{font-family:var(--mono);font-size:11.5px;font-weight:600;color:var(--sb-tx-2)}
/* the user row is the one tip that carries two lines, name over role */
.rail-tip.two{flex-direction:column;align-items:flex-start;gap:1px;white-space:normal}
.rail-tip.two .n{font-family:var(--font);font-size:11px}

/* Reduced motion. This block must sit AFTER every rule it cancels and must
   match their specificity: html.sb-anim .sidebar is (0,2,1) and a bare
   .sidebar here would lose to it, while a .rail-tip written above the
   .rail-tip transition would lose on source order. Both were true before. */
@media(prefers-reduced-motion:reduce){
  html.sb-anim .sidebar,.rail-t .ic,.rail-tip{transition:none}}

/* ============================================================ MOBILE TAB BAR
   Hidden on desktop; shown only at ≤640px (see RESPONSIVE block).
   Painted with the light tokens, not the sidebar's dark palette: the bar
   sits on the page, and the last dark values left the selected label white
   on a white bar, unreadable on every phone. */
.tabbar{display:none}
.tab{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  height:100%;color:var(--muted);font-size:11px;font-weight:600;letter-spacing:.01em;position:relative}
/* count badge riding the tab icon (Home = overdue red, Pipeline = unseen new) */
.tab-b{position:absolute;top:5px;left:calc(50% + 4px);min-width:17px;height:17px;padding:0 5px;
  border-radius:999px;font-family:var(--mono);font-size:10.5px;font-weight:700;line-height:17px;
  text-align:center;background:var(--accent);color:#fff;pointer-events:none}
.tab-b.bad{background:var(--bad);color:#fff}
.tab .ic{width:21px;height:21px;opacity:.85}
.tab span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.tab.on{color:var(--text)}
.tab.on span{color:var(--text);font-weight:700}
.tab.on .ic{opacity:1;color:var(--accent)}

/* ============================================================ BUTTONS */
/* Labels never wrap (nowrap), so without a ceiling a long one would burst
   out of its card. Cap the width and clip instead: a button always stays
   inside the thing that contains it. Keep labels short enough not to clip. */
.btn{display:inline-flex;align-items:center;gap:8px;font-size:13px;font-weight:600;padding:9px 14px;
  border-radius:var(--radius-sm);border:1px solid var(--line-2);background:transparent;color:var(--text);
  white-space:nowrap;max-width:100%;overflow:hidden;
  transition:background var(--fast),border-color var(--fast),color var(--fast)}
.btn:hover{background:var(--surface-2);border-color:var(--line-2)}
.btn .ic{width:16px;height:16px}
.btn.primary{background:var(--action);border-color:var(--action);color:#fff}
.btn.primary:hover{background:var(--action-2);border-color:var(--action-2)}
.btn.soft{background:var(--accent-soft);border-color:transparent;color:var(--accent-2)}
.btn.soft:hover{background:color-mix(in srgb,var(--accent) 14%,var(--accent-soft))}
.btn.ghost{border-color:transparent;background:transparent;color:var(--muted)}
.btn.ghost:hover{background:var(--surface-2);color:var(--text)}
.btn.ok{background:var(--ok);border-color:var(--ok);color:#fff}
.btn.ok:hover{filter:brightness(1.07)}
.btn.danger{border-color:transparent;background:var(--bad-bg);color:var(--bad)}
.btn.danger:hover{background:var(--bad);color:#fff}
/* a destructive PRIMARY (Mark lost, the danger confirms): the apex button
   in the colour of what it does, so nobody reads it as the blue "go on".
   White on --bad is 6.55:1. Disabled falls back to the house disabled look,
   which the three class specificity would otherwise override. */
.btn.primary.cf-danger{background:var(--bad);border-color:var(--bad)}
.btn.primary.cf-danger:hover{background:color-mix(in srgb,var(--bad) 85%,black);border-color:color-mix(in srgb,var(--bad) 85%,black)}
.btn.primary.cf-danger:disabled{background:transparent;border-color:var(--line);color:var(--faint)}
.btn.sm{padding:6px 10px;font-size:12px;border-radius:var(--radius-xs)}
.btn.disabled,.btn:disabled{color:var(--faint);background:transparent;border-color:var(--line);cursor:not-allowed}
.iconbtn{width:34px;height:34px;border:1px solid var(--line-2);background:transparent;border-radius:var(--radius-sm);
  display:inline-flex;align-items:center;justify-content:center;color:var(--muted);
  transition:background var(--fast),color var(--fast)}
.iconbtn:hover{background:var(--surface-2);color:var(--text)}
.iconbtn.danger:hover{background:var(--bad-bg);color:var(--bad)}
.iconbtn .ic{width:18px;height:18px}

/* keyboard focus ring. One geometry, 2px outside the control, so the ring
   follows each control's own radius and a focused pill stays a pill.
   [contenteditable] is the template composer, which no element selector
   reaches. */
a:focus-visible,button:focus-visible,[data-action]:focus-visible,[tabindex]:focus-visible,
[contenteditable]:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{
  outline:2px solid var(--focus);outline-offset:2px}

/* ============================================================ CHIPS / PILLS */
/* SLA age chip — mono, status-tinted */
.age{display:inline-flex;align-items:center;gap:5px;font-family:var(--mono);font-size:11.5px;font-weight:600;
  padding:3px 8px;border-radius:7px;white-space:nowrap}
.age .ic{width:12px;height:12px}
.age.ok{color:var(--ok);background:var(--ok-bg)}
.age.warn{color:var(--warn);background:var(--warn-bg)}
.age.crit{color:var(--bad);background:var(--bad-bg)}
/* stage chip: glyph and label */
.stage-chip{display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:600;color:var(--text-2);
  background:var(--surface-2);border:1px solid var(--line);padding:4px 10px;border-radius:999px;white-space:nowrap}
.stage-chip .ic{width:13px;height:13px;flex:none;color:var(--muted);opacity:.9}
/* the sub stage, a second cell beside the stage on the car's page: New, No
   answer, Follow up, Post follow up, and Contacted's two. The same pill, with
   the fill taken out, so the pair reads as one fact qualified rather than as
   two chips competing for the eye. */
.stage-chip.sub{background:transparent;color:var(--muted)}
/* generic pill / badge */
.pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:4px 10px;border-radius:999px;
  background:var(--surface-2);color:var(--text-2);border:1px solid var(--line)}
.pill .dot{width:7px;height:7px;border-radius:50%;flex:none}
.pill.bad{background:var(--bad-bg);color:var(--bad);border-color:transparent}
.pill.warn{background:var(--warn-bg);color:var(--warn);border-color:transparent}
.pill.ok{background:var(--ok-bg);color:var(--ok);border-color:transparent}
.pill.accent{background:var(--accent-soft);color:var(--accent-2);border-color:transparent}
/* source dot + label */
.src{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:500;color:var(--muted)}
.src .dot{width:6px;height:6px;border-radius:50%;flex:none}
/* brand tag (The Car Buyers / EV Car Buyers). Shares .src geometry so it sits
   naturally beside the source chip; never named .brand (sidebar logo owns it). */
.brandtag{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;
  color:var(--text-2);background:var(--surface-2);border:1px solid var(--line);
  border-radius:999px;padding:2px 8px;white-space:nowrap}
.brandtag .dot{width:6px;height:6px;border-radius:50%;flex:none;background:var(--brand-tcb)}
/* SOLID, not a tint. Every hue near this row is already purple (the accent,
   the unseen rail, the NEW badge), so the EV mark separates by value rather
   than hue: on a fifty row mixed list a pale lavender EV pill and the pale
   lavender NEW badge sitting one line apart read as the same thing. White on
   #6A2BE8 measures 6.7:1. */
.brandtag.ev{color:#fff;background:var(--brand-ev);border-color:transparent}
.brandtag.ev .dot{background:rgba(255,255,255,.9)}
.brandtag.sm{font-size:11px;font-weight:700;letter-spacing:.04em;padding:1px 6px;gap:4px}
/* rego tag */
.rego{display:inline-flex;align-items:center;font-family:var(--mono);font-weight:600;font-size:12px;letter-spacing:.05em;
  background:var(--surface-2);border:1px solid var(--line-2);border-radius:var(--radius-xs);padding:3px 8px;color:var(--text)}
.rego.empty,.rego.none{color:var(--faint);letter-spacing:0;font-weight:500}
.verified-km{display:inline-flex;align-items:center;gap:4px;font-size:11.5px;font-weight:600;color:var(--ok)}
.verified-km .ic{width:13px;height:13px;stroke-width:2.2}

/* ============================================================ CARDS / PANELS */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:16px}
.panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius)}
.panel-h{display:flex;align-items:baseline;gap:10px;padding:15px 18px;border-bottom:1px solid var(--line)}
.panel-h h3{font-size:14px;font-weight:600;letter-spacing:-.01em}
.panel-h .sub{font-size:12px;color:var(--muted)}
.panel-b{padding:16px 18px}
.cap{font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}

/* ============================================================ PAGE SCAFFOLD */
.page{padding:24px 28px}
.page-h{display:flex;align-items:flex-start;gap:16px;margin-bottom:22px}
.page-h h1{font-family:var(--font-display);font-size:24px;font-weight:700;letter-spacing:-.01em;line-height:1.15}
.page-h .sub{font-size:13.5px;color:var(--muted);margin-top:4px}
.page-h .right{margin-left:auto;display:flex;align-items:center;gap:10px;flex-wrap:wrap;row-gap:8px;justify-content:flex-end}
.empty{padding:54px 24px;text-align:center;color:var(--muted);font-size:13.5px}
.empty b{display:block;color:var(--text-2);font-size:15px;font-weight:600;margin-bottom:5px}

/* search box */
.searchbox{position:relative}
.searchbox .ic{position:absolute;left:11px;top:50%;transform:translateY(-50%);width:15px;height:15px;color:var(--faint)}
.searchbox input{height:38px;width:240px;border:1px solid var(--line-2);background:var(--surface);border-radius:var(--radius-sm);
  padding:0 12px 0 34px;font-size:13px;color:var(--text)}
.searchbox input:focus{border-color:var(--accent)}

/* ============================================================ SEGMENTED CONTROL */
.seg{display:inline-flex;background:var(--surface);border:1px solid var(--line-2);border-radius:var(--radius-sm);padding:3px;gap:2px}
.seg button{border:none;background:transparent;padding:6px 13px;font-size:12.5px;font-weight:600;color:var(--muted);border-radius:7px;white-space:nowrap;
  transition:color var(--fast),background var(--fast)}
.seg button:hover{color:var(--text)}
.seg button.on{background:var(--accent);color:#fff}
.seg button.on.ok{background:var(--ok-bg);color:var(--ok)}
.seg button.on.warn{background:var(--warn-bg);color:var(--warn)}
.seg button.on.bad{background:var(--bad-bg);color:var(--bad)}

/* ============================================================ TABLE / LIST */
/* overflow-x:auto at EVERY width, not just on phones: between 641px and the
   desktop layout these tables were `overflow:hidden`, so columns wider than
   the panel were clipped with no way to scroll to them. Wide screens still
   show no scrollbar because the table fits. */
.tablewrap{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;overflow-x:auto}
table.grid{width:100%;border-collapse:collapse}
table.grid thead th{text-align:left;font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);padding:12px 16px;border-bottom:1px solid var(--line);white-space:nowrap;background:var(--bg-deep)}
table.grid thead th.num{text-align:right}
table.grid tbody td{padding:14px 16px;border-bottom:1px solid var(--line);font-size:13px;vertical-align:middle}
table.grid tbody td.num{text-align:right;font-family:var(--mono)}
table.grid tbody tr{cursor:pointer;position:relative;transition:background var(--fast)}
table.grid tbody tr:last-child td{border-bottom:none}
table.grid tbody tr:hover{background:var(--surface-2)}
table.grid tbody tr.sel{background:var(--accent-soft)}
table.grid tbody tr.sel td:first-child{box-shadow:inset 3px 0 0 var(--accent)}
.veh{font-weight:600;color:var(--text);display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.veh .sub{width:100%;font-weight:400;color:var(--muted);font-size:11.5px;margin-top:1px;display:flex;align-items:center;gap:8px}
.cust{font-weight:500;color:var(--text);white-space:nowrap;max-width:190px;overflow:hidden;text-overflow:ellipsis}
.cust .sub{font-weight:400;color:var(--muted);font-size:11.5px;margin-top:1px;overflow:hidden;text-overflow:ellipsis}
td.ph{white-space:nowrap}
.price-rng{font-family:var(--mono);font-weight:600;color:var(--accent-2)}
/* the seller's own asking price (New leads). Mono and right aligned with the
   other figures through .num, tabular so a column of them compares straight
   down, and one line so a narrow screen scrolls the table rather than growing
   the row. Deliberately NOT .price-rng: that purple says "our number". */
td.ask,th.ask{white-space:nowrap}

/* pager (queues run in pages of 50) */
.pager{display:flex;align-items:center;gap:10px;padding:12px 16px;border-top:1px solid var(--line);
  color:var(--muted);font-size:12.5px}
.pager .pg{margin-left:auto;display:flex;gap:5px;align-items:center}

/* New leads comes from the database a page at a time, so its rows arrive after
   the chrome does. The skeleton holds the layout for that gap, and aria-busy
   dims the rows already on screen while a search or a Load more is in flight,
   rather than collapsing them back to a skeleton and flashing the list. */
.sk-row td{padding:11px 14px}
.sk-bar{display:block;height:11px;border-radius:6px;background:var(--surface-2);
  animation:sk-pulse 1.2s ease-in-out infinite}
.sk-row:nth-child(2n) .sk-bar{width:78%}
.sk-row:nth-child(3n) .sk-bar{width:62%}
@keyframes sk-pulse{0%,100%{opacity:.45}50%{opacity:.9}}
@media (prefers-reduced-motion:reduce){.sk-bar{animation:none;opacity:.6}}
/* The lead list on its way, for a screen that cannot draw a row without it.
   Same bars, because waiting should look the same wherever it happens, and
   widths that vary so it reads as content arriving rather than a progress
   bar that never moves. */
/* a home screen list on its way: the rows it is about to be, so the panel
   keeps its height and nothing under it jumps when they land */
.cc-wait{padding:14px 16px}
.cc-wait .sk-bar{margin:0 0 14px;height:14px}
.cc-wait .sk-bar:last-child{margin-bottom:0}
#cc-focus-list[aria-busy="true"]{opacity:.55;transition:opacity var(--fast)}
.ld-wait{padding:20px 18px}
.ld-wait .sk-bar{margin:0 0 15px}
.ld-wait .sk-bar:last-child{margin-bottom:0}
.ld-wait .sk-bar:nth-child(3n+2){width:78%}
.ld-wait .sk-bar:nth-child(3n){width:62%}
#stg-live[aria-busy="true"]{opacity:.55;transition:opacity var(--fast)}
#stg-live[aria-busy="true"] .pager .btn{pointer-events:none}
/* The Load more button while its page is in flight. It is read, not pressed,
   so it takes the readable muted rather than the faint the disabled style
   gives controls that are out of play (2.68:1, which is fine for a control
   nobody is meant to read). */
.pager .btn[aria-busy="true"]{color:var(--muted)}
td.act{text-align:right;white-space:nowrap}
td.act .btn,td.act .iconbtn{vertical-align:middle}
td.act .iconbtn{margin-left:6px}
/* The queue's row actions stay reachable. Every cell is nowrap and the wrap
   scrolls sideways by design, so on a 1440 laptop with the sidebar open New
   leads runs about 180px past its wrap and Open, Call, Contacted and Lost
   sat past the right edge until the row was scrolled. Above the phone
   break the actions cell pins to that edge and the facts scroll under it.
   Opaque on purpose, with the row's own tints repeated: a see through
   sticky cell shows the phone number sliding beneath the buttons. */
@media (min-width:761px){
  #stg-live table.grid td.act,#stg-live table.grid th.act{position:sticky;right:0;z-index:1}
  #stg-live table.grid td.act{background:var(--surface)}
  #stg-live table.grid tbody tr:hover td.act{background:var(--surface-2)}
  /* the same 5% violet tr.unseen paints, mixed to an opaque colour */
  #stg-live table.grid tr.unseen td.act{background:color-mix(in srgb,#6e6cf2 5%,var(--surface))}
  #stg-live table.grid tr.unseen:hover td.act{background:var(--surface-2)}
  /* the seam where the facts slide under */
  #stg-live table.grid td.act::before{content:'';position:absolute;left:0;top:0;bottom:0;width:1px;background:var(--line)}
}
/* The pin is for a screen narrower than the row, not for a laptop. At 1440
   with the sidebar open and at 1280 on the rail every New leads and
   Contacted view fits its wrap, so nothing sits under the pinned buttons.
   It takes this, the Age cell on two lines and the missed call clock on
   three (.age-col, .sq-top), and on a wide enough wrap the Vehicle cell
   giving way and the Seller asks heading taking two lines (stg-rows, under
   STAGE PAGE). 16px a side still ran the Follow up view past its wrap; 10px
   still leaves the facts their air, and the rows keep their 14px above and
   below. Fitting a full row is not free, and stg-rows says what it costs. */
#stg-live table.grid thead th,#stg-live table.grid tbody td{padding-left:10px;padding-right:10px}
/* New leads' row actions on one line: Call, Contacted, and Lost as an icon.
   The row itself opens the car, so there is no Open. Two by two with Open
   the buttons set the row's height, 100px against the 44 the facts need,
   and a laptop showed five sellers where eight fit. nowrap so the line never
   folds back into two rows under a squeeze. */
.act-line{display:inline-flex;gap:6px;align-items:center;white-space:nowrap;vertical-align:middle}
/* .btn caps itself at 100% of its container and clips. Inside a shrink to
   fit box that percentage is cyclic, and every button clipped its own label
   to "Contac". Uncapped here; the line's own width is the limit instead. */
.act-line .btn{max-width:none;flex:none}
.act-line .iconbtn{margin:0;flex:none}
/* A call outcome being recorded (_flow.js callWaiting): the first No answer
   texts the seller inside the request, so the Call control pulses and its row
   dims until the reply lands. */
.btn[aria-busy="true"]{cursor:progress;animation:ck-walk-wait .9s ease-in-out infinite}
table.grid tbody tr[aria-busy="true"] td{opacity:.6;transition:opacity var(--fast)}
@media (prefers-reduced-motion:reduce){
  .btn[aria-busy="true"]{animation:none;opacity:.5}
}

/* ============================================================ MODAL & TOAST */
.modal-back{position:fixed;inset:0;background:rgba(16,24,40,.45);backdrop-filter:blur(2px);
  display:flex;align-items:center;justify-content:center;z-index:60;padding:20px}
.modal{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);width:100%;max-width:460px;
  box-shadow:var(--shadow-pop);max-height:88vh;overflow:auto;animation:riseIn .16s ease}
.modal.wide{max-width:600px}
.modal-h{display:flex;align-items:center;justify-content:space-between;padding:17px 19px;border-bottom:1px solid var(--line)}
.modal-h h3{font-size:16px;font-weight:600}
.modal-b{padding:19px}
.modal-f{display:flex;justify-content:flex-end;gap:10px;padding:15px 19px;border-top:1px solid var(--line)}
label.fld{display:block;margin-bottom:14px}
label.fld .lab{display:block;font-size:11.5px;font-weight:600;color:var(--muted);margin-bottom:6px}
.input,.select,textarea.input{width:100%;height:38px;border:1px solid var(--line-2);background:var(--bg-deep);border-radius:var(--radius-sm);
  padding:0 12px;font-size:13.5px;color:var(--text)}
textarea.input{height:auto;padding:9px 12px;resize:vertical;min-height:64px;line-height:1.5}
.input:focus,.select:focus,textarea.input:focus{border-color:var(--accent)}
.select{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%236A6680' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 11px center;padding-right:32px}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:0 14px}
/* A box placed at left:50% is only offered the right half of the screen, so
   with no width of its own a toast of two sentences wrapped a word a line on
   a phone. It takes its text's width now, up to a readable line or the
   screen less a margin, whichever is narrower. */
#toast-root{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);z-index:80;display:flex;flex-direction:column;gap:8px;align-items:center;
  width:max-content;max-width:min(720px,calc(100vw - 24px))}
/* ============================================================ WORKFLOW H1
   Buy-this-car, walk-away reasons, deposits, unwind — audit 2026-07-20 */
/* the co-equal road: soft green so it reads as "money moves" next to the
   purple stage primary without shouting over it */
.btn.buy{background:var(--ok-bg);border-color:transparent;color:var(--ok);font-weight:600}
.btn.buy:hover{background:color-mix(in srgb,var(--ok) 8%,var(--ok-bg))}
/* reason picker (discard + unwind modals) */
.reason-list{display:flex;flex-direction:column;gap:6px}
.reason-opt{display:flex;align-items:center;gap:10px;padding:9px 12px;border:1px solid var(--line);
  border-radius:10px;cursor:pointer;font-size:13px;background:var(--bg-deep)}
.reason-opt:hover{border-color:var(--line-2);background:var(--surface-2)}
.reason-opt input{accent-color:var(--accent)}
.reason-opt:has(input:checked){border-color:var(--accent);background:var(--accent-soft)}
/* the Lost dialog: a decision, not a form. Five reasons one tap each, the
   note only once Other is picked (label.fld is display:block, which would
   beat the browser's own [hidden] rule, hence the explicit one). */
.lost-intro{color:var(--muted);font-size:13px;line-height:1.5;margin:0 0 12px}
.lost-list .reason-opt{font-weight:500;padding:10px 13px}
.lost-note{margin:12px 0 0}
label.fld.lost-note[hidden]{display:none}
/* destination picker */
.dest-opt{display:block;width:100%;text-align:left;padding:11px 14px;border:1px solid var(--line);
  border-radius:10px;background:var(--bg-deep);margin-bottom:8px;cursor:pointer}
.dest-opt:hover{border-color:var(--line-2);background:var(--surface-2)}
.dest-opt.on{border-color:var(--accent);background:var(--accent-soft)}
.dest-opt b{display:block;font-size:13.5px}
.dest-opt span{display:block;font-size:12px;color:var(--muted);margin-top:1px}
/* deposit chip on the price card */
.ck-dep{display:flex;align-items:center;gap:7px;margin-top:10px;padding:7px 10px;border-radius:9px;
  background:var(--ok-bg);color:var(--ok);font-size:12px;font-weight:600}
.ck-dep .ic{width:13px;height:13px}
.ck-dep b{color:inherit}
/* records ledger: an unwound purchase reads as un-happened */
tr.unwound-row td{opacity:.62}
tr.unwound-row .pill.bad{opacity:1}
td.uw-cost{text-decoration:line-through;text-decoration-color:var(--bad)}

/* click-to-call: phone links inside tables/rows — quiet until hover */
a.tel{color:inherit;border-bottom:1px dashed var(--line-2)}
a.tel:hover{color:var(--accent-2);border-bottom-color:var(--accent-2)}

.toast{background:var(--surface);border:1px solid var(--line);color:var(--text);font-size:13px;font-weight:500;
  padding:11px 16px;border-radius:var(--radius-sm);box-shadow:var(--shadow-pop);display:flex;align-items:center;gap:9px;animation:riseIn .2s ease}
.toast .ic{width:15px;height:15px;color:var(--ok)}
/* UI.toast picks the glyph and the class together, so an error can never
   arrive under a green tick */
.toast.warn .ic{color:var(--warn)}
.toast.bad .ic{color:var(--bad)}
.toast .undo{margin-left:6px;font-weight:700;color:var(--accent);background:none;border:none;border-left:1px solid var(--line);padding:2px 4px 2px 12px}
.toast .undo:hover{color:var(--accent-2);text-decoration:underline}

/* ============================================================ COMMAND CENTER */
.cc-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:18px}
.stat{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;position:relative;cursor:pointer}
.stat:hover{border-color:var(--line-2)}
.stat .l{font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}
.stat .n{font-family:var(--mono);font-size:30px;font-weight:600;letter-spacing:-.02em;margin-top:8px;line-height:1}
.stat .s{font-size:12px;color:var(--muted);margin-top:7px}
.stat.alert{border-color:color-mix(in srgb,var(--bad) 16%,var(--bad-bg));background:color-mix(in srgb,var(--bad-bg) 50%,var(--surface))}
.stat.alert .n{color:var(--bad)}
.stat.alert .l{color:var(--bad)}
/* stat cards can be buttons (in-page jumps) — same look as the anchor cards */
button.stat{width:100%;text-align:left;font-family:inherit;font-size:inherit;display:block}
/* landing highlight when a stat card jumps to a panel */
@keyframes panelFlash{0%,60%{box-shadow:0 0 0 2px var(--accent-soft),0 0 0 1px var(--accent)}100%{box-shadow:none}}
.panel.flash{animation:panelFlash 1.25s ease}
/* Past-SLA filter chip in the Focus panel header */
.focus-clear{margin-left:auto;display:inline-flex;align-items:center;gap:5px;padding:4px 10px;
  border-radius:999px;border:1px solid color-mix(in srgb,var(--bad) 16%,var(--bad-bg));background:var(--bad-bg);color:var(--bad);
  font-size:11.5px;font-weight:600}
.focus-clear:hover{background:color-mix(in srgb,var(--bad) 5%,var(--bad-bg))}
.focus-clear .ic{width:12px;height:12px}

/* the board — auto-fit keeps 6 OR 7 tiles (Follow-up appears when parked
   deals exist) in ONE even row instead of orphaning the seventh */
.board{display:grid;grid-template-columns:repeat(auto-fit,minmax(116px,1fr));gap:11px}
.btile{background:var(--bg-deep);border:1px solid var(--line);border-radius:12px;padding:12px 13px;
  display:flex;flex-direction:column;position:relative;min-height:118px;cursor:pointer}
.btile:hover{border-color:var(--line-2);background:var(--surface);box-shadow:var(--shadow-card)}
.btile .bh{display:flex;align-items:center;gap:7px;font-size:11px;font-weight:600;color:var(--text-2);
  white-space:nowrap;overflow:hidden}
.btile .bh .ic{width:13px;height:13px;flex:none;color:var(--muted)}
.btile .bn{font-family:var(--mono);font-size:26px;font-weight:600;margin-top:10px;line-height:1}
.btile .late{font-size:11px;font-weight:600;color:var(--bad);margin-top:5px;margin-bottom:10px;min-height:16px}
.btile .late.clear{color:var(--faint)}
.btile .pbar{height:4px;border-radius:3px;background:var(--line);overflow:hidden;margin-top:auto}
.btile .pbar > i{display:block;height:100%;border-radius:3px}
/* Bottleneck badge floats on the tile's top edge — never over the label */
.btile .bneck{position:absolute;top:-8px;right:8px;font-size:10.5px;font-weight:800;letter-spacing:.07em;
  color:var(--warn);background:var(--warn-bg);border:1px solid color-mix(in srgb,var(--warn) 18%,var(--warn-bg));border-radius:5px;padding:1px 6px}

/* focus + rail columns */
.cc-cols{display:grid;grid-template-columns:1fr 360px;gap:16px;margin-top:18px;align-items:start}
.focus-row{display:flex;align-items:center;gap:14px;padding:13px 18px;border-bottom:1px solid var(--line);cursor:pointer;transition:background var(--fast)}
.focus-row:last-child{border-bottom:none}
.focus-row:hover{background:var(--surface-2)}
.focus-row .fv{flex:1;min-width:0}
.focus-row .fv b{font-size:13.5px;font-weight:600}
.focus-row .fv .m{font-size:12px;color:var(--muted);margin-top:2px}
.focus-row .chev{color:var(--faint)}
.focus-row .chev .ic{width:16px;height:16px}
.focus-row .price-rng{font-size:12.5px}
/* right rail blocks */
.rail-block{margin-bottom:16px}
.today-row{display:flex;align-items:center;gap:12px;padding:12px 18px;border-bottom:1px solid var(--line);cursor:pointer;transition:background var(--fast)}
.today-row:last-child{border-bottom:none}
.today-row:hover{background:var(--surface-2)}
.today-row .ti{width:32px;height:32px;flex:none;border-radius:9px;background:var(--surface-2);color:var(--text-2);display:flex;align-items:center;justify-content:center}
.today-row .ti .ic{width:16px;height:16px}
.today-row .tt{flex:1;min-width:0}
.today-row .tt b{font-size:13px;font-weight:600;display:block}
.today-row .tt span{font-size:11.5px;color:var(--muted)}
.today-row .tn{font-family:var(--mono);font-size:16px;font-weight:600}
.hot-row{display:flex;align-items:center;gap:12px;padding:11px 18px;border-bottom:1px solid var(--line);cursor:pointer;transition:background var(--fast)}
.hot-row:last-child{border-bottom:none}
.hot-row:hover{background:var(--surface-2)}
.hot-row .hv{flex:1;min-width:0}
.hot-row .hv b{font-size:13px;font-weight:600;display:block}
.hot-row .hv .stage-chip{margin-top:4px;font-size:11px;padding:2px 8px}
.hot-row .price-rng{font-size:12.5px;white-space:nowrap}

/* ============================================================ STAGE PAGE */
.stage-count{font-family:var(--mono)}
.stage-purpose{font-size:13px;color:var(--muted);margin-top:4px}
/* compact stage-row Vehicle cell — title + inline rego on line 1, source + km on line 2.
   plain block layout (no flex-wrap on the cell) so rows stay dense single-liners. */
.veh-cell{min-width:0}
.veh-line{display:flex;align-items:center;gap:8px;font-weight:600;color:var(--text)}
.veh-line .vt{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* The New leads title is a link into the car (stage.js), so a keyboard has a
   way in without the Open button that row gave up. It reads as the title it
   was, and takes the same focus ring every other control takes. */
.veh-line a.vt{color:inherit;text-decoration:none}
.veh-line a.vt:hover{text-decoration:underline}
/* a hyphenated word in a title (stage.js, vehTitleHtml) */
.veh-line .vt .whole{white-space:nowrap}
.veh-line .rego{flex:none}
/* On a queue wide enough to hold the whole row, a squeezed Vehicle cell
   gives way, and never by cutting a word. The plate moves to the front of
   the meta line, at the size of the brand tag beside it, so the title has
   the top line to itself; the Replied and NEW marks go up a line when the
   title needs the room; a title too long for the column wraps between its
   words, never "Mercedes-" over "Benz"; and a meta line too long for it
   moves whole facts down, never "Meta" over "Ads" or "212,000" over "km".
   Held to one line the title was cut to "2021 Ford R…" and the whole line
   set the column's floor, which is what pushed the row under the pinned
   buttons. A plate left to drop under its title stood alone on a line of
   its own and made every squeezed row a line taller.
   It gives way only so far. Every other column holds its lines, so all the
   width they want comes out of this one: a try chip turning to "just now"
   took it to 116px, and the rows grew by up to 40px, to 180, under the
   pointer that had just logged the call. 145px keeps a plate and a brand
   tag on one line and Meta Ads or Website beside a six figure km on the
   next, so their meta line stops at two, and a row that wants more scrolls
   under the pin rather than growing. A long try chip goes under the age
   chip (.age-top) before it widens its column. 155px would hold Google Ads
   there too, but on the fullest rows it put the end of the phone number
   under the pin, and a number that cannot be read is worse than a line.
   What fitting costs, measured at 1440 with the sidebar open: with ordinary
   titles and names the rows stay at the 100px their buttons set. With every
   column filled (a seller ask, a form state, Meta Ads, an EV tag, long
   names, "2017 Toyota Landcruiser Prado", a try chip reading "just now")
   the rung views' rows run to 136px, nothing scrolls, and a chip turning
   to "just now" makes one row a line taller at most. A title on three
   lines makes a row 155px, and a source label too wide to sit beside its
   km makes it 156: Text message on those rows, Google Ads once the cell is
   down at its floor. With phone numbers stored with spaces and a "try 12
   just now" chip as well, up to 10px of the Phone cell sits under the pin,
   all of it the cell's own padding.
   Measured on the wrap, not the viewport, because the sidebar decides it,
   and with the scrollbar the office sees (#view keeps its gutter, so a long
   list and a short one are the same width). 1440 with the sidebar open is a
   1124px wrap under this file's 10px scrollbar, 1117 in a browser that
   ignores that and draws a 17px one, 1134 where the scrollbar is drawn over
   the page; 1280 on the rail is 1148. The cutoff sits under all three.
   Below it, 1366 with the sidebar open for one, a full row needs more than
   giving way can find, so the cell keeps its one line, the cut title
   carries its whole name on hover, and the row scrolls under the pin. The
   meta line's facts are whole either way. */
#stg-live .tablewrap{container:stg-rows/inline-size}
.veh-meta{display:flex;align-items:center;gap:8px;margin-top:3px;font-size:11.5px;color:var(--muted)}
.veh-meta > *{white-space:nowrap}
.veh-meta .rego{display:none}
/* Lead source, its own column on New leads (stage.js COL.leadSrc): the
   source's dot and label with the EV tag beside it, each held whole. */
.lsrc-cell{display:flex;align-items:center;gap:6px}
.lsrc-cell > *{white-space:nowrap}
@container stg-rows (min-width:1100px){
  #stg-live .veh-cell{min-width:145px}
  #stg-live .veh-line{flex-wrap:wrap;row-gap:4px}
  #stg-live .veh-line .vt{white-space:normal;overflow:visible}
  #stg-live .veh-line .rego{display:none}
  #stg-live .veh-meta{flex-wrap:wrap;row-gap:3px}
  #stg-live .veh-meta .rego{display:inline-flex;font-size:11px;padding:1px 6px}
  /* The age chip and the try chip share a line only while the column has
     the room (.age-col says why they share one). "try 12 just now" is 40px
     wider than "try 2 8h", and held on one line it widened the Age column
     for every row on the view. */
  #stg-live .age-top{flex-wrap:wrap;row-gap:4px}
  /* "Seller asks" is the widest heading over the narrowest figures, so here
     it takes two lines and the column is as wide as a figure; the figures
     under it never wrap (td.ask). The 1px is a floor the column always
     outgrows, and it keeps the heading from taking width the Vehicle cell
     needs. On a narrower wrap the row scrolls anyway, so the heading keeps
     one line and the header its height. */
  #stg-live table.grid thead th.ask{white-space:normal;width:1px}
  /* Lead source takes 82px of a fitted row: its heading on two lines and
     the EV tag under the label. With the Call button gone from New leads
     that keeps every row the height it was (measured 23 Sep 2026 at 1440
     with the sidebar open and 1280 on the rail) with nothing under the
     pinned actions. On a narrower wrap the row scrolls anyway, so it keeps
     one line, like th.ask. */
  #stg-live table.grid thead th.lsrc{white-space:normal;width:1px}
  #stg-live .lsrc-cell{flex-wrap:wrap;row-gap:4px}
}
/* ============================================================ COCKPIT (#/lead/:id) */
.ck-page{padding:18px 24px}
/* top bar. Pinned, the way the report's .rv-top is: scroll to the Notes card
   and the back link, the stepper and the next move are still on screen. It
   takes the page's top padding as its own (negative margin, matching padding)
   so its background covers the strip above the title once it sticks, or the
   rows would show through that gap. The bottom padding replaces the old
   margin so the messages column, pinned at --ck-top-h below, meets it with
   nothing scrolling through between the two. 98px is the bar's measured box
   at desktop widths: the 62px title block plus 18px of padding each side. */
.ck-page{--ck-top-h:98px}
.ck-top{display:flex;align-items:center;gap:14px;position:sticky;top:0;z-index:20;background:var(--bg);
  margin:-18px 0 0;padding:18px 0}
.ck-top .iconbtn{flex:none}
.ck-top-title{flex:1;min-width:0}
.ck-top-title .ck-veh{font-family:var(--font-display);font-size:24px;font-weight:700;letter-spacing:-.01em;line-height:1.15}
.ck-top-meta{display:flex;align-items:center;gap:9px;margin-top:6px;flex-wrap:wrap}
.ck-id{font-size:11.5px;color:var(--faint)}
.ck-top-act{flex:none;margin-left:auto;display:flex;align-items:center;gap:8px}
.ck-done-pill{display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:600;color:var(--ok);
  background:var(--ok-bg);border-radius:var(--radius-sm);padding:9px 14px}
.ck-done-pill .ic{width:16px;height:16px}

/* the lead stepper, walking the queue you came from one car at a time. The
   counter is orientation, not a headline, so it stays faint and mono; the
   arrows are the ordinary header icon buttons rotated, the same way the photo
   viewer draws its prev/next. Nothing renders at all for a lead with no queue
   behind it, hence :empty. */
.ck-walk{display:flex;align-items:center;gap:4px;flex:none;margin-left:-6px}
.ck-walk:empty{display:none}
.ck-walk-n{font-size:11.5px;color:var(--faint);
  min-width:56px;text-align:center;white-space:nowrap}
.ck-walk-b[data-d="prev"] .ic{transform:rotate(90deg)}
.ck-walk-b[data-d="next"] .ic{transform:rotate(-90deg)}
.ck-walk-b:disabled{opacity:.32;cursor:default}
.ck-walk-b:disabled:hover{background:transparent;color:var(--muted)}
.ck-walk .w-short{display:none}
.ck-walk[aria-busy="true"] .ck-walk-b{pointer-events:none}
.ck-walk[aria-busy="true"] .ck-walk-b[data-d="next"]{animation:ck-walk-wait .9s ease-in-out infinite}
@keyframes ck-walk-wait{0%,100%{opacity:1}50%{opacity:.3}}
@media (prefers-reduced-motion:reduce){
  .ck-walk[aria-busy="true"] .ck-walk-b[data-d="next"]{animation:none;opacity:.5}
}

/* overflow (⋯) menu — park / un-park / discard */
.ck-menu{position:relative;flex:none}
.ck-menu-pop{position:absolute;right:0;top:calc(100% + 6px);z-index:40;min-width:230px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);
  box-shadow:var(--shadow-pop);padding:5px;animation:riseIn .14s ease}
.ck-menu-it{display:flex;align-items:center;gap:9px;width:100%;padding:9px 11px;border:none;
  background:none;border-radius:8px;font-size:13px;font-weight:500;color:var(--text);text-align:left}
.ck-menu-it:hover{background:var(--surface-2)}
.ck-menu-it .ic{width:15px;height:15px;color:var(--muted)}
.ck-menu-it.danger{color:var(--bad)}
.ck-menu-it.danger .ic{color:var(--bad)}
.ck-menu-it.danger:hover{background:var(--bad-bg)}
/* An item whose name needs its reason says it under the name, the way
   App.UI.menu draws `sub`. A title never shows on a phone, and there
   Contacted and the Call menu's "Spoke to them" read as the same thing. */
.ck-menu-t{display:flex;flex-direction:column;gap:1px;min-width:0}
.ck-menu-t small{font-size:11.5px;font-weight:400;color:var(--muted)}

/* Shared anchored popover menu (App.UI.menu), used by any row, anywhere.
   position:fixed, not absolute: the queue scrolls inside .tablewrap, and an
   absolutely positioned menu would be clipped by that overflow. */
.pop-menu{position:fixed;z-index:80;min-width:236px;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius-sm);
  box-shadow:var(--shadow-pop);padding:5px;animation:riseIn .14s ease}
.pop-menu-it{display:flex;align-items:center;gap:10px;width:100%;padding:9px 11px;
  border:none;background:none;border-radius:8px;font-size:13px;color:var(--text);
  text-align:left;cursor:pointer}
.pop-menu-it:hover,.pop-menu-it:focus-visible{background:var(--surface-2);outline:none}
.pop-menu-it .ic{width:15px;height:15px;color:var(--muted);flex:none}
.pop-menu-it .pm-t{display:flex;flex-direction:column;gap:1px;min-width:0}
.pop-menu-it .pm-t b{font-weight:600}
.pop-menu-it .pm-t span{font-size:11.5px;color:var(--muted)}
.pop-menu-it.danger{color:var(--bad)}
.pop-menu-it.danger .ic{color:var(--bad)}
.pop-menu-it.danger:hover{background:var(--bad-bg)}

/* 4-zone grid: rail · left cards · centre · right messages */
/* 3 columns now: the progress rail moved INSIDE the left column, so the
   reference material reads as one block and the centre gets the width. */
.ck-grid{display:grid;grid-template-columns:250px minmax(0,1fr) 340px;gap:16px;align-items:start}
.ck-left-col{display:flex;flex-direction:column;gap:14px;min-width:0}
.ck-right-col{display:flex;flex-direction:column;gap:14px;min-width:0;position:sticky;top:var(--ck-top-h)}

/* tabs */
.ck-tabs{display:flex;gap:2px;margin:0 0 16px;border-bottom:1px solid var(--line);overflow-x:auto}
.ck-tab{padding:11px 15px 10px;border:0;background:transparent;color:var(--muted);
  font-size:13px;font-weight:700;border-bottom:2.5px solid transparent;white-space:nowrap;cursor:pointer}
.ck-tab:hover{color:var(--text)}
.ck-tab.on{color:var(--accent);border-bottom-color:var(--accent)}
.ck-tab-n{display:inline-grid;place-items:center;min-width:18px;height:18px;margin-left:7px;padding:0 5px;
  border-radius:999px;background:var(--surface-2);color:var(--muted);font-size:11px;font-weight:700}
.ck-tab.on .ck-tab-n{background:var(--accent-soft);color:var(--accent-2)}
.ck-panel{display:none}
.ck-panel.on{display:block}

/* hero step card, every stage renders into this. Plain .card material on
   purpose: an accent edge and a glow made it the one card that looked
   different, on the screen the operator reads most. */
.ck-hero-h{display:flex;gap:14px;align-items:flex-start;justify-content:space-between;padding:16px 16px 0}
.ck-hero-t{min-width:0}
.ck-eyebrow{font-size:10.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}
.ck-hero-h h3{margin:6px 0 0;font-size:19px;letter-spacing:-.01em}
.ck-hero-h p{margin:6px 0 0;font-size:12.5px;line-height:1.5;color:var(--muted);max-width:52ch}
.ck-steppill{flex:none;border-radius:999px;background:var(--accent-soft);color:var(--accent-2);
  padding:6px 10px;font-size:11px;font-weight:700;white-space:nowrap}
.ck-hero-b{padding:16px}
/* the tinted working panel: the stage's controls sit on their own surface so
   the card reads as "here is the job", not a list of rows. A flat tint and no
   border, because a bordered box inside a bordered card is a second card. */
.ck-hero .ck-act{display:flex;flex-direction:column;gap:10px;padding:14px;
  border-radius:13px;background:var(--bg-deep)}
/* status rows inside the panel: label and value on one line, a hairline
   between rows. They used to be white boxes, a third card nested in the
   second, and boxes in boxes cost reading speed here more than anywhere. */
.ck-hero .ck-act .ck-rows{gap:0}
.ck-hero .ck-act .ck-row{padding:9px 0;border-bottom:1px solid var(--line);align-items:center}
.ck-hero .ck-act .ck-row:last-child{border-bottom:none}
.ck-hero .ck-act .ck-row .k{font-size:11px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted)}
.ck-hero .ck-act .ck-row .v{font-size:12.5px;font-weight:700}
/* the phone number reads as the thing to press, like the prototype's call line */
.ck-hero .ck-tel-btn{justify-content:space-between;background:var(--surface);
  border:1px solid var(--line);color:var(--text);font-size:14px;padding:12px 14px}
.ck-hero .ck-tel-btn:hover{border-color:var(--accent);color:var(--accent-2)}
.ck-hero .ck-act > .btn{min-height:42px}
.ck-hero .ck-act .ck-fl > span{font-size:11px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted)}
.ck-hero .ck-act .ck-note{margin-top:0}
.ck-pw-sum{margin-top:10px;font-size:11px;color:var(--muted)}

/* notes */
.ck-notes{width:100%;resize:vertical;min-height:74px;font-family:inherit;line-height:1.5;padding:10px 11px}
.ck-notes-s{font-size:11px;color:var(--ok);font-weight:600;margin-top:7px}

/* snapshot strip */
.ck-snap{display:grid;grid-template-columns:repeat(2,1fr);padding:0;overflow:hidden}
.ck-metric{padding:13px 14px;border-right:1px solid var(--line);min-width:0}
.ck-metric:last-child{border-right:0}
.ck-metric span{display:block;font-size:10.5px;color:var(--muted);margin-bottom:5px;
  text-transform:uppercase;letter-spacing:.07em;font-weight:700}
.ck-metric strong{font-size:12.5px;font-weight:700;overflow-wrap:anywhere}

/* quick actions */
.ck-qa{display:grid;grid-template-columns:repeat(4,1fr);gap:9px}
.ck-qa-b{display:flex;flex-direction:column;align-items:flex-start;gap:3px;min-height:74px;padding:11px;
  border:1px solid var(--line);border-radius:11px;background:var(--surface);cursor:pointer;text-align:left;
  transition:border-color var(--fast),background var(--fast)}
.ck-qa-b:hover{border-color:var(--accent);background:var(--accent-soft)}
.ck-qa-b .ic{width:17px;height:17px;color:var(--accent);margin-bottom:3px}
.ck-qa-b b{font-size:12px;font-weight:700}
.ck-qa-b small{font-size:11px;color:var(--muted)}

/* full-specs expander on the Vehicle card */
.ck-more{margin-top:10px;border-top:1px solid var(--line);padding-top:10px}
.ck-more summary{cursor:pointer;font-size:11.5px;font-weight:700;color:var(--accent);list-style:none;
  display:flex;align-items:center;gap:6px}
.ck-more summary::-webkit-details-marker{display:none}
.ck-more summary .ic{width:13px;height:13px;flex:none;transition:transform var(--fast)}
.ck-more[open] summary .ic{transform:rotate(90deg)}
.ck-more summary .mono{margin-left:auto;color:var(--faint);font-size:11px}
.ck-more .ck-rows{margin-top:10px}

/* reminder */
.ck-rem-add{display:flex;align-items:center;gap:7px;width:100%;padding:11px 13px;border:1px dashed var(--line-2);
  border-radius:var(--radius-sm);background:transparent;color:var(--muted);font-size:12px;font-weight:600;cursor:pointer}
.ck-rem-add:hover{border-color:var(--accent);color:var(--accent)}
.ck-rem-add .ic{width:14px;height:14px}
.ck-rem.over{border-color:var(--bad)}
.ck-rem-tag{margin-left:6px;padding:1px 6px;border-radius:5px;background:var(--bad-bg,rgba(180,35,35,.1));
  color:var(--bad);font-size:10.5px;font-weight:700;letter-spacing:.07em}
.ck-rem-t{font-size:13px;font-weight:600;line-height:1.4}
.ck-rem-d{font-size:11.5px;color:var(--muted);margin-top:5px}
.ck-rem-a{display:flex;gap:7px;margin-top:11px}
.ck-rem-a .btn{flex:1;justify-content:center}

/* files tab — document rows carry the prototype's icon-tile treatment */
.ck-files{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
.ck-docs{display:flex;flex-direction:column;gap:9px}
.ck-doc{display:flex;align-items:center;gap:12px;padding:11px 12px;border:1px solid var(--line);
  border-radius:12px;background:var(--surface)}
.ck-doc > .ic{width:36px;height:36px;flex:none;padding:9px;border-radius:10px;
  background:var(--accent-soft);color:var(--accent);box-sizing:border-box}
.ck-doc-t{min-width:0}
.ck-doc-t b{display:block;font-size:12px;font-weight:700}
.ck-doc-t span{display:block;font-size:11px;color:var(--muted);margin-top:3px}

/* the whole lead page picks up the prototype's softer, roomier card feel */
.ck-page .card{border-radius:16px}
.ck-page .ck-card{padding:16px}
.ck-page .cap{font-size:10.5px;letter-spacing:.07em}
/* messages tab: the same thread, given the whole page */
.ck-msgs-full{max-width:860px}
/* The Messages tab's card. Capped to the viewport under the pinned top bar
   and the tabs, so the thread is a scroll box: the composer is always in
   reach and mount() can land on the newest message. Uncapped, the thread
   simply grew to fit and scrollTop had nothing to move, which is why the
   tab, built for the long conversations, opened at the oldest message. */
.ck-right.full{max-height:calc(100vh - 220px);position:static;min-height:60vh}
.ck-msgs-note{margin-top:10px;font-size:11.5px;color:var(--faint)}

/* activity drawer — the ONE home for the activity log */
.ck-drawer-back{position:fixed;inset:0;background:rgba(12,14,20,.38);opacity:0;pointer-events:none;
  transition:opacity var(--fast);z-index:70}
.ck-drawer-back.on{opacity:1;pointer-events:auto}
.ck-drawer{position:fixed;top:0;right:0;height:100vh;width:min(480px,92vw);background:var(--surface);
  border-left:1px solid var(--line);box-shadow:var(--shadow-pop);
  transform:translateX(100%);transition:transform var(--move);z-index:71;display:flex;flex-direction:column}
.ck-drawer.on{transform:translateX(0)}
.ck-drawer-h{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:16px 18px;border-bottom:1px solid var(--line)}
.ck-drawer-h h3{margin:5px 0 0;font-size:17px}
.ck-drawer-b{padding:16px 18px;overflow:auto}
.ck-act-btn{flex:none}

@media(max-width:1180px){
  .ck-qa{grid-template-columns:1fr 1fr}
  .ck-files{grid-template-columns:1fr}
}

/* progress rail (vertical stepper) */
.ck-rail{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:16px 14px}
.ck-rail .cap{margin-bottom:14px}
.ck-step{display:flex;align-items:center;gap:10px;position:relative;padding-bottom:18px}
.ck-step:last-child{padding-bottom:0}
.ck-step:not(:last-child)::before{content:"";position:absolute;left:9px;top:20px;bottom:-2px;width:2px;background:var(--line-2)}
.ck-step.done:not(:last-child)::before{background:var(--accent)}
.ck-step .mk{width:20px;height:20px;flex:none;border-radius:50%;border:2px solid var(--line-2);background:var(--bg-deep);
  display:flex;align-items:center;justify-content:center;z-index:1}
.ck-step .mk .ic{width:12px;height:12px;color:#fff;stroke-width:3}
.ck-step .mk .d{width:8px;height:8px;border-radius:50%;background:var(--accent)}
.ck-step.done .mk{background:var(--accent);border-color:var(--accent)}
.ck-step.now .mk{border-color:var(--accent);box-shadow:0 0 0 4px var(--accent-soft)}
.ck-step .lbl{font-size:12px;font-weight:500;color:var(--muted);line-height:1.2}
.ck-step .l-short{display:none}
.ck-step.done .lbl{color:var(--text-2)}
.ck-step.now .lbl{color:var(--text);font-weight:600}

/* left column cards */
.ck-left{display:flex;flex-direction:column;gap:14px}
.ck-card{padding:15px 16px}
.ck-card .cap{display:flex;align-items:center;gap:8px;margin-bottom:12px}
.ck-eval-btn{margin-top:12px}
.ck-est{display:inline-block;margin-left:5px;padding:1px 5px;border-radius:5px;font-family:var(--font);
  font-size:10.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  background:var(--warn-bg,rgba(191,143,26,.14));color:var(--warn)}
.ck-carok,.ck-carbad{display:flex;align-items:flex-start;gap:7px;margin-top:12px;padding:8px 10px;
  border-radius:9px;font-size:12px;font-weight:600;line-height:1.35}
.ck-carok{background:var(--ok-bg,rgba(15,138,99,.09));color:var(--ok)}
.ck-carbad{background:var(--bad-bg,rgba(180,35,35,.09));color:var(--bad)}
.ck-carok .ic,.ck-carbad .ic{width:13px;height:13px;flex:none;margin-top:1px}
.ck-asked{display:flex;align-items:center;gap:7px;margin-top:12px;padding:8px 10px;border-radius:9px;
  background:var(--surface-2);color:var(--muted);font-size:12px;font-weight:600;
  line-height:1.35}
.ck-asked .ic{width:13px;height:13px;flex:none}
.ck-asked span{min-width:0}

.ck-seller{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.ck-seller-h{display:flex;align-items:center;gap:7px;font-size:11px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--ok);margin-bottom:10px}
.ck-seller-h .ic{width:13px;height:13px;flex:none}
.ck-seller-view{margin-left:auto;font-size:11px;font-weight:700;letter-spacing:0;text-transform:none;
  color:var(--accent);cursor:pointer}
.ck-seller-view:hover{text-decoration:underline}
.ck-seller .ck-rows{gap:9px}
.ck-seller-none{font-size:12px;color:var(--muted)}
/* the missed call text sequence, a footnote under the seller it texts: is the
   automation on, how many texts have really gone, how many are left. Discreet
   by the owner's ask, so it borrows .ck-seller's rule and cap geometry and
   only the glyph and the cap carry any colour. */
.ck-txt{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.ck-txt-h{display:flex;align-items:center;gap:7px;font-size:11px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted)}
.ck-txt-h .ic{width:13px;height:13px;flex:none}
.ck-txt-n{margin-left:auto;font-size:11px;font-weight:600;letter-spacing:.02em;
  text-transform:none;color:var(--text-2);white-space:nowrap}
.ck-txt-s{margin-top:6px;font-size:12px;color:var(--muted);line-height:1.45}
.ck-txt.on .ck-txt-h{color:var(--ok)}
.ck-txt.off .ck-txt-h,.ck-txt.none .ck-txt-h{color:var(--warn)}
/* A lead nobody has rung. Deliberately NOT the green of .on: the owner read
   that tick as a sequence running on every lead in the business, and nothing
   is running until somebody clicks No answer. Ink, not a signal colour. */
.ck-txt.wait .ck-txt-h{color:var(--text-2)}

/* Who holds this lead, under the seller it is about, in the same footnote
   shape the texts note uses: they answer one question between them, whose
   name and number a seller reads. The name itself is card-title sized because
   it is the answer; the line under it is the consequence. "Nobody" is amber
   and said in words, never a blank: a lead nobody holds speaks in the office's
   name, and with that unset the sentence is dropped. */
.ck-alloc{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.ck-alloc-h{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:700;
  letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}
.ck-alloc-go{margin-left:auto;background:none;border:0;padding:0;font:inherit;font-size:11px;
  font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--accent-2);cursor:pointer}
.ck-alloc-go:hover{color:var(--accent)}
.ck-alloc-who{margin-top:7px;font-size:14px;font-weight:600;letter-spacing:-.01em;
  display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.ck-alloc-you{font-size:10.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  padding:2px 7px;border-radius:999px;background:var(--accent-soft);color:var(--accent-2)}
.ck-alloc-none{color:var(--warn)}
.ck-alloc-sub{margin-top:5px;font-size:12px;color:var(--muted);line-height:1.45}
/* Said inside the allocate dialog only, and only to the person it is true of:
   your own two fields are empty, so a lead you take speaks as the office. */
.ck-alloc-warn{display:flex;gap:9px;align-items:flex-start;margin-top:12px;padding:10px 12px;
  border-radius:var(--radius-sm);background:var(--warn-bg);color:var(--text);
  font-size:12.5px;line-height:1.5}
.ck-alloc-warn .ic{width:15px;height:15px;flex:none;margin-top:1px;color:var(--warn)}
.ck-alloc-warn a{color:var(--accent-2);font-weight:600;text-decoration:underline}

/* registration-state picker (shown before any paid Eval lookup) */
.st-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-top:14px}
.st-opt{padding:14px 0;border:1.5px solid var(--line);border-radius:11px;background:var(--surface);
  font-family:'JetBrains Mono',monospace;font-size:14px;font-weight:700;color:var(--text);
  cursor:pointer;transition:border-color var(--fast),background var(--fast)}
.st-opt:hover{border-color:var(--accent)}
.st-opt.on{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
@media (max-width:520px){.st-grid{grid-template-columns:repeat(2,1fr)}}

/* saved messages (templates) */
.ck-tpl-btn{flex:none}
.tpl-list{display:flex;flex-direction:column;gap:8px}
.tpl-pick{display:block;width:100%;text-align:left;border:1px solid var(--line);border-radius:10px;
  padding:11px 13px;background:var(--surface);cursor:pointer;transition:border-color var(--fast),background var(--fast)}
.tpl-pick:hover{border-color:var(--accent);background:var(--surface-2)}
.tpl-pick b{display:block;font-size:13px;font-weight:700;margin-bottom:3px}
.tpl-pick span{display:block;font-size:12px;color:var(--muted);line-height:1.45}
/* an unfilled field inside a picker row reads as its name, not as braces */
.tpl-pick .tplx-tk{display:inline-block;width:auto;font-size:11.5px;padding:0 5px;line-height:1.5}  /* .tpl-pick span above also matches the pill, which is a span: force it back inline */
.ck-name{font-size:15px;font-weight:600;letter-spacing:-.01em;margin-bottom:10px}
.ck-rows{display:flex;flex-direction:column;gap:9px}
.ck-row{display:flex;align-items:baseline;justify-content:space-between;gap:12px;font-size:13px}
.ck-row .k{color:var(--muted);font-size:12px;flex:none}
.ck-row .v{font-weight:500;text-align:right;min-width:0;word-break:break-word}
.ck-tel{color:var(--text)}
.ck-tel:hover{color:var(--accent-2)}
.ck-price-big{font-family:var(--font-display);font-size:26px;font-weight:700;letter-spacing:-.01em;line-height:1;color:var(--text)}
.ck-price-cap{font-size:11.5px;color:var(--muted);margin-top:8px}

/* centre column */
.ck-centre{display:flex;flex-direction:column;gap:14px;min-width:0}
.ck-wide{width:100%;justify-content:center}
.ck-tel-btn{width:100%;justify-content:center;font-weight:600}
/* Phase D: cockpit Offer-stage wholesaler-link summary */
.ck-price-set{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.ck-fl{display:flex;flex-direction:column;gap:5px}
.ck-fl > span{font-size:11.5px;font-weight:600;color:var(--muted)}
.ck-await{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;font-weight:600;color:var(--warn);
  background:var(--warn-bg);border-radius:var(--radius-sm);padding:9px 12px}
.ck-await .ic{width:15px;height:15px}
/* inspection booking dialogs (book / move / cancel): a quiet one-line hint,
   and a row of equal-width buttons for Move + Cancel on the booked summary */
.ck-quiet{font-size:12.5px;color:var(--muted);line-height:1.5}
.btn-row{display:flex;gap:8px}
.btn-row .btn{flex:1}
/* these three dialogs stack .ck-fl/.ck-quiet directly in modal-b with no
   wrapper (every other modal here nests them or inlines a margin) */
.modal-b > .ck-fl,.modal-b > .ck-quiet{margin-top:14px}
.modal-b > .ck-fl:first-child,.modal-b > .ck-quiet:first-child{margin-top:0}

/* activity timeline */
.ck-tl-list{display:flex;flex-direction:column;gap:0}
.ck-ev{display:flex;align-items:flex-start;gap:11px;padding:11px 0;border-bottom:1px solid var(--line)}
.ck-ev:first-child{padding-top:0}
.ck-ev:last-child{border-bottom:none;padding-bottom:0}
.ck-ev-dot{width:8px;height:8px;flex:none;border-radius:50%;margin-top:5px;background:var(--muted)}
.ck-ev-dot.accent{background:var(--accent)} .ck-ev-dot.green{background:var(--ok)}
.ck-ev-dot.amber{background:var(--warn)} .ck-ev-dot.red{background:var(--bad)}
.ck-ev-b{flex:1;min-width:0}
.ck-ev-s{font-size:13px;font-weight:500;line-height:1.4}
.ck-ev-d{font-size:11.5px;color:var(--muted);margin-top:3px;line-height:1.4}
.ck-ev-t{font-size:11px;color:var(--faint);flex:none;margin-top:1px}

/* right column: messages */
.ck-right{display:flex;flex-direction:column;padding:0;max-height:calc(100vh - 120px);position:sticky;top:var(--ck-top-h)}
.ck-right-h{display:flex;align-items:baseline;gap:8px;padding:15px 16px;border-bottom:1px solid var(--line)}
.ck-right-h .cap{margin:0}
.ck-right-sub{font-size:12px;color:var(--muted)}
.ck-thread{flex:1;min-height:160px;overflow-y:auto;padding:14px 16px;display:flex;flex-direction:column;gap:12px}
/* min-width:0 matters: without it a flex item refuses to shrink below its
   content's minimum, and one long unbreakable URL drags the bubble wider
   than the panel (spilling off the LEFT on right-aligned outbound ones). */
.ck-msg{display:flex;flex-direction:column;max-width:84%;min-width:0}
.ck-msg.out{align-self:flex-end;align-items:flex-end}
.ck-msg.in{align-self:flex-start;align-items:flex-start}
/* `anywhere`, not `break-word`: only `anywhere` also shrinks the element's
   min-content width, which is what lets a pasted link wrap instead of
   stretching the bubble. Links are the normal case here — we text them. */
.ck-bub{font-size:13px;line-height:1.45;padding:9px 12px;border-radius:13px;
  overflow-wrap:anywhere;word-break:break-word;max-width:100%}
.ck-msg.out .ck-bub{background:var(--accent);color:#fff;border-bottom-right-radius:4px}
.ck-msg.in .ck-bub{background:var(--surface-2);color:var(--text);border:1px solid var(--line);border-bottom-left-radius:4px}
.ck-bub-ph{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;opacity:.85;margin-top:2px}
.ck-bub-ph .ic{width:13px;height:13px}
.ck-bub-t{font-size:11px;color:var(--muted);margin-top:4px;padding:0 3px}
.ck-composer{display:flex;gap:8px;padding:12px 14px;border-top:1px solid var(--line)}
.ck-composer .input{flex:1}
.ck-composer .btn.iconish{padding:0;width:38px;height:38px;justify-content:center}
.ck-composer .btn.iconish .ic{width:18px;height:18px}

@media(max-width:1180px){
  .ck-grid{grid-template-columns:1fr 1fr;grid-auto-flow:row}
  .ck-rail{grid-column:1 / -1}
  /* The rail stays VERTICAL at every width now that it lives inside the
     left column (owner's choice). The old horizontal stepper is gone: it
     broke labels mid-word ("Inspec / tion / booke / d") the moment the
     column narrowed. */
  .ck-centre{grid-column:1 / -1}
  .ck-right-col{grid-column:1 / -1;position:static}
  .ck-right{max-height:none;position:static}
}
@media(max-width:760px){
  .ck-page{padding:14px}
  .ck-top{margin-top:-14px;padding-top:14px}
  .ck-grid{grid-template-columns:1fr}
  .ck-left-col{grid-column:1 / -1}
}

/* ============================================================ INSPECTION REPORT (#/report/:id) */
.rv-page{padding:0 0 40px}
/* top bar */
.rv-top{display:flex;align-items:center;gap:16px;padding:16px 28px;border-bottom:1px solid var(--line);
  position:sticky;top:0;z-index:20;background:var(--bg)}
.rv-top-l{display:flex;align-items:center;gap:10px;min-width:0}
.rv-badge-ic{width:30px;height:30px;flex:none;border-radius:9px;background:var(--accent-soft);color:var(--accent-2);
  display:flex;align-items:center;justify-content:center}
.rv-badge-ic .ic{width:17px;height:17px;stroke-width:2}
.rv-top-t{font-size:15px;font-weight:700;letter-spacing:-.01em;white-space:nowrap}
.rv-top-id{font-size:12px;color:var(--faint)}
.rv-top-r{margin-left:auto;display:flex;align-items:center;gap:10px;flex:none}

/* body */
.rv-body{padding:22px 28px;display:flex;flex-direction:column;gap:16px}

/* header band */
.rv-head{display:flex;align-items:flex-start;gap:16px}
.rv-head-meta{display:flex;align-items:center;gap:11px;flex-wrap:wrap}
.rv-cap{font-size:12.5px;color:var(--muted)} .rv-cap b{color:var(--text-2);font-weight:600}
.rv-veh{font-family:var(--font-display);font-size:25px;font-weight:700;letter-spacing:-.01em;line-height:1.12;margin:9px 0 8px}
.rv-head-sub{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.rv-km{font-size:12.5px;color:var(--text-2)}
.rv-seller{font-size:12.5px;color:var(--muted)}

/* legend (two authorship colours) */
.rv-legend{display:flex;align-items:center;gap:18px;padding:2px 2px 4px}
.rv-leg{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;font-weight:500;color:var(--muted)}
.rv-leg .d{width:11px;height:11px;flex:none;border-radius:4px;border:1px solid}
.rv-leg.insp .d{background:var(--surface-2);border-color:var(--line-2)}
.rv-leg.admin .d{background:var(--warn-bg);border-color:var(--warn)}
/* wholesaler / "what we send" banner */
.rv-ws-banner{display:flex;align-items:center;gap:9px;font-size:12.5px;font-weight:500;color:var(--ok);
  background:var(--ok-bg);border:1px solid transparent;border-radius:var(--radius-sm);padding:11px 14px}
.rv-ws-banner .ic{width:16px;height:16px;flex:none}

/* panel + section header (authorship tag) */
.rv-panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px}
.rv-sec-h{display:flex;align-items:center;gap:10px;margin-bottom:16px}
.rv-sec-t{font-size:14.5px;font-weight:700;letter-spacing:-.01em}
.rv-sec-sub{margin-left:auto;font-size:12px;color:var(--muted)}
.rv-tag{font-size:10.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;border-radius:6px;padding:3px 8px;line-height:1}
.rv-tag.insp{background:var(--surface-2);color:var(--muted);border:1px solid var(--line)}
.rv-tag.admin{background:var(--warn-bg);color:var(--warn);border:1px solid transparent}
/* admin-internal panel gets an amber edge ("never sent") */
.rv-panel.rv-admin{border-color:rgba(244,182,90,.4);background:var(--warn-bg)}

/* two-column body under photos */
.rv-cols{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}
.rv-col{display:flex;flex-direction:column;gap:16px;min-width:0}

/* photos grid */
.rv-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
.rv-tile{position:relative;background:var(--bg-deep);border:1px solid var(--line);border-radius:11px;
  aspect-ratio:4/3;display:flex;align-items:center;justify-content:center;overflow:hidden}
.rv-tile.off{opacity:.42}
.rv-tile-ph{color:var(--faint);opacity:.5}
.rv-tile-ph .ic{width:30px;height:30px}
.rv-tile-lbl{position:absolute;left:9px;bottom:9px;display:inline-flex;align-items:center;gap:6px;
  background:rgba(10,11,13,.72);border-radius:6px;padding:3px 8px;font-size:11px;font-weight:600;color:var(--text)}
.rv-dmgdot{width:7px;height:7px;border-radius:50%;background:var(--bad);flex:none}
.rv-chk{position:absolute;top:9px;right:9px;width:26px;height:26px;border-radius:7px;border:1px solid var(--line-2);
  background:var(--surface);color:transparent;display:flex;align-items:center;justify-content:center}
.rv-chk .ic{width:15px;height:15px;color:#fff;stroke-width:3}
.rv-chk:hover{border-color:var(--accent)}
.rv-chk.on{background:var(--accent);border-color:var(--accent)}

/* condition rows */
.rv-cond{display:flex;flex-direction:column;gap:12px}
.rv-cond-row{display:flex;align-items:center;gap:14px}
.rv-cond-lbl{flex:none;width:165px;font-size:13px;font-weight:500;color:var(--text-2)}
.rv-rates{display:grid;grid-template-columns:repeat(4,1fr);gap:7px;flex:1;min-width:0}
.rv-rates.wrap{grid-template-columns:repeat(2,1fr)}
.rv-rate{border:1px solid var(--line-2);background:var(--bg-deep);color:var(--muted);font-size:12px;font-weight:600;
  padding:8px 6px;border-radius:8px;white-space:nowrap}
.rv-rate:not(:disabled):hover{color:var(--text);border-color:var(--line-2);background:var(--surface-2)}
.rv-rate:disabled{cursor:default}
/* the tone variants below own the real colours. The base keeps a readable
   one so a rating with no matching tone class never renders white on the tint */
.rv-rate.on{color:var(--text)}
.rv-rate.on.acc{background:var(--accent-soft);border-color:var(--accent);color:var(--accent-2)}
.rv-rate.on.ok{background:var(--ok-bg);border-color:var(--ok);color:var(--ok)}
.rv-rate.on.warn{background:var(--warn-bg);border-color:var(--warn);color:var(--warn)}
.rv-rate.on.bad{background:var(--bad-bg);border-color:var(--bad);color:var(--bad)}

/* defects */
.rv-defs{display:flex;flex-direction:column;gap:11px}
.rv-def{display:flex;align-items:flex-start;gap:11px}
.rv-def-ic{width:28px;height:28px;flex:none;border-radius:8px;background:var(--bad-bg);color:var(--bad);
  display:flex;align-items:center;justify-content:center}
.rv-def-ic .ic{width:16px;height:16px}
.rv-def-t{font-size:13px;font-weight:600}
.rv-def-n{font-size:11.5px;color:var(--muted);margin-top:2px}

/* notes */
.rv-notes{font-size:13px;line-height:1.55;color:var(--text-2)}

/* specs */
.rv-specs{display:flex;flex-direction:column;gap:0}
.rv-spec{display:flex;align-items:baseline;justify-content:space-between;gap:14px;padding:9px 0;border-bottom:1px solid var(--line)}
.rv-spec:last-child{border-bottom:none}
.rv-spec-k{font-size:12.5px;color:var(--muted)}
.rv-spec-v{font-size:13px;font-weight:600;text-align:right;word-break:break-all}

/* quick facts */
.rv-facts{display:grid;grid-template-columns:repeat(3,1fr);gap:11px}
.rv-fact{background:var(--bg-deep);border:1px solid var(--line);border-radius:10px;padding:12px 14px}
.rv-fact-k{font-size:11px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}
.rv-fact-v{font-size:16px;font-weight:600;margin-top:6px}

/* admin-internal recon */
.rv-admin-note{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;font-weight:500;color:var(--warn);margin-bottom:14px}
.rv-admin-note .ic{width:14px;height:14px}
.rv-recon{display:flex;flex-direction:column;gap:0;margin-bottom:14px}
.rv-recon-row{display:flex;align-items:baseline;justify-content:space-between;gap:14px;padding:8px 0;
  font-size:13px;color:var(--text-2);border-bottom:1px solid var(--line)}
.rv-recon-row .mono{font-weight:600;color:var(--text)}
.rv-recon-row.total{border-bottom:none;border-top:1px solid var(--line-2);margin-top:2px;padding-top:11px;font-weight:700;color:var(--text)}
.rv-recon-row.total .mono{color:var(--warn)}
.rv-recon-input{display:grid;grid-template-columns:1fr auto;gap:8px;align-items:end}
.rv-recon-input > span{grid-column:1/-1;font-size:11.5px;font-weight:600;color:var(--muted);margin-bottom:2px}
.rv-recon-input .input{width:100%}

/* empty report */
.rv-empty{max-width:560px;margin:8px auto}

/* ---- inspector capture (mobile preview) ---- */
.rv-cap-shell{display:flex;justify-content:center;padding:6px 0 0}
.rv-cap-phone{width:100%;max-width:420px;display:flex;flex-direction:column;gap:13px}
.rv-cap-bar{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:15px 17px}
.rv-cap-veh{font-size:16px;font-weight:700;letter-spacing:-.01em}
.rv-cap-sub{font-size:12px;color:var(--muted);margin-top:3px}
.rv-cap-step{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:15px 17px}
.rv-cap-h{display:flex;align-items:center;gap:10px;margin-bottom:13px}
.rv-cap-n{width:24px;height:24px;flex:none;border-radius:50%;background:var(--accent-soft);color:var(--accent-2);
  font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center}
.rv-cap-t{font-size:14px;font-weight:700;letter-spacing:-.01em}
.rv-cap-prog{font-size:12px;color:var(--muted);margin-bottom:11px}
.rv-shots{display:flex;flex-direction:column;gap:8px}
.rv-shot{display:flex;align-items:center;gap:11px;padding:10px 12px;border:1px solid var(--line);border-radius:10px;
  background:var(--bg-deep);font-size:13px;font-weight:500;color:var(--text-2)}
.rv-shot .rv-shot-ic{width:28px;height:28px;flex:none;border-radius:8px;background:var(--surface-2);color:var(--muted);
  display:flex;align-items:center;justify-content:center}
.rv-shot .rv-shot-ic .ic{width:15px;height:15px}
.rv-shot.done{color:var(--text)}
.rv-shot.done .rv-shot-ic{background:var(--ok-bg);color:var(--ok)}
.rv-shot.done .rv-shot-ic .ic{stroke-width:3}
.rv-shot > span{display:inline-flex;align-items:center;gap:7px}
.rv-cap-conds{display:flex;flex-direction:column;gap:14px}
.rv-cap-cond .rv-cond-lbl{display:block;width:auto;margin-bottom:8px;color:var(--text)}
.rv-cap-cond .rv-rates{display:grid}
.rv-cap-facts{display:flex;flex-direction:column;gap:14px}
.rv-cap-fact{display:flex;align-items:center;justify-content:space-between;gap:12px}
.rv-cap-fact > span{font-size:13px;font-weight:500;color:var(--text-2)}
.seg.sm button{padding:6px 11px;font-size:12px}
.rv-cap-done{width:100%;justify-content:center;padding:12px}
.rv-cap-foot{font-size:11.5px;color:var(--faint);text-align:center;padding:2px 8px 4px}

/* ============================================================ OFFERS (#/offers) */
.of-page .page-h{margin-bottom:18px}
.of-split{display:grid;grid-template-columns:320px 1fr;gap:18px;align-items:start}
/* LEFT — cars-on-offer list */
.of-list{overflow:hidden}
.of-list-b{display:flex;flex-direction:column;padding:8px}
.of-item{display:flex;flex-direction:column;gap:7px;text-align:left;width:100%;
  background:transparent;border:1px solid transparent;border-radius:var(--radius-sm);padding:11px 12px;cursor:pointer}
.of-item:hover{background:var(--surface-2)}
.of-item.on{background:var(--accent-soft);border-color:transparent;box-shadow:inset 3px 0 0 var(--accent)}
.of-item-h{display:flex;align-items:center;gap:8px}
.of-veh{font-size:13.5px;font-weight:600;color:var(--text);letter-spacing:-.01em}
.of-item-m{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.of-best{font-size:14px;font-weight:600;color:var(--accent-2)}
.of-item-m .muted{font-size:12px}
.of-item-m .age{font-size:11px;padding:2px 7px}
/* RIGHT — compare table */
.of-detail{overflow:hidden}
.of-stick{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap;
  padding:14px 18px;border-bottom:1px solid var(--line);background:var(--surface)}
.of-stick-veh{font-size:15px;font-weight:600;color:var(--text);letter-spacing:-.01em;display:inline-flex;align-items:center;gap:9px}
.of-stick-meta{font-size:12.5px;color:var(--text-2);display:inline-flex;align-items:center;gap:8px}
.of-stick-meta .mono{color:var(--text)}
.of-stick-meta .age{font-size:11px;padding:2px 7px}
/* the room fills the detail pane; what buyers typed reads underneath it */
.of-room{padding:14px}
.of-notes{border-top:1px solid var(--line);padding:12px 14px 14px}
.of-notes-h{font-size:11.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;font-weight:600;margin-bottom:8px}
.of-note{display:grid;grid-template-columns:150px 1fr auto;gap:10px;align-items:baseline;
  padding:7px 0;border-bottom:1px solid var(--line);font-size:12.5px}
.of-note:last-child{border-bottom:0}
.of-note-ws{font-weight:600;color:var(--text)}
.of-note-t{color:var(--text-2);line-height:1.5}
.of-note-w{color:var(--muted);font-size:11.5px;white-space:nowrap}
@media (max-width:760px){.of-note{grid-template-columns:1fr auto}.of-note-t{grid-column:1/-1}}

/* ===== the offer room (app/screens/_offerroom.js) =====
   One panel in two homes at very different widths: the cockpit's Offer hero
   (~256px at a 1280 screen) and the Offers detail pane (~900px). It sizes
   itself off ITS OWN width, not the window's, because at 1280 those two are
   the same window and a media query would have to be wrong for one of them.
   Stacked is the default, so a browser without container queries still gets
   a row that reads; the wide single line is the upgrade. */
.or{border:1px solid var(--line);border-radius:11px;background:var(--surface);overflow:hidden;
  container-type:inline-size}
.or-h{display:flex;align-items:center;gap:10px;padding:9px 12px;background:var(--bg-deep);
  border-bottom:1px solid var(--line);font-size:12.5px}
.or-h-l{display:flex;align-items:center;gap:7px;font-weight:600}
.or-h-l svg{width:14px;height:14px;color:var(--muted)}
.or-h-r{margin-left:auto}
.or-h-r .age{font-size:11px;padding:2px 7px}
.or-n{color:var(--muted);font-weight:500}
.or-best{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;padding:10px 12px;border-bottom:1px solid var(--line)}
.or-best .k{font-size:11.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}
.or-best .v{font-size:17px;font-weight:700}
.or-best .who{font-size:12.5px;color:var(--muted)}
.or-best.none{color:var(--muted);font-size:12.5px}
.or-delta{margin-left:auto;font-size:11.5px;font-weight:700}
.or-delta.up{color:var(--ok)} .or-delta.down{color:var(--bad)}
/* narrow: who and where they got to on top, how the text went and what you
   can do underneath. The buyer's name never truncates, which is the whole
   reason this is not one rigid row at every width. */
.or-row{display:grid;grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:"ws state" "send acts";gap:3px 8px;align-items:center;
  padding:9px 12px;border-bottom:1px solid var(--line);font-size:12.5px}
.or-row:last-child{border-bottom:0}
.or-row.best{background:var(--ok-bg)}
.or-ws{grid-area:ws;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.or-send{grid-area:send;font-size:11px;min-width:0}
.or-state{grid-area:state;white-space:nowrap;text-align:right}
.or-acts{grid-area:acts;display:flex;gap:6px;justify-content:flex-end}
.or-s.ok{color:var(--ok)} .or-s.bad{color:var(--bad)}
.or-s.mid{color:var(--muted)} .or-s.none{color:var(--faint)}
.or-amt{font-weight:700} .or-amt.win{color:var(--ok)}
.or-acts .btn.sm{white-space:nowrap}
/* wide enough for one line: four real columns, denser per buyer */
@container (min-width:520px){
  .or-row{grid-template-columns:minmax(120px,1.3fr) minmax(0,1fr) auto auto;
    grid-template-areas:"ws send state acts";gap:10px}
  .or-send{text-align:left}
}
.or-f{display:flex;gap:8px;flex-wrap:wrap;padding:9px 12px;background:var(--bg-deep);border-top:1px solid var(--line)}
.or-empty{padding:16px 12px;text-align:center;color:var(--muted);font-size:12.5px}
.or-empty b{display:block;color:var(--text);margin-bottom:3px}

/* ============================================================ INVENTORY (#/inventory) */
.inv-filter{flex-wrap:wrap}
.inv-filter button .mono{font-size:11px;opacity:.85;margin-left:2px}
.inv-seg{padding:2px}
.inv-seg button{padding:5px 10px;font-size:11.5px}
.inv-dest{width:1%;white-space:nowrap}
.inv-days{color:var(--text)}
table.grid td.inv-dest .seg{vertical-align:middle}

/* ============================================================ REPORTS (#/reports) */
.rp-cols{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}
.rp-note{display:inline-flex;align-items:center;gap:8px;font-size:12px;font-weight:600;color:var(--muted);
  background:var(--surface);border:1px solid var(--line);border-radius:999px;padding:5px 12px}
.rp-note .ic{width:13px;height:13px}
/* horizontal bar list (leads by source / stage throughput) */
.barlist{display:flex;flex-direction:column;gap:2px}
.barrow{display:grid;grid-template-columns:118px 1fr 44px;align-items:center;gap:12px;padding:9px 18px;border-bottom:1px solid var(--line)}
.barrow:last-child{border-bottom:none}
.barrow .bl{display:flex;align-items:center;gap:8px;font-size:12.5px;font-weight:500;color:var(--text-2);min-width:0}
.barrow .bl .dot{width:8px;height:8px;border-radius:50%;flex:none}
.barrow .bl span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.barrow .bt{height:9px;border-radius:5px;background:var(--surface-2);overflow:hidden}
.barrow .bt > i{display:block;height:100%;border-radius:5px;min-width:3px}
.barrow .bv{font-family:var(--mono);font-size:13px;font-weight:600;text-align:right;color:var(--text)}
.barrow.zero .bv{color:var(--faint)}
/* Leads by brand: a bar row plus the numbers that make the split useful */
.rp-brow{padding:11px 18px;border-bottom:1px solid var(--line)}
.rp-brow:last-child{border-bottom:none}
.rp-brow .barrow{padding:0;border-bottom:none}
.rp-bsub{display:flex;flex-wrap:wrap;gap:14px;margin:7px 0 0 130px;font-size:11.5px;color:var(--muted)}
.rp-bsub b{font-family:var(--mono);font-weight:600;color:var(--text-2)}
.rp-brow.zero .rp-bsub{color:var(--faint)}
.rp-foot{padding:12px 18px;border-top:1px solid var(--line);font-size:11.5px;
  color:var(--faint);line-height:1.55}
/* Reports reuses the queue's result line verbatim (.stg-result / .stg-chip),
   so a filtered page discloses itself the same way on both screens */
.rp-result{margin:0 0 14px}
@media(max-width:760px){.rp-bsub{margin-left:0}}

/* ============================================================ SETTINGS (#/settings) */
.set-grid{display:grid;grid-template-columns:196px 1fr;gap:20px;align-items:start}
/* The content column has to be allowed to be narrower than its widest table.
   A grid item's automatic minimum size is its content, so without this the
   Team table shoves the whole page sideways on a phone instead of scrolling
   inside its own .tablewrap card. */
.set-grid > div{min-width:0}
.set-nav{display:flex;flex-direction:column;gap:2px;position:sticky;top:0}
/* A gap opens ahead of each group of sections (TABS in screens/settings/
   index.js), which is how the order reads as daily, now and then, and set
   once, without a label saying so. Reset where the nav becomes a row. */
.set-nav a.grp{margin-top:12px}
/* The heading over each tab and the one line under it saying what the tab
   is for and what changing it affects. --text-2 on the page ground measures
   10.01:1, and the notes under the tables move off --faint (2.68:1 here)
   onto --muted (5.13:1). */
.set-head{margin:0 0 16px}
.set-head h2{font-size:17px;font-weight:600;letter-spacing:-.01em;line-height:1.25}
.set-lead{font-size:13.5px;color:var(--text-2);line-height:1.55;margin:5px 0 0;max-width:72ch}
.set-grid .hintline{color:var(--muted)}
.set-grid .hint{font-size:12px;color:var(--muted);line-height:1.45}
.set-nav a{display:flex;align-items:center;gap:9px;padding:9px 12px;border-radius:var(--radius-sm);
  font-size:13px;font-weight:500;color:var(--text-2);cursor:pointer;border:1px solid transparent}
.set-nav a:hover{background:var(--surface-2);color:var(--text)}
.set-nav a.on{background:var(--surface-3);color:var(--text);border-color:var(--line-2);font-weight:600}
.set-nav a .ic{width:16px;height:16px;flex:none;color:var(--muted)}
.set-nav a.on .ic{color:var(--accent-2)}
/* One mark on the nav, for the one tab that can be UNDONE: an account with no
   name or number for customers. Ink on the amber tint rather than amber text,
   so an 10.5px pill is read rather than squinted at, and the hairline carries
   the colour. It is rendered only while something is missing. */
.set-nav-flag{margin-left:auto;flex:none;font-size:10.5px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;padding:1px 7px;border-radius:999px;
  background:var(--warn-bg);color:var(--text);border:1px solid var(--warn)}
.set-sub{font-size:12.5px;color:var(--muted);margin:-2px 0 14px;line-height:1.5}
.swatch{display:inline-block;width:12px;height:12px;border-radius:4px;flex:none}
/* integration / toggle rows */
.set-rows{display:flex;flex-direction:column}
.set-row{display:flex;align-items:center;gap:14px;padding:14px 18px;border-bottom:1px solid var(--line)}
.set-row:last-child{border-bottom:none}
.set-row .ri{width:34px;height:34px;flex:none;border-radius:9px;background:var(--surface-2);color:var(--text-2);
  display:flex;align-items:center;justify-content:center}
.set-row .ri .ic{width:17px;height:17px}
.set-row .rt{flex:1;min-width:0}
.set-row .rt b{display:block;font-size:13.5px;font-weight:600}
.set-row .rt span{font-size:12px;color:var(--muted)}
.set-row .rmeta{font-family:var(--mono);font-size:12.5px;color:var(--text-2);white-space:nowrap}
/* on/off toggle */
.tgl{position:relative;width:38px;height:22px;border-radius:999px;background:var(--surface-2);border:1px solid var(--line-2);
  flex:none;cursor:pointer;transition:background var(--fast),border-color var(--fast)}
.tgl::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--faint);transition:left var(--fast),background var(--fast)}
.tgl.on{background:var(--accent-soft);border-color:var(--accent)}
.tgl.on::after{left:18px;background:var(--accent-2)}
/* small mono SLA input */
.sla-inp{width:74px;height:34px;text-align:right;font-family:var(--mono)}
/* the one stage whose thresholds do not reach every lead in it says so on
   its own row. Indented under the stage name, and held narrow so a long
   sentence cannot push the two number columns off a phone. */
.sla-note{margin:4px 0 0 26px;max-width:38ch;font-size:11.5px;line-height:1.4;color:var(--faint)}
.set-add{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;padding:14px 18px;border-top:1px solid var(--line)}
.set-add .fld{margin-bottom:0;flex:1;min-width:140px}
.av-sm{width:30px;height:30px;flex:none;border-radius:50%;background:var(--accent-soft);border:1px solid var(--line-2);
  color:var(--accent-2);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}

/* ---- My details, and the same pair on the Team table ---------------------
   What a CUSTOMER sees of an account: the name a seller reads in a text about
   a lead this person holds, and the number they are asked to ring. Two boxes
   and an example of the text they land in, because the whole question anybody
   has here is "what will a stranger actually read". */
.md-wrap{display:flex;flex-direction:column;gap:14px}
.md-card{padding:16px 18px}
.md-h b{display:block;font-size:13.5px;font-weight:600}
.md-h span{display:block;margin-top:4px;font-size:12.5px;color:var(--muted);line-height:1.5;max-width:72ch}
.md-fields{display:flex;gap:14px;flex-wrap:wrap;margin-top:14px}
/* Each box takes half the card and neither drops below a readable number:
   "0412 345 678" in a 120px input is a scroll, not a field. */
.md-fields .fld{flex:1 1 260px;min-width:0;margin-bottom:0}
.md-fields .hint{display:block;margin-top:6px;font-size:11.5px;color:var(--muted);line-height:1.45}
.md-why{margin-top:14px;font-size:12.5px;color:var(--text-2);line-height:1.5;max-width:72ch}
.md-act{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:14px;
  padding-top:14px;border-top:1px solid var(--line)}
.md-act-note{font-size:11.5px;color:var(--muted)}
/* The example. A text bubble, because that is where these two words end up,
   and a line the server would DROP is shown as dropped rather than as a
   sentence with a hole in it (services/missed_call.without_the_sentence). */
.md-eg-bubble{display:flex;flex-direction:column;gap:6px;margin-top:14px;padding:12px 14px;
  border-radius:var(--radius-sm);background:var(--bg-deep);border:1px solid var(--line);
  font-size:13px;line-height:1.5;color:var(--text)}
.md-eg-v{font-weight:700;color:var(--accent-2)}
.md-eg-gone{color:var(--muted);font-style:italic;
  padding-left:10px;border-left:2px solid var(--line-2)}
/* The nudge. Amber tint, ink text, and it is not rendered at all once both
   fields are set: nobody is told twice about something they have done. */
.md-nudge{display:flex;gap:10px;align-items:flex-start;padding:12px 14px;border-radius:var(--radius-sm);
  background:var(--warn-bg);color:var(--text);font-size:12.5px;line-height:1.55}
.md-nudge .ic{width:16px;height:16px;flex:none;margin-top:1px;color:var(--warn)}
/* The Team table's column. A whole team's worth has to be scannable, so the
   name sits on top and the number under it, and the accounts with nothing
   set carry the only colour in the column. */
.tm-cust{display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  background:none;border:0;padding:0;font:inherit;text-align:left;cursor:pointer;min-width:0}
.tm-cust b{font-weight:600;font-size:13px;border-bottom:1px dotted var(--line-2)}
.tm-cust small{font-size:11.5px;color:var(--muted)}
.tm-cust small.tm-cust-half{color:var(--warn);font-weight:600}
.tm-cust:hover b{border-bottom-color:var(--accent)}
.tm-cust-na{font-size:11.5px;color:var(--muted)}

@media(max-width:980px){
  .of-split{grid-template-columns:1fr}
  .rp-cols{grid-template-columns:1fr}
  .set-grid{grid-template-columns:1fr}
  .set-nav{flex-direction:row;flex-wrap:wrap;position:static}
  .set-nav a.grp{margin-top:0}
}

@media(max-width:980px){
  .rv-cols{grid-template-columns:1fr}
  .rv-grid{grid-template-columns:repeat(3,1fr)}
}
@media(max-width:720px){
  .rv-top{flex-wrap:wrap;gap:10px;padding:12px 16px}
  .rv-top-r{width:100%;margin-left:0}
  .rv-body{padding:16px}
  .rv-grid{grid-template-columns:repeat(2,1fr)}
  .rv-cond-row{flex-direction:column;align-items:stretch;gap:7px}
  .rv-cond-lbl{width:auto}
  .rv-facts{grid-template-columns:1fr}
}

/* ============================================================ RESPONSIVE
   Desktop-first. Tablet (≤960) = icon-rail sidebar + denser grids.
   Phone (≤640) = bottom tab bar replaces the sidebar; screens stack. */

/* ---- early grid relax (wide tablets / small laptops) ---- */
@media(max-width:1040px){
  .cc-stats{grid-template-columns:repeat(2,1fr)}
  .board{grid-template-columns:repeat(3,1fr)}
  .cc-cols{grid-template-columns:1fr}
}

/* ---- TABLET: the sidebar rail (642 to 960px) is NOT a media query any more.
   It is html.rail, set by js/shell.js before first paint and owned by
   setRail() after that, and it is the DEFAULT in this band. One trigger, one
   definition, and the operator can override it at any width. See the RAIL
   block in the SIDEBAR section. ---- */
@media(max-width:960px){
  .page{padding:20px 18px}
  .board{grid-template-columns:repeat(3,1fr)}
  .rv-grid{grid-template-columns:repeat(3,1fr)}
}

/* ---- PHONE: bottom tab bar, stacked screens (≤640px) ---- */
@media(max-width:640px){
  /* sidebar out, bottom bar in (app shell only — never on portal) */
  #app{display:block;height:auto;min-height:100vh;overflow:visible}
  .sidebar{display:none}
  /* The rail gutter goes with it. html.rail #view carries a 64px margin so
     that widening the fixed sidebar on hover cannot reflow the queue behind
     it, and that margin means nothing once the sidebar is display:none. Left
     in, every phone rendered the whole CRM into 326px of a 390px screen, a
     sixth of it held open for a sidebar that is not there. */
  html.rail #view{margin-left:0}
  #view{height:auto;min-height:100vh;overflow:visible}
  body:not(.portal):not(.auth) #view{padding-bottom:calc(64px + env(safe-area-inset-bottom,0))}
  body:not(.portal):not(.auth) .tabbar{
    display:flex;position:fixed;left:0;right:0;bottom:0;z-index:60;height:56px;
    background:var(--surface);border-top:1px solid var(--line);
    padding-bottom:env(safe-area-inset-bottom,0)}

  /* no iOS zoom — every editable control ≥16px */
  .input,.select,textarea.input,.searchbox input,.sla-inp,input,select,textarea{font-size:16px}
  .sla-inp{height:38px}

  /* page + headers reflow */
  .page{padding:16px 14px}
  .page-h{flex-direction:column;align-items:stretch;gap:12px}
  .page-h .right{margin-left:0;flex-wrap:wrap}
  .page-h h1{font-size:24px}
  .searchbox input{width:100%}

  /* Command Center: stats 2-up, board wraps, focus + Today/Hot rail stack */
  .cc-stats{grid-template-columns:repeat(2,1fr);gap:10px}
  .board{grid-template-columns:repeat(2,1fr);gap:10px}
  /* minmax(0,...) not 1fr. A grid item's automatic minimum is its min-content,
     so a 1fr track cannot shrink below the widest thing inside it. The focus
     row put four nowrap boxes on one line and floored the panel at 377px, and
     the track grew to match, which scrolled the whole home screen sideways:
     1px at 390, 31px at 360. The wrap below is what makes the row narrow, and
     this is what stops any future row doing the same thing again. */
  .cc-cols{grid-template-columns:minmax(0,1fr)}

  /* The focus row wraps on a phone. Age chip and vehicle keep the first line,
     stage chip and price take the second, and the chevron closes it out on
     the right. Unwrapped, the stage chip was drawn on top of the car name. */
  .focus-row{flex-wrap:wrap;gap:4px 10px}
  .focus-row .fv{flex:1 1 60%}
  .focus-row .chev{margin-left:auto}

  /* dense tables → horizontal scroll (keep the dense row layout) */
  .tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
  table.grid{min-width:560px}
  .inv-dest{min-width:200px}

  /* Cockpit: single column (progress → cards → centre → messages) */
  .ck-page{padding:14px}
  .ck-grid{grid-template-columns:1fr;gap:12px}
  /* one-word step labels — the 6-across stepper can't fit the full ones */
  .ck-step .l-full{display:none}
  .ck-step .l-short{display:inline}
  .ck-step .lbl{font-size:10.5px}
  .ck-left-col,.ck-centre,.ck-right-col{grid-column:1 / -1}
  .ck-right-col{position:static}
  .ck-right{max-height:none;position:static}
  .ck-top{flex-wrap:wrap;gap:8px}
  /* The vehicle title drops the display face on a phone rather than
     shrinking it. ELEVATION-KIT rule 1 puts a hard floor under
     Schibsted at 24px, and 24px Schibsted in the 247px title column
     a 375px screen leaves takes "2019 Toyota LandCruiser Prado GXL"
     to three lines where 20px Manrope takes two. That is about 37px,
     a line and a half of queue, pushed below the fold on every
     cockpit open, and the owner asked for density. Below the floor
     the two grotesks are not distinguishable anyway, so the face is
     what gives, not the size. */
  .ck-top-title .ck-veh{font-family:var(--font);font-size:20px;letter-spacing:-.02em}
  .ck-top-act{margin-left:0;width:100%}
  .ck-top-act .btn{flex:1;justify-content:center}
  /* The header is already tight at 375. The arrows keep their full thumb
     targets (.iconbtn is 40px here) because they are the control the owner
     asked for; what gives is the counter, which drops to "7/61" (the same
     full/short swap the progress rail uses a few lines up), and the car's
     title, which takes a line of its own so the stepper cannot squeeze the
     rego and stage chips into a stack. Only when the arrows are actually
     there: a lead opened with no queue behind it keeps the old header. */
  .ck-walk{margin-left:0;gap:2px}
  .ck-walk-n{min-width:0;padding:0 2px}
  .ck-walk .w-full{display:none}
  .ck-walk .w-short{display:inline}
  .ck-top.has-walk .ck-top-title{flex-basis:100%}

  /* Offers: master/detail stacks (list above, compare below) */
  .of-split{grid-template-columns:1fr;gap:14px}
  .of-list-b{flex-direction:row;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch}
  .of-item{flex:0 0 220px}

  /* Inspection report: photo grid → 1 column, body padding tighter */
  .rv-page{padding-bottom:32px}
  .rv-body{padding:14px}
  .rv-cols{grid-template-columns:1fr}
  .rv-grid{grid-template-columns:1fr}
  .rp-cols{grid-template-columns:1fr}

  /* Settings + reports: single column */
  .set-grid{grid-template-columns:1fr}
  .set-nav{flex-direction:row;flex-wrap:wrap;position:static}

  /* modals sit near the top so the on-screen keyboard can't hide the fields */
  .modal-back{align-items:flex-start;padding:12px}
  .modal{max-height:calc(100dvh - 24px)}
  /* toast clears the bottom tab bar so it never covers nav or the Undo action */
  body:not(.portal):not(.auth) #toast-root{bottom:calc(68px + env(safe-area-inset-bottom,0))}
  /* comfortable thumb targets for the most-tapped controls */
  .iconbtn{min-width:40px;min-height:40px}
  .btn.sm{padding:10px 14px}
  /* report top bar: don't stay stuck once it wraps (it ate scroll height) */
  .rv-top{position:static}
  /* the cockpit's bar wraps to three lines here and would eat the same height */
  .ck-top{position:static}
}

/* tiny phones — board to a single column so tiles stay legible */
@media(max-width:380px){
  .cc-stats{grid-template-columns:1fr}
  .board{grid-template-columns:1fr}
}

/* read/unread: NEW badge + unseen row accent + Unseen/All filter */
.new-badge{display:inline-block;font-size:10.5px;font-weight:800;letter-spacing:.07em;
  color:var(--accent-2);background:var(--accent-soft);border-radius:5px;padding:2px 6px;margin-right:2px;vertical-align:middle}
tr.unseen{background:rgba(110,108,242,.05)}
tr.unseen .vt{font-weight:700}
tr.unseen td:first-child{box-shadow:inset 3px 0 0 var(--accent)}
/* ---- New leads sub-stage bar (New / No answer / Follow up / Post follow up)
   Four steps of one lead's week, left to right, each with its live count,
   and Replied on the far end: the row badge as a filter. Deliberately NOT
   styled as another filter segment. Which pile you work is the first
   decision of the day, so it gets the number at full size and its own row
   above the filter bar. Every step is drawn at zero too, a count of nothing
   is still a place on the clock. A chevron in each gap says "then", so the
   four read as one week, and the selected step carries the same three marks
   a selected row does, the violet edge, the violet tint and the violet
   figure, so it cannot be mistaken for a hover. The tiles rest flat and
   lift on hover like every tile in the app (.btile). The container keeps
   its id and class (stg-buckets, bkt): stage.js and the tests know them,
   and a DOM hook is not the concept it draws. */
.stg-buckets{display:flex;align-items:stretch;gap:14px;margin:0 0 12px;container:stg-bar/inline-size}
.bkt-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;flex:1 1 auto;min-width:0}
.bkt{position:relative;display:flex;align-items:center;gap:12px;padding:12px 14px;text-align:left;cursor:pointer;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);min-width:0;
  transition:border-color var(--fast),background var(--fast),box-shadow var(--fast)}
.bkt:hover{border-color:var(--line-2);background:var(--surface-2);box-shadow:var(--shadow-card)}
/* the "then" between steps, drawn in the gap: a 7px chevron, its box
   centred on the 14px gap, in the same ink as the hint line under it */
.bkt-row .bkt:not(:last-child)::after{content:'';position:absolute;right:-10.5px;top:50%;width:7px;height:7px;
  border-top:1.5px solid var(--muted);border-right:1.5px solid var(--muted);
  transform:translateY(-50%) rotate(45deg);pointer-events:none}
/* 22px is the ceiling for --font (see the header) and tabular Manrope keeps
   a 9 and a 12 the same width, so the tiles do not shift as counts move */
.bkt .bkt-n{font-size:22px;font-weight:700;color:var(--text);line-height:1;min-width:1.4em;flex:none}
.bkt .bkt-sk{width:1.2em;height:14px;margin:0}
.bkt .bkt-t{display:flex;flex-direction:column;gap:2px;min-width:0}
/* the name may wrap: it is the point of the tile, and a name out of room
   painted on under the next tile instead (see the stg-bar container below) */
.bkt .bkt-t b{display:inline-flex;align-items:center;gap:5px;font-size:13px;font-weight:600;color:var(--text)}
.bkt .bkt-t b .ic{width:13px;height:13px;flex:none}
.bkt .bkt-t span{font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bkt.on{border-color:var(--accent);background:var(--accent-soft);box-shadow:inset 3px 0 0 var(--accent)}
.bkt.on:hover{box-shadow:inset 3px 0 0 var(--accent),var(--shadow-card)}
.bkt.on .bkt-n,.bkt.on .bkt-t b{color:var(--accent-2)}
/* New is the day's work, so it reads as the live one even unselected */
.bkt.primary .bkt-n{color:var(--accent-2)}
/* Replied: the row badge, made a step. Red only while somebody is waiting,
   the way the SLA chip goes red for the same seller; plain when nobody is,
   and the count stays because zero replies is information too. */
.bkt.rp{flex:0 0 auto;min-width:176px}
.bkt.rp .bkt-t b .ic{color:var(--muted)}
.bkt.rp.has{background:var(--bad-bg);border-color:transparent}
.bkt.rp.has .bkt-n,.bkt.rp.has .bkt-t b,.bkt.rp.has .bkt-t b .ic{color:var(--bad)}
.bkt.rp.has:hover{background:color-mix(in srgb,var(--bad) 8%,var(--bad-bg))}
.bkt.rp.on{border-color:var(--bad);background:var(--bad-bg);box-shadow:inset 3px 0 0 var(--bad)}
.bkt.rp.on:hover{box-shadow:inset 3px 0 0 var(--bad),var(--shadow-card)}
.bkt.rp.on .bkt-n,.bkt.rp.on .bkt-t b,.bkt.rp.on .bkt-t b .ic{color:var(--bad)}
/* Contacted's bar: To book and Follow up contacted. Two steps get two
   halves of the row, not two quarters of a four step grid with the rest
   missing, and no chevron, because a lead moves both ways between them (Park
   sends it right, Reached them brings it back), so "then" would be a lie.
   Follow up contacted carries its due split at the far end of the tile, in
   the DUE column's own marks, so a broken promise reads from To book. */
.bkt-row.two{grid-template-columns:repeat(2,minmax(0,1fr))}
.bkt-row.two .bkt:not(:last-child)::after{content:none}
/* The story and the due split wrap as one box beside the count. Each goes on
   the line at its whole width, so the split sits at the far end while both
   fit and drops under the story, lined up with it, the moment they do not.
   A breakpoint could not know when that is: the tile is half a row that the
   sidebar widens and narrows, and the split grows with its counts. Pinned to
   one line instead, "Follow up contacted" painted over "5 overdue" from the
   phone layout up to a 1024 laptop. */
.bkt-body{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;flex:1 1 auto;min-width:0}
.bkt-body .bkt-t{flex:1 1 auto;max-width:100%}
.bkt-due{display:flex;flex-wrap:wrap;align-items:center;gap:4px 14px;flex:0 1 auto;min-width:0;
  font-size:12px;line-height:1.2;color:var(--text);white-space:nowrap}
.bkt-due .due-dot{margin-right:6px}
.bkt-due .due-later{color:var(--muted);font-weight:500}
@media (max-width:760px){
  /* a phone gets a second layout, not the desktop one squeezed: two steps a
     row, still read left to right then down, and Replied as a full width
     strip under them. The chevrons go, a "then" that turns a corner is
     noise; the hints stay, the story is the point. */
  .stg-buckets{flex-direction:column;gap:8px}
  .bkt-row{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  .bkt-row .bkt:not(:last-child)::after{display:none}
  .bkt{gap:10px;padding:10px 12px}
  .bkt .bkt-n{font-size:20px}
  /* two across, a hint wraps rather than clips: the story is the point */
  .bkt .bkt-t span{white-space:normal}
  .bkt.rp{min-width:0}
  /* Contacted's two stack, one full width row each. Two across would give
     "Follow up contacted" 170px, and the name, its story and the due split
     would wrap to four lines of a tile nobody can read at a glance. */
  .bkt-row.two{grid-template-columns:minmax(0,1fr)}
  /* the due split needs no rule of its own here: .bkt-body drops it under
     the story whenever the two do not fit side by side */
}
/* New leads' four steps two by two, with Replied still beside them, once the
   bar is too narrow for four names in a row. The bar is its own container
   because a viewport breakpoint cannot know its width: the sidebar decides
   it, and pinned wide at 1024 it left a 720px bar where "Post follow up" was
   cut to "Post follow u" under Replied. 928px is the row they need with
   three digit counts: four tiles of 42px padding, border and gap, a 41px
   count and the 87px name, the three gaps between them, then Replied.
   Replied stays beside the four, running the height of both rows, so the
   bar is two tiles tall on a laptop and not the phone's three. The chevrons
   go as they do on a phone, because one would turn a corner and another
   would point at Replied. */
@container stg-bar (max-width:927px){
  .bkt-row{grid-template-columns:repeat(2,minmax(0,1fr))}
  .bkt-row .bkt:not(:last-child)::after{display:none}
}

/* how many times we actually rang, beside the age chip */
.try-chip{display:inline-flex;align-items:center;gap:4px;margin:0;
  font-family:var(--mono);font-size:11px;font-weight:600;color:var(--muted);
  background:var(--surface-2);border-radius:6px;padding:2px 6px;white-space:nowrap}
.try-chip .ic{width:11px;height:11px}
.try-chip .sub{font-weight:500;opacity:.72}

/* Replied on a row: the same glyph and word as the bar's step, the NEW
   badge's geometry (they share the identity line) in the SLA red, and a red
   edge on the first cell that outranks the unseen violet below its rule
   here, because a reply matters more than a first look. The row says "this
   person wants to talk to you" before a word of it is read. */
.replied-badge{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:800;letter-spacing:.07em;
  text-transform:uppercase;color:var(--bad);background:var(--bad-bg);border-radius:5px;padding:2px 7px 2px 6px;
  margin-right:2px;vertical-align:middle;white-space:nowrap;flex:none}
.replied-badge .ic{width:11px;height:11px}
tr.replied td:first-child{box-shadow:inset 3px 0 0 var(--bad)}

/* the missed call clock (New leads, the rung views): seven segments for the
   seven texts, the tally under them, how long since the miss under that. The
   tally went under the track so the column is as wide as "4 of 6, stopped"
   and not the track and the tally side by side, which is what let the rung
   views fit at 1440 with the sidebar open. Three lines of 11px sit inside
   the row the two rows of buttons already set. Violet
   for a text the CRM has sent, it is the CRM working, not a warning; the
   hairline where one is still to go. Once a reply has stopped the sequence
   the word turns red and the track stays as it was: a red track would read
   as a failure on a lead that has just come good. */
.sq{display:flex;flex-direction:column;gap:3px;line-height:1.25}
.sq-top{display:flex;flex-direction:column;align-items:flex-start;gap:3px}
.sq-track{display:inline-flex;gap:2px;flex:none}
.sq-seg{width:9px;height:4px;border-radius:2px;background:var(--line-2)}
.sq-seg.on{background:var(--accent)}
/* The id of another card, drawn as the way to open it. Underlined on hover
   only, so a dense queue row does not gain a second permanent rule through
   it, and it carries the colour of the words around it rather than the link
   blue, because it IS the label. */
.lead-go{color:inherit;text-decoration:none;border-bottom:1px dotted currentColor}
.lead-go:hover,.lead-go:focus-visible{text-decoration:underline;border-bottom-color:transparent}
.sq-lb{font-size:11px;font-weight:600;color:var(--text-2);white-space:nowrap}
.sq.stopped .sq-lb{color:var(--bad)}
/* Twilio says our texts are not arriving on this number. The same red a
   stopped sequence gets, because both mean the office has to pick up a phone,
   and a colour of its own here would be a third thing to learn for a state
   that asks for the same action. */
.sq.done .sq-lb{color:var(--muted)}
/* texts that are over without this card sending them, "texts on L-4091" or
   "1 of 7, ended": muted like a finished run, never red, nothing failed */
.sq.ended .sq-lb{color:var(--muted)}
.sq-sub{font-size:11px;color:var(--muted);white-space:nowrap}

/* who holds the lead (every queue), the third line of the Seller cell. Inside
   .cust because that cell is capped at 190px, so a display name of any length
   cannot widen the table: as a column of its own it cost between 90 and 138px
   and the New leads views, which fit 1440 with the sidebar open by 10px of
   cell padding and a Vehicle cell that gives way, had none to give. The glyph
   is what keeps a name on OUR side from reading as a second seller. A lead
   nobody holds is the common case on production, so Nobody is quiet ink
   rather than the amber the car's page gives it: a state, not fifty alarms. */
.cust .hb{display:flex;align-items:center;gap:4px;min-width:0;margin-top:2px;
  font-size:11.5px;font-weight:600;color:var(--text-2)}
.cust .hb .ic{width:11px;height:11px;flex:none;opacity:.75}
.hb-n{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cust .hb.me{color:var(--accent-2)}
.cust .hb.none,.cust .hb.gone{font-weight:500;color:var(--muted)}
/* an account that has been disabled: it speaks for nothing, so the row may
   not read as looked after (services/allocation.speaks_for) */
.hb-tag{font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  color:var(--warn);flex:none}

.seg-filter{display:inline-flex;background:var(--surface-2);border:1px solid var(--line);border-radius:9px;padding:2px;gap:2px}
.seg-filter .segf{font-size:12px;font-weight:600;color:var(--muted);background:transparent;border:none;border-radius:7px;padding:5px 11px;cursor:pointer}
/* the selected segment carried its whole signal in text colour, on a track
   three percent lighter than the button. This is the primary brand switch on
   the queues, Reports and Records, so give it a real edge and a lift. Inset
   shadow, not a border: a border would resize the button and shift the row. */
.seg-filter .segf.on{background:var(--surface-3);color:var(--text);
  box-shadow:inset 0 0 0 1px var(--line-2),0 1px 2px rgba(16,24,40,.10)}
.seg-filter .segf .mono{opacity:.7;margin-left:2px}
/* A segment count still on its way. Sized in em off the button's own font so
   it holds roughly the width two digits take, which is what stops the row
   shifting under the cursor when the real figures land. Its own colour, not
   the skeleton's: this track is already --surface-2, so the shared bar is
   invisible on the segments nobody has selected, which is most of them. */
.seg-filter .segf .seg-sk{display:inline-block;width:1.2em;height:9px;
  vertical-align:middle;margin:0;background:var(--line-2)}
.sortby{display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:600;color:var(--muted)}
.sortby .select{width:auto;height:32px;font-size:12.5px;color:var(--text);padding:0 30px 0 11px;background-position:right 9px center;border-radius:8px}

/* ===== stage filter bar (brand / search / sort + the collapsible row) =====
   Two rows under the page header, above the table. Deliberately NOT sticky:
   the table already scrolls inside #view and a sticky bar costs vertical
   space on a laptop. Both rows wrap, so they reflow instead of overflowing. */
.page-h.stg-h{margin-bottom:13px}
.stg-filters{display:flex;flex-direction:column;gap:8px;margin:0 0 12px}
.stg-frow{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
/* the search box absorbs whatever room row 1 has left, up to a sane cap, so
   the placeholder stays readable at 1440 and the row still holds one line on a
   1366 laptop instead of dropping a lonely control onto a second line */
.stg-search{flex:1 1 260px;max-width:340px;min-width:0}
.stg-search input{width:100%;height:34px}
.stg-frow .flex1{flex:1 1 0}
.stg-fl{display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:600;color:var(--muted)}
.stg-num{height:32px;width:88px;font-size:12.5px;background:var(--surface)}
.stg-src{width:auto;max-width:132px;height:32px;font-size:12.5px;background-color:var(--surface);padding:0 30px 0 11px;background-position:right 9px center;border-radius:8px}
/* longest option is "Opened, not finished", which will not fit a source-sized box */
.stg-form{max-width:178px}
/* a campaign name runs longer than any source or form state */
.stg-camp{max-width:240px}
/* the collapsible row is a drawer, not a second toolbar: at 1440 it wraps to
   two lines and a bare wrap reads as a broken row, so give it a surface */
.stg-more-row{background:var(--surface-2);border:1px solid var(--line);border-radius:11px;padding:9px 11px;gap:9px 16px}
.stg-more-row .segf{padding:5px 9px}
.stg-more-row .seg-filter{background:var(--surface);border-color:var(--line-2)}
.stg-more{position:relative}
.stg-more .stg-n{margin-left:2px;min-width:18px;height:18px;padding:0 5px;border-radius:9px;
  background:var(--accent);color:#fff;font-size:11px;font-weight:700;display:inline-flex;
  align-items:center;justify-content:center}
.stg-more-row[hidden]{display:none}
/* the result line: the ONE place the filtered number appears, plus a removable
   chip per active filter. Somebody who filters, walks away and comes back must
   see instantly why the screen is short, and get out of it in one click. */
.stg-result{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 0 10px;font-size:12.5px;color:var(--muted)}
.stg-result b{color:var(--text);font-weight:700}
.stg-chip{display:inline-flex;align-items:center;gap:4px;font-size:11.5px;font-weight:600;
  background:var(--accent-soft);color:var(--accent-2);border-radius:999px;padding:3px 4px 3px 10px}
.stg-chip button{border:none;background:transparent;color:inherit;cursor:pointer;
  display:inline-flex;padding:2px;border-radius:50%}
.stg-chip button:hover{background:rgba(66,58,156,.14)}
.stg-chip .ic{width:12px;height:12px}
.stg-note{color:var(--faint)}
.stg-esum{margin-bottom:12px}
.empty .btn{margin-top:2px}
/* the way out of a filtered empty queue can be two buttons, and they need a
   real gap side by side and when they stack on a phone */
.empty-acts{display:flex;flex-wrap:wrap;justify-content:center;gap:8px}
/* the way OUT of a filtered view has to look like a control. A transparent
   ghost beside three solid chips reads as a caption, not a button. */
.btn.stg-clear{border-color:var(--line-2);background:var(--surface);color:var(--text-2)}
.btn.stg-clear:hover{border-color:var(--accent);color:var(--accent-2)}
/* Mark-seen renders into two slots and exactly one is shown: row 1 on a
   desktop, the bottom of the drawer on a phone. Empty (nothing unseen in the
   filtered set) collapses, or the flex item still eats a gap. */
.stg-markslot:empty{display:none}
.stg-mark-drawer{display:none}
@media(max-width:760px){
  /* phone: everything full width, segments spread so they stay tappable */
  .stg-search{flex:1 1 100%;max-width:none}
  .stg-search input{width:100%;height:38px}
  .stg-frow > .seg-filter{flex:1 1 100%}
  /* flex:1 1 auto, never flex:1: equal-width segments force "The Car Buyers"
     to wrap inside its own button */
  .stg-frow > .seg-filter .segf{flex:1 1 auto;text-align:center;white-space:nowrap;padding:7px 9px}
  .stg-fl{flex:1 1 100%;flex-wrap:wrap}
  .stg-fl > span{flex:1 1 100%}
  .stg-fl > .seg-filter{flex:1 1 100%}
  .stg-fl > .seg-filter .segf{flex:1 1 auto;text-align:center;white-space:nowrap}
  /* the drawer's own segments were 24px tall next to 38px inputs. Match them. */
  .stg-more-row .segf{padding:10px 9px}
  /* min-width:0 or the pair stacks: an input's min-content width is its size
     attribute (about 20 characters), which two of will never share a line */
  .stg-num,.stg-src{flex:1 1 0;width:auto;min-width:0;max-width:none;height:38px}
  .stg-more,.sortby{flex:1 1 auto}
  .sortby .select{flex:1;width:auto;height:38px}
  .stg-frow > .btn{flex:1 1 auto;justify-content:center}
  /* the drawer OVERLAYS the queue instead of pushing it down. Pushed down it
     was 356px of filter panel above the first lead in an 812px phone, which
     is a screen with zero leads on it. Anchored to .stg-filters, so it opens
     directly under row 1 and closes from the same More filters button. */
  .stg-filters{position:relative}
  .stg-more-row{position:absolute;left:0;right:0;top:100%;z-index:40;margin-top:6px;
    background:var(--surface);box-shadow:var(--shadow-pop);max-height:68vh;overflow:auto}
  .stg-mark-bar{display:none}
  .stg-mark-drawer{display:flex;flex:1 1 100%}
  .stg-mark-drawer .btn{flex:1;justify-content:center;min-height:40px;
    border-color:var(--line-2);background:var(--surface)}
  /* the chip close buttons were 16x16, three abreast, on a touch screen. The
     pseudo-element grows the hit area without changing the chip's layout. */
  .stg-chip{padding:5px 5px 5px 11px;font-size:12px}
  .stg-chip button{padding:5px;position:relative}
  .stg-chip button::after{content:'';position:absolute;left:50%;top:50%;
    width:44px;height:44px;transform:translate(-50%,-50%)}
  .btn.stg-clear{min-height:36px}
}

/* stage rows: the relative age chip with the try chip beside it, and the
   exact arrival moment on a second line under the two. Two lines, never
   three: all three stacked set a 96px row while the Vehicle cell that
   carries the identifying facts needed 68. All three on one line was the
   fix for that, and at about 280px it became the widest column in the
   queue, which at 1440 with the sidebar open pushed the facts under the
   pinned actions. Two lines is no taller than the Vehicle cell beside it,
   and each line is held whole because inline boxes still break between
   themselves in a squeezed column. The one exception is a fitted queue
   squeezed for room (stg-rows, under STAGE PAGE), where the try chip goes
   under the age chip rather than take its width from the Vehicle cell.
   Measured at 1440 with the sidebar open it made no row taller, since the
   squeezed Vehicle cell beside it was taller still, and without it 40 to
   70px of Phone went under the pin. */
.age-col{display:inline-flex;flex-direction:column;align-items:flex-start;gap:4px}
.age-top{display:inline-flex;align-items:center;gap:6px}
td:has(> .age-col){white-space:nowrap}
.age-exact{font-size:11px;color:var(--muted);white-space:nowrap;letter-spacing:.01em}

/* real photos — report tiles + cockpit gallery */
.rv-tile-ph.has-img{opacity:1;position:absolute;inset:0;display:flex}
.rv-tile-ph.clickable{cursor:pointer}
.rv-tile-ph.clickable:not(.has-img):hover{opacity:.9;color:var(--accent-2)}
.rv-tile-img{width:100%;height:100%;object-fit:cover;display:block}
.rv-tile-addbtn{cursor:pointer;border-style:dashed;border-color:var(--line-2)}
.rv-tile-addbtn:hover{border-color:var(--accent);color:var(--accent-2)}
.rv-tile-addbtn .rv-tile-ph{opacity:.8}
.ck-phs{display:grid;grid-template-columns:repeat(4,1fr);gap:7px;padding:2px 0 4px}
.ck-ph{position:relative;aspect-ratio:1/1;border-radius:8px;overflow:hidden;border:1px solid var(--line);
  background:var(--bg-deep);display:flex;align-items:center;justify-content:center}
.ck-ph img{width:100%;height:100%;object-fit:cover;display:block}
.ck-ph.add{cursor:pointer;border-style:dashed;border-color:var(--line-2);color:var(--muted)}
.ck-ph.add:hover{border-color:var(--accent);color:var(--accent-2)}
.ck-ph.add .ic{width:18px;height:18px}

/* ============================================================
   KEY/VALUE ROWS
   All that is left of the Phase 1 in-app paperwork portal, because
   Records reuses these three: .review-row and .specs draw the car
   and the money on a purchase card (records.js), .hintline carries
   the small grey note under a field in six places. They stay at
   this point in the file rather than moving up with the rest of the
   shared components, because their position is what decides which
   of two rules wins and a move is not a deletion.
   ============================================================ */
.review-row{display:flex;justify-content:space-between;padding:9px 0;border-bottom:1px solid var(--line);font-size:13.5px}
.review-row .k{color:var(--muted)} .review-row .v{font-weight:600}
.specs{display:grid;grid-template-columns:1fr 1fr;gap:0 26px}
.specs .review-row{padding:8px 0}
.hintline{font-size:11.5px;color:var(--faint);margin-top:8px;line-height:1.45}

@media (max-width:640px){ .specs{grid-template-columns:1fr} }

@media print{
  .sidebar,.tabbar,#toast-root,#modal-root{display:none!important}
  #view{overflow:visible}
  body{background:#fff;padding:0}
  @page{size:A4 portrait;margin:0}
}

/* ---- Phase C: inspector-capture review extras (report admin view) ---- */
.rv-skip{display:flex;align-items:center;gap:10px;background:var(--warn-bg);
  border:1px solid rgba(244,182,90,.45);color:var(--warn);border-radius:10px;
  padding:12px 14px;margin-bottom:12px;font-size:13.5px}
.rv-skip .ic{width:18px;height:18px;flex:none}
.rv-skip b{font-weight:700}
.rv-skip span{color:var(--muted)}
.rv-rt-row{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.rv-rt{font-size:12px;font-weight:700;border-radius:7px;padding:4px 9px;text-transform:capitalize}
.rv-rt.ok{background:var(--ok-bg);color:var(--ok)}
.rv-rt.iss{background:var(--bad-bg);color:var(--bad)}
.rv-rt .ic{width:13px;height:13px;margin-left:5px}
.rv-rt-note{margin-top:8px;font-size:13px;color:var(--muted)}
.rv-price-set{display:flex;gap:8px;margin-top:10px}
.rv-price-set .input{flex:1}
.rv-price-cap{margin-top:8px;font-size:12.5px;color:var(--muted)}

/* ---- DTPicker: calendar + time popover (js/datetime.js) ---- */
.dtp{position:fixed;z-index:9999;width:302px;max-width:calc(100vw - 16px);
  --dtp-bg:var(--surface-2,#1b1d24);--dtp-elev:var(--surface-3,#23262f);
  --dtp-line:var(--line,#2b2e38);--dtp-tx:var(--text,#e9eaf0);
  --dtp-mut:var(--muted,#8b8e99);--dtp-acc:var(--accent);
  background:var(--dtp-bg);border:1px solid var(--dtp-line);border-radius:14px;
  box-shadow:var(--shadow-pop,0 18px 48px rgba(17,19,24,.22));padding:12px;color:var(--dtp-tx);
  font-size:13.5px;-webkit-font-smoothing:antialiased}
.dtp-head{display:flex;align-items:center;gap:4px;margin-bottom:8px}
.dtp-nav{width:34px;height:34px;border:none;background:transparent;color:var(--dtp-mut);
  font-size:20px;border-radius:9px;cursor:pointer;line-height:1}
.dtp-nav:hover{background:var(--dtp-elev);color:var(--dtp-tx)}
.dtp-title{flex:1;height:34px;border:none;background:transparent;color:var(--dtp-tx);
  font-weight:700;font-size:14px;cursor:pointer;border-radius:9px}
.dtp-title:hover{background:var(--dtp-elev)}
.dtp-wd{display:grid;grid-template-columns:repeat(7,1fr);margin-bottom:2px}
.dtp-wd span{text-align:center;font-size:11px;font-weight:700;color:var(--dtp-mut);padding:4px 0}
.dtp-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}
.dtp-day{height:36px;border:none;background:transparent;color:var(--dtp-tx);border-radius:9px;
  font-size:13.5px;font-weight:600;cursor:pointer}
.dtp-day:hover{background:var(--dtp-elev)}
.dtp-day.other{color:var(--dtp-mut);opacity:.45}
.dtp-day.today{box-shadow:inset 0 0 0 1.5px var(--dtp-acc)}
.dtp-day.sel{background:var(--dtp-acc);color:#fff}
.dtp-years{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;padding:4px 0}
.dtp-yr{height:46px;border:none;background:var(--dtp-elev);color:var(--dtp-tx);border-radius:9px;
  font-weight:700;font-size:14px;cursor:pointer}
.dtp-yr:hover{outline:1.5px solid var(--dtp-acc)}
.dtp-yr.sel{background:var(--dtp-acc);color:#fff}
.dtp-time{margin-top:10px;padding-top:10px;border-top:1px solid var(--dtp-line)}
.dtp-time-lb{display:block;font-size:11px;font-weight:700;color:var(--dtp-mut);margin-bottom:6px}
.dtp-time-ctl{display:flex;align-items:center;gap:6px}
.dtp-sel{height:38px;border:1px solid var(--dtp-line);background:var(--dtp-elev);color:var(--dtp-tx);
  border-radius:9px;padding:0 8px;font-size:14px;font-weight:600;cursor:pointer}
.dtp-colon{font-weight:700;color:var(--dtp-mut)}
.dtp-ap{height:38px;min-width:44px;border:1px solid var(--dtp-line);background:var(--dtp-elev);
  color:var(--dtp-mut);border-radius:9px;font-weight:700;font-size:13px;cursor:pointer}
.dtp-ap.on{background:var(--dtp-acc);border-color:var(--dtp-acc);color:#fff}
.dtp-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.dtp-chip{height:30px;padding:0 10px;border:1px solid var(--dtp-line);background:transparent;
  color:var(--dtp-mut);border-radius:8px;font-weight:600;font-size:12.5px;cursor:pointer}
.dtp-chip:hover{color:var(--dtp-tx)}
.dtp-chip.on{background:var(--dtp-acc);border-color:var(--dtp-acc);color:#fff}
.dtp-foot{display:flex;align-items:center;gap:8px;margin-top:12px;padding-top:10px;border-top:1px solid var(--dtp-line)}
.dtp-quick{height:34px;padding:0 12px;border:1px solid var(--dtp-line);background:transparent;
  color:var(--dtp-tx);border-radius:9px;font-weight:600;font-size:12.5px;cursor:pointer}
.dtp-quick:hover{background:var(--dtp-elev)}
.dtp-done{height:34px;padding:0 18px;border:none;background:var(--dtp-acc);color:#fff;
  border-radius:9px;font-weight:700;font-size:13px;cursor:pointer}
/* the trigger inputs read as buttons */
input[data-datetime],input[data-date]{cursor:pointer}

/* ---- Report-in: inspector-condition + office-facts reconciliation ---- */
.rv-cond-note{display:block;font-size:11.5px;color:var(--muted);font-weight:400;margin-top:2px;font-style:italic}
.rv-cond-skip{font-size:12.5px;font-weight:600;color:var(--warn)}
.rv-keys{display:inline-flex;gap:6px;align-items:center}
.rv-keys .input{width:64px;height:32px}

/* ---- Phase D: send-to-wholesalers modal + bidding panel ---- */
.rv-send-cap{font-size:12.5px;color:var(--muted);margin-bottom:12px;line-height:1.5}
.rv-send-cap b{color:var(--text)}
.rv-send-list{display:flex;flex-direction:column;gap:2px;max-height:280px;overflow-y:auto;margin:0 -6px}
.rv-send-row{display:flex;align-items:center;gap:10px;padding:9px 6px;border-radius:8px;cursor:pointer}
.rv-send-row:hover{background:var(--surface-2)}
.rv-send-row input{width:16px;height:16px;accent-color:var(--accent)}
.rv-send-nm{font-weight:600;font-size:13.5px;flex:1;min-width:0}
.rv-send-ct{font-size:11.5px;color:var(--muted)}
.rv-send-add{display:flex;gap:8px;margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}
.rv-send-add .input{height:34px;font-size:12.5px}
.rv-send-add .input:first-child{flex:1.2}
.rv-send-add .input:nth-child(2){flex:1}
/* W1a send screen: car header, deadline chips, message, per buyer results */
.rv-send-car{display:flex;gap:12px;align-items:center;margin-bottom:12px}
.rv-send-ph{width:74px;height:56px;object-fit:cover;border-radius:9px;border:1px solid var(--line)}
.rv-send-meta{display:flex;gap:10px;color:var(--muted);font-size:12px;margin-top:2px}
.rv-send-warn{color:var(--warn);font-size:12px;margin-top:4px}
.rv-send-dl{display:flex;align-items:center;gap:10px;margin:10px 0;font-size:12.5px;color:var(--muted);flex-wrap:wrap}
.rv-dl-h{width:76px;height:32px}
.rv-dl-when{color:var(--text-2);font-weight:600}
.rv-send-noph{color:var(--faint);font-size:11.5px}
.rv-send-msg{margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}
.rv-res{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:600}
.rv-res.ok{color:var(--ok)}
.rv-res.bad{color:var(--bad)}
.rv-res.grey{color:var(--muted)}
.rv-bid-err{color:var(--bad);font-size:12.5px;font-weight:600;margin-top:10px}
.rv-links{display:flex;flex-direction:column;gap:8px}
.rv-link-row{display:flex;align-items:center;gap:10px;background:var(--surface-2);border:1px solid var(--line);border-radius:10px;padding:10px 12px}
.rv-link-t{flex:1;min-width:0}
.rv-link-t b{display:block;font-size:12.5px}
.rv-link-url{display:block;font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}
.rv-invs{display:flex;flex-direction:column}
.rv-inv-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line)}
.rv-inv-row:last-child{border-bottom:0}
.rv-inv-ws{font-weight:600;font-size:13px;flex:1;min-width:0}
.rv-inv-st{font-size:12px}
.rv-inv-st.bid{color:var(--ok);font-weight:700}
.rv-inv-st.seen{color:var(--accent-2)}
.rv-inv-st.sent{color:var(--muted)}
.rv-inv-st.dim{color:var(--faint,var(--muted));text-decoration:line-through}
.rv-inv-acts{display:flex;gap:6px}
.rv-close-bids{margin-top:10px}
.btn.danger-ghost{color:var(--bad)}
.rv-cond-note-in{height:30px;font-size:11.5px;margin:4px 0 8px;font-style:italic}

/* ---- Phase D pt 2: cockpit Paperwork panel + stage back-nav ---- */
.ck-pwc{display:flex;flex-direction:column;gap:5px;margin:4px 0 10px}
.ck-pwc-row{display:flex;align-items:center;gap:8px;font-size:12.5px}
.ck-pwc-row .ic{width:13px;height:13px;flex:none}
.ck-pwc-row.ok{color:var(--muted)}
.ck-pwc-row.ok .ic{color:var(--ok)}
.ck-pwc-row.no{color:var(--bad);font-weight:600}
.ck-pwi-row{display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:4.5px 0;font-size:12.5px}
.ck-pwi-k{color:var(--text)}
.ck-pwi-st{font-size:12px;flex:none}
.ck-pwi-st.ok{color:var(--ok);font-weight:700}
.ck-pwi-st.seen{color:var(--accent-2)}
.ck-pwi-st.sent{color:var(--muted)}
.ck-pwi-st.dim{color:var(--muted);text-decoration:line-through}
.ck-step.done[data-action]{cursor:pointer;border-radius:7px}
.ck-step.done[data-action]:hover{background:var(--surface-2)}
.ck-step.done[data-action]:hover .lbl{color:var(--accent-2);text-decoration:underline}

/* ===== Paperwork tab (app/screens/_paperwork.js) =====
   A header that says where the deal is, then a grid of equal cards. The old
   panel was one card of full width label/value rows, which is what made it
   read small: the content was tiny against its container. */
.pw-tab{display:flex;flex-direction:column;gap:12px}
.pw-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;align-items:start}

.pwh{padding:16px 18px}
.pwh-top{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.pwh-t{font-size:17px;font-weight:700;margin:0}
.pwh-who{margin-left:auto;font-size:12px;color:var(--muted)}
.pwh-badge{font-size:11px;font-weight:700;padding:3px 9px;border-radius:6px}
.pwh-badge.ok{background:var(--ok-bg);color:var(--ok)}
.pwh-badge.mid{background:var(--accent-soft);color:var(--accent-2)}
.pwh-badge.bad{background:var(--bad-bg);color:var(--bad)}
.pwh-rail{display:flex;gap:8px;margin-top:14px}
.pwh-bead{flex:1;min-width:0}
.pwh-bar{display:block;height:3px;border-radius:2px;background:var(--line);
  transform-origin:left;animation:pwh-fill .5s ease both}
.pwh-bead.on .pwh-bar{background:var(--ok)}
.pwh-bead.skip .pwh-bar{background:repeating-linear-gradient(90deg,var(--line) 0 4px,transparent 4px 8px)}
.pwh-lb{display:block;font-size:11px;margin-top:5px;color:var(--faint);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pwh-bead.on .pwh-lb{color:var(--ok);font-weight:600}
.pwh-next{display:flex;align-items:center;gap:12px;margin-top:14px;padding-top:13px;border-top:1px solid var(--line)}
.pwh-words{font-size:13px;color:var(--text-2)}
.pwh-go{margin-left:auto;flex:none}
@keyframes pwh-fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}

.pwc{padding:0;overflow:hidden}
.pwc-h{padding:11px 15px;border-bottom:1px solid var(--line);background:var(--bg-deep);
  font-size:11.5px;font-weight:700;color:var(--muted);letter-spacing:.05em;text-transform:uppercase}
.pwc-b{padding:14px 15px}
.pw-quiet{color:var(--muted);font-size:12.5px;line-height:1.6}
.pw-quiet b{display:block;color:var(--text);margin-bottom:3px}

.pw-name{font-size:16px;font-weight:700}
.pw-sub{font-size:12.5px;color:var(--muted);margin-top:2px}
.pw-shots{display:flex;gap:9px;margin-top:13px}
.pw-shot{flex:1;margin:0;min-width:0}
.pw-shot img{width:100%;height:74px;object-fit:cover;border-radius:8px;border:1px solid var(--line);
  display:block;cursor:zoom-in;transition:box-shadow var(--fast)}
.pw-shot img:hover{box-shadow:var(--shadow-card)}
.pw-shot figcaption{font-size:11px;margin-top:5px}
.pw-shot.none{height:74px;border:1px dashed var(--line);border-radius:8px;display:flex;
  flex-direction:column;align-items:center;justify-content:center;gap:3px;color:var(--faint);font-size:11px}
.pw-shot-x{display:inline-flex;width:18px;height:18px;border-radius:50%;background:var(--bad-bg);
  color:var(--bad);align-items:center;justify-content:center}
.pw-shot-x .ic{width:11px;height:11px}
.pw-ok{color:var(--ok);font-weight:600;display:inline-flex;align-items:center;gap:3px}
.pw-vbtn{background:none;border:0;padding:0;color:var(--accent-2);font:inherit;font-size:11px;
  font-weight:600;cursor:pointer;text-decoration:underline}
.pw-dl{display:grid;grid-template-columns:92px 1fr;gap:3px 8px;margin:13px 0 0;
  padding-top:12px;border-top:1px solid var(--line);font-size:12.5px}
.pw-dl dt{color:var(--muted)}
.pw-dl dd{margin:0}
.pw-more{margin-top:12px}

.pw-amt{display:flex;align-items:baseline;gap:8px}
.pw-amt .v{font-size:22px;font-weight:700}
.pw-amt .k{font-size:12px;color:var(--muted)}
.pw-bank{background:var(--bg-deep);border:1px solid var(--line);border-radius:9px;
  padding:8px 11px;margin-top:12px}
.pw-bank-row{display:flex;align-items:center;gap:8px;padding:3px 0;font-size:12.5px}
.pw-bank-k{color:var(--muted);width:84px;flex:none}
.pw-bank-v{min-width:0;overflow:hidden;text-overflow:ellipsis}
.pw-mini{margin-left:auto;background:none;border:0;padding:0 0 0 8px;color:var(--accent-2);
  font:inherit;font-size:11.5px;font-weight:600;cursor:pointer}
.pw-mini + .pw-mini{margin-left:0}
.pw-unpaid{background:var(--warn-bg);color:var(--warn);border-radius:8px;padding:9px 11px;
  margin-top:11px;font-size:12.5px}
.pw-paid{display:flex;gap:9px;align-items:flex-start;background:var(--ok-bg);border-radius:8px;
  padding:9px 11px;margin-top:11px;color:var(--ok);font-size:12.5px}
.pw-paid span{display:block;color:var(--text-2);font-size:11.5px;margin-top:1px}

.pw-void{display:flex;gap:8px;align-items:flex-start;background:var(--bad-bg);color:var(--bad);
  border-radius:8px;padding:9px 11px;margin-bottom:12px;font-size:12px;line-height:1.45}
.pw-void .ic{width:14px;height:14px;flex:none;margin-top:1px}
.pw-pay-f{display:grid;grid-template-columns:1fr 150px;gap:10px}
.pw-pay-hint{margin-top:9px;background:var(--bg-deep);border-radius:8px;padding:8px 11px;
  font-size:12px;color:var(--muted);line-height:1.5}
.pw-pay-note{margin-top:11px;font-size:11.5px;color:var(--faint);line-height:1.5}
.pw-paid .pw-mini{margin-left:auto;align-self:flex-start}
@media (max-width:520px){.pw-pay-f{grid-template-columns:1fr}}

.pw-docs{display:flex;flex-direction:column;gap:12px}
.pw-docs.void .pw-page,.pw-docs.void .pw-doc-m b{opacity:.6}
.pw-doc{display:flex;gap:12px;align-items:center}
.pw-doc + .pw-doc{border-top:1px solid var(--line);padding-top:12px}
.pw-page{width:52px;height:66px;border-radius:6px;border:1px solid var(--line-2);background:var(--surface);
  padding:5px;flex:none;display:block;transition:transform var(--fast)}
.pw-doc:hover .pw-page{transform:translateY(-1px)}
.pw-page .l{display:block;height:2px;background:var(--line);margin-bottom:3px}
.pw-page .l.w80{width:80%;height:3px;background:var(--line-2)}
.pw-page .l.w70{width:70%}
.pw-page .l.w55{width:55%;margin-bottom:7px}
.pw-page .sig{display:block;width:60%;border-bottom:1.5px solid var(--accent)}
.pw-doc-m{flex:1;min-width:0}
.pw-doc-m b{display:block;font-size:13.5px}
.pw-doc-m span{display:block;font-size:11.5px;color:var(--muted);margin-top:2px}
.pw-doc-acts{display:flex;gap:7px;margin-top:8px;flex-wrap:wrap}
.pw-prev{padding:0}
.pw-prev iframe{width:100%;height:70vh;border:0;display:block;background:var(--bg-deep)}

/* flex-start, not center: an attached check now carries a row of actions under
   its label, so centring floated the tick and the Replace button against the
   middle of a two-line block instead of lining them up with the title. */
.pw-chk{display:flex;align-items:flex-start;gap:10px}
.pw-chk .pw-doc-acts{display:flex;flex-wrap:wrap;gap:2px 4px;margin:5px 0 0 -6px}
.pw-chk .pw-doc-acts .btn{padding:2px 6px;font-size:11.5px;height:auto;line-height:1.6}
.pw-chk + .pw-chk{border-top:1px solid var(--line);margin-top:10px;padding-top:10px}
.pw-chk-i{width:20px;height:20px;border-radius:50%;background:var(--bad-bg);color:var(--bad);
  display:inline-flex;align-items:center;justify-content:center;flex:none}
.pw-chk.ok .pw-chk-i{background:var(--ok-bg);color:var(--ok)}
.pw-chk-m{flex:1;min-width:0}
.pw-chk-m b{display:block;font-size:13px}
.pw-chk-m span{display:block;font-size:11.5px;color:var(--muted)}
.pw-chk-note{margin-top:11px;padding-top:10px;border-top:1px solid var(--line);
  font-size:11.5px;color:var(--faint)}
.pw-wide{width:100%;justify-content:center;margin-top:10px}

.pw-more-d{border:1px solid var(--line);border-radius:11px;background:var(--surface)}
.pw-more-d summary{padding:10px 15px;font-size:12.5px;color:var(--muted);cursor:pointer;font-weight:600}
.pw-more-b{padding:0 15px 14px;display:flex;flex-direction:column;gap:10px}
.pw-trail-rows{display:flex;flex-direction:column}

/* this tab handles money and ID, so every control has to be reachable and
   visibly focused. The bare buttons carry no .btn class, so the app's own
   focus rule does not reach them. */
.pw-vbtn:focus-visible,.pw-mini:focus-visible,.pw-more-d summary:focus-visible{
  outline:2px solid var(--focus);outline-offset:2px}

@media (prefers-reduced-motion:reduce){
  .pwh-bar{animation:none}
  .pw-shot img,.pw-page{transition:none}
}

/* ---- Phase D: offers screen invite strip ---- */

/* ---- records (the permanent register: purchases ledger + clients) ---- */
.rec-bar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:0 0 10px}
.rec-bar .input{height:34px;font-size:13px}
.rec-q{flex:1 1 240px;min-width:180px}
.rec-num{width:92px}
.rec-date{width:130px}
.rec-bar .flex1{flex:1 1 auto}
.rec-kpis{display:flex;gap:8px;align-items:center;margin:0 0 10px}
.rec-grid td{vertical-align:middle}
.rec-grid tr[data-action]{cursor:pointer}
.rec-grid tr.no-nav{cursor:default}
th.sortable{cursor:pointer;user-select:none;white-space:nowrap}
th.sortable:hover{color:var(--text)}
th.sortable .dir{font-size:10.5px;opacity:.75}
/* Licence images on a client profile. Taller than the cockpit's 74px strip:
   this is the archive copy someone comes back to months later to check a
   name against a face, so it is worth being readable before the lightbox. */
.rec-shots{display:flex;gap:12px;margin-top:16px;flex-wrap:wrap}
.rec-shot{flex:1 1 220px;margin:0;min-width:0;max-width:340px}
.rec-shot img{width:100%;height:132px;object-fit:cover;border-radius:10px;
  border:1px solid var(--line);display:block;cursor:zoom-in;
  transition:box-shadow var(--fast)}
.rec-shot img:hover{box-shadow:var(--shadow-card)}
.rec-shot figcaption{font-size:11.5px;margin-top:6px;color:var(--muted)}
.rec-pager{display:flex;align-items:center;justify-content:center;gap:14px;padding:12px 0;color:var(--muted)}
.rec-pager .btn[disabled]{opacity:.35;pointer-events:none}
.rec-loading{height:2px;border-radius:2px;margin:0 0 10px;background:
  linear-gradient(90deg,transparent 20%,var(--accent) 50%,transparent 80%) 0 0/60% 100% no-repeat,
  var(--surface-2);animation:rec-slide 1s linear infinite}
.rec-loading.idle{visibility:hidden}
@keyframes rec-slide{from{background-position:-60% 0}to{background-position:160% 0}}
@media (max-width:640px){
  .rec-q{flex-basis:100%}
  .rec-date,.rec-num{flex:1 1 40%}
  .rec-bar .seg{flex-wrap:wrap}   /* 9 AU-state chips must wrap, not overflow */
}

/* ===== WORKFLOW G: stage-aware work columns (Chunk G, 2026-07-22) ===== */
/* nowrap: on narrow screens the queue table scrolls inside .tablewrap —
   a wrapped work cell balloons the row instead of staying dense */
.wk{white-space:nowrap}
.wk b{font-weight:600}
.wk-sub{color:var(--muted);font-size:11.5px;margin-top:1px;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.wk-mut{color:var(--muted)}
.wk-best{color:var(--accent-2)}
.wk-chip{display:inline-flex;align-items:center;font-size:11px;font-weight:700;border-radius:6px;padding:1.5px 7px;letter-spacing:.01em}
.wk-chip.ok{background:var(--ok-bg);color:var(--ok)}
.wk-chip.warn{background:var(--warn-bg);color:var(--warn)}
.wk-chip.bad{background:var(--bad-bg);color:var(--bad)}
.wk-chip.soft{background:var(--accent-soft);color:var(--accent-2)}
.wk-tick{color:var(--ok);font-weight:700}
.wk-cross{color:var(--bad);font-weight:700}
.ic.wk-tick,.ic.wk-cross{width:14px;height:14px}

/* ===== welcome form progress (New leads queue) =====
   Three segments, a word, and the fact that decides whether to call. The
   track is the point: a column of them reads as a funnel at a glance, so an
   operator finds the stalled sellers without reading a single row. */
.fm{display:flex;flex-direction:column;gap:3px;line-height:1.25}
.fm-top{display:flex;align-items:center;gap:7px}
.fm-track{display:inline-flex;gap:2px;flex:none}
.fm-seg{width:13px;height:4px;border-radius:2px;background:var(--line)}
.fm-lb{font-size:11px;font-weight:600;white-space:nowrap}
.fm-sub{font-size:11px;color:var(--muted);white-space:nowrap}
.fm.done .fm-seg.on{background:var(--ok)}
.fm.done .fm-lb{color:var(--ok)}
/* Started and Opened share amber deliberately: both are "interested and
   stalled", both belong on the same call list, and the word tells them apart */
.fm.started .fm-seg.on,.fm.opened .fm-seg.on{background:var(--warn)}
.fm.started .fm-lb,.fm.opened .fm-lb{color:var(--warn)}
.fm.failed .fm-seg{background:var(--bad-bg)}
.fm.failed .fm-seg.on{background:var(--bad)}
.fm.failed .fm-lb{color:var(--bad)}
/* Sending shares Sent's neutral grey deliberately, the way Started and Opened
   share amber above. It is NOT red and NOT amber: the text has not failed for
   the seller, it is still on the retry ladder, and a row that looks like a
   problem is a row somebody bins, which is exactly what happened to 23 sellers
   on 15 August 2026. The label and the sub line carry the difference. */
.fm.sending .fm-seg.on,.fm.sent .fm-seg.on{background:var(--faint)}
.fm.sending .fm-lb,.fm.sent .fm-lb{color:var(--muted)}
td.fmc,th.fmc{white-space:nowrap}
.stage-sortnote{color:var(--muted);font-size:12px}

/* ===== honest progress rail: skipped stages (2026-07-23) ===== */
.ck-step.skip .mk{border:1.5px dashed var(--line);background:transparent}
.ck-step.skip .lbl{color:var(--faint)}
.skipped-tag{display:inline-block;margin-left:7px;font-size:10.5px;font-weight:700;
  letter-spacing:.07em;text-transform:uppercase;color:var(--faint);
  border:1px solid var(--line);border-radius:5px;padding:1px 5px;vertical-align:1px}

/* ===== R3: paperwork submission viewer + progress trail (2026-07-23) ===== */
.pw-trail{display:inline-flex;align-items:center;gap:4px;margin:0 8px}
.pw-dot{width:7px;height:7px;border-radius:50%;background:var(--line)}
.pw-dot.on{background:var(--ok)}
.pw-sub-body{max-height:64vh;overflow-y:auto}
.pw-ups{display:flex;flex-direction:column;gap:8px}
.pw-up{display:flex;align-items:center;gap:12px;border:1px solid var(--line);border-radius:10px;padding:8px 10px}
.pw-thumb{width:56px;height:40px;object-fit:cover;border-radius:7px;border:1px solid var(--line);display:block}
.pw-thumb.doc{display:flex;align-items:center;justify-content:center;background:var(--accent-soft);color:var(--accent-2)}
.pw-up-open{display:block;flex:none;line-height:0;border-radius:7px}
.pw-up-meta{flex:1;min-width:0}
.pw-up-meta b{display:block;font-size:13px}
.pw-ver{font-size:11.5px;color:var(--faint)}
.pw-ver.ok{color:var(--ok);font-weight:700;display:inline-flex;align-items:center;gap:4px}

/* buy modal: the six paperwork fields in two tidy columns */
.buy-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 12px}
@media (max-width:640px){.buy-grid{grid-template-columns:1fr}}

/* ============================================================
   TplField — saved-message editor (js/tplfield.js)
   Fields read as words inside the sentence, so staff never type
   braces. The pill is contenteditable=false, which is what makes
   one backspace remove a whole field instead of half a token.
   ============================================================ */
.tplx-wrap{position:relative}
.tplx{min-height:96px;padding:11px 12px;border:1px solid var(--line-2);border-radius:var(--radius-sm);
  background:var(--surface);color:var(--text);font:inherit;font-size:13.5px;line-height:1.85;
  white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;cursor:text}
/* keyboard focus: the app's one ring rule reaches this via [contenteditable] */
.tplx:empty:before{content:attr(data-ph);color:var(--muted)}
.tplx-tk{display:inline-block;background:var(--accent-soft);color:var(--accent-2);
  border-radius:6px;padding:1px 7px;margin:0 1px;font-size:12.5px;font-weight:600;
  white-space:nowrap;user-select:none;vertical-align:baseline}

/* toolbar under the box: add a field, then the live cost */
.tplx-bar{display:flex;align-items:center;gap:10px;margin-top:8px;flex-wrap:wrap}
.tplx-add{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 11px;
  border:1px solid var(--line-2);border-radius:var(--radius-sm);background:var(--surface);
  color:var(--text-2);font-size:12.5px;font-weight:600;cursor:pointer;
  transition:border-color var(--fast),color var(--fast),background var(--fast)}
.tplx-add:hover{border-color:var(--accent);color:var(--accent-2);background:var(--accent-soft)}
.tplx-meter{margin-left:auto;font-size:11.5px;color:var(--muted)}
.tplx-meter.over{color:var(--warn);font-weight:600}
.tplx-warn{margin-top:7px;font-size:11.5px;line-height:1.6;color:var(--warn);
  background:var(--warn-bg);border-radius:8px;padding:7px 10px}

/* what the seller actually reads */
.tplx-pv{margin-top:10px;border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface-2);padding:10px 12px}
.tplx-pv .lab{display:block;font-size:10.5px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted);margin-bottom:5px}
.tplx-pv .msg{font-size:13px;line-height:1.65;color:var(--text-2);white-space:pre-wrap}

/* field picker */
.tplx-pop{position:absolute;z-index:60;left:0;bottom:100%;margin-bottom:8px;width:290px;max-width:calc(100vw - 32px);
  background:var(--surface-3);border:1px solid var(--line);border-radius:var(--radius-sm);
  box-shadow:var(--shadow-pop);overflow:hidden;animation:riseIn .12s ease}
/* flipped under the Add field bar when there is no room above (tplfield.js
   openPicker says when); top is set inline from the bar's position */
.tplx-pop.down{bottom:auto;margin-bottom:0}
.tplx-pop-q{width:100%;height:38px;padding:0 12px;border:0;border-bottom:1px solid var(--line);
  background:transparent;color:var(--text);font:inherit;font-size:13px}
.tplx-pop-q:focus{outline:none}
.tplx-pop-l{max-height:244px;overflow:auto;padding:5px}
.tplx-pop-i{display:flex;align-items:baseline;gap:8px;width:100%;text-align:left;border:0;
  background:transparent;border-radius:8px;padding:7px 9px;cursor:pointer;color:var(--text)}
.tplx-pop-i:hover,.tplx-pop-i.on{background:var(--accent-soft)}
.tplx-pop-i .nm{font-size:13px;font-weight:600}
.tplx-pop-i .eg{font-size:11.5px;color:var(--muted);margin-left:auto;white-space:nowrap}
.tplx-pop-none{padding:14px 11px;font-size:12.5px;color:var(--muted);text-align:center}

/* ============================================================
   The situation, at the top of a lead. Same facts the CRM already
   holds, said as a sentence, so picking up a card does not mean
   scrolling the thread to work out where it got to.
   A callout, not a card: the accent edge is the one thing saying read this
   first, so it carries no hairline and no shadow to compete with it.
   ============================================================ */
.ck-sum{background:var(--surface);border-left:3px solid var(--accent);
  border-radius:var(--radius);padding:13px 16px;margin-bottom:12px}
.ck-sum.warn{border-left-color:var(--warn)}
.ck-sum .cap{display:block;font-size:10.5px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--muted);margin-bottom:6px}
.ck-sum p{font-size:13.5px;line-height:1.6;color:var(--text)}
.ck-sum-next{display:flex;align-items:center;gap:6px;margin-top:8px;padding-top:8px;
  border-top:1px solid var(--line);font-size:12.5px;font-weight:600;color:var(--accent-2)}
.ck-sum-next .ic{width:14px;height:14px;flex:none}

/* ============================================================
   The voicemail on a lead (cockpit Overview, app/screens/cockpit.js
   voicemailCard). A missed call is a lead whose entire content is a
   recording, so the player sits directly under the situation line
   instead of inside the activity drawer.

   Deliberately compact. Ten seconds of audio does not earn a hero:
   one head row saying whose number it is, how long the message runs
   and when it landed, the native player under it, and a note that
   only appears while the file loads or when it never arrives. The
   head row is plain flex-wrap rather than a grid, which is what
   makes the phone layout a reflow of the same DOM: at 375px it
   breaks after the number and the download button keeps its right
   edge on the second line.
   ============================================================ */
.ck-vm{padding:13px 16px;display:flex;flex-direction:column;gap:9px}
.ck-vm-h{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.ck-vm-h .cap{display:inline-flex;align-items:center;gap:6px;margin:0;flex:none}
.ck-vm-h .cap .ic{width:13px;height:13px}
.ck-vm-num{font-size:14px;font-weight:600;letter-spacing:-.01em}
/* --muted, NOT --faint. "No number came through" is the most consequential
   sentence this card can say, it means there is nobody to ring back, and
   --faint measures about 2.6:1 on white, under AA. --muted is 4.9:1 and is
   already the token on the meta line beside it. */
.ck-vm-num.none{font-size:12.5px;font-weight:500;color:var(--muted)}
/* the length as a quiet chip rather than another word in the line: Time.exact
   already separates its own halves with a middle dot, so joining them made a
   length and a moment read as three things of equal weight */
.ck-vm-len{font-size:11px;font-weight:600;color:var(--text-2);background:var(--surface-2);
  padding:3px 8px;border-radius:7px;white-space:nowrap}
.ck-vm-meta{font-size:11.5px;color:var(--muted);white-space:nowrap}
.ck-vm-dl{margin-left:auto;flex:none}
/* The height is left to the browser on purpose. Chrome draws its controls at
   a fixed size and forcing the element shorter clips them, so what is set
   here is the width, which does NOT stretch on its own (the default is a
   fixed 300px that would sit in a card twice that wide). */
.ck-vm-a{width:100%;display:block}
.ck-vm-note{font-size:12px;color:var(--muted)}
.ck-vm-note.bad{color:var(--bad);font-weight:600}
@media(max-width:640px){
  /* Everything stays and nothing is hidden, it just tightens: the number and
     the player are the two things worth a thumb on a phone. The meta line is
     allowed to break rather than push a fixed 25 character run past the edge
     of a 375px card. */
  .ck-vm{padding:12px 13px}
  .ck-vm-h{gap:8px}
  .ck-vm-meta{white-space:normal}
}

/* sellers the welcome text never reached: a worklist, not a log line */
.cc-unreached{border-color:var(--warn)}
.cc-unreached .panel-h h3{color:var(--warn)}

/* ============================================================
   Automated texts. Cards rather than table rows, because each one
   is a thing you switch on and off and read, not a record you scan.
   The Podium settings pattern: a clear title, a plain English line
   about what it targets, the content itself, and the action on the
   right where the eye ends up.
   ============================================================ */
.au-wrap{display:flex;flex-direction:column;gap:10px}
.au-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:14px 16px;transition:border-color var(--fast),background var(--fast)}
/* Off: dormant in colour, the way the missed call sequence says it
   (.au-mc.off). Opacity faded every word on the card under 4.5:1, the
   same fault that rule was written to avoid. A greyer card, a softer name,
   muted ink and grey chips read as switched off and stay readable, and the
   controls keep full strength, because a rule is switched off to be
   rewritten as often as to be forgotten. */
.au-card.off{background:var(--surface-2)}
.au-card.off .au-title b{color:var(--text-2)}
.au-card.off .au-body{background:var(--surface);color:var(--muted)}
.au-card.off .au-chip{background:var(--surface);color:var(--muted);border-color:var(--line)}
.au-head{display:flex;align-items:center;gap:12px}
.au-title{min-width:0;flex:1}
.au-title b{display:block;font-size:14px;font-weight:700;color:var(--text)}
.au-state{font-size:11.5px;color:var(--muted)}
.au-act{display:flex;gap:6px;flex:none}

/* the switch */
.au-toggle{flex:none;width:40px;height:23px;border-radius:12px;border:1px solid var(--line-2);
  background:var(--surface-2);position:relative;cursor:pointer;transition:background var(--fast),border-color var(--fast);padding:0}
.au-toggle i{position:absolute;top:2px;left:2px;width:17px;height:17px;border-radius:50%;
  background:var(--muted);transition:transform var(--fast),background var(--fast)}
.au-toggle.on{background:var(--accent);border-color:var(--accent)}
.au-toggle.on i{transform:translateX(17px);background:#fff}
.au-toggle:disabled{cursor:default;opacity:.55}

/* what the rule targets, said in chips rather than a query */
.au-targets{display:flex;flex-wrap:wrap;gap:5px;margin:10px 0 9px}
.au-chip{font-size:11px;font-weight:600;padding:2.5px 8px;border-radius:20px;
  background:var(--surface-2);color:var(--text-2);border:1px solid var(--line)}
.au-chip.brand{background:var(--accent-soft);color:var(--accent-2);border-color:transparent}
.au-chip.any{color:var(--muted);font-weight:500}
.au-chip.camp{background:var(--warn-bg);color:var(--warn);border-color:transparent}

.au-body{font-size:13px;line-height:1.75;color:var(--text-2);
  background:var(--surface-2);border-radius:var(--radius-sm);padding:10px 12px}
.au-meta{margin-top:8px;font-size:11.5px;color:var(--muted)}
.au-add{align-self:flex-start;margin-top:4px}

/* source tick boxes in the editor */
.au-checks{display:flex;flex-wrap:wrap;gap:7px}
.au-check{display:inline-flex;align-items:center;gap:7px;padding:7px 11px;border:1px solid var(--line-2);
  border-radius:var(--radius-sm);font-size:12.5px;cursor:pointer;background:var(--surface);user-select:none}
.au-check:hover{border-color:var(--accent)}
.au-check input{accent-color:var(--accent);width:15px;height:15px}
.au-check:has(input:checked){border-color:var(--accent);background:var(--accent-soft);color:var(--accent-2);font-weight:600}

/* text spend */
.sp-stats{margin-bottom:2px}
/* Five tiles, not the Command Center's four: the two totals over a row of
   the three kinds of text, welcome, missed call and by hand. On a 4 column
   grid the fifth sat alone on a second row and read as a leftover. Declared
   after the shared .cc-stats breakpoints, so it carries its own. */
.sp-stats{grid-template-columns:repeat(6,minmax(0,1fr))}
.sp-stats .stat{grid-column:span 2}
.sp-stats .stat:nth-child(-n+2){grid-column:span 3}
@media(max-width:640px){
  .sp-stats{grid-template-columns:repeat(2,minmax(0,1fr))}
  .sp-stats .stat,.sp-stats .stat:nth-child(-n+2){grid-column:auto}
  .sp-stats .stat:last-child{grid-column:1/-1}
}
@media(max-width:380px){.sp-stats{grid-template-columns:1fr}}
.sp-h{font-size:12px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  color:var(--muted);margin:20px 0 9px}
.au-up{display:inline-flex;transform:rotate(180deg)}
.au-act .iconbtn.sm{width:28px;height:28px}
.au-act .iconbtn.sm:disabled{opacity:.3;cursor:default}
/* A phone gives a rule's controls a row of their own. Beside the switch,
   the two arrows, Edit and the cross left the name one word wide and it
   read down the card, "EV / Car / Buyers / welcome". Now the name has the
   width beside the switch, the arrows sit on the left under it and Edit
   and the cross on the right, at the 40px the phone rules give a target. */
@media(max-width:640px){
  .au-head{flex-wrap:wrap;row-gap:10px}
  .au-act{flex-basis:100%;gap:8px}
  .au-act .iconbtn + .btn{margin-left:auto}
  .au-act .btn{min-height:40px}
  /* the switch keeps its drawn size and takes a 44px square to the touch */
  .au-toggle::after{content:'';position:absolute;left:50%;top:50%;width:44px;height:44px;transform:translate(-50%,-50%)}
}
.au-warn{display:flex;gap:7px;align-items:flex-start;margin-top:9px;padding:8px 10px;
  border-radius:var(--radius-sm);background:var(--warn-bg);color:var(--warn);
  font-size:12px;line-height:1.5;font-weight:600}
.au-warn .ic{width:14px;height:14px;flex:none;margin-top:1px}

/* ---- The missed call sequence. One opening text, then six follow ups in
   order. Its own group under the arrival rules: the rules are separate
   things switched on and off one by one, the sequence is one thing with
   one switch, so it gets one header, one switch and the seven texts under
   it. The six are a grid, not a column, because at desktop width seven
   full width cards is a page of scrolling to see the shape of something
   that fits on one screen. Order is carried by the numeral on each card
   and no card carries a time of day: which of 9am and 3pm a slot lands on
   depends on when the call was missed. ---- */
.au-mc{margin-top:28px;padding-top:22px;border-top:1px solid var(--line);
  container-type:inline-size;display:flex;flex-direction:column;gap:10px}
.au-mc .au-head{margin-bottom:2px}
.au-state.off{color:var(--warn);font-weight:600}
.au-mc-lead{font-size:13px;line-height:1.55;color:var(--text-2);max-width:72ch;margin:0 0 4px}
.au-mc-h{display:flex;align-items:center;gap:10px;min-width:0}
.au-mc-h > b{flex:1;min-width:0;font-size:13px;font-weight:700;color:var(--text)}
.au-mc-h .au-title{flex:1}
.au-mc-h .btn.sm{flex:none}
/* the order marker: a numeral on the six, the phone on the opening text,
   which is the one thing here that is not a follow up */
.au-mc-n{flex:none;width:24px;height:24px;border-radius:50%;display:inline-flex;align-items:center;
  justify-content:center;font-size:12px;font-weight:800;background:var(--accent-soft);color:var(--accent-2)}
.au-mc-n.open{background:var(--accent);color:#fff}
.au-mc-n .ic{width:13px;height:13px}
.au-mc-open .au-body,.au-mc-slot .au-body{margin-top:10px}
/* an empty wording is a deliberate gap in the sequence, said in words */
.au-mc-skip{display:flex;gap:8px;align-items:flex-start;margin-top:10px;padding:10px 12px;
  border:1px dashed var(--line-2);border-radius:var(--radius-sm);font-size:12.5px;line-height:1.5;color:var(--muted)}
.au-mc-skip .ic{width:14px;height:14px;flex:none;margin-top:2px}
.au-mc-foot{display:flex;align-items:center;flex-wrap:wrap;gap:6px 14px;margin-top:9px;
  font-size:11.5px;color:var(--muted)}
.au-mc-parts.over{color:var(--warn);font-weight:600}
.au-mc-sent{display:inline-flex;align-items:center;gap:8px;margin-left:auto;
  font-family:var(--mono);font-weight:600;color:var(--text-2)}
.au-mc-sent.zero{font-weight:500;color:var(--muted)}
.au-mc-bar{display:inline-block;width:56px;height:5px;border-radius:3px;background:var(--line);overflow:hidden}
.au-mc-bar b{display:block;height:100%;border-radius:3px;background:var(--accent)}
/* the step from the opening text down to the six: a short line dropping
   from under the opening card's marker, then the caption */
.au-mc-then{display:flex;align-items:center;gap:10px;font-size:11.5px;font-weight:700;
  letter-spacing:.05em;text-transform:uppercase;color:var(--muted)}
.au-mc-then::before{content:'';display:block;width:2px;height:16px;margin-left:27px;
  background:var(--line-2);border-radius:1px}
.au-mc-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}
/* The grid already stretches the cards in a row to one height; the foot
   takes the spare room above it, so the parts line, the bar and the sent
   count sit on the floor of every card and line up across the row however
   long the wording above them runs. */
.au-mc-slot{display:flex;flex-direction:column}
.au-mc-slot .au-mc-foot{margin-top:auto;padding-top:9px}
.au-mc-rule{margin-top:4px;max-width:72ch}
/* Who a text speaks as when nobody holds the lead. A card in the sequence's
   own shape, because it is read at the same moment as the wordings: they say
   a name and give a number, and this is where those come from until somebody
   takes the lead. */
.au-off-rows{display:flex;flex-direction:column;gap:8px;margin-top:11px}
.au-off-row{display:flex;align-items:baseline;gap:12px;font-size:13px}
.au-off-row .k{flex:none;width:64px;font-size:12px;color:var(--muted)}
.au-off-row .v{font-weight:600;min-width:0;word-break:break-word}
.au-off-empty{font-style:normal;font-weight:600;color:var(--warn)}
.au-off-none{display:flex;gap:8px;align-items:flex-start;margin-top:11px;padding:10px 12px;
  border-radius:var(--radius-sm);background:var(--warn-bg);color:var(--text);
  font-size:12.5px;line-height:1.5}
.au-off-none .ic{width:15px;height:15px;flex:none;margin-top:1px;color:var(--warn)}
.au-off-why{margin-top:11px;font-size:12px;color:var(--muted);line-height:1.5;max-width:72ch}
/* Column count follows the width this section really has, not the
   viewport: the sidebar can be a rail or full at the same viewport width
   and the settings nav moves above the content below 980px, so the
   viewport says nothing reliable about how wide these cards are. Under
   about 280px a body is a ribbon, so three columns want 900px and two
   want 600px. On one column the cards become a stepper, a short line
   joining each numeral to the next. */
@container (max-width:899px){.au-mc-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@container (max-width:599px){
  .au-mc-grid{grid-template-columns:1fr}
  .au-mc-slot{position:relative}
  .au-mc-slot + .au-mc-slot::before{content:'';position:absolute;left:27px;top:-10px;width:2px;height:10px;
    background:var(--line-2)}
}
/* a phone gets one column whatever the container maths says */
@media(max-width:640px){.au-mc-grid{grid-template-columns:1fr}}
/* Off: everything stays readable and in place, greyed rather than faded,
   because the owner switches it off to read and rewrite it, not to forget
   it. Opacity would take the text under 4.5:1; a greyer card and muted ink
   do not. The switch itself is outside the cards and stays full strength. */
.au-mc.off .au-card{background:var(--surface-2);border-color:var(--line)}
.au-mc.off .au-body{background:var(--surface);color:var(--muted)}
.au-mc.off .au-mc-n{background:var(--surface);color:var(--muted)}
.au-mc.off .au-mc-n.open{background:var(--muted);color:#fff}
.au-mc.off .au-mc-bar b{background:var(--muted)}
.au-mc.off .au-mc-h > b,.au-mc.off .au-mc-h .au-title b{color:var(--text-2)}
/* loading: the same cards, holding their place */
.au-sk{display:flex;flex-direction:column;gap:10px;min-height:88px;justify-content:center}
.au-sk-note{font-size:12.5px;color:var(--muted)}
/* The editor modal's labels and hints. label.fld styles its own .lab, but a
   field whose control is a block (the pill editor, the source tick boxes)
   cannot be a label: a label's click lands on its first labelable
   descendant, which here would be the Add field button. So the same look
   is carried on a div, and .hint is styled here because the modal root sits
   outside .set-grid, the only place .hint is styled. */
.au-fld .lab{display:block;font-size:11.5px;font-weight:600;color:var(--muted);margin-bottom:6px}
.au-fld .hint{display:block;margin-top:8px;font-size:12px;color:var(--muted);line-height:1.45}

/* ============================================================
   Lightbox (js/lightbox.js). A seller's photos are the basis of a
   price, so they get the whole screen: arrows, keyboard, swipe, and
   a filmstrip when there is more than one.
   ============================================================ */
body.pvw-open{overflow:hidden}
.pvw{position:fixed;inset:0;z-index:200;background:#0b0d12;
  display:grid;grid-template-columns:64px 1fr 64px;grid-template-rows:52px 1fr auto;
  animation:lbIn .14s ease}
@keyframes lbIn{from{opacity:0}to{opacity:1}}
.pvw-bar{grid-column:1/-1;grid-row:1;display:flex;align-items:center;
  justify-content:space-between;padding:0 14px}
.pvw-count{color:rgba(255,255,255,.72);font-size:12.5px}
.pvw-btn{width:36px;height:36px;border:0;border-radius:9px;background:rgba(255,255,255,.1);
  color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background var(--fast)}
.pvw-btn:hover{background:rgba(255,255,255,.2)}

.pvw-stage{grid-column:2;grid-row:2;display:flex;align-items:center;justify-content:center;
  min-height:0;padding:4px 0}
.pvw-stage img{max-width:100%;max-height:100%;object-fit:contain;border-radius:8px;
  box-shadow:var(--shadow-pop)}

.pvw-nav{grid-row:2;align-self:center;justify-self:center;width:44px;height:44px;border:0;
  border-radius:50%;background:rgba(255,255,255,.1);color:#fff;cursor:pointer;
  display:flex;align-items:center;justify-content:center;transition:background var(--fast)}
.pvw-nav:hover{background:rgba(255,255,255,.22)}
.pvw-nav:disabled{opacity:0;pointer-events:none}
.pvw-nav.prev{grid-column:1}
.pvw-nav.next{grid-column:3}
.pvw-nav .ic{width:20px;height:20px}
.pvw-nav.prev .ic{transform:rotate(90deg)}
.pvw-nav.next .ic{transform:rotate(-90deg)}

.pvw-strip{grid-column:1/-1;grid-row:3;display:flex;gap:7px;overflow-x:auto;
  padding:12px 14px calc(12px + env(safe-area-inset-bottom,0));scrollbar-width:none}
.pvw-strip::-webkit-scrollbar{display:none}
.pvw-th{flex:0 0 auto;width:58px;height:44px;border-radius:7px;overflow:hidden;padding:0;
  border:2px solid transparent;background:none;cursor:pointer;opacity:.5;transition:opacity var(--fast),border-color var(--fast)}
.pvw-th img{width:100%;height:100%;object-fit:cover;display:block}
.pvw-th:hover{opacity:.85}
.pvw-th.on{opacity:1;border-color:#fff}

@media (max-width:640px){
  .pvw{grid-template-columns:0 1fr 0}
  .pvw-nav{display:none}          /* swipe instead, the arrows would cover the photo */
}

/* Due column (Follow up contacted), its step on the Contacted bar, and the
   DUE NOW rail. Overdue is the only state that gets colour: "today" is just
   today, and a queue where every row is red is the New leads alarm C1 spent
   a chunk undoing. Later steps back to the secondary ink, it is not today's
   work. */
.due-dot{display:inline-block;width:6px;height:6px;border-radius:50%;margin-right:7px;vertical-align:1px}
.due-over{color:var(--bad);font-weight:600}
.due-over .due-dot{background:var(--bad)}
.due-today{font-weight:600}
.due-today .due-dot{background:var(--accent)}
.due-later{color:var(--text-2)}
.due-none{color:var(--muted)}
/* the reason is typed, up to 180 characters, in a nowrap cell: clipped here,
   whole on hover */
.due-why{display:inline-block;max-width:26ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}

.cc-due{display:flex;flex-direction:column;gap:2px;margin-bottom:6px}
.cc-due-row{display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:9px;
  text-decoration:none;color:inherit}
.cc-due-row:hover{background:var(--surface-2)}
.cc-due-w{flex:1;min-width:0}
.cc-due-w b{display:block;font-size:13px;font-weight:600;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.cc-due-w span{display:block;font-size:11.5px;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cc-due-t{font-size:11.5px;font-weight:600;white-space:nowrap;flex:none}
.cc-due-t.over{color:var(--bad)}
.cc-due-more{display:block;padding:7px 10px;font-size:12px;color:var(--muted);
  text-decoration:none}
.cc-due-more:hover{color:var(--text)}
.cc-sub{font-size:11px;letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);font-weight:600;padding:10px 10px 6px}
