/* =========================================================================
   BC Automotive — booking platform prototype
   Structure & app-shell patterns mirror the FCC LeadCourt prototype.
   Palette recoloured to the BC Automotive brand: charcoal + yellow + white.
   ========================================================================= */

:root{
  /* brand — sampled directly from the BC Automotive logo */
  --char:#353535; --char2:#454545;            /* charcoal chrome (matches logo bg) */
  --brand:#fcd007; --brand-d:#d9b000; --brand-soft:#fef6d2; /* signature yellow */
  --ink-on-brand:#2a2300;                     /* dark text used on yellow */
  --green:#2f9e5b; --red:#d2443c; --amber:#e8a13c; --blue:#2f6bd8; --violet:#7048c9;
  --bg:#f4f5f7; --card:#ffffff; --line:#e3e6ea; --txt:#1c2733; --mut:#677181;
  /* Craig Creative's logomark, at the foot of every page. Not BC's palette and
     deliberately not derived from it — it is somebody else's mark, and these
     are that mark's own two colours, the light-ground pair its site uses. On
     this page: slate 9.19:1, sage 3.04:1. The sage is the tightest of the
     three grounds the mark stands on across the three apps that draw it, so it
     is the value to check first if any of them moves.

     THE SLATE MOVED ON 11 SEP 2026, from #2f4257 to #204755 — same mark, new
     paint. Craig Creative took its outer C off the pure-blue axis (OKLCH hue
     252) and a third of the way toward the inner C's green (to 224), because
     at 252 the two Cs read as two unrelated marks bolted together rather than
     one drawn object. Its own note for this: the pair must stay at least 3:1
     apart in LUMINANCE or the rings merge at favicon size, so the colour could
     be re-hued but not lightened. Nothing here needs to change but the value —
     9.19:1 is still far clear of the 3:1 this fill needs. */
  --cc-slate:#204755; --cc-sage:#7a9478;
  /* …and the outer C's light-ground twin, for the one surface in this app that
     is charcoal: the staff rail, where the credit now lives. The sage is
     unchanged — it is the colour that stands on both, and at 3.70:1 on --char
     it is comfortably clear of the 3:1 a graphical object needs, where on the
     light page it is 3.04:1 and is the value to check first if either ground
     moves. Both pairings are in tests/ui-contrast.test.js. */
  --cc-cream:#fdfcf8;
  /* The staff rail's two widths, and the difference between them is a column of
     the diary on a 13" laptop.

     72px, WHERE THE FCC TWIN COLLAPSES TO 64, and the logo is the whole reason.
     LeadCourt's mark is a compact badge that centres happily in 40px of content;
     `icons/bc-logo.png` is a wide lockup at 2.1:1 — "BC", the car, and
     "automotive" under them — and at 40px across the second line is a smear.
     72px leaves 56px of content once the collapsed padding is off, which is
     where that lockup still reads as itself. Copying the twin's 64 exactly
     would have been consistency with the wrong thing: the number is a
     consequence of the artwork, and the artwork is not the same.
     See the `.sidenav` block for why the collapse is a width on the rail and an
     overlay on what is drawn inside it. */
  --rail-w:216px; --rail-c:72px;
  /* WCAG 1.4.3 — the brand fills above are correct as BACKGROUNDS but fail 4.5:1
     as text. These -ink tokens are the text-safe equivalents; the fill colours are
     deliberately left untouched so buttons, dots and accents look exactly the same.

     EVERY RATIO IN THIS COMMENT USED TO BE AGAINST WHITE, AND THAT WAS NOT SAID.
     One colour, checked against one surface, painted on five: --red is 4.53 on
     --card and fails on all four of the others it is used on — worst of all
     3.93 on the pink #fcebea, which is where it renders "MOT expired" on the
     customer's free health check, the headline result of that screen. Likewise
     --green-ink (4.18) and --amber-ink (4.21) were below 4.5 on --bg, having
     been chosen against white.
     The ratios are no longer written down here at all, because a number in a
     comment goes stale silently. tests/ui-contrast.test.js reads these tokens
     out of this file and asserts each one against every surface it is actually
     painted on; change a token or paint it somewhere new and that test is the
     thing that answers. */
  --brand-ink:#876d00; --amber-ink:#8f6224; --green-ink:#237a45; --red-ink:#b3352e;
  --r:14px; --shadow:0 1px 3px rgba(16,24,40,.08),0 4px 14px rgba(16,24,40,.06);
  --safe-b:env(safe-area-inset-bottom,0px);

  /* ===== TYPE, WEIGHT AND RADIUS SCALES (bc-design-system) =====
     THE COLOUR HALF OF THIS WAS DONE ON 2026-09-02 and the rest was owed for
     six weeks. `.review/scan.sh` counted what the rest looked like: 28 distinct
     font sizes, NINE OF THEM FRACTIONAL (8.5, 9.5, 10.5, 11.5, 12.5, 13.5,
     14.5, 15.5, 16.5), six weights and fifteen radii.

     A fractional size is the signature: nobody designs a 12.5px step, they
     nudge one component until it looks right and leave the nudge behind. Half a
     pixel does not survive the browser's own rounding at most zoom levels
     anyway, so most of the nudges were decoration on the stylesheet rather than
     on the page — which is why snapping them moved so little.

     WHAT THE SCALE IS. Twelve steps, each a size already in use, with every
     value within ~2px of what it replaced:

       10 <- 8.5 9 9.5 10       13 <- 12.5 13         22 <- 20 21 22 23
       11 <- 10.5 11            14 <- 13.5 14         26 <- 24 25 26
       12 <- 11.5 12            15 <- 14.5 15 15.5    30 <- 30
                                16 <- 16 16.5         38 <- 38
                                18 <- 17 18

     The two display sizes keep their own steps because they are used once each
     and a headline is where a 25% jump is visible.

     VERIFIED BY SCREENSHOT, NOT BY REASONING — this repo's own rule, from the
     `.editchev` note below. All eleven routes at 375px and 1280px, before and
     after: no horizontal overflow anywhere, every page within 2.7% of its old
     height, and 470 text elements checked for wrapping with none wrapping that
     did not wrap before. */
  --fs-2xs:10px; --fs-xs:11px;  --fs-sm:12px;  --fs-md:13px;
  --fs-lg:14px;  --fs-xl:15px;  --fs-2xl:16px; --fs-3xl:18px;
  --fs-4xl:22px; --fs-5xl:26px; --fs-6xl:30px; --fs-7xl:38px;

  /* Six weights for a four-weight vocabulary. 650 and 750 are the same nudge
     habit as the half-pixels, and 850 is 800 with the system font's own
     rounding on top — most stacks have no 850 face and synthesise it from 800. */
  --fw-med:600; --fw-semi:700; --fw-bold:800;

  /* Fifteen radii for five. 3/4/5 are one corner, 9/10/11/12/13 are another
     seen at different sizes, and 99/999 are both "a pill" — the second is the
     idiom for "however tall this gets", so it is the one that survives. */
  --r-xs:4px; --r-sm:8px; --r-md:12px; --r-lg:16px; --r-pill:999px;
}
*{box-sizing:border-box;margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;-webkit-tap-highlight-color:transparent}

/* ===== icons =====
   One stroke set replacing ~37 emoji (see ICON_PATHS in app.js). Sized in em so
   an icon always matches the text it sits beside, and drawn in currentColor so
   it inherits state — something colour emoji could never do. */
.ic-svg{width:1.15em;height:1.15em;display:inline-block;vertical-align:-.19em;flex:none;
  fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
.ic-lg{width:1.7em;height:1.7em;vertical-align:-.35em}
.ic-xl{width:34px;height:34px;stroke-width:1.5}
.ic-ok{color:var(--green)}
/* an icon key the owner typed by hand still renders as whatever they typed */
.ic-raw{display:inline-block;font-style:normal}
html,body{height:100%}
/* never allow sideways panning — on iOS a single overflowing element otherwise
   lets the page scroll past the header's right edge */
html,body{overflow-x:hidden;overflow-x:clip}
body{background:var(--bg);color:var(--txt)}
button{font:inherit;background:none;border:none;cursor:pointer;color:inherit}
a{color:inherit;text-decoration:none}
input,select,textarea{font:inherit}

/* ===== app shell ===== */
#app{min-height:100%;display:flex;flex-direction:column}
.shell{display:flex;min-height:100vh}
.sidenav{display:none}
.content{flex:1;min-width:0;display:flex;flex-direction:column}
/* min-width:0 — as flex items these must never be widened by a child's
   intrinsic width (e.g. the reg-plate input), which broke iOS layouts */
.main{flex:1;min-width:0;padding:16px 16px calc(86px + var(--safe-b));max-width:1100px;width:100%;margin:0 auto}

.appbar{position:relative;z-index:30;background:var(--char);color:#fff;padding:11px 16px;display:flex;align-items:center;justify-content:space-between}
.brand{display:flex;align-items:center;gap:10px;font-weight:var(--fw-bold);font-size:var(--fs-xl);color:#fff}
.blogo{height:30px;width:auto;display:block;flex-shrink:0}
.brand .lc{color:#fff;font-weight:var(--fw-bold);line-height:1.05}
.brand .lc small{display:block;font-size:var(--fs-2xs);font-weight:var(--fw-semi);letter-spacing:.8px;color:var(--brand);opacity:.95;margin-top:2px}
.avatar{width:32px;height:32px;border-radius:50%;background:var(--brand);display:flex;align-items:center;justify-content:center;font-size:var(--fs-sm);font-weight:var(--fw-bold);color:var(--ink-on-brand);border:none}

/* Five destinations, each a 44px-tall target — the bar carried seven at 39px,
   below the minimum, for hands straight off a car. */
.tabbar{position:fixed;bottom:0;left:0;right:0;z-index:30;display:flex;background:#fff;border-top:1px solid var(--line);padding:4px 0 calc(6px + var(--safe-b))}
.tab{position:relative;flex:1;min-height:46px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  text-align:center;font-size:var(--fs-xs);color:var(--mut);font-weight:var(--fw-med);border-radius:var(--r-md)}
.tab .ic{display:flex;line-height:0}
.tab .ic .ic-svg{width:21px;height:21px;vertical-align:0}
.tab.on{color:var(--char);font-weight:var(--fw-bold)}
.tab.on .ic{color:var(--brand-ink)}
.tabdot{position:absolute;top:2px;right:calc(50% - 22px);min-width:16px;height:16px;border-radius:var(--r-sm);background:var(--brand);
  color:var(--ink-on-brand);font-size:var(--fs-2xs);font-weight:var(--fw-bold);line-height:16px;padding:0 4px}
/* the overflow tabs are listed in the account menu, but only on a phone */
.menu-phone{display:block}
.menu-sep{height:1px;background:var(--line);margin:6px 4px}
@media(min-width:900px){.menu-phone{display:none}}

@media(min-width:900px){
  .appbar,.tabbar{display:none}
  /* THE RAIL IS THE LAYOUT; `.railinner` IS THE PAINT.
     `.sidenav` holds only the width the row gives up — 216px open, 72px
     collapsed — and nothing is drawn in it. Everything visible lives in
     `.railinner`, which is absolutely positioned against it and is therefore
     free to be wider than the space the rail occupies.

     That is the whole trick behind the hover peek: a collapsed rail opens back
     OVER the page instead of shoving the diary, the catalogue table and the
     reports grid 144px sideways every time the pointer crosses it. A width
     change on `.sidenav` itself would reflow the page, which is exactly the
     cost this feature exists to remove. Copied, deliberately, from the FCC
     LeadCourt twin's rail — the two consoles are the same shell and a staff
     member who learns one should not have to learn the other. */
  .sidenav{display:block;width:var(--rail-w);background:var(--char);flex-shrink:0;
    position:sticky;top:0;height:100vh;z-index:31;transition:width .16s ease}
  .railinner{position:absolute;top:0;bottom:0;left:0;width:var(--rail-w);
    display:flex;flex-direction:column;background:var(--char);color:#9fb0c5;
    padding:18px 12px;overflow:hidden;transition:width .16s ease}
  .sidenav .brand{margin-bottom:24px;padding:2px 6px}
  /* The lockup and the toggle share a row so the toggle has somewhere to be
     that is not over a nav item. `position:relative` is for the collapsed
     state, where the toggle is taken out of the flow against this box. */
  .railtop{position:relative;display:flex;align-items:center;justify-content:space-between;gap:10px}
  .railtoggle{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
    width:28px;height:28px;border-radius:var(--r-sm);color:#9fb0c5;transition:background .12s,color .12s}
  .railtoggle:hover{background:rgba(255,255,255,.10);color:#fff}
  .railtoggle .ic{display:flex;line-height:0}
  .railtoggle .ic .ic-svg{width:16px;height:16px;vertical-align:0}

  /* ---- collapsed, and the hover peek ----
     The rail gives back 144px; `.railinner` keeps the open width the moment a
     pointer is over it or anything inside it has focus. `:focus-within` is not
     a nicety — the toggle is the first thing Tab reaches inside the rail, so
     without it a keyboard user would be operating a control they cannot see. */
  .sidenav.collapsed{width:var(--rail-c)}
  .sidenav.collapsed .railinner{width:var(--rail-c)}
  .sidenav.collapsed:hover .railinner,
  .sidenav.collapsed:focus-within .railinner{width:var(--rail-w);
    box-shadow:10px 0 30px rgba(16,24,40,.28)}

  /* WHAT THE COLLAPSED RAIL DROPS. Opacity, not `display:none`: every one of
     these is still in the DOM and still read, so a collapsed rail's Bookings
     button is still announced as "Bookings" rather than as an unnamed button.
     The toggle goes with them — at 72px it would otherwise show as a sliver of
     a chevron — and takes `pointer-events` with it so the sliver is not
     clickable either. Hovering the rail is what brings it back. */
  .sidenav.collapsed:not(:hover):not(:focus-within) :is(.nvl,.ftxt,.who,.cctxt,.railtoggle){
    opacity:0;pointer-events:none;transition:opacity .1s ease}
  /* …and the toggle leaves the ROW as well as the paint, so the logo can centre
     itself in 72px. Out of flow rather than `display:none`, because a display
     of none is not focusable — and the toggle is the one thing Tab has to be
     able to reach to open a rail without a mouse. */
  .sidenav.collapsed:not(:hover):not(:focus-within) .railtoggle{position:absolute;right:0;top:0}
  .sidenav.collapsed:not(:hover):not(:focus-within) .railtop{justify-content:center}
  .sidenav.collapsed:not(:hover):not(:focus-within) .brand{padding:0}
  /* The padding comes off so the lockup gets the rail's full 72px less 16, and
     the lockup is sized by WIDTH rather than height here — the open rail sets
     `height:40px` inline, which at 2.1:1 is 84px across and half of it would be
     outside the rail. `!important` because that height is an inline style and
     nothing else can reach it; the alternative is a second copy of the <img>
     for a state that differs only in its size. */
  .sidenav.collapsed:not(:hover):not(:focus-within) .railinner{padding:18px 8px}
  .sidenav.collapsed:not(:hover):not(:focus-within) .blogo{width:100%;height:auto!important}
  /* Centred, and the padding goes with it: an 18px icon left-aligned in 56px of
     column sits visibly off to one side of a rail whose only remaining content
     is icons.
     THE LABEL HAS TO LEAVE THE FLOW FOR THAT TO MEAN ANYTHING — fifth time, and
     the same bargain as `.who`, `.ftxt` and `.cctxt`. A label at `opacity:0` is
     still a flex item claiming ~90px, so `justify-content:center` centres the
     icon against the icon PLUS the invisible word and puts it hard against the
     left edge. Measured, not guessed: that is exactly what the first cut of
     this rule did. */
  .sidenav.collapsed:not(:hover):not(:focus-within) .nav-it{justify-content:center;padding:10px 0}
  .sidenav.collapsed:not(:hover):not(:focus-within) .nvl{position:absolute;left:45px;top:10px}
  /* The name and email go out of flow for the same reason, and it is the same
     bargain: `display:none` would leave the account button with no accessible
     name at all, and leaving them in flow squeezes the avatar into an ellipse
     — 24px of circle against 56px of column, with the words still claiming
     their width behind an opacity of nought. */
  .sidenav.collapsed:not(:hover):not(:focus-within) .who{position:absolute;left:45px;top:10px}
  .sidenav.collapsed:not(:hover):not(:focus-within) .sideuser{justify-content:center;padding:10px 0}
  /* Out of flow, third time, same bargain: "Prototype · sample data / Staff
     console" is wider than 56px, and a row centred on words nobody can see
     leaves nothing on screen but its own empty height. */
  .sidenav.collapsed:not(:hover):not(:focus-within) .ftxt{position:absolute;left:0;top:10px}
  .sidenav.collapsed:not(:hover):not(:focus-within) .sidefoot{padding:10px 0}
  /* Out of flow, FOURTH time, and the same bargain again: "Built & maintained
     by craig-creative.ai" is wider than 56px, and a row centred on words nobody
     can see puts the one thing left on screen — the mark — off centre. (This
     quoted the pre-9-Sep copy, "Tailor Made by Craig Creative…", until a grep
     for the replaced string found it; the rule holds either way.) The link is
     named by its own `aria-label`, so a collapsed rail still announces where it
     goes rather than reading out an href. `.ccredit` is `position:relative`
     (below) so this lands inside it: absolute against `.railinner` would park
     the words behind the lockup at the top of the rail. */
  .sidenav.collapsed:not(:hover):not(:focus-within) .cctxt{position:absolute;left:0;top:0}
  .sidenav.collapsed:not(:hover):not(:focus-within) .ccdark{justify-content:center;padding:12px 0}
  /* The count of new jobs, as a dot on the corner of the Today icon. The number
     cannot fit at 72px and is still in the DOM for a screen reader. */
  .sidenav.collapsed:not(:hover):not(:focus-within) .newdot{
    position:absolute;top:5px;left:calc(50% + 6px);min-width:9px;width:9px;height:9px;
    padding:0;margin:0;border-radius:50%;font-size:0;line-height:0;overflow:hidden}
  .main{padding:24px 28px 40px}
}

/* AN IPAD IS NOT A DESKTOP WITH A MOUSE, and 900px does not tell them apart.
   Above the breakpoint is an iPad in landscape too, and there the hover peek
   never fires: `:hover` does not exist on the device, and the toggle the
   collapsed rail hides is `pointer-events:none`, so a tap where it sits lands
   on the logo behind it — leaving the rail collapsed with no way back. That is
   the tablet propped by the ramp, which is the device the 144px matters most
   on.

   So where there is no hover, the collapsed rail does not rely on one. The
   toggle comes back into the flow under the logo: visible, 36px, and the only
   thing in the header that is not the lockup.

   AND THE SELECTOR DROPS `:not(:hover)`, WHICH IS THE WHOLE FIX rather than a
   tidy-up — the first cut of this block repeated the one above verbatim and did
   not work, on the device it was written for. Chromium applies `:hover` to what
   a finger is touching, and it applies `:focus-within` on the press rather than
   the release. So a tap on the toggle turns BOTH of those on before the click
   is dispatched, the rules above stop matching mid-tap, the toggle returns to
   `position:absolute` at the top-right of a rail that has just widened to
   216px, and the click lands on the logo it left behind. Measured with touch
   emulation at 1180px: the tap produced no click on the button at all, and the
   rail could not be re-opened.

   A control has to be in the same place at press and at release, so on a device
   with no hover the toggle's box may not depend on a hover or focus state at
   all. `!important` is how that is said against selectors upstream that carry
   two `:not()`s of specificity each; the alternative is duplicating the whole
   collapse list twice under `@media (hover:hover)`, which is more surface for
   the next person to get half-right. */
@media(min-width:900px) and (hover:none){
  /* NO PEEK EITHER, and that is the second half of the same fix. Leaving it in
     was not enough on its own: with the toggle pinned but the rail still
     widening to 216px under the press, a centred toggle slides 24px right
     between press and release and the tap misses by six pixels. Measured, both
     times. A `:hover` a finger left behind is not an intention anyway — the
     rail's width is the toggle's business alone on a device with no pointer.
     Same specificity as the peek above, later in source, so it wins. */
  .sidenav.collapsed:hover .railinner,
  .sidenav.collapsed:focus-within .railinner{width:var(--rail-c);box-shadow:none}
  /* …and the two rules that would otherwise flicker back mid-tap, restated
     without the `:not()`s so the rail's geometry is the same at press and at
     release. Same values as above; only their condition changes. */
  .sidenav.collapsed .railinner{padding:18px 8px}
  .sidenav.collapsed .blogo{width:100%;height:auto!important}
  .sidenav.collapsed .railtop{flex-direction:column;justify-content:center;gap:8px}
  .sidenav.collapsed .railtoggle{
    position:static!important;opacity:1!important;pointer-events:auto!important;
    background:rgba(255,255,255,.08)}
  /* 44px, WHICH IS THE POINT OF THE WHOLE BLOCK AND WAS 36 UNTIL 9 Sep 2026.
     `.qa/checklists/07-ui-quality.md` puts the floor at 44 — "a garage counter
     is not a precise environment" — and this is the one control in the sheet
     that exists purely because a finger is going to press it. A fallback that
     makes a control reachable and leaves it under the floor has done half its
     job, which is the second time that sentence applies to this block: the
     first was a tap that missed by six pixels because the toggle moved, and
     this is six more pixels of margin for a finger that lands slightly off
     centre rather than off control. Raised by the QA review of this branch.

     BOTH RAIL STATES, not just the collapsed one: on a tablet the expanded
     rail's toggle is the same finger and the same 28px. `min-*` rather than
     `width`, so it raises the base rule without having to out-specify it.
     The 72px rail leaves 56px of content, so 44 fits with room either side.

     The FCC twin carries the identical rule for the identical reason. */
  .railtoggle{min-width:44px;min-height:44px}
}
.nav-it{position:relative;display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:var(--r-sm);font-size:var(--fs-lg);font-weight:var(--fw-med);margin-bottom:3px;color:#aab6c4;width:100%;text-align:left}
.nav-it.on{background:rgba(245,197,24,.16);color:#fff;box-shadow:inset 3px 0 0 var(--brand)}
.nav-it .ic{width:18px;display:flex;justify-content:center;line-height:0}
.nav-it .ic .ic-svg{width:18px;height:18px;vertical-align:0}
.sidefoot{margin-top:auto;padding:10px 6px;font-size:var(--fs-xs);color:#8f9fb2;line-height:1.5}
.sideuser{display:flex;align-items:center;gap:9px;padding:10px 6px;border-top:1px solid rgba(255,255,255,.08);margin-top:10px;width:100%;text-align:left}
.sideuser .nm{font-size:var(--fs-md);font-weight:var(--fw-semi);color:#dfe6ee}
.sideuser .em{font-size:var(--fs-xs);color:#6b7785}

/* ===== shared bits ===== */
.h2{font-size:var(--fs-3xl);font-weight:var(--fw-bold);color:var(--char)}
.sub{font-size:var(--fs-md);color:var(--mut);margin-top:3px;line-height:1.5}
.pagehead{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;flex-wrap:wrap}
.tgl{border:1px solid var(--line);background:#fff;border-radius:var(--r-pill);padding:7px 16px;font-size:var(--fs-md);font-weight:var(--fw-semi);color:var(--char)}
.tgl.on{background:var(--brand);color:var(--ink-on-brand);border-color:var(--brand)}
.chiprow{display:flex;gap:7px;overflow-x:auto;padding:12px 0 6px;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.chiprow::-webkit-scrollbar{display:none}
.chip{flex-shrink:0;border:1px solid var(--line);background:#fff;border-radius:var(--r-pill);padding:7px 14px;font-size:var(--fs-md);font-weight:var(--fw-med);color:var(--mut)}
.chip.on{background:var(--char);border-color:var(--char);color:#fff}
.datechip{font-size:var(--fs-xs);font-weight:var(--fw-bold);color:var(--mut);margin:16px 2px 8px;text-transform:uppercase;letter-spacing:.6px}
.empty{background:#fff;border:1px dashed var(--line);border-radius:var(--r);padding:26px;text-align:center;color:var(--mut);font-size:var(--fs-md);margin-top:10px}

/* buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;border-radius:var(--r-md);padding:12px 18px;font-size:var(--fs-xl);font-weight:var(--fw-bold);transition:.14s}
.btn-pri{background:var(--brand);color:var(--ink-on-brand)}
.btn-pri:hover{background:var(--brand-d)}
.btn-dark{background:var(--char);color:#fff}
.btn-ghost{background:#fff;border:1.5px solid var(--line);color:var(--char)}
.btn-ghost:hover{border-color:var(--char)}
.btn-block{width:100%}
.btn:disabled{opacity:.45;cursor:not-allowed}

/* ===== CUSTOMER booking flow ===== */
/* width:100% is load-bearing: with margin:0 auto inside a column flexbox the
   auto margins disable stretch, so without it the page sizes to its content
   and can grow wider than the phone's viewport */
.cwrap{max-width:560px;width:100%;min-width:0;margin:0 auto;padding:16px 16px calc(96px + var(--safe-b))}
.steps{display:flex;gap:6px;margin:4px 0 16px}
.steps .s{flex:1;height:5px;border-radius:var(--r-pill);background:var(--line)}
.steps .s.on{background:var(--brand)}
.ch{font-size:var(--fs-4xl);font-weight:var(--fw-bold);letter-spacing:-.4px;color:var(--char)}
.csub{color:var(--mut);font-size:var(--fs-lg);margin:5px 0 16px;line-height:1.5}

.svc{display:flex;gap:13px;align-items:center;background:#fff;border:1px solid var(--line);border-left:4px solid var(--brand);
  border-radius:var(--r);padding:14px;margin-bottom:11px;box-shadow:var(--shadow);width:100%;text-align:left;transition:.14s}
.svc:hover{transform:translateY(-1px);box-shadow:0 6px 20px rgba(47,52,57,.10)}
.svc .ic{width:48px;height:48px;border-radius:var(--r-md);background:var(--brand-soft);display:grid;place-items:center;font-size:var(--fs-4xl);flex:none}
.svc .bd{flex:1;min-width:0}
.svc .bd b{font-size:var(--fs-xl);color:var(--char)}
.svc .bd p{margin:2px 0 0;font-size:var(--fs-md);color:var(--mut)}
.svc .pr{text-align:right;flex:none}
.svc .pr b{font-size:var(--fs-xl);color:var(--char)}
.svc .pr span{display:block;font-size:var(--fs-xs);color:var(--mut)}

/* customer service-menu tiles */
.svctiles{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;margin-bottom:14px}
@media(max-width:560px){.svctiles{grid-template-columns:1fr}}

.svctile{position:relative;align-self:start;min-width:0;min-height:172px;display:flex;flex-direction:column;
  background:#fff;border:1px solid var(--line);border-left:4px solid var(--brand);border-radius:var(--r-lg);box-shadow:var(--shadow);
  padding:15px;text-align:left;width:100%;cursor:pointer;transition:box-shadow .18s,transform .18s,border-color .18s}
.svctile:hover{box-shadow:0 8px 24px rgba(47,52,57,.12)}
.svctile.single:hover{transform:translateY(-2px)}
.svctile-top{display:flex;align-items:center;gap:11px}
.svctile-ic{width:44px;height:44px;flex:none;border-radius:var(--r-md);background:var(--brand-soft);display:grid;place-items:center;font-size:var(--fs-4xl)}
.svctile-body{margin-top:12px}
/* footer pinned to the bottom so the price + Book → line up across every tile */
.svctile-foot{display:flex;align-items:baseline;justify-content:space-between;gap:8px;margin-top:auto;padding-top:12px}
.svctile-price{font-size:var(--fs-2xl);font-weight:var(--fw-bold);color:var(--char)}
.svctile-go{font-size:var(--fs-md);font-weight:var(--fw-bold);color:var(--brand-ink);white-space:nowrap}

/* single-service tile (direct book) */
.svctile-kick{font-size:var(--fs-xs);font-weight:var(--fw-bold);letter-spacing:.5px;text-transform:uppercase;color:var(--mut)}
.svctile-name{font-size:var(--fs-2xl);font-weight:var(--fw-bold);color:var(--char);margin:0 0 3px;line-height:1.25}
.svctile-desc{font-size:var(--fs-md);color:var(--mut);line-height:1.45;margin:0}

/* multi-service tile (summary → expands) */
.svctile-head{flex:1;min-width:0}
.svctile-cat{display:block;font-size:var(--fs-xl);font-weight:var(--fw-bold);color:var(--char)}
.svctile-cat i{font-style:normal;font-size:var(--fs-sm);font-weight:var(--fw-semi);color:var(--mut);margin-left:7px;
  background:var(--bg);border:1px solid var(--line);border-radius:var(--r-pill);padding:1px 8px;vertical-align:middle}
.svctile-sum{font-size:var(--fs-md);color:var(--mut);margin:0;line-height:1.45;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.svctile-chev{flex:none;align-self:flex-start;font-size:var(--fs-3xl);line-height:1;color:var(--mut);transition:transform .25s ease}

/* smooth expand; once open the summary + parent footer give way to the child rows */
.svctile-sub{display:grid;grid-template-rows:0fr;transition:grid-template-rows .28s ease}
.svctile-sub-in{overflow:hidden;min-height:0}
.svctile.multi:hover .svctile-sub,.svctile.multi.open .svctile-sub{grid-template-rows:1fr}
.svctile.multi:hover .svctile-chev,.svctile.multi.open .svctile-chev{transform:rotate(180deg)}
.svctile.multi:hover .svctile-body,.svctile.multi.open .svctile-body,
.svctile.multi:hover .svctile-foot,.svctile.multi.open .svctile-foot{display:none}

/* child rows — mirror the tile: yellow margin, full details, price + Book → */
.subrow{display:flex;flex-direction:column;width:100%;text-align:left;cursor:pointer;
  background:#fff;border:1px solid var(--line);border-left:4px solid var(--brand);border-radius:var(--r-md);
  padding:11px 13px;margin-top:10px;transition:box-shadow .14s,background .14s}
.subrow:first-child{margin-top:14px}
.subrow:hover{background:#fffdf3;box-shadow:0 4px 14px rgba(47,52,57,.10)}
.subrow-top{display:flex;align-items:center;gap:10px}
.subrow-ic{width:32px;height:32px;flex:none;border-radius:var(--r-sm);background:var(--brand-soft);display:grid;place-items:center;font-size:var(--fs-2xl)}
.subrow-nm{flex:1;min-width:0;font-size:var(--fs-lg);font-weight:var(--fw-bold);color:var(--char);line-height:1.25}
.subrow-desc{font-size:var(--fs-sm);color:var(--mut);line-height:1.5;margin:8px 0 0}
.subrow-foot{display:flex;align-items:baseline;justify-content:space-between;gap:8px;margin-top:9px}
.subrow-pr{font-size:var(--fs-lg);font-weight:var(--fw-bold);color:var(--char)}

.cbox{background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:16px;box-shadow:var(--shadow);margin-bottom:12px}
.fld{margin-bottom:13px}
.fld:last-child{margin-bottom:0}
.fld label{display:block;font-size:var(--fs-md);font-weight:var(--fw-semi);margin-bottom:6px;color:var(--char)}
.fld input,.fld select,.fld textarea{width:100%;padding:12px 13px;border:1.5px solid var(--line);border-radius:var(--r-md);background:#fff;transition:.14s}
.fld input:focus,.fld select:focus,.fld textarea:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px rgba(245,197,24,.22)}
.reg{display:flex;gap:10px}
.plate,.fld input.plate{font-weight:var(--fw-bold);background:#ffd400;border:2px solid #111;border-radius:var(--r-sm);padding:11px 14px;font-size:var(--fs-4xl);letter-spacing:1.5px;text-transform:uppercase;width:100%;min-width:0;text-align:center}
/* inputs in flex rows must be allowed to shrink below their intrinsic width */
.reg .plate,.checkhero-in .plate,.remind-in input,.keyrow input{min-width:0;flex:1}
.found{margin-top:11px;padding:13px;border:1.5px solid #bfe3cb;background:#f1faf3;border-radius:var(--r-md)}
.found .pill{background:var(--green-ink);color:#fff;padding:3px 10px;border-radius:var(--r-pill);font-size:var(--fs-xs);font-weight:var(--fw-bold)}

.daystrip{display:flex;gap:8px;overflow-x:auto;padding:2px 0 8px;scrollbar-width:none}
.daystrip::-webkit-scrollbar{display:none}
.day{flex:none;width:60px;border:1.5px solid var(--line);border-radius:var(--r-md);background:#fff;padding:10px 0;text-align:center;transition:.12s}
.day small{display:block;font-size:var(--fs-xs);color:var(--mut);text-transform:uppercase;font-weight:var(--fw-semi)}
.day b{display:block;font-size:var(--fs-3xl);margin-top:2px;color:var(--char)}
.day.sel{background:var(--char);border-color:var(--char)}
.day.sel small{color:var(--brand)}.day.sel b{color:#fff}
.day:disabled{opacity:.35}
.slots{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin-top:8px}
.slot{padding:12px 0;border:1.5px solid var(--line);border-radius:var(--r-md);background:#fff;font-weight:var(--fw-semi);font-size:var(--fs-xl);color:var(--char);transition:.12s}
.slot:hover:not(:disabled){border-color:var(--brand)}
.slot.sel{background:var(--brand);border-color:var(--brand);color:var(--ink-on-brand)}
.slot:disabled{opacity:.3;text-decoration:line-through}

.row{display:flex;justify-content:space-between;gap:12px;padding:11px 0;border-bottom:1px dashed var(--line);font-size:var(--fs-lg)}
.row:last-child{border:none}
.row .k{color:var(--mut)}.row .v{font-weight:var(--fw-semi);text-align:right;color:var(--char);min-width:0;overflow-wrap:anywhere}
.total{display:flex;justify-content:space-between;align-items:baseline;margin-top:6px;padding-top:12px;border-top:2px solid var(--char)}
.total b{font-size:var(--fs-4xl);color:var(--char)}
.cardbox{border:1.5px solid var(--line);border-radius:var(--r-md);padding:14px;background:#fbfbfc}
.incl{display:flex;gap:9px;padding:7px 0;font-size:var(--fs-lg);align-items:flex-start}
.incl span:last-child{min-width:0;overflow-wrap:anywhere}
/* list glyphs: plain icon, no background, fixed column so rows line up */
.incl .tk{color:var(--green-ink);font-weight:var(--fw-bold);flex:none;width:20px;text-align:center;line-height:1.4}
.incl .tk.warn{color:var(--amber-ink)}
.incl .tk.rep{color:var(--violet);font-size:var(--fs-2xl)}

.cta{position:fixed;bottom:0;left:0;right:0;z-index:40;background:linear-gradient(180deg,rgba(244,245,247,0),var(--bg) 30%);
  padding:14px 16px calc(14px + var(--safe-b));display:flex;justify-content:center}
.cta .in{width:100%;max-width:528px}
.tick{width:74px;height:74px;border-radius:50%;background:var(--green);display:grid;place-items:center;margin:6px auto 12px;color:#fff;font-size:var(--fs-7xl);box-shadow:0 10px 30px rgba(47,158,91,.34);animation:pop .4s ease}
@keyframes pop{0%{transform:scale(.6);opacity:0}100%{transform:scale(1);opacity:1}}

/* ===== STAFF: KPIs, diary, cards ===== */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin:14px 0 12px}
.kpi{background:#fff;border-radius:var(--r);box-shadow:var(--shadow);padding:15px;border-top:3px solid var(--brand)}
/* THE STEP BELOW, NOT THE NEAREST, and this is the one place the scale needed
   an argument rather than arithmetic. This line was 11.5px — a half-pixel nudge,
   and a load-bearing one: the lead tile's sub-line is "EK58 NXP · Full Service"
   in a 136px column, and it fitted on one line at 11.5 and wrapped at 12.
   Snapping up broke it, which the before/after screenshots showed and no amount
   of reading the rule would have.
   Restoring 11.5 would have been re-adding the nudge. It takes --fs-xs instead:
   on the scale, closer to what it was, and it fits — and it was always tuned to
   ONE sample string anyway, since a longer service name wrapped at 11.5 too. */
.kpi b{font-size:var(--fs-5xl);color:var(--char)}.kpi span{display:block;font-size:var(--fs-xs);color:var(--mut);font-weight:var(--fw-med);margin-top:3px}
.kpi .delta{font-size:var(--fs-xs);font-weight:var(--fw-bold);margin-top:6px;display:inline-block;border-radius:var(--r-sm);padding:2px 7px}
.up{background:#e7f5ec;color:var(--green-ink)}.dn{background:#fcebea;color:var(--red-ink)}

.section{background:#fff;border-radius:var(--r);box-shadow:var(--shadow);padding:14px 15px;margin:0 0 12px}
.sectitle{font-size:var(--fs-xs);font-weight:var(--fw-bold);color:var(--mut);letter-spacing:.6px;text-transform:uppercase;margin-bottom:10px;display:flex;align-items:center;justify-content:space-between}

/* unified job row (diary + bookings) */
.joblist{margin-top:2px}
.daygroup{display:flex;align-items:center;gap:10px;margin:14px 2px 6px}
.daygroup:first-child{margin-top:2px}
.daygroup b{font-size:var(--fs-sm);font-weight:var(--fw-bold);color:var(--char);text-transform:uppercase;letter-spacing:.5px}
.daygroup span{flex:1;height:1px;background:var(--line)}
.daygroup em{font-style:normal;font-size:var(--fs-sm);color:var(--mut);font-weight:var(--fw-med)}
.job{display:flex;align-items:center;gap:13px;padding:12px 12px;border:1px solid transparent;border-radius:var(--r-md);cursor:pointer;transition:.12s}
.job + .job{margin-top:2px}
.job:hover{background:#fafbfc;border-color:var(--line)}
.jaccent{width:4px;align-self:stretch;min-height:40px;border-radius:var(--r-xs);flex:none}
.jtime{width:52px;flex:none;text-align:center}
.jtime b{font-size:var(--fs-xl);font-weight:var(--fw-bold);color:var(--char);display:block;letter-spacing:-.3px}
.jtime small{color:var(--mut);font-size:var(--fs-xs);font-weight:var(--fw-semi)}
.jicon{width:40px;height:40px;border-radius:var(--r-md);background:var(--brand-soft);display:grid;place-items:center;font-size:var(--fs-4xl);flex:none}
.jinfo{flex:1;min-width:0}
.jinfo .jveh{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.jinfo b{font-size:var(--fs-xl);color:var(--char);font-weight:var(--fw-bold)}
.reg{font-size:var(--fs-xs);font-weight:var(--fw-bold);letter-spacing:.5px;background:#ffd400;color:#111;border-radius:var(--r-xs);padding:2px 7px;border:1px solid #e6bf00}
.jinfo p{margin:3px 0 0;font-size:var(--fs-md);color:var(--mut);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.jright{text-align:right;flex:none;display:flex;flex-direction:column;align-items:flex-end;gap:5px}
.due{font-size:var(--fs-sm);color:var(--amber-ink);font-weight:var(--fw-bold)}
.paidtag{font-size:var(--fs-sm);color:var(--green-ink);font-weight:var(--fw-bold)}
@media(max-width:560px){
  .jicon{display:none}
  .jinfo p{white-space:normal}
}

.st{padding:4px 11px;border-radius:var(--r-pill);font-size:var(--fs-sm);font-weight:var(--fw-bold);white-space:nowrap;display:inline-block}
.st-booked{background:#eef3fd;color:var(--blue)}
.st-checked_in{background:#fdf3e0;color:#b97f1e}
.st-in_progress{background:#f1ecfb;color:var(--violet)}
.st-ready{background:#e7f5ec;color:var(--green-ink)}
.st-completed{background:#eef0f2;color:var(--mut)}
.st-no_show{background:#fcebea;color:var(--red-ink)}

/* table */
.dt{width:100%;border-collapse:collapse}
.dt th{text-align:left;font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.5px;color:var(--mut);padding:10px 12px;border-bottom:1px solid var(--line);font-weight:var(--fw-bold)}
.dt td{padding:12px;border-bottom:1px solid #f1f3f5;font-size:var(--fs-lg)}
.dt tr:last-child td{border:none}
.dt tr.clk:hover{background:#fafbfc;cursor:pointer}
.veh{font-weight:var(--fw-bold);color:var(--char)}
.s2{color:var(--mut);font-size:var(--fs-sm)}

/* ===== the five repeats (bc-design-system) =====
   `.review/scan.sh` counts the most-repeated inline `style=` attributes under
   the heading "a repeat is a class not yet written", and these were the five:
   margin-top:12px at 23 sites, text-align:center at 13, color:var(--red-ink) at
   12, margin:6px 0 0 at 11 and margin-top:10px at 10 — 69 attributes saying one
   of five things.

   Deliberately NOT a utility framework. These are the five the count actually
   found, named for what they are rather than for their values, so a sixth does
   not arrive by habit; the gate's design-system check fails when the inline
   count RISES, which is what keeps the list from growing quietly. Only whole
   attributes were replaced — a style that combines two declarations stays
   inline, because splitting it would change which rule wins. */
.mt-md{margin-top:12px}
.mt-sm{margin-top:10px}
.stack-xs{margin:6px 0 0}
.centred{text-align:center}
.warn-ink{color:var(--red-ink)}
/* A HEADING THAT MUST NOT LOOK LIKE ONE. The home page's two section labels
   were <b> so that <h2>'s own margins and size would not disturb the card they
   sit in — which left the page with one h1 and zero h2s, while #/check and the
   staff screens use real h2s throughout. They are headings now, painted exactly
   as the <b> was: verified by screenshotting the page before and after.

   NOT `display:contents`, which would have been the tidiest way to make the
   wrapper disappear and is the one thing this must not do: several browsers
   have dropped elements with it from the accessibility tree, and a heading
   nobody can navigate to is the defect this was fixing. A block with no margin
   does the same job and stays a heading. */
.h2-plain{margin:0;font-size:inherit;font-weight:inherit;color:inherit;line-height:inherit}
/* The confirmation route with no booking to show, and the sign-in card when
   Google cannot be reached. Both are small centred states; neither earns a
   one-off inline style, and the gate counts those for exactly this reason. */
.nobooking{text-align:center}
.nobooking .ch{margin:0 0 8px}
.nobooking .csub{margin:0 0 12px}
.nobooking .csub+.csub{margin-bottom:16px}
.gsi-note{text-align:center;margin:0}
/* Where a screen's figures came from. The staff console's only provenance note
   used to be in `.sidenav`, which is display:none below 900px — so on the phone
   the console is built for, the Reports screen carried no indication that its
   numbers were not real. This renders at every width. */
.provenance{margin:14px 0 0;padding-top:10px;border-top:1px solid var(--line)}

/* job detail */
.dheader{background:var(--char);color:#fff;padding:16px 18px 18px;border-radius:0}
@media(min-width:900px){.dheader{border-radius:var(--r-lg)}}
.dheader .addr{color:#fff;font-size:var(--fs-3xl);font-weight:var(--fw-bold)}
.dheader .meta{color:#b3bdc7;font-size:var(--fs-md);margin-top:3px}
/* used on both <a> and <button> — the in-flow "‹ Back" steps are buttons now
   that there are no javascript: hrefs, so reset the button chrome */
.backlnk{font-size:var(--fs-sm);color:var(--brand);margin-bottom:6px;display:inline-block;font-weight:var(--fw-semi);
  background:none;border:0;padding:0;font-family:inherit;cursor:pointer;text-align:left}
.scorebar{display:flex;gap:8px;margin-top:13px}
.sb{flex:1;background:rgba(255,255,255,.08);border-radius:var(--r-md);padding:9px 11px;min-width:0}
.sb b{display:block;font-size:var(--fs-xl);white-space:nowrap}.sb span{font-size:var(--fs-2xs);color:#aab6c4;font-weight:var(--fw-semi);letter-spacing:.3px}
/* four stat cells don't fit a phone — wrap to a tidy 2×2 */
@media(max-width:560px){.scorebar{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}}
.dbody{padding:12px 0}
@media(min-width:900px){.dbody{margin-top:12px;display:grid;grid-template-columns:1.2fr .8fr;gap:12px;align-items:start;padding:0}.dbody>div{min-width:0}}
.kv{display:flex;justify-content:space-between;gap:12px;font-size:var(--fs-md);padding:7px 0;border-bottom:1px solid #f1f3f5}
.kv:last-child{border:none}.kv b{font-weight:var(--fw-semi);text-align:right;color:var(--char);min-width:0;overflow-wrap:anywhere}.kv span{color:var(--mut);flex-shrink:0}
.stage-pills{display:flex;gap:6px;flex-wrap:wrap}
.sp{border-radius:var(--r-pill);border:1.5px solid var(--line);padding:8px 14px;font-size:var(--fs-md);font-weight:var(--fw-semi);color:var(--mut);background:#fff}
.sp.cur{background:var(--char);border-color:var(--char);color:#fff}
.sp.done{background:var(--brand-soft);border-color:var(--brand);color:var(--brand-ink)}
/* Closing a job out — cancelled or a no-show. Deliberately a separate row from
   .stage-pills with a rule above it: these end the job rather than advancing it,
   and a mis-tap on "Completed" must not be able to land on "Cancelled". */
/* The diary's past bookings. A <details> rather than a tab: the diary is about
   what is coming, and history is something you go looking for. It opens itself
   while a search is running — somebody searching wants the match, not a drawer. */
/* A setting that is real but not editable here. It reads as a value, not as a
   disabled input: the point is what this deployment is running, and an input
   that cannot be typed into invites the tap that discovers it. */
.fixedset{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;padding:8px 0;border-bottom:1px solid #f1f3f5}
.fixedset-k{font-size:var(--fs-md);color:var(--txt);flex:1;min-width:140px}
.fixedset-v{font-size:var(--fs-md);color:var(--char);font-weight:var(--fw-bold);white-space:nowrap}
.fixedset-w{font-style:normal;font-size:var(--fs-sm);color:var(--mut);flex-basis:100%}
.hrs-val{font-size:var(--fs-md);color:var(--char);font-weight:var(--fw-bold);margin-left:auto}
.settings-note{margin-top:12px;padding:9px 11px;border-radius:var(--r-sm);background:var(--bg);line-height:1.5}
.settings-note .ic-svg{color:var(--brand-ink);vertical-align:-.2em}
.settings-warn{margin-top:12px;padding:9px 11px;border-radius:var(--r-sm);background:#fcebea;
  border-left:3px solid var(--red);line-height:1.5}
.settings-warn b{color:var(--red-ink)}
.settings-warn .ic-svg{color:var(--red);vertical-align:-.2em}
.earlier{margin-top:18px;border-top:1px solid var(--line);padding-top:12px}
.earlier summary{cursor:pointer;font-size:var(--fs-md);font-weight:var(--fw-bold);color:var(--mut);
  letter-spacing:.3px;text-transform:uppercase;padding:6px 2px;list-style:none}
.earlier summary::-webkit-details-marker{display:none}
.earlier summary::before{content:"\25B8";display:inline-block;margin-right:7px;transition:transform .15s}
.earlier[open] summary::before{transform:rotate(90deg)}
.earlier summary:hover{color:var(--char)}
.listcap{margin:10px 2px 0;color:var(--mut)}
.remind-note{margin:10px 0 0;padding:9px 11px;border-radius:var(--r-sm);background:var(--brand-soft);
  border-left:3px solid var(--brand-d);line-height:1.5}
.remind-note b{color:var(--char)}
.remind-note .ic-svg{color:var(--brand-ink);vertical-align:-.2em}
.jobclose{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}
.jobclosed{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:12px;padding:10px 12px;border-radius:var(--r-md);
  background:var(--bg);border-left:4px solid var(--red);font-size:var(--fs-md);line-height:1.5;color:var(--txt)}
.jobclosed b{color:var(--red-ink)}
/* What the customer was actually told, under the stage pills. A strip rather
   than a paragraph, because it answers a question the staff member is holding
   in their head at the counter — "does she know it's ready?" — and body text
   in the same colour as the sentence above it does not get read. Green when
   the message went, red when it did not; the button sits inline because the
   remedy belongs next to the problem. */
/* The customer's own booking (#/manage). Two actions, side by side on a phone
   and never stacked into a column of identical-looking buttons: one of them
   cancels an appointment and the other does not. */
.mgacts{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}
.mgacts .btn{flex:1 1 200px}
.mgfoot{margin-top:10px;color:var(--mut)}
.mgnone{color:var(--mut);padding:14px 0}
.stagenote{margin-top:10px;padding:9px 12px;border-radius:var(--r-md);background:var(--bg);
  border-left:4px solid var(--green);font-size:var(--fs-md);line-height:1.5;color:var(--txt)}
/* NOT display:flex, which is what the first version used. A flex container makes
   each text run and each <b> its own item, so "Customer not told the car is
   ready" wrapped between "told" and "the" — a sentence broken at the one place
   it has to hold together. Normal flow, and the icon aligns to the text. */
.stagenote svg{vertical-align:-2px;margin-right:2px}
.stagenote .btn{margin-top:8px}
.stagenote.bad{border-left-color:var(--red)}
.stagenote.bad b{color:var(--red-ink)}
.btn-sm{padding:7px 13px;font-size:var(--fs-md)}
.note{background:var(--bg);border-radius:var(--r-md);padding:10px 12px;font-size:var(--fs-md);margin-bottom:8px;line-height:1.5}
.note b{color:var(--char)}.note span{color:var(--mut);font-size:var(--fs-xs)}

/* catalogue admin */
.cat{display:flex;align-items:center;gap:13px;padding:13px 4px;border-bottom:1px solid #f1f3f5}
.cat:last-child{border:none}
.cat .ci{width:42px;height:42px;border-radius:var(--r-md);background:var(--brand-soft);display:grid;place-items:center;font-size:var(--fs-4xl);flex:none}
.cat .cb{flex:1;min-width:0}.cat .cb b{font-size:var(--fs-lg);color:var(--char)}.cat .cb p{margin:1px 0 0;font-size:var(--fs-sm);color:var(--mut)}
.cat .mt{display:flex;gap:16px;align-items:center;flex:none}
.cat .m{text-align:center}.cat .m small{display:block;font-size:var(--fs-2xs);color:var(--mut);text-transform:uppercase;letter-spacing:.4px;font-weight:var(--fw-bold)}.cat .m b{font-size:var(--fs-lg);color:var(--char)}
.toggle{width:42px;height:25px;border-radius:var(--r-pill);background:#d4d9df;position:relative;transition:.15s;flex:none}
.toggle.on{background:var(--green)}
.toggle::after{content:"";position:absolute;top:3px;left:3px;width:19px;height:19px;border-radius:50%;background:#fff;transition:.15s;box-shadow:0 1px 2px rgba(0,0,0,.2)}
.toggle.on::after{left:20px}
@media(max-width:560px){.cat .mt{gap:10px}.cat .m.hide-xs{display:none}}

/* chart — same scroll guard as the mileage chart */
.chart{display:flex;align-items:flex-end;gap:8px;height:134px;padding:8px 4px 4px;
  overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;scrollbar-width:thin}
.bar-w{flex:1 0 36px;min-width:36px;display:flex;flex-direction:column;align-items:center;gap:5px;height:100%;justify-content:flex-end}
.bar{width:100%;max-width:40px;border-radius:var(--r-sm) 6px 0 0;background:var(--char2);position:relative}
.bar.hot{background:var(--brand)}
.bar-w span{font-size:var(--fs-2xs);color:var(--mut);font-weight:var(--fw-semi)}
.bar em{position:absolute;top:-18px;left:0;right:0;text-align:center;font-size:var(--fs-xs);font-weight:var(--fw-bold);color:var(--char);font-style:normal}
.grid2{display:block}
@media(min-width:900px){.grid2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.grid2 .section{margin-bottom:0}}
.admin-flag{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;padding:9px 0;border-bottom:1px solid #f1f3f5;font-size:var(--fs-md)}
.admin-flag:last-child{border:none}
/* A row that reports a SERVER setting rather than toggling a local one: the
   status chip and its explanation are one item, so the hairline goes under the
   pair and not between them. Without this the caption reads as the start of the
   next setting. */
.admin-note{border-bottom:1px solid #f1f3f5}
.admin-note .admin-flag{border:none;padding-bottom:2px}
.admin-note p{margin:0 0 9px}
/* settings: opening-hours rows — shrinkable time fields so the row always fits */
.hrsrow{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid #f1f3f5;min-width:0}
/* The editable half of Settings (bc-capacity-tuning). The read-only rows kept
   their shape; these add the inputs beside them, and wrap rather than squeeze
   on a phone — the console's own device. */
.hrsrow-edit{flex-wrap:wrap;gap:8px 10px}
.hrsrow-edit .hrs-day{flex:1 0 auto;min-width:88px}
.hrs-times{display:flex;align-items:center;gap:6px}
.hrs-in{width:104px;padding:8px 9px;border:1px solid var(--line);border-radius:var(--r-sm);font:inherit;font-size:var(--fs-md);background:#fff}
.hrs-in:disabled{background:var(--bg);color:var(--mut)}
.hrs-dash{color:var(--mut)}
.setgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-top:14px}
.closedrow{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid #f1f3f5}
.closedrow b{min-width:104px}
.closedrow .s2{flex:1 1 auto}
.hrs-day{width:88px;flex:none;font-size:var(--fs-lg);font-weight:var(--fw-med)}
.hrs-t{width:76px;min-width:0;flex:0 1 76px;padding:7px 8px;text-align:center}
@media(max-width:560px){.hrs-day{width:44px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}

/* ===== login ===== */
.loginwrap{min-height:100vh;min-height:100dvh;display:flex;align-items:center;justify-content:center;background:linear-gradient(160deg,var(--char) 0%,var(--char2) 100%);
  padding:calc(20px + env(safe-area-inset-top,0px)) 20px calc(20px + var(--safe-b))}
.logincard{background:#fff;border-radius:var(--r-lg);padding:30px 28px;width:360px;max-width:100%;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,.35)}
.loginlogo{background:var(--char);border-radius:var(--r-lg);padding:20px 18px;margin:-6px -6px 18px}
.loginlogo img{width:210px;max-width:80%;height:auto;display:block;margin:0 auto}
.gbtn{display:flex;align-items:center;justify-content:center;gap:9px;border:1px solid var(--line);border-radius:var(--r-pill);padding:11px;font-size:var(--fs-lg);font-weight:var(--fw-semi);color:var(--txt);margin-top:18px;width:100%;background:#fff}
.gdot{width:18px;height:18px;border-radius:50%;background:conic-gradient(#ea4335 0 25%,#fbbc05 0 50%,#34a853 0 75%,#4285f4 0)}
.lock{font-size:var(--fs-sm);color:var(--mut);margin-top:14px;line-height:1.5}
.demonote{margin-top:16px;border-top:1px solid var(--line);padding-top:14px;font-size:var(--fs-xs);color:var(--mut)}
.demousers{display:flex;gap:7px;margin-top:9px;justify-content:center;flex-wrap:wrap}
.duser{border:1px solid var(--line);border-radius:var(--r-sm);padding:6px 12px;font-size:var(--fs-sm);font-weight:var(--fw-semi);color:var(--char);background:#fff}
/* The emailed-link alternative under the Google button. Left-aligned against
   the card's centred chrome on purpose: it contains a label and a field, and a
   centred form label reads as decoration rather than as an instruction. */
.linkalt{margin-top:18px;text-align:left}
.linkalt-or{display:flex;align-items:center;gap:10px;margin:0 0 14px;color:var(--mut);font-size:var(--fs-sm);text-transform:uppercase;letter-spacing:.06em}
.linkalt-or::before,.linkalt-or::after{content:"";flex:1;height:1px;background:var(--line)}
.linkalt .fld{margin-bottom:10px}
.denied{margin-top:18px;background:#fcebea;border-radius:var(--r-md);padding:16px;text-align:center}
.denied-h{font-weight:var(--fw-bold);color:var(--red-ink);font-size:var(--fs-xl);margin-top:4px}
.denied-b{font-size:var(--fs-md);color:var(--txt);margin-top:6px;line-height:1.5}

/* ===== demo toggle bar ===== */
/* safe-area top padding: in iOS standalone/PWA mode the status bar overlays
   the page — the topmost bar absorbs the inset so content never sits under it */
.demobar{position:sticky;top:0;z-index:35;background:var(--char);display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:calc(7px + env(safe-area-inset-top,0px)) 12px 7px;border-bottom:1px solid var(--char2)}
.seg{display:inline-flex;background:rgba(255,255,255,.09);border-radius:var(--r-pill);padding:3px;gap:3px}
.seg-b{padding:6px 15px;border-radius:var(--r-pill);font-size:var(--fs-md);font-weight:var(--fw-bold);color:#c7cdd4;display:flex;align-items:center;gap:6px;transition:.12s}
.seg-b:hover{color:#fff}
.seg-b.on{background:var(--brand);color:var(--ink-on-brand)}
.demobar .note{font-size:var(--fs-xs);color:#98a1ab;white-space:nowrap}
.demobar .note button{color:var(--brand);font-weight:var(--fw-semi);text-decoration:underline;font-size:var(--fs-xs)}
@media(max-width:560px){ .demobar .note{display:none} }
/* legacy banner (login back-link contexts) */
.demobanner{background:var(--char);color:#e7ebef;font-size:var(--fs-sm);font-weight:var(--fw-med);text-align:center;padding:8px 12px;line-height:1.4;display:flex;align-items:center;justify-content:center;gap:10px;flex-wrap:wrap}
.demobanner b{color:var(--brand)}
.demobanner button{font-weight:var(--fw-bold);text-decoration:underline;color:var(--brand);font-size:var(--fs-sm)}
#toasts{position:fixed;bottom:calc(92px + var(--safe-b));left:0;right:0;display:flex;flex-direction:column;align-items:center;gap:8px;z-index:90;pointer-events:none;padding:0 16px}
@media(min-width:900px){#toasts{bottom:28px}}
.toast{background:var(--char);color:#fff;font-size:var(--fs-md);font-weight:var(--fw-med);border-radius:var(--r-md);padding:11px 18px;box-shadow:0 8px 30px rgba(0,0,0,.25);animation:tin .2s ease;max-width:440px;text-align:center}
.toast b{color:var(--brand)}
@keyframes tin{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.menu{position:absolute;right:14px;top:56px;background:#fff;border-radius:var(--r-md);box-shadow:0 12px 40px rgba(0,0,0,.22);padding:7px;z-index:60;min-width:210px}
.menu .mi{display:flex;align-items:center;gap:9px;width:100%;text-align:left;padding:9px 11px;border-radius:var(--r-sm);font-size:var(--fs-md);font-weight:var(--fw-med);color:var(--txt)}
.menu .mi:hover{background:var(--bg)}
.menu .mhead{font-size:var(--fs-xs);font-weight:var(--fw-bold);color:var(--mut);text-transform:uppercase;letter-spacing:.5px;padding:7px 11px 3px}
.mini-av{width:24px;height:24px;border-radius:50%;background:var(--char2);color:#fff;font-size:var(--fs-2xs);font-weight:var(--fw-bold);display:flex;align-items:center;justify-content:center}
.newdot{display:inline-block;min-width:17px;height:17px;border-radius:var(--r-sm);background:var(--brand);color:var(--ink-on-brand);font-size:var(--fs-2xs);font-weight:var(--fw-bold);text-align:center;line-height:17px;padding:0 4px;margin-left:6px}

/* =========================================================================
   MOT lookup, health-check report & recommendations
   ========================================================================= */
/* customer landing "see what your car needs" hero */
.checkhero{background:linear-gradient(135deg,var(--char) 0%,var(--char2) 100%);color:#fff;border-radius:var(--r);padding:16px 16px 14px;margin:14px 0;box-shadow:var(--shadow)}
.checkhero-h{display:flex;gap:12px;align-items:flex-start}
.checkhero-ic{font-size:var(--fs-5xl);line-height:1}
.checkhero-h b{font-size:var(--fs-2xl);color:#fff}
.checkhero-h p{margin:3px 0 0;font-size:var(--fs-md);color:#c9d2db;line-height:1.4}
.checkhero-in{display:flex;gap:10px;margin-top:13px}
.checkhero-in .btn{white-space:nowrap}
.checkhero-note{display:block;margin-top:9px;font-size:var(--fs-xs);color:#aab6c4;text-align:center}

/* MOT status chip */
.motstat{display:flex;gap:11px;align-items:center;padding:11px 13px;border-radius:var(--r-md);border:1.5px solid var(--line);background:#fafbfc}
.motstat-ic{font-size:var(--fs-4xl);line-height:1}
.motstat b{display:block;font-size:var(--fs-lg);color:var(--char)}
.motstat span{font-size:var(--fs-sm);color:var(--txt)}
.motstat.ok{background:#f1faf3;border-color:#bfe3cb}
.motstat.warn{background:#fff7e9;border-color:#f2d99a}
.motstat.bad{background:#fcebea;border-color:#f3c0bd}.motstat.bad b{color:var(--red-ink)}
.motstat.neutral{background:#f4f5f7}

/* recall banner */
.recallbar{margin-top:11px;padding:11px 13px;border-radius:var(--r-md);background:#fcebea;border-left:4px solid var(--red);font-size:var(--fs-md);color:var(--txt);line-height:1.45}

/* recommended-service cards */
.recos{display:flex;flex-direction:column;gap:10px}
.reco{display:flex;gap:12px;align-items:center;padding:12px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--card)}
.reco-ic{width:42px;height:42px;flex:none;display:flex;align-items:center;justify-content:center;font-size:var(--fs-4xl);background:var(--brand-soft);border-radius:var(--r-md)}
.reco-bd{flex:1;min-width:0}
.reco-h{display:flex;gap:8px;align-items:center}
.reco-h b{font-size:var(--fs-lg);color:var(--char)}
.reco-badge{font-size:var(--fs-2xs);font-weight:var(--fw-bold);text-transform:uppercase;letter-spacing:.4px;padding:2px 7px;border-radius:var(--r-pill);background:var(--line);color:var(--mut);white-space:nowrap;flex:none}
.reco-bd p{margin:4px 0 0;font-size:var(--fs-md);color:var(--mut);line-height:1.4}
.reco-act{display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex:none}
.reco-pr{font-size:var(--fs-md);font-weight:var(--fw-bold);color:var(--char);white-space:nowrap}
.reco-urgent{border-left:4px solid var(--red)}.reco-urgent .reco-badge{background:var(--red);color:#fff}
.reco-soon{border-left:4px solid var(--amber)}.reco-soon .reco-badge{background:var(--amber-ink);color:#fff}
.reco-advisory{border-left:4px solid var(--blue)}.reco-advisory .reco-badge{background:var(--blue);color:#fff}
.reco-routine{border-left:4px solid var(--mut)}
/* mini recommendation chips inside the booking lookup card */
.reco-mini{margin-top:10px;display:flex;gap:7px;flex-wrap:wrap;align-items:center}
.reco-mini-link{font-size:var(--fs-sm);font-weight:var(--fw-semi);color:var(--brand-ink);margin-left:auto}

/* vehicle spec grid — minmax(0,…) so long values can never blow the grid
   wider than the viewport (the iOS "header doesn't extend" bug) */
.vehspecs{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-top:12px}
.vehspecs>div{background:#fafbfc;border:1px solid var(--line);border-radius:var(--r-sm);padding:7px 9px}
.vehspecs small{display:block;font-size:var(--fs-2xs);color:var(--mut);font-weight:var(--fw-semi);text-transform:uppercase;letter-spacing:.3px}
.vehspecs b{font-size:var(--fs-lg);color:var(--char);overflow-wrap:anywhere}
/* quick facts row */
.motfacts{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin-top:12px}
@media(max-width:420px){.motfacts{grid-template-columns:repeat(2,minmax(0,1fr))}}
.motfacts>div{text-align:center;background:#fafbfc;border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 6px}
.motfacts small{display:block;font-size:var(--fs-2xs);color:var(--mut);font-weight:var(--fw-semi)}
.motfacts b{font-size:var(--fs-lg);color:var(--char);overflow-wrap:anywhere}

/* mileage mini-chart — scrolls horizontally once the MOT history has more
   bars than the card can fit (real DVSA histories can have 10+ tests) */
.milechart{display:flex;align-items:flex-end;gap:6px;height:116px;padding:14px 4px 6px;
  overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;scrollbar-width:thin}
.mile-w{flex:1 0 34px;min-width:34px;display:flex;flex-direction:column;align-items:center;gap:4px;height:100%;justify-content:flex-end}
.mile-b{width:100%;max-width:34px;border-radius:var(--r-xs) 5px 0 0;background:var(--char2);position:relative;min-height:6px}
.mile-w span{font-size:var(--fs-2xs);color:var(--mut);font-weight:var(--fw-semi)}
.mile-b em{position:absolute;top:-16px;left:0;right:0;text-align:center;font-size:var(--fs-2xs);font-weight:var(--fw-bold);color:var(--char);font-style:normal}

/* MOT history timeline */
.motline{display:flex;flex-direction:column}
.motline-row{display:flex;gap:12px;padding:0 0 14px;position:relative}
.motline-row:not(:last-child)::before{content:"";position:absolute;left:6px;top:16px;bottom:0;width:2px;background:var(--line)}
.motline-dot{width:14px;height:14px;flex:none;border-radius:50%;margin-top:3px;border:3px solid #fff;box-shadow:0 0 0 2px var(--line);z-index:1}
.motline-dot.ok{background:var(--green);box-shadow:0 0 0 2px #bfe3cb}
.motline-dot.bad{background:var(--red);box-shadow:0 0 0 2px #f3c0bd}
.motline-bd{flex:1;min-width:0}
.motline-head{display:flex;gap:7px;align-items:baseline;flex-wrap:wrap}
.motline-head b{font-size:var(--fs-md);font-weight:var(--fw-bold);letter-spacing:.3px}
.motline-head span{font-size:var(--fs-sm);color:var(--mut)}
.defects{margin-top:7px;display:flex;flex-direction:column;gap:5px}
.defect{display:flex;gap:8px;align-items:flex-start;font-size:var(--fs-md);color:var(--txt);line-height:1.4}
.dtag{flex:none;font-size:var(--fs-2xs);font-weight:var(--fw-bold);letter-spacing:.3px;padding:2px 6px;border-radius:var(--r-xs);margin-top:1px;color:#fff}
.defect.bad .dtag{background:var(--red)}
.defect.warn .dtag{background:var(--amber-ink)}
.defect.adv .dtag{background:var(--blue)}

/* MOT-expiry reminder opt-in card */
.remindcard{background:#fffdf2;border:1px solid #f0e6bd;border-left:4px solid var(--brand)}
/* The same card when the opt-in was NOT stored — see remindCardHtml(). */
.remindcard.is-off{border-left-color:var(--red-ink)}
.stack-xxs{margin:2px 0 0}
.remind-h{display:flex;gap:11px;align-items:flex-start}
.remind-in{display:flex;gap:10px;margin-top:11px}
.remind-in .btn{white-space:nowrap}

/* Landing: MOT lookup as the hero + collapsible services fold */
.checkhero.hero-lg{padding:22px 18px 18px}
.hero-lg .checkhero-ic{font-size:var(--fs-6xl)}
.hero-lg .checkhero-h b{font-size:var(--fs-3xl)}
.hero-lg .checkhero-in{margin-top:16px}
.svcfold{margin-top:16px}
.svcfold-h{width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:15px 16px;
  font-weight:var(--fw-bold);font-size:var(--fs-xl);color:var(--char);cursor:pointer;box-shadow:var(--shadow);text-align:left}
.svcfold-h:hover{border-color:var(--brand-ink)}
.svcfold-chev{font-size:var(--fs-3xl);color:var(--mut);transition:transform .2s}
.svcfold.open .svcfold-h{border-color:var(--brand);border-bottom-left-radius:0;border-bottom-right-radius:0}
.svcfold.open .svcfold-chev{transform:rotate(180deg)}
.svcfold-body{display:none;margin-top:12px}
.svcfold.open .svcfold-body{display:block}

/* =========================================================================
   Vehicle-based pricing & polished customer flow
   ========================================================================= */
/* landing headline */
.chero{font-size:var(--fs-5xl);line-height:1.15;margin-top:6px}

/* trust strip under the hero */
.trustrow{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:0 0 14px}
@media(max-width:560px){.trustrow{grid-template-columns:repeat(2,1fr)}}
.trust{background:#fff;border:1px solid var(--line);border-radius:var(--r-md);padding:9px 6px;text-align:center;box-shadow:var(--shadow)}
.trust b{display:block;font-size:var(--fs-md);color:var(--char);white-space:nowrap}
.trust span{display:block;font-size:var(--fs-xs);color:var(--mut);font-weight:var(--fw-med);margin-top:1px;line-height:1.3}

/* "prices shown for your car" banner */
.vehbar{display:flex;gap:11px;align-items:center;background:var(--brand-soft);border:1.5px solid var(--brand);
  border-radius:var(--r-md);padding:11px 13px;margin:0 0 14px}
.vehbar-ic{font-size:var(--fs-4xl);line-height:1}
.vehbar-bd{flex:1;min-width:0}
.vehbar-bd b{display:block;font-size:var(--fs-lg);color:var(--char)}
.vehbar-bd span{font-size:var(--fs-sm);color:var(--mut);font-weight:var(--fw-med)}
.vehbar-x{flex:none;font-size:var(--fs-sm);font-weight:var(--fw-bold);color:var(--brand-ink);text-decoration:underline;padding:6px}

/* price-breakdown panel on the service page */
.pbreak{border-left:4px solid var(--brand)}
.pbhead{font-size:var(--fs-lg);font-weight:var(--fw-bold);color:var(--char);margin-bottom:8px}
.pbrow{display:flex;justify-content:space-between;gap:12px;padding:7px 0;border-bottom:1px dashed var(--line);font-size:var(--fs-md);color:var(--mut)}
.pbrow b{color:var(--char);font-weight:var(--fw-bold)}
.pbrow.pbtotal{border-bottom:none;border-top:2px solid var(--char);margin-top:2px;padding-top:10px;color:var(--char);font-weight:var(--fw-bold)}
.pbrow.pbtotal b{font-size:var(--fs-3xl)}
.lnk{color:var(--brand-ink);font-weight:var(--fw-semi);text-decoration:underline;font-size:inherit}

/* exact price line inside the booking lookup result */
.vehprice{margin-top:10px;background:var(--brand-soft);border:1px solid #f0e6bd;border-radius:var(--r-sm);
  padding:9px 11px;font-size:var(--fs-md);color:var(--char)}
.vehprice b{font-weight:var(--fw-bold)}

/* labelled booking stepper */
.steps4{display:flex;gap:4px;margin:4px 0 18px}
.st4{flex:1;display:flex;flex-direction:column;align-items:center;gap:5px;position:relative;padding-top:2px}
.st4::before{content:"";position:absolute;top:13px;left:-50%;width:100%;height:2.5px;background:var(--line);z-index:0}
.st4:first-child::before{display:none}
.st4.on::before,.st4.done::before{background:var(--brand)}
.st4-dot{width:24px;height:24px;border-radius:50%;background:#fff;border:2px solid var(--line);color:var(--mut);
  font-size:var(--fs-xs);font-weight:var(--fw-bold);display:grid;place-items:center;position:relative;z-index:1}
.st4.on .st4-dot{background:var(--brand);border-color:var(--brand);color:var(--ink-on-brand)}
.st4.done .st4-dot{background:var(--char);border-color:var(--char);color:var(--brand)}
.st4-l{font-size:var(--fs-xs);font-weight:var(--fw-semi);color:var(--mut)}
.st4.on .st4-l{color:var(--char);font-weight:var(--fw-bold)}

/* reminder promo card + page */
.remindpromo{background:#fffdf2;border:1px solid #f0e6bd;border-left:4px solid var(--brand);margin-top:16px}

/* staff catalogue CRUD */
.cat.clickable{cursor:pointer;border-radius:var(--r-md);transition:background .12s;margin:0 -4px;padding-left:8px;padding-right:8px}
.cat.clickable:hover{background:#fafbfc}
.cat.sel{background:var(--brand-soft)}
.cat.offline .cb b,.cat.offline .cb p{opacity:.55}
.varytag{font-size:var(--fs-2xs);font-weight:var(--fw-bold);letter-spacing:.3px;background:var(--brand-soft);border:1px solid #f0e6bd;color:var(--brand-ink);border-radius:var(--r-pill);padding:1px 7px;vertical-align:2px;white-space:nowrap}
.editchev{font-size:var(--fs-3xl);color:var(--mut);font-weight:var(--fw-semi);margin-left:2px}
.synccard{padding:12px 15px}
.syncrow{display:flex;gap:10px;align-items:center}
.syncrow b{font-size:var(--fs-lg);color:var(--char)}
.syncdot{width:10px;height:10px;border-radius:50%;flex:none;box-shadow:0 0 0 3px rgba(0,0,0,.05)}
.keyrow{display:flex;gap:9px;margin-top:11px;flex-wrap:wrap;align-items:center}

/* =========================================================================
   Mobile hardening (iOS / Android)
   ========================================================================= */
/* iOS Safari auto-zooms any focused input with font-size < 16px, which jolts
   the whole layout — force 16px on touch-sized screens (the reg plate is
   already 20px and unaffected) */
@media(max-width:900px){
  input,select,textarea,input.tgl{font-size:var(--fs-2xl)}
}
/* long MOT defect wording must wrap, never widen the page */
.defect span:last-child,.reco-bd p,.motline-head span{min-width:0;overflow-wrap:anywhere}
/* recommendation cards: on narrow phones the price + button drop to their own
   row instead of crushing the description */
@media(max-width:420px){
  .reco{flex-wrap:wrap}
  .reco-bd{flex-basis:calc(100% - 54px)}
  .reco-act{flex-direction:row;width:100%;justify-content:space-between;align-items:center;margin-top:2px}
}

/* customer footer */
.cfoot{margin:26px -4px 0;border-top:2px solid var(--line);padding:20px 4px calc(20px + var(--safe-b))}
.cfoot-grid{display:grid;grid-template-columns:1fr;gap:16px}
@media(min-width:560px){.cfoot-grid{grid-template-columns:1.2fr 1fr 1fr}}
.cfoot b{font-size:var(--fs-md);color:var(--char)}
.cfoot p{margin:5px 0 0;font-size:var(--fs-sm);color:var(--mut);line-height:1.6}
.cfoot-legal{margin-top:18px;text-align:center;font-size:var(--fs-xs);color:var(--mut)}

/* The maker's credit — greyscale, unobtrusive, very bottom of every page.

   THE TONE MET NO CONTRAST FLOOR UNTIL 9 SEP, and finding that was a side
   effect of shortening the copy. It rested at #9aa3ad, which is 2.34:1 on the
   page — 11px at weight 600, so 1.4.3's 4.5:1 applies and nothing here is
   large text. It went unmeasured because the only pairing on this credit was
   the mark's two fills and the DARK rail's words; the light ground's own colour
   was a literal on a selector nothing listed, which is the same blind spot the
   comment below records for the mark itself, one rule up.

   It survived this long partly because the bold half was brighter (#7d8894,
   3.31:1 — still short, but visibly darker), and removing the `<b>` with the
   brand name put the whole credit on the resting tone. That made a
   pre-existing failure uniform, which is what surfaced it.

   Both values are `--mut` and `--txt` now: paired tokens rather than literals,
   4.52:1 and 13.88:1 on the page and 4.93:1 in the account menu's white. The
   hover had to move with the resting tone rather than stay — #6b7686 is
   LIGHTER than `--mut`, so keeping it would have made hovering fade the credit
   instead of firming it. */
.ccredit{display:flex;align-items:center;justify-content:center;gap:7px;margin:24px auto 4px;
  font-size:var(--fs-xs);font-weight:var(--fw-med);color:var(--mut);letter-spacing:.2px;transition:color .15s}
.ccredit:hover{color:var(--txt)}
/* NO `color` HERE ANY MORE. The old drawing was stroked in `currentColor` and
   took it from this rule, which is exactly why nothing ever measured the mark:
   it was #8a939e, 2.85:1 on the page, under the 3:1 a graphical object needs.
   The redrawn mark carries its own two fills, and both are paired in
   tests/ui-contrast.test.js. */
.ccredit-logo{display:block}
.ccredit-logo svg{width:16px;height:16px;display:block}
.ccredit-logo .cc-outer{fill:var(--cc-slate)}
.ccredit-logo .cc-inner{fill:var(--cc-sage)}
/* Named rather than `> span:last-child`, so the two grounds below can re-align
   it without having to out-specify a structural selector. */
.ccredit .cctxt{text-align:center}
.ccredit u{white-space:nowrap;text-decoration-color:#c2c9d1;text-underline-offset:2px}
.ccredit:hover u{text-decoration-color:#6b7686}

/* ---- THE SAME CREDIT ON THE STAFF RAIL ----
   Where the FCC LeadCourt twin has always carried its own: last thing in the
   charcoal sidebar, under the account button, and off the page body entirely.
   The customer site still shows it under the footer, because the customer site
   has a footer and a scroll to put it at the bottom of; the console has neither
   — every staff screen is a working surface, and a credit centred under the
   day's diary reads as part of the day's diary.

   NO BORDER-TOP, deliberately. `.sideuser` has one, and a second rule 30px
   below it would draw a box around the account button, turning two quiet things
   into a panel and giving the credit more weight than the person's own name.

   AND IT IS THE FIRST THING CLIPPED on a rail too short for its contents, which
   is a property of the layout rather than of this rule — worth writing down
   because it is what makes "a credit is the right thing to lose" true, and
   because it is one declaration away from inverting. `.railinner` is a column
   flex box with `overflow:hidden`, and a column flex item's `min-height:auto`
   resolves to its content height, so neither `.nav-it` nor this can shrink: the
   overflow falls off the BOTTOM, where this is. Give a nav item a `min-height:0`
   or an `overflow` of its own and the nav buttons squash instead while the
   credit survives — silently, and exactly backwards. */
.ccdark{position:relative;align-items:flex-start;justify-content:flex-start;margin:2px 0 0;
  padding:12px 6px;gap:9px;font-size:var(--fs-xs);line-height:1.45;color:#8f9fb2;text-align:left}
.ccdark:hover,.ccdark:focus-visible{color:#cfd8e2}
.ccdark .cctxt{text-align:left}
/* The mark sits on the FIRST line rather than in the middle of the block. The
   customer's copy is one centred line and centring is right there; here the
   words wrap and a mark floating beside a later line reads as a bullet for a
   list. 1px is the optical drop onto a 10.5px cap height. (This said "run to
   three" until the copy shrank on 9 Sep, when it became two — a count in a
   comment that the copy it counts had moved out from under.) */
.ccdark .ccredit-logo{margin-top:1px}
/* The domain on its own line here, where the footer's copy keeps it inline. The
   `·` separator that used to divide them went with the copy on 9 Sep: one
   sentence needs no divider, and the dot would otherwise dangle at the end of a
   wrapped line. */
.ccdark .ccurl{display:block;margin-top:1px}
.ccdark u{text-decoration-color:#6f7d8e}
.ccdark:hover u{text-decoration-color:#cfd8e2}
/* The two fills swap for the charcoal ground: the outer C takes the mark's own
   light tone, the inner sage is the colour that stands on both. Tokens rather
   than literals so tests/ui-contrast.test.js can pair them — which is the whole
   lesson of the stroked drawing this replaced. */
.ccdark .ccredit-logo .cc-outer{fill:var(--cc-cream)}
.ccdark .ccredit-logo .cc-inner{fill:var(--cc-sage)}

/* ---- and on a staff PHONE, inside the account menu ----
   The rail is `display:none` below 900px, so this is the only place under that
   width the console says who built it. It sits under Sign out, so it needs the
   top rule the rail’s copy refuses: without one it reads as one more menu item
   somebody forgot to make tappable. */
.menu .ccredit{margin:6px 0 2px;padding:9px 11px 5px;border-top:1px solid var(--line);
  align-items:flex-start;justify-content:flex-start;text-align:left;gap:9px;line-height:1.45}
.menu .ccredit .cctxt{text-align:left}
.menu .ccredit .ccredit-logo{margin-top:1px}
/* Wrapped, so the same rule the rail needs: a 210px menu takes these words to
   two lines. The separator rule that stood beside this one went with the `·`
   itself when the copy shrank on 9 Sep. */
.menu .ccredit .ccurl{display:block;margin-top:1px}

/* diagnostics / client log view (staff Settings) */
.logview{max-height:320px;overflow:auto;border:1px solid var(--line);border-radius:var(--r-md);
  background:#0d1117;padding:8px 10px;font:11.5px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace}
.logrow{display:flex;align-items:baseline;gap:7px;padding:2px 0;white-space:nowrap;color:#c9d1d9}
.logrow b{font-weight:var(--fw-semi)}
.logrow .s2{overflow:hidden;text-overflow:ellipsis;color:#8b949e}
.logdot{flex:none;width:7px;height:7px;border-radius:50%;transform:translateY(1px)}
.logt{flex:none;color:#6e7681}
/* One field's before → after inside a change-log row (job History, and the
   Changes panel in the Logs tab). The separator is a pseudo-element rather than
   markup because the row is a single ellipsised line — a wrapper element would
   give the browser somewhere to break it. */
.chgf{color:#8b949e}
.chgf+.chgf::before{content:' · '}
.chgf b{color:#c9d1d9}

/* =========================================================================
   ACCESSIBILITY (WCAG 2.2 AA)
   The spec commits to AA, so these are load-bearing, not polish. Grouped here
   rather than scattered so the commitment is auditable in one place.
   ========================================================================= */

/* Visually hidden but still announced — used for switch labels and the
   route-change live region. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* 2.4.1 — bypass the nav/demo chrome. Visible only when focused. */
.skiplink{position:absolute;left:-9999px;top:0;z-index:100;background:var(--char);color:#fff;
  padding:11px 17px;border-radius:0 0 var(--r-md) 0;font-weight:var(--fw-bold);font-size:var(--fs-md);text-decoration:none}
.skiplink:focus{left:0}

/* 2.4.7 / 2.4.13 — one obvious focus indicator everywhere. Needed now that
   diary rows, catalogue rows and toggles are real buttons and can be tabbed to. */
/* A ONE-COLOUR FOCUS RING CANNOT PASS ON BOTH HALVES OF THIS APP. --brand-d is
   2.07:1 on white — below the 3:1 a focus indicator needs — and the yellow was
   chosen because it is highly visible on the charcoal chrome, where it is
   8.27:1. Neither colour can do both.
   So the ring is two-tone, which is the documented way out: a dark inner ring
   that carries the contrast on light surfaces (--char is 12.27:1 on white) and
   the yellow outer ring that carries it on the charcoal sidebar and header. One
   of the two always clears 3:1 against whatever is behind the control. */
:focus-visible{outline:3px solid var(--brand-d);outline-offset:2px;border-radius:var(--r-xs);
  box-shadow:0 0 0 2px var(--char)}
.fld input:focus-visible,.fld select:focus-visible,.fld textarea:focus-visible{outline-offset:0}

/* 2.4.11 (Focus Not Obscured) — the sticky bottom CTA is fixed over the page,
   so anything scrolled to must clear it. This criterion is 2.2-specific and
   directly on point for the AA claim.

   The padding-bottom here used to be 8px, which overrode .cwrap's own clearance
   and left the last thing on the page under the fixed CTA — on the details step
   that was the consent sentence, cut off mid-word behind the button. */
html{scroll-padding-bottom:120px}
.cwrap{padding-bottom:calc(104px + var(--safe-b))}

/* A programmatic focus is not a keyboard focus. afterRender() moves focus to
   the page heading on every route change so screen readers announce it — but
   the heading is tabindex="-1", which means it can only ever be focused this
   way, so painting a 3px ring around the page title on every navigation showed
   sighted users a rectangle that looked like a rendering fault. Nothing is lost
   by suppressing it: you cannot tab to a tabindex="-1" element. */
[tabindex="-1"]:focus,[tabindex="-1"]:focus-visible{outline:none;box-shadow:none}
/* BOTH HALVES, and the second one is why this line has a test behind it. The
   ring above is TWO-TONE — an `outline` for the yellow and a `box-shadow` for
   the dark inner ring — and this rule suppressed only the outline, because it
   was written when the ring was outline-only and was not revisited when the
   contrast fix added the second property. The result was the exact rectangle
   the comment above says it removed: a 2px charcoal box around the page
   heading, on every route change, on every screen, for anyone who had not
   touched a key. It survived because nothing renders this app to look at it —
   reading the stylesheet shows a rule that plainly handles the case.
   tests/ui-contrast.test.js now asserts this rule clears every property
   `:focus-visible` paints with, so a third one cannot reintroduce it. */

/* 4.1.2 — the on/off pills are <button role="switch"> now, not <div onclick>.
   Reset the button chrome; the visual is unchanged. */
button.toggle{border:0;padding:0;cursor:pointer;-webkit-appearance:none;appearance:none;display:block}

/* 2.1.1 — diary rows are role="button" + tabindex now (a real <button> can't
   hold the <p> they contain). Catalogue rows keep the whole-row click for the
   mouse but expose a real <button> chevron as the keyboard/AT control, because
   a row already contains the online switch and interactive controls must not
   nest. */
.editchev{border:0;background:none;padding:2px 4px;line-height:1;cursor:pointer}
.editchev:focus-visible{outline:3px solid var(--brand-d);outline-offset:1px;border-radius:var(--r-sm);box-shadow:0 0 0 1px var(--char)}

/* the "‹ Back" steps and the user menu trigger are buttons too */
.menu{outline:none}
.menu .mi:focus-visible{background:var(--bg)}

/* -------------------------------------------------------------------------
   2.5.5 / 2.5.8 — THE 44px TAP FLOOR, FOR ANY POINTER THAT IS A FINGER.

   `.qa/checklists/07-ui-quality.md` puts the floor at 44px: "a garage counter
   is not a precise environment." A survey of the rendered app on 9 Sep 2026
   found thirty distinct interactive elements under it, across both the
   customer site and the staff console — the rail toggle that prompted the
   sweep was one of thirty, not a one-off.

   `any-pointer:coarse`, NOT `hover:none`, and the difference is the point.
   `hover:none` describes a device with no pointer that can hover — an iPad.
   It says nothing about a laptop with a touchscreen, which reports
   `hover:hover` because it also has a trackpad, and still has a finger. The
   floor is about fingers, so the query has to ask whether ANY available
   pointer is coarse. The rail's own fallback block correctly uses
   `hover:none` for a different question — whether a hover peek can fire at
   all — and both are right about their own question.

   NOT APPLIED ON A MOUSE-ONLY DEVICE, deliberately. 2.5.8 (AA) asks 24px of
   any pointer and every control here clears that; 44px is 2.5.5 (AAA), which
   is a finger measurement. Raising every button to 44px on a precise pointer
   would relayout the whole console for no accessibility gain.

   WHAT IS NOT HERE, and why it is not an oversight: inline text links.
   `.lnk`, `.cfoot-legal-a`, `.cfoot-link`, `.backlnk` and `.ccredit` are
   words in a sentence, and 2.5.8's own inline exception covers a target whose
   size is constrained by the line-height of the text around it. Padding them
   to 44px would push the sentences they live in apart. They are declared,
   with that reason, in `tests/tap-targets.json` — the audit reads that file,
   so an exemption is a visible diff with a stated reason rather than a hole.

   Enforced by `scripts/tap-audit.mjs`, which measures the real rendered boxes
   in Chromium under touch emulation rather than reading this stylesheet. A
   floor asserted against CSS text is the shape of check that let the rail
   toggle sit at 36px through two reviews.
   ------------------------------------------------------------------------- */
@media (any-pointer:coarse){
  /* Buttons, chips, pills and the nav — everything that is a discrete control
     with room to grow. `min-height` rather than `height`, so a control that is
     already taller keeps its size. */
  .btn,.chip,.tgl,.nav-it,.sideuser,.mi{min-height:44px}
  /* Square icon controls need both dimensions. */
  .avatar,.railtoggle{min-width:44px;min-height:44px}

  /* THE CATALOGUE CHEVRON GETS A HIT AREA, NOT A BOX, AND THAT IS A CORRECTION.
     The first cut gave `.editchev` `min-width:44px` like the avatar, and it
     took roughly 30px out of a catalogue row that has none to spare: on a
     390px phone "Interim Service" broke onto two lines and its description
     went from three to five. Caught by screenshotting the change against the
     same screen on `main` rather than by reasoning about it — the audit was
     perfectly happy, because a 44px box is exactly what it asks for.

     So the glyph stays 14px and the region around it grows instead. Vertical
     is free; horizontal reaches into the row's own gaps.

     ASYMMETRIC, AND THAT IS THE CORRECTION. The first cut reached 15px each
     way on the reasoning that the switch to its left kept a clear ~18px. It
     did not: the audit measured the SWITCH at 40px wide on the catalogue,
     because this overlay had taken 4px of it. Two controls whose hit areas
     overlap make a tap between them ambiguous, which is worse than either
     being small — so the reach goes right, into the card's own padding where
     nothing else lives, and only 6px left. The arithmetic is the same 44; who
     owns the pixels is not. Found by the audit, after its pass condition was
     tightened from "either dimension" to "both". */
  .editchev{position:relative;min-height:44px;display:inline-flex;align-items:center;justify-content:center;padding:2px 4px}
  .editchev::before{content:"";position:absolute;top:-11px;bottom:-11px;left:-6px;right:-24px}
  /* Settings' own inputs. The time boxes paint 38px from the browser's default
     UA styling, which is under this project's floor on the device the console is
     built for — and a time picker is a control you tap twice. */
  .hrs-in,.setgrid input,.setgrid select{min-height:44px}

  /* The lockup in the app bar is a link home. */
  a.brand{min-height:44px}

  /* THE PRODUCT'S ONLY UNDO CONTROL WAS 15px TALL. Measured with a stage-change
     toast on screen at 375px: `.toast-btn` painted 33×15 and hit-tested 34×16,
     against this project's own 44px floor — and the job screen's copy makes it
     the promised recovery path ("a mis-tap can be undone from the message that
     appears"). A 15px underlined word at the bottom of a phone, live for six
     seconds, on a garage floor.

     It was not in `tap-targets.json` because the audit had never seen it: the
     sweep walks routes and measures what they render AT REST, and this control
     only exists after a mutation. The audit fires one now — see
     scripts/tap-audit.mjs — which is the general remedy: drive one mutation per
     surface, rather than add a selector.

     A hit area rather than a box, like `.editchev` and `.toggle` above: the
     toast is a 11px-padded pill whose height IS its appearance, and a 44px-tall
     button inside it makes a different, taller component. -15 vertically takes
     15px to 45; ±6 horizontally takes 33 to 45. Both clear the floor without a
     pixel of the toast moving. */
  .toast-btn{position:relative}
  .toast-btn::before{content:"";position:absolute;top:-15px;bottom:-15px;left:-6px;right:-6px}

  /* THE SWITCH IS THE ONE THAT CANNOT SIMPLY GROW. `.toggle` is a 42x25 pill
     whose size IS its appearance — a 44px-tall pill is a different control.
     So the paint stays and the HIT AREA is extended past it with a
     pseudo-element: `::after` is the knob, `::before` is free, and an absolute
     inset of -12px vertically takes 25px to 49px without moving a pixel of
     what is drawn. Not -10, which measured 44 exactly — a floor met to the
     pixel is one rounding decision from being missed. This is the standard remedy and 2.5.8 measures the
     activatable region rather than the ink.
     THE MARGIN IS THE OTHER HALF, and it was measured rather than assumed:
     with the overlay alone the region came out 25px up and 18px down — 44
     exactly, capped by whatever sits under the switch rather than by the
     inset, and a floor met to the pixel is one layout change from being
     missed. 10px of margin reserves the space the overlay reaches into, so
     the region is the overlay's own size and neighbours cannot take it back.

     `tests/tap-targets.json` records it, because the audit measures the
     element's own box and would otherwise report the pill it can see. */
  .toggle{margin-top:10px;margin-bottom:10px}
  .toggle::before{content:"";position:absolute;top:-12px;bottom:-12px;left:-1px;right:-1px;border-radius:var(--r-pill)}
}

/* =========================================================================
   Logs tab (owner only) — see staffLogs() in app.js.
   Deliberately built from the same primitives as the rest of the console
   (.section/.kv/.kpi/.logrow) so this reads as one product, not a bolt-on
   dashboard. No chart library: a bar is a div with a percentage height.
   ========================================================================= */
.logbars{display:flex;align-items:flex-end;gap:3px;height:96px;padding-top:6px;overflow-x:auto;scrollbar-width:none}
.logbars::-webkit-scrollbar{display:none}
.logbar{flex:1 0 12px;min-width:12px;height:100%;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;gap:4px}
.logbar-fill{width:100%;background:var(--brand);border-radius:var(--r-xs) 3px 0 0;min-height:3px}
.logbar-l{font-size:var(--fs-2xs);color:var(--mut);font-weight:var(--fw-semi)}
/* An inline bar under a label: proportion at a glance without a second column. */
.logmeter{display:block;height:4px;border-radius:var(--r-pill);background:var(--line);margin-top:5px;overflow:hidden}
.logmeter i{display:block;height:100%;background:var(--brand);border-radius:var(--r-pill)}
/* The sign-in screen's "checking the cookie" state — one round-trip, so this
   is visible for a moment rather than not at all. */
.spinner{width:22px;height:22px;border-radius:50%;border:2.5px solid var(--line);border-top-color:var(--char);animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.spinner{animation-duration:2.4s}}

/* =========================================================================
   UX REVIEW — everything below came out of the August 2026 design review.
   Grouped here, in review order, so each change can be read against the
   finding it answers rather than hunted for across the file.
   ========================================================================= */

/* --- icon tiles: the containers were sized for emoji glyphs --- */
.svc .ic .ic-svg{width:24px;height:24px}
.svctile-ic .ic-svg{width:23px;height:23px}
.subrow-ic .ic-svg{width:17px;height:17px}
.reco-ic .ic-svg{width:22px;height:22px}
.jicon .ic-svg{width:21px;height:21px}
.cat .ci .ic-svg{width:21px;height:21px}
.svc .ic,.svctile-ic,.subrow-ic,.reco-ic,.jicon,.cat .ci{color:var(--brand-ink)}
.ic-hero{width:62px;height:62px;margin:2px auto 10px;border-radius:var(--r-lg);background:var(--brand-soft);
  display:grid;place-items:center;color:var(--brand-ink)}
.ic-hero .ic-svg{width:30px;height:30px}
.checkhero-ic .ic-svg{width:26px;height:26px;color:var(--brand)}
.hero-lg .checkhero-ic .ic-svg{width:30px;height:30px}
.vehbar-ic .ic-svg,.remind-ic .ic-svg{width:22px;height:22px;color:var(--brand-ink)}
.trust b .ic-svg{color:var(--brand-ink);margin-right:1px}
.motstat-ic .ic-svg{width:21px;height:21px}
.motstat.ok .motstat-ic{color:var(--green)}
.motstat.warn .motstat-ic{color:var(--amber-ink)}
.motstat.bad .motstat-ic{color:var(--red)}
.tick .ic-svg{width:38px;height:38px;stroke-width:2.6}
.incl .tk .ic-svg{width:16px;height:16px}
.recallbar .ic-svg{color:var(--red);vertical-align:-.22em}

/* --- "Sample data" was grey-on-grey and read as a selection artifact --- */
.pill{padding:3px 10px;border-radius:var(--r-pill);font-size:var(--fs-xs);font-weight:var(--fw-bold);white-space:nowrap}
.pill-live{background:var(--green-ink);color:#fff}
.pill-demo{background:var(--brand-soft);border:1px solid #ecdca4;color:var(--brand-ink)}

/* --- health report: vehicle heading, MOT urgency --- */
.vehhead{display:flex;justify-content:space-between;align-items:flex-start;gap:10px}
.vehhead-bd{min-width:0}
.vehhead-bd b{display:block;color:var(--char);font-size:var(--fs-2xl);line-height:1.25}
.vehhead-bd span{display:block;font-size:var(--fs-md);color:var(--mut);margin-top:2px}
.motstat-bd{min-width:0;flex:1}
.motstat-cta{padding:8px 14px;font-size:var(--fs-md);white-space:nowrap;flex:none}
@media(max-width:460px){
  .motstat{flex-wrap:wrap}
  .motstat-cta{width:100%;margin-top:4px}
}

/* --- recommendations: one lead action, the rest tick to add --- */
.reco-lead{border-width:1.5px;box-shadow:var(--shadow)}
.reco-picked{background:#fffdf2;border-color:#ecdca4}
.reco-hint{font-size:var(--fs-sm);color:var(--mut);margin:10px 2px 0;line-height:1.5}
.addbtn{display:inline-flex;align-items:center;gap:7px;border:1.5px solid var(--line);background:#fff;
  border-radius:var(--r-md);padding:8px 13px;font-size:var(--fs-md);font-weight:var(--fw-semi);color:var(--char);white-space:nowrap}
.addbtn:hover{border-color:var(--brand-ink)}
.addbtn.on{background:var(--char);border-color:var(--char);color:#fff}
.addbox{display:grid;place-items:center;width:18px;height:18px;border-radius:var(--r-xs);border:1.5px solid var(--line);color:var(--mut)}
.addbtn.on .addbox{background:var(--brand);border-color:var(--brand);color:var(--ink-on-brand)}
.addbox .ic-svg{width:12px;height:12px;stroke-width:2.6;vertical-align:0}
.basket-cta{display:flex;justify-content:space-between;gap:12px}

/* --- the summary strip carried on every booking step --- */
.booksum{display:flex;justify-content:space-between;align-items:center;gap:12px;
  background:var(--char);color:#fff;border-radius:var(--r-md);padding:11px 14px;margin:0 0 14px}
.booksum-main{min-width:0}
.booksum-main b{display:block;font-size:var(--fs-lg);line-height:1.3}
.booksum-main span{display:block;font-size:var(--fs-sm);color:#b6c0cb;margin-top:2px;overflow-wrap:anywhere}
.booksum-pr{text-align:right;flex:none}
.booksum-pr b{display:block;font-size:var(--fs-xl);color:var(--brand)}
.booksum-pr span{display:block;font-size:var(--fs-xs);color:#b6c0cb;margin-top:1px}

/* --- time picker: next-available shortcut, grouped slots --- */
.soonbtn{display:flex;align-items:center;gap:11px;width:100%;text-align:left;margin:0 0 14px;
  background:#fff;border:1.5px solid var(--line);border-left:4px solid var(--brand);border-radius:var(--r-md);
  padding:12px 14px;box-shadow:var(--shadow);color:var(--char)}
.soonbtn:hover{border-color:var(--brand-ink)}
.soonbtn.on{background:var(--brand-soft);border-color:var(--brand)}
.soonbtn .ic-svg{width:20px;height:20px;color:var(--brand-ink);flex:none}
.soonbtn span{flex:1;min-width:0;font-size:var(--fs-lg)}
.soonbtn span b{display:block;font-size:var(--fs-lg)}
.soonbtn em{font-style:normal;font-size:var(--fs-sm);font-weight:var(--fw-bold);color:var(--brand-ink);white-space:nowrap}
.daystrip-m{font-size:var(--fs-sm);font-weight:var(--fw-bold);color:var(--mut);text-transform:uppercase;letter-spacing:.5px;margin:0 2px 7px}
.slotgroup{margin-top:14px}
.slotgroup-h{display:flex;align-items:baseline;gap:8px;font-size:var(--fs-sm);font-weight:var(--fw-bold);color:var(--char);
  text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px}
.slotgroup-h em{font-style:normal;font-size:var(--fs-sm);font-weight:var(--fw-semi);color:var(--mut);text-transform:none;letter-spacing:0}
.availnote{display:flex;gap:9px;align-items:flex-start;background:#fff7e9;border:1px solid #f2d99a;
  border-radius:var(--r-md);padding:10px 12px;font-size:var(--fs-md);color:var(--txt);line-height:1.45;margin-bottom:14px}
.availnote .ic-svg{color:var(--amber-ink);flex:none}

/* --- payment: a choice, not a card form --- */
.paytitle{font-size:var(--fs-xl);color:var(--char);display:block;margin-bottom:12px}
.payopts{display:flex;flex-direction:column;gap:9px;margin-bottom:14px}
.payopt{display:flex;align-items:center;gap:11px;width:100%;text-align:left;
  border:1.5px solid var(--line);border-radius:var(--r-md);padding:12px 14px;background:#fff}
.payopt:hover{border-color:var(--brand-ink)}
.payopt.on{border-color:var(--brand);background:var(--brand-soft)}
.payradio{width:19px;height:19px;border-radius:50%;border:2px solid var(--line);flex:none;position:relative;background:#fff}
.payopt.on .payradio{border-color:var(--brand-d)}
.payopt.on .payradio::after{content:"";position:absolute;inset:3px;border-radius:50%;background:var(--brand-d)}
.payopt-bd{min-width:0}
.payopt-bd b{display:block;font-size:var(--fs-lg);color:var(--char)}
.payopt-bd span{display:block;font-size:var(--fs-sm);color:var(--mut);margin-top:1px}
.cardbox-h{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
.cardbox-h .ic-svg{width:20px;height:20px;color:var(--mut)}
.row-sub{display:block;font-style:normal;font-size:var(--fs-sm);color:var(--mut);margin-top:1px}
.est-note{margin:10px 0 0;line-height:1.5;background:var(--bg);border-radius:var(--r-sm);padding:9px 11px}
.est-note .ic-svg{color:var(--brand-ink);vertical-align:-.22em}
.paid-v{color:var(--green-ink)}
.optin{display:flex;gap:9px;align-items:flex-start;cursor:pointer;line-height:1.5}
.optin input{width:auto;margin-top:3px;flex:none}

/* --- confirmation: where to come, what to bring --- */
.conf-where{border-left:4px solid var(--brand)}
.conf-h{display:flex;align-items:center;gap:8px;font-size:var(--fs-xl);color:var(--char)}
.conf-h .ic-svg{color:var(--brand-ink)}
.conf-addr{margin:9px 0 6px;font-size:var(--fs-lg);line-height:1.55;color:var(--txt);font-weight:var(--fw-med)}
.conf-acts{display:flex;gap:10px;margin-top:12px}
.conf-acts .btn{gap:7px}
@media(max-width:400px){.conf-acts{flex-direction:column}}
.conf-bring{margin-top:12px;line-height:1.55;display:flex;gap:8px;align-items:flex-start}
.conf-bring .ic-svg{color:var(--mut);flex:none;margin-top:1px}

/* --- footer: contact details are links now --- */
.cfoot-grid{gap:18px}
@media(min-width:760px){.cfoot-grid{grid-template-columns:1.4fr 1fr 1fr 1.1fr}}
.cfoot-link{display:inline-flex;gap:7px;align-items:flex-start;color:var(--mut);line-height:1.6}
.cfoot-link:hover{color:var(--brand-ink);text-decoration:underline}
.cfoot-link .ic-svg{flex:none;margin-top:.24em;color:var(--brand-ink)}
.cfoot-legal{line-height:2}
.cfoot-legal-a{color:var(--mut);text-decoration:underline;font-size:var(--fs-xs);font-weight:var(--fw-med)}
.cfoot-legal-a:hover{color:var(--brand-ink)}

/* --- terms page --- */
.tsub{display:block;font-size:var(--fs-lg);color:var(--char);margin:16px 0 4px}
.tsub:first-child{margin-top:0}
.tp{font-size:var(--fs-lg);color:var(--txt);line-height:1.65}

/* --- staff: the lead KPI answers "what's next" --- */
.kpi-lead{border-top-color:var(--char);background:var(--char);color:#fff}
.kpi-lead b{color:var(--brand)}
.kpi-lead span{color:#c2ccd6}
.kpi-sub{display:block;font-size:var(--fs-xs);color:var(--mut);font-weight:var(--fw-med);margin-top:6px}
.kpi-lead .kpi-sub{color:#98a4b1}

/* --- staff: where the day has got to --- */
.nowline{display:flex;align-items:center;gap:9px;margin:8px 2px;color:var(--red-ink);
  font-size:var(--fs-xs);font-weight:var(--fw-bold);letter-spacing:.5px}
.nowline::after{content:"";flex:1;height:1px;background:currentColor;opacity:.35}
.nowline span{background:var(--red);color:#fff;border-radius:var(--r-pill);padding:1px 8px}
.nowline-end{opacity:.6}

/* --- staff diary rows stack on a phone instead of crushing --- */
@media(max-width:560px){
  /* wrapped flex lines don't stretch, so the status bar is absolute here —
     otherwise the colour spans only the first line of a three-line row */
  .job{position:relative;flex-wrap:wrap;gap:9px;padding:11px 10px 11px 20px}
  .jaccent{position:absolute;left:8px;top:10px;bottom:10px;min-height:0}
  .jtime{width:auto;text-align:left;display:flex;align-items:baseline;gap:6px}
  .jtime small{font-size:var(--fs-xs)}
  .jinfo{flex-basis:100%;order:3}
  .jright{margin-left:auto;flex-direction:row;align-items:center;gap:8px}
}

/* --- staff catalogue: one header row, not four labels per row --- */
.cathead{display:flex;align-items:center;gap:13px;padding:0 4px 8px;border-bottom:1px solid var(--line);margin-bottom:2px}
.cathead-sp{flex:1}
.cathead-chev{width:22px;flex:none}
.cathead .mt{display:flex;gap:16px;align-items:center;flex:none}
.cathead .m{text-align:center}
.cathead .m small{display:block;font-size:var(--fs-2xs);color:var(--mut);text-transform:uppercase;letter-spacing:.4px;font-weight:var(--fw-bold)}
.cat .m{min-width:64px}
.cathead .m{min-width:64px}
.cathead .m:nth-child(4){min-width:42px}
.cat .m:nth-child(4){min-width:42px}
@media(max-width:560px){.cathead{display:none}}

.infobox{padding:13px 15px;display:flex;gap:11px;align-items:flex-start;background:#fffdf2;
  border:1px solid #f0e6bd;border-left:4px solid var(--brand)}
.infobox .ic-svg{color:var(--brand-ink);flex:none;margin-top:1px}

/* --- staff: search box with the icon outside the placeholder --- */
.searchbox{display:flex;align-items:center;gap:8px;background:#fff;border:1px solid var(--line);
  border-radius:var(--r-pill);padding:0 14px;min-width:230px}
.searchbox .ic-svg{color:var(--mut);flex:none}
/* 16px, NOT 13px. iOS Safari zooms the viewport whenever a focused input's text
   is under 16px, and it does not zoom back out on blur — so the page stays
   magnified and the layout around it is broken until the user pinches it back.
   The staff diary's search is the control staff use most, at a garage counter,
   on a phone, which is exactly the case. The placeholder can stay smaller.

   AND THE REASON IT SURVIVED THE JULY MOBILE PASS IS WORTH KNOWING: that pass
   added `@media(max-width:900px){ input,select,textarea{font-size:var(--fs-2xl)} }`
   above, which looks like it covers everything. This rule is later in the file
   AND more specific (0,1,1 against 0,0,1), so it won on every phone. A blanket
   fix is only as good as the selectors that come after it — grep for the
   property, not for the rule that was supposed to have handled it. (bc-ios-zoom) */
.searchbox input{border:0;background:none;padding:8px 0;flex:1;min-width:0;font-size:var(--fs-2xl);font-weight:var(--fw-med)}
.searchbox input::placeholder{font-size:var(--fs-md);font-weight:var(--fw-semi)}
.searchbox input:focus{outline:none}
.searchbox:focus-within{border-color:var(--brand-d);box-shadow:0 0 0 3px rgba(245,197,24,.22)}

/* --- staff job: current stage is the brightest, done stages step back --- */
.sp{display:inline-flex;align-items:center;gap:6px}
.sp .ic-svg{width:13px;height:13px;stroke-width:2.6}
.sp.done{background:#fff;border-color:var(--line);color:var(--mut)}
.sp.done .ic-svg{color:var(--green)}
.sp.cur{background:var(--brand);border-color:var(--brand);color:var(--ink-on-brand);box-shadow:0 2px 8px rgba(252,208,7,.5)}
.jobacts{display:flex;gap:9px;margin-top:12px}
.jobacts .btn{gap:7px}
@media(max-width:420px){.jobacts{flex-direction:column}}

/* --- reports: the tallest bar's label was clipped by the chart's overflow --- */
.chart{padding-top:24px}
.chartkey{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-xs);font-weight:var(--fw-semi);color:var(--mut);
  text-transform:none;letter-spacing:0}
.chartkey i{width:10px;height:10px;border-radius:var(--r-xs);background:var(--brand);display:block}

/* --- an undoable action needs a clickable toast --- */
#toasts{pointer-events:none}
.toast-act{display:flex;align-items:center;gap:14px;pointer-events:auto}
.toast-btn{color:var(--brand);font-weight:var(--fw-bold);font-size:var(--fs-md);text-decoration:underline;white-space:nowrap}
.toast-btn:hover{color:#fff}
