/* ============ TIMECH HIRE — BRAND FOUNDATION ============
   Ported verbatim from design/Website/assets/brand.css (design prototype) per
   01-UI-SPEC.md "Brand Color Tokens" / "Typography". Do not hand-edit tokens
   here without updating both the prototype and UI-SPEC.md. */
@import url('https://fonts.googleapis.com/css2?family=Zilla+Slab:wght@400;500;600;700&family=Archivo:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap');

:root{
  /* Warm Charcoal palette (from brand sheet) */
  --charcoal:#2E2A25;   /* primary · ink   */
  --oat:#E7E2D8;        /* secondary·paper */
  --bone:#F4F1EA;       /* light paper     */
  --stone:#B6AC99;      /* support·dividers*/
  --ink:#16140F;        /* contrast        */

  /* tonal helpers */
  --charcoal-90:rgba(46,42,37,.90);
  --charcoal-70:rgba(46,42,37,.62);
  --charcoal-45:rgba(46,42,37,.45);
  --oat-70:rgba(231,226,216,.72);
  --oat-45:rgba(231,226,216,.45);
  --line:rgba(46,42,37,.14);
  --line-strong:rgba(46,42,37,.26);
  --line-oat:rgba(231,226,216,.18);

  /* functional accent — kept within the warm family */
  --signal:#C0602B;        /* safety amber, used sparingly */
  --signal-soft:rgba(192,96,43,.12);
  --go:#5E7A52;            /* available/confirmed green */
  --go-soft:rgba(94,122,82,.14);

  /* destructive — declared Phase 1, first rendered in Phase 3 (03-UI-SPEC.md
     "Notable milestone this phase"): the Cancelled status pill and the
     cancellation confirmation panel/button (03-02+) are its exhaustive use. */
  --destructive:#9C3B2E;
  --destructive-soft:rgba(156,59,46,.12);

  --display:'Zilla Slab',Georgia,serif;
  --sans:'Archivo','Helvetica Neue',Arial,sans-serif;
  --mono:'Space Mono',ui-monospace,'SF Mono',monospace;

  --r:4px;        /* tight, utilitarian radii */
  --r-lg:8px;
  /* v1.6 Phase 64 (VIS-01, design brief §6 Geometry): admin panels/cards use
     6px, not --r-lg's 8px. --r-lg is shared with ~15 customer-facing rules
     (.tm-catalog-card, .tm-cc, .tm-checkout-*, .tm-booking-card, etc.) that
     this milestone must not touch, so this is a separate, admin-scoped
     token rather than a global --r-lg retune. */
  --r-admin-panel:6px;
  --shadow:0 1px 2px rgba(22,20,15,.06),0 8px 28px rgba(22,20,15,.07);
  --shadow-lg:0 2px 6px rgba(22,20,15,.08),0 24px 60px rgba(22,20,15,.14);

  /* Destructive (plan 04-09) — declared in 01-UI-SPEC.md since Phase 1,
     unused until now. Reserved EXCLUSIVELY for the "Charge card"/confirm-
     modal pair and the "Delete account"/confirm-modal pair (04-UI-SPEC.md
     Color section, exhaustive reservation) — never a default admin CTA
     color. */
  --destructive:#9C3B2E;
}

*{box-sizing:border-box}
body{margin:0;font-family:var(--sans);color:var(--charcoal);-webkit-font-smoothing:antialiased;}

/* utility label */
.tm-label{font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;}

/* v1.6 Phase 64 (VIS-04, design brief §6 Type): shared "tabular figure"
   primitive — money, meters, dates, times, refs, counts are Space Mono
   "without exception". New utility, not a retune of an existing shared
   class (so it's safe on both admin and customer markup) — spot-checked
   several admin screens against this rule (today.cljs/booking_record.cljs
   already correct; customers.cljs's booking-history table was missing it,
   fixed as the one concrete instance found and corrected this phase). Every
   later phase should use this class, or verify its own mono-figure sites,
   when it restyles its own screen — this phase did not attempt an
   exhaustive re-audit of every money/date/ref render site in the app. */
.tm-figure{font-family:var(--mono);}

/* striped placeholder for imagery */
.tm-ph{
  position:relative;overflow:hidden;background:var(--stone);
  background-image:repeating-linear-gradient(45deg,rgba(46,42,37,.10) 0 2px,transparent 2px 11px);
  display:flex;align-items:center;justify-content:center;
}
.tm-ph span{
  font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--charcoal-70);background:var(--oat);padding:5px 10px;border-radius:2px;
  border:1px solid var(--line-strong);
}

/* basic catalog grid — superseded by the full CatalogCard grid below
   (plan 01-04); kept only so any stray reference doesn't 404. */
.tm-catalog-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:20px;padding:24px;max-width:1080px;margin:0 auto;}
.tm-catalog-card{background:var(--bone);border:1px solid var(--line);border-radius:var(--r-lg);padding:20px;box-shadow:var(--shadow);}
.tm-catalog-card h3{font-family:var(--display);margin:0 0 8px;color:var(--ink);}
.tm-catalog-card p{color:var(--charcoal-70);font-size:14px;line-height:1.4;}
.tm-catalog-card .tm-price{font-family:var(--mono);color:var(--signal);font-weight:700;}

/* ============ CUSTOMER APP — NAV (plan 01-04) ============
   Slim sticky wordmark bar shared by catalog/product/checkout — height is
   exposed as --nav-h so the product page's sticky booking rail (UI-SPEC
   "Sticky rail top-offset" exception note), the checkout summary rail, and
   the GEO FAQ scroll-margin offsets can offset against the SAME value
   rather than a hardcoded pixel guess. Quick task 260815-fgj: raised
   60px -> 66px after the header logo grew to 49px tall (1.75x its prior
   28px) — 49px logo + .tm-nav-inner's 8px top+bottom padding + .tm-nav's
   1px bottom border = 66px. Leaving it at 60px would put those sticky/
   scroll offsets 6px too high once the taller logo changed the real
   rendered header height. */
:root{ --nav-h:66px; }
.tm-nav{position:sticky;top:0;z-index:40;background:var(--bone);border-bottom:1px solid var(--line);min-height:var(--nav-h);display:flex;align-items:center;}
/* min-height (was a fixed height) + the .tm-nav-inner flex-wrap below (Phase
   14, D-03 backstop) let the row grow to a second line at narrow widths
   instead of clipping/truncating the new "Catalog" link against the
   account chip — --nav-h still governs the common single-line case since
   flex align-items:center keeps content vertically centered either way. */
.tm-nav-inner{max-width:1240px;margin:0 auto;padding:8px 24px;width:100%;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;row-gap:6px;column-gap:16px;}
.tm-nav-wordmark{font-family:var(--display);font-weight:600;font-size:18px;color:var(--charcoal);}
.tm-nav-home{color:var(--charcoal);display:flex;align-items:center;text-decoration:none;}
.tm-nav-links{display:flex;align-items:center;gap:12px;flex-wrap:wrap;}
/* BRAND-03 (plan 45-06): desktop-only free-delivery note, sitting between
   the wordmark link and .tm-nav-links inside the existing 2-group
   space-between flex row (undisturbed). Hidden below 1024px (raised from
   768px by quick task 260815-fgj) — the row above already documents that
   narrow viewports crowd, and the note is now both longer (55 characters
   vs 36) and larger (15px vs 12px) while still white-space:nowrap, and the
   logo beside it gets wider too (see .tm-nav-home/.tm-hero-mark below), so
   the width at which it stops fitting on one row moves up with it. */
.tm-nav-delivery{font-family:var(--sans);font-size:15px;color:var(--charcoal-70);white-space:nowrap;}
@media (max-width:1024px){.tm-nav-delivery{display:none;}}

/* Account nav entry (plan 03-01, ACC-01) — bordered-ghost chip, visually
   matching .tm-admin-signout, labelled "Sign in"/"My account" per auth
   state (03-UI-SPEC.md "Nav — My Account entry point"). */
.tm-nav-account-link{
  background:transparent;border:1px solid var(--line-strong);border-radius:var(--r);
  padding:8px 16px;font-family:var(--sans);font-size:14px;font-weight:600;color:var(--charcoal);
  cursor:pointer;text-decoration:none;display:inline-block;}

/* ============ CUSTOMER APP — CATALOG (plan 01-04, CAT-01) ============ */
.tm-hero{background:var(--bone);padding:40px 24px 32px;text-align:center;}
.tm-hero-inner{max-width:720px;margin:0 auto;}
/* BRAND-02 (plan 45-06): hero wordmark, first child of .tm-hero-inner,
   above the h1 — larger than the persistent nav mark. Quick task
   260815-fgj: the mark is now a fixed warm-charcoal PNG
   (/assets/timech-hire-logo.png) with its own baked-in colour, not an
   inline SVG path inheriting currentColor — it still reads correctly on
   .tm-hero's var(--bone) background and on .tm-nav's (also var(--bone)). */
.tm-hero-mark{display:flex;justify-content:center;margin:0 0 16px;}
.tm-hero h1{font-family:var(--display);font-weight:600;font-size:clamp(28px,4vw,36px);line-height:1.15;margin:0 0 12px;color:var(--ink);}
.tm-hero p{font-size:16px;line-height:1.5;color:var(--charcoal-70);margin:0;}
/* BRAND-03 (plan 45-06): hero free-delivery subheading, between the body
   copy <p> and the .tm-cta button — full-length form of the same claim as
   .tm-nav-delivery. Quick task 260815-fgj: this rule was previously
   `.tm-hero-delivery` alone (specificity 0,1,0), which the `.tm-hero p`
   rule above (specificity 0,1,1) silently outranked regardless of source
   order — the font-size/margin declared here never actually took effect
   on screen. Qualified as `.tm-hero p.tm-hero-delivery` (0,2,1) so this
   rule now wins. font-size is a clamp() sized to the midpoint of the hero
   body copy (16px flat) and the <h1> (clamp(28px,4vw,36px)) at both ends
   of the h1's own responsive curve. */
.tm-hero p.tm-hero-delivery{font-family:var(--sans);font-size:clamp(21px,2.9vw,25px);font-weight:400;color:var(--charcoal-70);margin:0 0 16px;}

.tm-catalog-section{max-width:1240px;margin:0 auto;padding:32px 24px 64px;}
.tm-catalog-section-head{margin:0 0 24px;}
/* Capped/centred fleet grid (plan 40-01, IMG-02, D-03). .tm-catalog-section's
   1240px max-width minus its 24px horizontal padding on each side leaves
   1192px of content width. With a 280px track minimum and a 24px gap,
   auto-fit would fit FOUR tracks in exactly 1192px (4 x 280 + 3 x 24 =
   1192), silently breaking the 3-wide requirement. Capping the grid's own
   width below that (see the rule's max-width below) makes four tracks
   impossible while still fitting three at their 380px maximum (3 x 380 +
   2 x 24 = 1188). justify-content:center plus auto-fit's empty-track
   collapsing is what makes a 1- or 2-card grid keep full-width cards and
   centre them instead of stretching (the old 1fr maximum being replaced
   was exactly the stretch defect). */
.tm-cc-grid{display:grid;gap:24px;justify-content:center;margin:0 auto;max-width:1188px;
  grid-template-columns:repeat(auto-fit,minmax(280px,380px));}

.tm-cc{background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;
  box-shadow:var(--shadow);text-decoration:none;color:inherit;display:block;
  transition:transform .16s ease, box-shadow .16s ease;}
.tm-cc:hover{box-shadow:var(--shadow-lg);transform:translateY(-3px);}
.tm-cc-media{position:relative;}
/* real per-item photo (2026-07-25 debug fix, generator-image-not-updating) —
   replaces the .tm-ph placeholder when the fleet item has a real photo
   uploaded via the admin Catalog tool; box is ratio-driven (4:3) to match
   the placeholder's own inline aspect-ratio override exactly (plan 40-01,
   IMG-01). */
.tm-cc-photo{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;}
.tm-cc-badge-tl{position:absolute;top:12px;left:12px;}
.tm-cc-badge-tr{position:absolute;top:12px;right:12px;}
.tm-cc-body{padding:18px 20px 22px;}
.tm-cc-body h3{font-family:var(--display);font-weight:600;font-size:21px;margin:0 0 6px;color:var(--ink);}
.tm-cc-body p{font-size:14px;line-height:1.5;color:var(--charcoal-70);margin:0 0 18px;min-height:42px;}
.tm-cc-footer{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;}
.tm-cc-price-label{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--charcoal-45);margin-bottom:3px;}
.tm-cc-price-value{font-family:var(--mono);font-size:22px;color:var(--charcoal);}
.tm-cc-price-unit{font-size:13px;color:var(--charcoal-45);}
.tm-cc-cta{font-family:var(--sans);font-weight:600;font-size:13px;border:none;border-radius:var(--r);
  padding:9px 15px;background:var(--charcoal);color:var(--oat);white-space:nowrap;}
.tm-cc:hover .tm-cc-cta{background:var(--signal);color:#fff;}

.tm-pill{font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;
  display:inline-flex;align-items:center;gap:7px;padding:6px 12px;border-radius:100px;border:none;background:none;}
.tm-pill--neutral{background:var(--bone);color:var(--charcoal-70);border:1px solid var(--line);}
.tm-pill--go{background:var(--go-soft);color:var(--go);}
.tm-pill--signal{background:var(--signal-soft);color:var(--signal);}
.tm-pill--dark{background:var(--charcoal);color:var(--oat);}
.tm-pill--destructive{background:var(--destructive-soft);color:var(--destructive);}
.tm-dot{width:7px;height:7px;border-radius:10px;display:inline-block;}

/* ============ CUSTOMER APP — PRODUCT DETAIL (plan 01-04, CAT-02) ============ */
.tm-product{max-width:1240px;margin:0 auto;padding:22px 24px 64px;}
.tm-breadcrumb{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);margin-bottom:20px;}
.tm-breadcrumb a{cursor:pointer;color:var(--charcoal-70);text-decoration:none;}
.tm-breadcrumb.tm-breadcrumb--back-link{font-size:20px;}
.tm-product-grid{display:grid;gap:32px;grid-template-columns:minmax(0,1.15fr) minmax(320px,420px);align-items:start;}
@media (max-width:768px){ .tm-product-grid{grid-template-columns:1fr;} .tm-booking-rail{position:static !important;} }

.tm-product-media{aspect-ratio:4/3;border-radius:var(--r-lg);}
/* real per-item photo (2026-07-25 debug fix, generator-image-not-updating) —
   scoped to the <img> tag specifically so it layers cleanly on top of
   .tm-product-media's shared ratio-driven box (4:3, plan 40-01, IMG-01)
   without touching the .tm-ph placeholder div's own (flex/background)
   styling. height:100% fills the ratio-derived box exactly. */
img.tm-product-media{width:100%;height:100%;object-fit:cover;display:block;}

/* quick task 260725-uww: hand-rolled photo gallery (product detail) --
   forward/back arrows + dot indicators for 2+ photos, no new dependency.
   .tm-gallery-frame wraps the inner .tm-gallery-img so the box still
   carries .tm-product-media (inheriting its existing height/border-radius
   unchanged) while `overflow:hidden` clips the image to that same shape,
   exactly as the old single-<img> markup did. */
.tm-gallery-frame{position:relative;overflow:hidden;}
.tm-gallery-img{width:100%;height:100%;object-fit:cover;display:block;}
.tm-gallery-arrow{
  position:absolute;top:50%;transform:translateY(-50%);
  width:44px;height:44px;border-radius:50%;border:none;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:rgba(0,0,0,.45);color:var(--oat);font-size:22px;line-height:1;}
.tm-gallery-arrow:hover{background:rgba(0,0,0,.65);}
.tm-gallery-arrow--prev{left:10px;}
.tm-gallery-arrow--next{right:10px;}
.tm-gallery-dots{display:flex;justify-content:center;gap:8px;margin-top:12px;}
.tm-gallery-dot{
  position:relative;width:26px;height:26px;border:none;background:transparent;cursor:pointer;padding:0;}
.tm-gallery-dot::before{
  content:"";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:8px;height:8px;border-radius:50%;background:var(--line-strong);}
.tm-gallery-dot--active::before{background:var(--signal);}

.tm-product-info{margin-top:28px;}
.tm-product-info h1{font-family:var(--display);font-weight:600;font-size:32px;line-height:1.15;margin:14px 0 10px;color:var(--ink);}
.tm-product-info p{font-size:16px;line-height:1.5;color:var(--charcoal-70);max-width:620px;margin:0;}

.tm-tabs{display:flex;gap:4px;margin-top:30px;border-bottom:1px solid var(--line);}
.tm-tab{background:none;border:none;cursor:pointer;padding:12px 16px;font-family:var(--sans);
  font-weight:600;font-size:14px;color:var(--charcoal-45);border-bottom:2px solid transparent;margin-bottom:-1px;}
.tm-tab--active{color:var(--charcoal);border-bottom:2px solid var(--signal);}
.tm-tab-panel{padding:24px 0 8px;}
.tm-tab-panel-note{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);margin:0 0 14px;}

.tm-spec-table{border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;}
.tm-spec-row{display:flex;flex-wrap:wrap;justify-content:space-between;gap:16px;padding:13px 18px;border-bottom:1px solid var(--line);}
.tm-spec-row:last-child{border-bottom:none;}
.tm-spec-row:nth-child(even){background:var(--bone);}
.tm-spec-row span:first-child{font-family:var(--sans);font-size:14px;color:var(--charcoal-70);min-width:0;overflow-wrap:anywhere;}
.tm-spec-row span:last-child{font-family:var(--mono);font-size:14px;color:var(--charcoal);text-align:right;min-width:0;overflow-wrap:anywhere;}

.tm-incl-list{display:flex;flex-direction:column;gap:14px;}
.tm-incl-card{border:1px solid var(--line);border-radius:var(--r);background:var(--bone);
  padding:14px 16px;}
.tm-incl-card--expandable{cursor:pointer;}
.tm-incl-check{width:22px;height:22px;border-radius:100px;background:var(--go);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0;}
.tm-incl-card span{font-family:var(--sans);font-weight:600;font-size:15px;}

.tm-addon-list{display:flex;flex-direction:column;gap:12px;}
.tm-addon-row{border:1px solid var(--line);border-radius:var(--r);background:var(--bone);
  padding:13px 16px;}
.tm-addon-row--expandable{cursor:pointer;}
.tm-addon-name{font-family:var(--sans);font-weight:600;font-size:15px;}
.tm-addon-meta{font-family:var(--mono);font-size:11px;color:var(--charcoal-45);}

/* quick task 260711-svk: optional per-row photo on an included item / add-on
   row; sized so a photo-bearing row and a text-only row sit comfortably in
   the same list. */
.tm-incl-photo,.tm-addon-photo{width:64px;height:64px;object-fit:cover;border-radius:8px;
  border:1px solid var(--line);flex:0 0 auto;}

.tm-incl-note,.tm-addon-note{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);
  margin:6px 0 0;}
.tm-incl-toggle,.tm-addon-toggle{display:inline-block;font-family:var(--mono);font-size:11px;
  color:var(--charcoal-45);cursor:pointer;margin-top:8px;}
.tm-spec-mini{display:flex;flex-wrap:wrap;gap:6px 20px;margin-top:10px;}
.tm-spec-mini-item{font-family:var(--mono);font-size:12px;color:var(--charcoal-70);}
.tm-spec-mini-label{color:var(--charcoal-45);}

/* ============ PRODUCT — GEO CONTENT SECTIONS (plan 17-03, GEO-03/GEO-04) ============
   Always-visible comparison table / Q&A / policy blocks rendered below
   .tm-product-grid (product.cljs geo-comparison-section/geo-qa-section/
   geo-policy-section) -- copy sourced entirely from timech.shared.geo-
   content, this file adds only structural sizing on top of existing
   tokens (--display font var, .tm-label kicker, .tm-spec-table/-row). */
.tm-geo-section{max-width:1240px;margin:0 auto;padding:40px 0 0;}
.tm-geo-qa h3,.tm-geo-policy h3{font-family:var(--display);font-weight:600;font-size:18px;color:var(--ink);margin:0 0 6px;}
.tm-geo-qa p,.tm-geo-policy p{font-size:15px;line-height:1.55;color:var(--charcoal-70);margin:0 0 22px;}
.tm-geo-qa [id^="faq-"]{scroll-margin-top:calc(var(--nav-h) + 24px);}
@media (max-width:768px){
  .tm-geo-section{padding:28px 0 0;}
  .tm-geo-qa h3,.tm-geo-policy h3{font-size:16px;}
}

/* ============ PRODUCT — STICKY BOOKING RAIL (plan 01-04, BOOK-01/02/03/09) ============ */
.tm-booking-rail{position:sticky;top:calc(var(--nav-h) + 24px);}
.tm-booking-card{background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow);overflow:hidden;}
.tm-booking-card-head{padding:18px 20px;border-bottom:1px solid var(--line);display:flex;align-items:baseline;justify-content:space-between;}
.tm-booking-card-body{padding:20px;}

.tm-label{font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--charcoal-90);}

.tm-block-row{display:flex;gap:8px;margin-bottom:8px;flex-wrap:wrap;}
.tm-block-btn{flex:1 1 auto;min-width:84px;padding:12px 6px;border-radius:var(--r);cursor:pointer;text-align:center;
  border:1px solid var(--line);background:var(--bone);color:var(--charcoal);}
.tm-block-btn--active{border:1.5px solid var(--charcoal);background:var(--charcoal);color:var(--oat);}
.tm-block-btn-label{font-family:var(--sans);font-weight:600;font-size:13px;}
.tm-block-btn-note{font-family:var(--mono);font-size:10px;opacity:.7;margin-top:2px;}
.tm-block-hint{font-family:var(--mono);font-size:11px;color:var(--charcoal-45);margin-bottom:18px;}

.tm-stepper{display:flex;align-items:center;gap:10px;margin:8px 0 18px;}
.tm-stepper button{width:44px;height:44px;border-radius:var(--r);border:1px solid var(--line-strong);
  background:var(--bone);cursor:pointer;font-size:16px;color:var(--charcoal);}
.tm-stepper span{font-family:var(--mono);font-size:15px;min-width:48px;text-align:center;}

.tm-cal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;}
.tm-cal-nav{width:44px;height:44px;border-radius:var(--r);border:1px solid var(--line-strong);
  background:transparent;cursor:pointer;font-size:18px;color:var(--charcoal);}
.tm-cal-nav:disabled{opacity:.35;cursor:not-allowed;}
.tm-cal-month{font-family:var(--display);font-weight:600;font-size:18px;}
.tm-cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;}
.tm-cal-dow{text-align:center;color:var(--charcoal-90);font-size:10px;padding:2px 0;}
.tm-cal-cell{aspect-ratio:1;border:none;border-radius:var(--r);position:relative;font-family:var(--mono);
  font-size:13px;background:var(--bone);color:var(--charcoal);cursor:pointer;}
.tm-cal-cell--empty{visibility:hidden;}
.tm-cal-cell--selected{background:var(--charcoal);color:var(--oat);}
.tm-cal-cell--disabled{background:transparent;color:var(--charcoal-45);cursor:not-allowed;opacity:.5;}
.tm-cal-cell--blocked{text-decoration:line-through;cursor:not-allowed;}
.tm-cal-cell-dot{position:absolute;bottom:4px;left:50%;transform:translateX(-50%);width:4px;height:4px;border-radius:4px;background:var(--destructive);}
.tm-cal-legend{display:flex;gap:18px;margin-top:14px;flex-wrap:wrap;}
.tm-cal-legend-item{display:flex;align-items:center;gap:7px;font-family:var(--mono);font-size:11px;color:var(--charcoal-70);}
.tm-cal-legend-swatch{width:13px;height:13px;border-radius:3px;display:inline-block;}

.tm-cal-error{font-family:var(--sans);font-size:13px;color:var(--destructive);margin-top:10px;padding:10px 12px;
  border:1px dashed var(--destructive);border-radius:var(--r);}

/* Quick task 260830-gni: admin blackout calendar's own per-item dot row.
   `.tm-cal-cell-dot` above is a single, hard-coded-colour, absolutely-
   centred dot the customer calendar still depends on -- a fleet-wide day
   needs N dots side by side in per-item inline colours, so this is a
   small sibling rule set, prefixed to avoid any collision. */
.tm-admin-blackout-cal-dot-row{position:absolute;bottom:4px;left:0;right:0;display:flex;
  justify-content:center;gap:2px;}
.tm-admin-blackout-cal-dot{width:5px;height:5px;border-radius:5px;display:inline-block;}

/* Quick task 260830-gni Task 2 (QT-GNI-02): the selected day cell's own
   modifier, and the day-detail list beneath the grid. */
.tm-admin-blackout-cal-cell--selected{outline:2px solid var(--charcoal);outline-offset:-2px;}
.tm-admin-blackout-day-detail{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:10px;}
.tm-admin-blackout-day-detail-note{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);margin:2px 0 0;}

.tm-slot-list{display:flex;flex-direction:column;gap:7px;}
.tm-slot-row{display:flex;align-items:center;gap:11px;padding:11px 14px;border-radius:var(--r);cursor:pointer;
  text-align:left;border:1px solid var(--line);background:var(--bone);width:100%;}
.tm-slot-row--selected{border:1.5px solid var(--charcoal);background:#fff;}
.tm-slot-row-dot{width:16px;height:16px;border-radius:100px;flex-shrink:0;border:1.5px solid var(--line-strong);background:#fff;}
.tm-slot-row--selected .tm-slot-row-dot{border:5px solid var(--charcoal);}
.tm-slot-row span:last-child{font-family:var(--mono);font-size:13px;}

/* Quick task 260728-mii: warning, so this uses --signal (mirrors
   .tm-checkout-banner's dashed callout) -- --destructive stays
   exhaustively reserved for the cancellation panel + .tm-btn-destructive +
   .tm-pill--destructive per the color contract at line ~738; this notice
   must never be recolored to --destructive. */
.tm-slot-warning{
  border:1.5px dashed var(--signal);border-radius:var(--r);background:var(--signal-soft);
  color:var(--signal);font-family:var(--sans);font-size:13px;line-height:1.5;
  padding:12px 14px;margin-top:12px;}
.tm-slot-warning a{color:inherit;text-decoration:underline;}

.tm-price-row{display:flex;justify-content:space-between;padding:4px 0;font-family:var(--sans);font-size:14px;color:var(--charcoal-70);}
.tm-price-row-value{font-family:var(--mono);font-size:14px;color:var(--charcoal);}
.tm-price-total{display:flex;justify-content:space-between;align-items:baseline;margin-top:12px;padding-top:12px;border-top:1px solid var(--line);}
.tm-price-total span:first-child{font-family:var(--display);font-weight:600;font-size:17px;}
.tm-price-total span:last-child{font-family:var(--mono);font-size:24px;}

/* Phase 66 (RECORD-03): booking-record Money panel's Total row highlight
   and a "positive amount owed" mono-figure warn tone -- additive modifier
   classes on the existing .tm-price-row/.tm-price-row-value pair, scoped
   only where booking_record.cljs applies them, so every other .tm-price-row
   consumer above (analytics/off_hire/off_session_charge/schedule/manual_
   booking/customers/lifecycle_panel) is untouched. Matches Handover 03's
   Overview Money panel: the Total row sits on a --bone field, and an
   outstanding balance reads in --signal rather than the default ink. */
.tm-price-row--total{background:var(--bone);padding:6px 10px;border-radius:var(--r);}
.tm-price-row--total .tm-price-row-value{font-weight:700;}
.tm-price-row-value--warn{color:var(--signal);}

/* Quick task 260919-c83 (ACCESSNOTE-01/FUELSTATION-01/FUELSTATION-02): a
   wrapping modifier for two opt-in .tm-price-row consumers whose value can
   be long or multi-line -- booking_record.cljs's Access notes row and
   booking_detail.cljs's Cheaper fuel row (now showing the station's street
   address alongside its name). Additive: only these two call sites attach
   the modifier via their props map's :class key; every other .tm-price-row
   consumer above is untouched. */
.tm-price-row--wrap{align-items:flex-start;gap:12px;}
.tm-price-row--wrap>span:first-child{flex:0 0 auto;white-space:nowrap;}
.tm-price-row--wrap .tm-price-row-value{text-align:right;min-width:0;white-space:pre-wrap;overflow-wrap:anywhere;}

.tm-cta{width:100%;font-family:var(--sans);font-weight:600;font-size:16px;border:none;border-radius:var(--r);
  padding:16px 28px;cursor:pointer;margin-top:16px;background:var(--signal);color:#fff;}
.tm-cta:disabled{background:var(--charcoal);opacity:.5;cursor:not-allowed;}
.tm-cta-footnote{font-family:var(--mono);font-size:11px;color:var(--charcoal-90);text-align:center;margin-top:12px;}
.tm-cta-footnote a{color:inherit;text-decoration:underline;}

/* Quick task 260822-6ag: the home hero's second CTA button, sitting beside
   "Browse the fleet". The two buttons deliberately wrap to a stacked column
   below ~480px via flex-wrap rather than a media query. .tm-cta-ghost must
   be declared AFTER the .tm-cta rule above -- the two selectors have equal
   0,1,0 specificity, so source order alone decides which wins, and the
   ghost variant needs to win on `.tm-cta.tm-cta-ghost` elements. */
.tm-hero-cta-row{display:flex;gap:12px;flex-wrap:wrap;margin-top:16px;}
.tm-hero-cta-row .tm-cta{flex:1 1 220px;margin-top:0;text-align:center;}
.tm-cta-ghost{background:transparent;color:var(--charcoal);border:1px solid var(--line);}

/* ============ ADMIN APP (plan 01-03 Task 3, AUTH-02) ============
   Minimal chrome only — no marketing Nav/Footer (D-16, UI-SPEC admin
   screens section). Spacing follows the 8-pt scale (12px/16px inputs +
   buttons per UI-SPEC's declared button/input padding exceptions);
   typography follows the two-weight discipline (400 body, 600 headings/
   buttons); color follows the 60/30/10 split (bone dominant, white card
   surface, charcoal as the default interactive color — NOT --signal,
   which stays reserved for the customer booking flow's forward-progress
   CTAs only, per UI-SPEC's exhaustive reserved-list). */

.tm-admin-login-page{max-width:440px;margin:min(8vh,70px) auto 0;padding:0 24px;}
.tm-admin-login-header{text-align:center;margin-bottom:24px;}
.tm-admin-login-header .tm-admin-wordmark{
  display:block;font-family:var(--display);font-weight:600;font-size:20px;
  color:var(--charcoal);margin-bottom:22px;}
.tm-admin-login-header h1{font-family:var(--display);font-weight:600;font-size:32px;margin:0 0 8px;color:var(--ink);}
.tm-admin-login-header p{color:var(--charcoal-70);font-size:16px;line-height:1.5;margin:0;}
.tm-admin-login-card{background:#fff;border:1px solid var(--line);border-radius:var(--r-admin-panel);padding:24px;box-shadow:var(--shadow);}
.tm-admin-login-card .tm-label{display:block;margin-bottom:8px;}
.tm-admin-input{
  width:100%;border:1px solid var(--line-strong);border-radius:var(--r);
  padding:12px 16px;font-family:var(--sans);font-size:16px;color:var(--charcoal);
  background:#fff;outline:none;margin:0 0 16px;}
.tm-admin-login-error{color:var(--destructive);font-size:14px;margin:0 0 16px;}
.tm-admin-btn-solid{
  width:100%;font-family:var(--sans);font-weight:600;font-size:16px;
  border:none;border-radius:var(--r);background:var(--charcoal);color:var(--oat);
  padding:12px 16px;cursor:pointer;}
.tm-admin-btn-solid:disabled{opacity:.6;cursor:default;}

/* v1.6 Phase 64 (VIS-02/VIS-03, design brief §6 Type): the shared .tm-label
   field-label class (used by both admin and customer forms — 20 admin files,
   12 customer files) can't be retuned globally without changing customer
   checkout too. Scoped to the admin app's two top-level wrappers instead:
   9.5px/.18em (Desk) per Handover 01's Type table, with a Field override to
   10.5px/.18em below. Letter-spacing narrows from the shared 11px/.22em
   default to the brief's 9.5–10.5px/.18em. */
.tm-admin-shell .tm-label,
.tm-admin-login-page .tm-label{font-size:9.5px;letter-spacing:.18em;}
.tm-admin-shell--field .tm-label{font-size:10.5px;}

/* VIS-02 Field override: the two page titles reachable in Field mode (New /
   .tm-admin-manual-booking, Take pay / .tm-admin-manual-sumup-charge) drop
   to the brief's 21px Field size. Every other 25px page title above lives on
   a Desk-only screen per brief §5 (unreachable in Field — a "switch to Desk"
   prompt shows instead), so no Field override is needed for those. */
.tm-admin-shell--field .tm-admin-manual-booking h2,
.tm-admin-shell--field .tm-admin-manual-sumup-charge h2{font-size:21px;}

/* VIS-02/VIS-03 baseline: sets the admin app's default body-text size to the
   brief's Desk/Field range (12.5–13 / 14.5–15) so any admin element that
   doesn't already carry its own explicit font-size inherits a brief-correct
   value, without touching the dozens of already-explicitly-sized component
   rules below (each restyle phase corrects its own screen's specific
   deviations against its own mockup — this sets the floor, not every ceiling). */
.tm-admin-shell,.tm-admin-login-page{font-size:13px;}
.tm-admin-shell--field{font-size:15px;}

/* Quick task 260828-bgc: 100vh keeps the fallback for engines without
   dvh support, but on a phone 100vh is the LARGE viewport measured with
   the browser's toolbars retracted — taller than what is actually on
   screen when a toolbar is showing, leaving a phantom scroll region
   beneath it. @supports upgrades to 100dvh (the viewport that IS really
   visible) wherever the engine supports it. Side padding keeps shell
   content clear of a landscape display cutout now that viewport-fit=cover
   is set in public/admin.html — without it, content could run under the
   cutout. .tm-admin-sidenav's own 100vh calc is untouched: the Desk rail
   is out of scope here and governed by its own max-width:767px query. */
.tm-admin-shell{
  min-height:100vh;background:var(--bone);
  padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px);}
@supports (min-height:100dvh){
  .tm-admin-shell{min-height:100dvh;}
}
/* Header height exposed as --admin-header-h (same convention as the
   customer nav's --nav-h above) so the sidenav's sticky top-offset and the
   mobile overlay's top-offset share one source of truth instead of two
   hardcoded guesses — min-height keeps the actual rendered header at or
   above this value so the offset never overlaps it. */
:root{ --admin-header-h:62px; }
.tm-admin-header{position:sticky;top:0;z-index:10;background:var(--bone);border-bottom:1px solid var(--line);min-height:var(--admin-header-h);}
.tm-admin-header-inner{max-width:1080px;margin:0 auto;padding:14px 24px;display:flex;align-items:center;gap:16px;}
.tm-admin-header-inner .tm-admin-wordmark{font-family:var(--display);font-weight:600;font-size:18px;color:var(--charcoal);}
.tm-admin-header-inner .tm-admin-label{
  font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--stone);}
.tm-admin-signout{
  margin-left:auto;background:transparent;border:1px solid var(--line-strong);border-radius:var(--r);
  padding:8px 16px;font-family:var(--sans);font-size:14px;font-weight:600;color:var(--charcoal);cursor:pointer;}
.tm-admin-signout:disabled{opacity:.6;cursor:default;}

/* ============ ADMIN SHELL — collapsible side nav (plan 15-04, ADM-06) ============
   Restructures the former horizontal .tm-admin-nav flex-wrap row (11 plain-
   text items directly under the header) into a two-column layout: a
   vertical .tm-admin-sidenav rail (left) + .tm-admin-main content (right).
   Header stays full-width sticky above, unchanged. .tm-admin-nav-item/
   .tm-admin-nav-active text treatment (14px sans, --charcoal-70 default,
   --charcoal + Semibold active) is reused verbatim, just re-flowed from a
   row into a stacked column — see brand.css:813-818 for the existing
   rotated-border-corner CSS-chevron technique reused below for the
   collapse toggle (no icon-font/SVG dependency, per 15-UI-SPEC.md). */
.tm-admin-shell-body{display:flex;align-items:flex-start;}
.tm-admin-sidenav{
  width:200px;flex:0 0 200px;background:#fff;border-right:1px solid var(--line);
  position:sticky;top:var(--admin-header-h);align-self:flex-start;
  height:calc(100vh - var(--admin-header-h));overflow-y:auto;
  display:flex;flex-direction:column;}
/* Expanded-only inset (Handover 02: rail container padding, not per-item
   margin) — the collapsed 56px icon rail keeps its own centred-tile rule
   below untouched. */
.tm-admin-sidenav:not(.tm-admin-sidenav--collapsed){padding:14px 10px 8px;}
.tm-admin-sidenav .tm-admin-nav-item{
  display:flex;align-items:center;gap:10px;width:100%;text-align:left;
  font-family:var(--sans);font-size:13px;color:var(--charcoal-70);padding:9px 11px;border-radius:var(--r);}
.tm-admin-nav-item{cursor:pointer;background:none;border:none;}
.tm-admin-nav-item svg{flex:none;}
.tm-admin-nav-item-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* Phase 65 (SHELL-01): Handover 02's ".k-nav.on" is a filled --charcoal
   pill (bg #2E2A25 / text #E7E2D8), not bold text on a transparent row —
   matches the same active-state language brief §9's confirm-button and
   §6's "structural nav, never --signal" note both use. */
.tm-admin-nav-item.tm-admin-nav-active{background:var(--charcoal);color:var(--oat);font-weight:600;}
.tm-admin-sidenav-toggle{
  display:flex;align-items:center;justify-content:center;
  width:32px;height:32px;margin:8px auto 4px;padding:0;
  background:none;border:none;cursor:pointer;}
.tm-admin-sidenav-toggle::before{
  content:"";display:inline-block;width:7px;height:7px;
  border-right:1.5px solid var(--charcoal-70);border-bottom:1.5px solid var(--charcoal-70);
  transform:rotate(135deg);} /* expanded default: chevron points left (‹) */
.tm-admin-sidenav--collapsed .tm-admin-sidenav-toggle::before{
  transform:rotate(-45deg);} /* collapsed: chevron points right (›) */
.tm-admin-main{flex:1 1 auto;min-width:0;}

/* Collapsed rail (mobile default <768px; owner-toggleable at any width):
   56px icon-only rail, 44×44 tap-target tiles showing a small monochrome
   line icon per nav item (QUICKSA4-02 -- nav-item swaps its rendered
   child for an inline SVG in core.cljs, replacing the earlier
   first-letter tiles that had become unreadable once five items shared
   the letter M), active item marked by a 2px left --charcoal border
   since bold text alone reads poorly at icon width (15-UI-SPEC.md
   "Collapsible side nav"; Color contract — never --signal, this is
   structural nav not a CTA). */
.tm-admin-sidenav--collapsed{width:56px;flex:0 0 56px;}
.tm-admin-sidenav--collapsed .tm-admin-nav-item{
  width:44px;height:44px;margin:0 auto;padding:0;
  display:flex;align-items:center;justify-content:center;text-align:center;
  font-weight:600;}
.tm-admin-sidenav--collapsed .tm-admin-nav-item.tm-admin-nav-active{
  border-left:2px solid var(--charcoal);}
.tm-admin-sidenav--collapsed .tm-admin-nav-item svg{display:block;flex:0 0 auto;}

/* Backdrop: transparent, click-to-dismiss overlay scrim. Only rendered
   (core.cljs) while the rail is expanded; only visually/interactively
   active below 768px via this media query — at desktop widths the
   expanded rail is the normal in-flow column, not an overlay, so the
   backdrop stays inert (display:none) there. */
.tm-admin-sidenav-backdrop{display:none;}

@media (max-width:767px){
  .tm-admin-sidenav-backdrop{
    display:block;position:fixed;inset:0;top:var(--admin-header-h);
    background:transparent;z-index:19;}
  /* Mobile expanded-from-collapsed: the SAME 200px labeled rail overlays
     the content instead of pushing it — position:fixed + shadow, dismissed
     by the backdrop, the toggle, or picking a nav item (core.cljs
     nav-item's on-click). The collapsed (icon-rail) variant above is
     unaffected by this query — it stays a normal in-flow column, matching
     "icon-only rail, not a fully-hidden hamburger" (15-UI-SPEC.md). */
  .tm-admin-sidenav:not(.tm-admin-sidenav--collapsed){
    position:fixed;top:var(--admin-header-h);left:0;bottom:0;
    height:auto;box-shadow:var(--shadow-lg);z-index:20;}
}

/* ============ ADMIN SHELL — Desk rail groups (Phase 58, SHELL-02) ============
   Three labelled groups (Operate / Review / Set up) wrap the rail's seven
   items -- purely a grouping/label addition over the existing
   .tm-admin-nav-item styling above, which stays untouched. Group labels
   only render when expanded (core.cljs); the collapsed icon rail shows no
   labels at all, matching the existing collapsed-rail convention. */
.tm-admin-nav-group{display:flex;flex-direction:column;gap:3px;}
.tm-admin-nav-group-label{
  font-family:var(--mono);font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--charcoal-45);padding:14px 11px 8px;}
.tm-admin-nav-group:first-child .tm-admin-nav-group-label{padding-top:4px;}

/* Phase 65 (SHELL-03): a two-label segmented Desk/Field control, matching
   Handover 02's `.k-nav`-adjacent switch (bordered 4px-radius container,
   two equal pill halves, active = filled --charcoal/--oat, inactive =
   --charcoal-70 text on transparent) — NOT the on/off `.tm-switch` toggle
   every other admin boolean setting uses (config_forms.cljs, catalog.cljs,
   faqs.cljs, reviews.cljs all keep that one, untouched). Placed before
   Sign out, after the Admin label. */
.tm-admin-shell-mode-switch{
  margin-left:auto;display:flex;border:1px solid var(--line-strong);border-radius:var(--r);
  overflow:hidden;}
.tm-admin-shell-mode-btn{
  border:none;background:none;cursor:pointer;font-family:var(--mono);font-size:9px;
  letter-spacing:.12em;text-transform:uppercase;padding:7px 15px;color:var(--charcoal-70);}
.tm-admin-shell-mode-btn--active{background:var(--charcoal);color:var(--oat);}
.tm-admin-shell-mode-switch + .tm-admin-signout{margin-left:0;}

/* ============ ADMIN SHELL — Field bottom tab bar (Phase 58, SHELL-03) ========
   Five tabs, no rail at all (criterion 3). Fixed to the viewport bottom,
   sized for daylight/one-handed on-site use — every tab at least 44px of
   hit area (the whole button, not just the icon), no hover-dependent
   affordance anywhere (buttons are tap targets by construction). Field's
   .tm-admin-main needs bottom padding equal to the bar's own height so the
   last piece of page content is never hidden underneath it -- --field-
   tabbar-h is the one shared source of truth for both. */
:root{ --field-tabbar-h:62px; } /* Phase 65: "Bottom tabs, 62px, sticky" — Handover 04 */
/* Quick task 260828-bgc: --safe-b is a named indirection for the bottom
   safe-area inset (real value only after public/admin.html's viewport-meta
   gained viewport-fit=cover, below) so its three consumers — the bar's own
   height, .tm-admin-main's bottom padding, and .tm-field-sticky-footer's
   bottom offset further down this file — share one source of truth, and so
   a headless harness (which cannot emulate a real device inset) can
   override it by name. --field-tabbar-total-h is the bar's full on-screen
   height (tap target + inset) those same three consumers need. */
:root{
  --safe-b:env(safe-area-inset-bottom,0px);
  --field-tabbar-total-h:calc(var(--field-tabbar-h) + var(--safe-b));
}
.tm-admin-shell--field .tm-admin-main{padding-bottom:calc(var(--field-tabbar-total-h) + 16px);}
.tm-admin-field-tabbar{
  /* height is the FULL total, not a flat 62px: with the global
     *{box-sizing:border-box}, a flat height would let the safe-area
     padding below shrink the 62px tap target instead of lifting the tabs
     above the home indicator — this keeps the full tap target and adds
     the inset beneath it. */
  position:fixed;left:0;right:0;bottom:0;z-index:15;height:var(--field-tabbar-total-h);
  display:flex;background:#fff;border-top:1px solid var(--line);
  padding-bottom:var(--safe-b);
  padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px);}
.tm-admin-field-tab{
  flex:1 1 0;min-height:44px;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:2px;background:none;border:none;cursor:pointer;
  color:var(--charcoal-70);}
.tm-admin-field-tab.tm-admin-field-tab-active{color:var(--charcoal);font-weight:600;}
.tm-admin-field-tab-label{font-family:var(--sans);font-size:10.5px;}

/* Field's switch-to-Desk prompt (criterion 4) -- never a blank screen, a
   404, or a silently ignored click for Fleet/Settings/Reports in Field. */
.tm-admin-field-desk-prompt{
  max-width:480px;margin:64px auto;padding:0 24px;text-align:center;}
.tm-admin-field-desk-prompt p{
  font-family:var(--sans);font-size:14.5px;color:var(--charcoal-70);margin:0 0 16px;}

.tm-admin-stub{max-width:1080px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-stub h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 8px;}
.tm-admin-stub p{color:var(--charcoal-70);font-size:16px;margin:0;}

/* ============ ADMIN — BLACKOUT FORM (plan 01-06 Task 2, ADM-04) ============
   No prototype precedent (01-UI-SPEC.md) — plain admin-form panel styling,
   D-13 waives self-service polish for this internal tool. Result list:
   success rows use the go-green token, conflict rows the inline callout
   treatment (dashed --signal border), per the plan's acceptance criteria. */
.tm-admin-blackout{max-width:560px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-blackout h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 16px;}
.tm-admin-blackout-scope{display:flex;gap:24px;margin:0 0 16px;}
.tm-admin-radio{display:flex;align-items:center;gap:8px;font-family:var(--sans);font-size:16px;color:var(--charcoal);cursor:pointer;}
.tm-admin-field{margin:0 0 16px;}
.tm-admin-field .tm-label{display:block;margin-bottom:8px;}
.tm-admin-blackout-dates{display:flex;gap:16px;}
.tm-admin-blackout-dates .tm-admin-field{flex:1;}
.tm-admin-textarea{min-height:80px;resize:vertical;font-family:var(--sans);}
.tm-admin-blackout-results{list-style:none;margin:16px 0 0;padding:0;display:flex;flex-direction:column;gap:8px;}
.tm-admin-blackout-ok{
  font-family:var(--sans);font-size:14px;color:var(--charcoal);
  background:var(--go-soft);border-radius:var(--r);padding:8px 16px;
  border-left:3px solid var(--go);}
.tm-admin-blackout-conflict{
  font-family:var(--sans);font-size:14px;color:var(--charcoal);
  background:var(--signal-soft);border:1px dashed var(--signal);border-radius:var(--r);
  padding:8px 16px;}

/* ============ ADMIN — SETTINGS second-level sidebar (Phase 70 gap close, ============
   FLEET-02) — Handover 05: "A second-level rail, not tabs. Seven sections
   is too many for a tab strip, and these are destinations you arrive at
   with intent." 214px, --bone fill, right border — deliberately the SAME
   visual language as the top-level Desk rail's .tm-admin-nav-item /
   .tm-admin-nav-active (brand.css:504-514): Handover 05's own mockup
   literally reuses ".k-nav"/".k-nav.on" for both rail levels, so this
   sidebar's items reuse those two classes rather than duplicating the
   active-state treatment. Settings is Desk-only (desk-only-views,
   core.cljs) so no Field/narrow-width variant is needed here — Field shows
   the switch-to-Desk prompt before this shell ever mounts. */
.tm-admin-settings-shell{display:flex;align-items:stretch;}
.tm-admin-settings-sidebar{
  width:214px;flex:0 0 214px;background:var(--bone);border-right:1px solid var(--line);
  padding:18px 12px;}
.tm-admin-settings-sidebar h2{
  font-family:var(--display);font-weight:600;font-size:18px;color:var(--ink);
  margin:0;padding:0 8px 12px;}
.tm-admin-settings-sidebar-list{display:flex;flex-direction:column;gap:2px;}
.tm-admin-settings-sidebar .tm-admin-nav-item{
  font-size:12.5px;display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  font-family:var(--sans);color:var(--charcoal-70);padding:9px 11px;border-radius:var(--r);}
.tm-admin-settings-sidebar-badge{margin-left:auto;}
.tm-admin-settings-content{flex:1 1 auto;min-width:0;}

/* ============ ADMIN — CONFIG FORMS (plan 01-06 Task 3, D-10/D-11/D-13) ============
   Plain tables-of-fields + save button — D-13 explicitly waives
   self-service polish for rental-block-type/delivery-day config editing. */
.tm-admin-config{max-width:960px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-config h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 16px;}
.tm-admin-config h3{font-family:var(--display);font-weight:600;font-size:15px;color:var(--ink);margin:0 0 8px;}
.tm-admin-config-hint{color:var(--charcoal-70);font-size:14px;margin:0 0 16px;}
.tm-admin-delivery-days{display:flex;flex-wrap:wrap;gap:16px;margin:0 0 32px;}
.tm-admin-config-table{width:100%;border-collapse:collapse;font-size:14px;}
.tm-admin-config-table th{
  font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--charcoal-70);text-align:left;padding:8px;border-bottom:1px solid var(--line-strong);}
.tm-admin-config-table td{padding:8px;border-bottom:1px solid var(--line);}
.tm-admin-config-table .tm-admin-input{margin:0;padding:8px;font-size:14px;width:100%;}

/* Quick task 260815-6c7: slot-checkbox-group (rental-block-row's dropoff/
   pickup slot picker) now groups its checkboxes into one collapsible
   <details> per day-of-week (mirroring slot-definitions-table's own
   day-grouping, phase 41-04), resolving the tension quick task 260814-r50
   deliberately left open -- that task's own comment here explained why it
   picked a flat bounded-width multi-column layout INSTEAD of the <details>
   pattern: collapsing groups would hide an already-checked slot behind a
   click. Day-grouping now does the primary space-saving job instead, and
   each group's checked-driven :open default (slot-checkbox-day-group)
   keeps any checked slot visible without a click -- so the collapse-vs-
   visibility tension is resolved, not reintroduced. 260814-r50's bounded-
   width multi-column layout is demoted from the whole flat list to inside
   each individual OPEN day-group's own inner list (.tm-admin-slot-picker-
   day below) -- it still earns its keep there for a day with many slots.
   The outer .tm-admin-slot-picker class stays on the picker's root
   deliberately -- it is still "the slot picker", only its internal layout
   changed. */
.tm-admin-slot-picker-day{column-width:130px;column-gap:12px;max-width:280px;}
.tm-admin-slot-picker .tm-admin-radio{font-size:14px;gap:6px;break-inside:avoid;}
.tm-admin-slot-picker details{margin:0 0 6px;}
.tm-admin-slot-picker summary{cursor:pointer;}

/* FIX-03/D-13: dedicated table-header class for the booking-reference
   picker (timech.admin.booking-picker) — its <th> cells previously carried
   .tm-label, which sits inside a .tm-admin-field wrapper (the <details>
   toggle) and so was shadowed by .tm-admin-field .tm-label{display:block}
   above (specificity 0-2-0, beating .tm-admin-config-table th's 0-1-1) and
   forced every column header to stack. Same .tm-label typography (the
   winning cascade declaration, line ~197: font-family/font-size/letter-
   spacing/text-transform/color), but NO display property, so a <th>'s
   default display:table-cell wins and the columns render side by side.
   Do NOT patch .tm-admin-field .tm-label itself — other admin form-label
   usages depend on its display:block (RESEARCH.md Anti-Patterns). */
.tm-admin-picker-th{font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--stone);}

/* ============ ADMIN — TM-SWITCH toggle switch (plan 02-05, D-02/D-03) ============
   02-UI-SPEC.md "Damage Waiver toggle switch": 44x24px pill track,
   border-radius:100px. Off = --bone track + 1px --line-strong border +
   white thumb. On = --go track (the SAME "available/confirmed" token as
   .tm-pill--go and the confirmation checkmark badge) + white thumb
   translated right. Deliberately NEVER --signal (accent stays reserved
   for forward-progress CTAs only — UI-SPEC's exhaustive list). Reused
   verbatim by this plan's admin Active/Retired toggle AND by plan 02-07's
   customer-facing Damage Waiver toggle — this is the single shared switch
   component contract for both. On-state label goes semibold (600) per the
   existing "active/selected-state emphasis" rule (01-UI-SPEC.md). */
.tm-switch{display:inline-flex;align-items:center;gap:10px;cursor:pointer;user-select:none;}
.tm-switch input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none;}
.tm-switch-track{
  position:relative;flex:0 0 auto;width:44px;height:24px;border-radius:100px;
  background:var(--bone);border:1px solid var(--line-strong);
  transition:background .15s ease,border-color .15s ease;}
.tm-switch-thumb{
  position:absolute;top:1px;left:1px;width:20px;height:20px;border-radius:100px;
  background:#fff;box-shadow:0 1px 2px rgba(22,20,15,.18);transition:transform .15s ease;}
.tm-switch input:checked + .tm-switch-track{background:var(--go);border-color:var(--go);}
.tm-switch input:checked + .tm-switch-track .tm-switch-thumb{transform:translateX(20px);}
.tm-switch-label{font-family:var(--sans);font-size:14px;color:var(--charcoal);}
.tm-switch input:checked ~ .tm-switch-label{font-weight:600;}

/* ============ ADMIN — CATALOG (plan 02-05, CAT-03/CAT-04) ============
   List view reuses .tm-admin-config-table/.tm-admin-btn-solid verbatim
   (no new table styling). Edit-Item page: nested sections use the SAME
   24px/16px (section/row) rhythm .tm-admin-config already established —
   .tm-admin-catalog-section is just a spacing wrapper, no new visual
   language. Photo section reuses .tm-checkout-photo-drop/-preview
   verbatim (declared once, above). */
.tm-admin-catalog{max-width:960px;margin:0 auto;padding:0 24px 48px;}
/* Phase 62 (INDEX-01..03, criterion 3): .tm-admin-requests is the outer
   Requests tab-frame's own page shell (core.cljs's requests-tab-frame) —
   same 960px/24px shell as .tm-admin-catalog above. Each of the three
   inner screens (emergency-requests/enquiries/waitlist) still wraps
   itself in its OWN .tm-admin-catalog unchanged, so nesting one shell
   inside another would double the horizontal/bottom padding and re-apply
   max-width inside an already-960px-capped container — the scoped
   override below neutralises the INNER .tm-admin-catalog's own shell
   properties, the same nested-shell precedent .tm-admin-catalog .tm-tabs
   below already sets for a narrower case. */
.tm-admin-requests{max-width:960px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-requests .tm-admin-catalog{max-width:none;margin:0;padding:0;}
.tm-admin-catalog-header{display:flex;justify-content:space-between;align-items:center;margin:0 0 16px;}
.tm-admin-catalog-header h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0;}
.tm-admin-catalog-edit-link{font-family:var(--sans);font-size:14px;font-weight:600;color:var(--charcoal);cursor:pointer;text-decoration:underline;background:none;border:none;padding:0;}
.tm-admin-catalog-empty{
  border:1.5px dashed var(--line-strong);border-radius:var(--r-admin-panel);padding:40px 24px;
  text-align:center;background:var(--bone);}
.tm-admin-catalog-empty h3{font-family:var(--display);font-weight:600;font-size:18px;margin:0 0 8px;}
.tm-admin-catalog-empty p{color:var(--charcoal-70);font-size:15px;margin:0 0 20px;}
.tm-admin-catalog-back{
  background:none;border:none;cursor:pointer;font-family:var(--mono);font-size:12px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--charcoal-70);padding:0;margin:0 0 16px;}
/* Phase 63 (ADMIN-01/02): the /settings hub -- a plain link list to each
   of the seven Settings sections. Quick task 260907-sac (NEWHUB-01) adds
   the /new chooser hub as the same visual treatment -- the two hubs share
   one ruleset by construction so they cannot drift apart. */
.tm-admin-settings-hub-list,.tm-admin-new-hub-list{list-style:none;margin:16px 0 0;padding:0;display:flex;flex-direction:column;gap:4px;}
.tm-admin-settings-hub-link,.tm-admin-new-hub-link{
  display:block;background:var(--bone);border:1px solid var(--line);border-radius:var(--r);
  padding:14px 16px;font-family:var(--sans);font-size:15px;font-weight:600;color:var(--ink);
  cursor:pointer;text-decoration:none;}
.tm-admin-settings-hub-link:hover,.tm-admin-new-hub-link:hover{border-color:var(--line-strong);}
/* Quick task 260806-fju (Task 3): the item id, always visible under the
   Edit-Item heading -- the owner cross-references this against rental
   blocks/bookings, so it can't stay hidden behind a name fallback. */
.tm-admin-catalog-item-id{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);margin:2px 0 16px;}
/* Phase 70 (FLEET-01/02/03, design brief §Handover 01 "Panels and tables" —
   white fill, 1px Charcoal-14% border, 6px radius, header row with a bottom
   border, heading left): .tm-admin-catalog-section is the SAME shared
   section wrapper already reused verbatim across catalog.cljs, blackout.cljs,
   analytics.cljs and (as of this phase) config_forms.cljs's settings-section
   forms — a single CSS-only uplift here panel-ifies Fleet, Settings and
   Reports sections at once with zero markup change at most call sites. The
   inner h3 bleeds to the panel edges via negative margin and gains its own
   bottom border, giving the k-ph header-row look without touching every
   call site's hiccup shape. Content padding is uniform 16px; call sites that
   embed a raw table (.tm-admin-config-table) get its existing cell padding
   for free, no double-border risk since child elements are never re-bordered
   here. */
.tm-admin-catalog-section{
  margin:0 0 20px;background:#fff;border:1px solid var(--line);
  border-radius:var(--r-admin-panel);padding:16px;}
.tm-admin-catalog-section h3{
  font-family:var(--display);font-weight:600;font-size:15px;color:var(--ink);
  margin:-16px -16px 14px;padding:12px 16px;border-bottom:1px solid var(--line);}
/* Numeric/money/percent inputs: Handover 01 §Type "Numbers (money, meters,
   dates, times, refs, counts) — Space Mono 400, without exception", and
   Handover 05's Pricing-tab/Settings mockups show every such input in mono.
   Additive modifier class — .tm-admin-input's own rule (font-family:var(
   --sans)) stays the default for every non-numeric text field; only call
   sites for a dollar, percent, count or rate figure add this class. */
.tm-admin-input--mono{font-family:var(--mono);}
/* Phase 70 (FLEET-01): the Fleet catalog list table has no h3/header-row of
   its own (the page-level "Catalog" h2 sits above it in
   .tm-admin-catalog-header) so it cannot reuse .tm-admin-catalog-section's
   negative-margin h3 trick — a plain bordered/rounded wrapper matching
   Handover 05's k-panel list frame (white fill, 1px Charcoal-14% border,
   6px radius, no shadow). */
.tm-admin-catalog-table-panel{
  background:#fff;border:1px solid var(--line);border-radius:var(--r-admin-panel);
  overflow:hidden;}
.tm-admin-catalog-table-panel .tm-admin-config-table{margin:0;}
.tm-admin-catalog-table-panel .tm-admin-config-table th{background:var(--bone);}
/* Phase 69 gap-closure (INDEX-02, customers.cljs): a .tm-admin-catalog-
   section header row that ALSO carries a right-aligned action (a Save
   button, or a plain count label) — Handover 08's k-ph pattern (heading
   left, action right). Same bled-to-edge/bottom-border treatment as
   .tm-admin-catalog-section's own bare-h3 rule above, moved onto a flex
   wrapper instead of applied straight to the h3, so a second element can
   share the header line. Presentation only — no new selectors touch
   .tm-admin-catalog-section itself, so every existing bare-h3 call site
   (catalog.cljs, blackout.cljs, analytics.cljs, config_forms.cljs, etc.)
   is unaffected. */
.tm-admin-catalog-section-header{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  margin:-16px -16px 14px;padding:12px 16px;border-bottom:1px solid var(--line);}
.tm-admin-catalog-section-header h3{
  font-family:var(--display);font-weight:600;font-size:15px;color:var(--ink);margin:0;}
.tm-admin-catalog-section-header .tm-admin-catalog-save-status{margin-left:0;}
.tm-admin-catalog-row{display:flex;gap:12px;align-items:flex-start;margin:0 0 16px;flex-wrap:wrap;}
.tm-admin-catalog-row .tm-admin-field{flex:1 1 160px;margin:0;}
.tm-admin-catalog-remove{
  background:none;border:none;cursor:pointer;font-family:var(--sans);font-size:13px;
  color:var(--charcoal-70);text-decoration:underline;padding:8px 0;white-space:nowrap;}
.tm-admin-catalog-add{
  background:transparent;border:1px dashed var(--line-strong);border-radius:var(--r);
  padding:8px 16px;font-family:var(--sans);font-size:14px;font-weight:600;color:var(--charcoal);
  cursor:pointer;margin:4px 0 0;}
.tm-admin-catalog-save-status{font-family:var(--sans);font-size:13px;margin-left:10px;}
.tm-admin-catalog-save-status--saved{color:var(--go);}
.tm-admin-catalog-save-status--error{color:var(--destructive);}
/* Phase 58 colour regression fix (design brief §6): field-level validation
   errors use --destructive, never --signal -- this shared class (~90 call
   sites across every admin form) was the one place the app still used
   --signal for this, unlike the customer-side twin .tm-checkout-field-err
   which already used --destructive correctly. */
.tm-admin-catalog-field-err{color:var(--destructive);font-size:13px;margin:8px 0 0;}
.tm-admin-catalog-photo{margin:0 0 8px;max-width:320px;}
/* quick task 260711-svk: per-row photo upload control on Included items /
   Add-ons rows (Edit Item page). */
.tm-admin-row-photo{width:56px;height:56px;object-fit:cover;border-radius:6px;}
.tm-admin-row-photo-placeholder{display:flex;align-items:center;justify-content:center;
  width:56px;height:56px;border:1px dashed var(--line);border-radius:6px;
  font-family:var(--sans);font-size:11px;color:var(--charcoal-45);cursor:pointer;flex-shrink:0;}
.tm-admin-row-photo-control{flex-shrink:0;}
/* quick task 260725-uww: Photos section (Edit Item page) -- per-photo row
   (reuses .tm-admin-row-photo/-placeholder/-control above verbatim via
   row-photo-control) plus its up/down/remove action group. */
.tm-admin-catalog-photo-row{display:flex;align-items:center;gap:12px;margin:0 0 8px;}
.tm-admin-catalog-photo-actions{display:flex;gap:8px;align-items:center;}
.tm-admin-catalog-photo-actions button{
  background:transparent;border:1px solid var(--line-strong);border-radius:var(--r);
  padding:6px 10px;font-family:var(--sans);font-size:13px;color:var(--charcoal);cursor:pointer;}
.tm-admin-catalog-photo-actions button:disabled{opacity:.35;cursor:not-allowed;}

/* Quick task 260806-fju: tabbed Edit-Item page + one sticky page-level Save
   action bar (replaces 13 stacked sections with 11 duplicate Save
   buttons). Scoped .tm-admin-catalog .tm-tabs override follows the SAME
   precedent as .tm-admin-schedule .tm-tabs above -- the base .tm-tabs rule
   has neither wrap nor horizontal scroll and its existing users have only
   2-3 tabs; 5 tabs at the base 12px/16px padding overflow a phone
   viewport, and the owner uses this admin on a phone. */
.tm-admin-catalog .tm-tabs{margin-top:12px;flex-wrap:wrap;}
.tm-tab-badge{
  display:inline-block;margin-left:6px;font-family:var(--sans);font-weight:700;
  font-size:11px;line-height:1;color:var(--charcoal-45);}
.tm-tab-badge--error{color:var(--destructive);}
.tm-tab-badge--dirty{color:var(--charcoal-45);}
.tm-admin-catalog-actions{
  position:sticky;bottom:0;z-index:5;margin-top:24px;padding:14px 0;
  background:var(--bone);border-top:1px solid var(--line);
  display:flex;flex-wrap:wrap;align-items:center;gap:12px;}
.tm-admin-catalog-unsaved-note{
  width:100%;margin:0;font-family:var(--sans);font-size:13px;color:var(--charcoal-70);}

/* ============ ADMIN — MANUAL BOOKING + RECORD PAYMENT (plan 01-09, ADM-03),
   MANUAL CHARGE (quick task 260727-sa4, QUICKSA4-01) ============
   Same D-13 plain-form treatment as blackout/config — item/block/slot
   pickers + the D-01 field grid (reusing timech.customer.checkout's field-
   grid/photo-drop CSS verbatim) + a payment-status radio row. Success
   panel reuses the go-soft token (same visual language as blackout's
   success rows); the pay-by-link box is a plain code chip. The Manual
   charge page (timech.admin.manual-sumup-charge) is the same narrow
   single-column form shape as Manual booking, so it shares this one
   declaration rather than a near-duplicate rule — a single rule means a
   future width/padding tweak can't land on one page and silently miss
   the other, the exact propagation failure mode phases 22/23/24's code
   reviews repeatedly caught. */
.tm-admin-manual-booking,
.tm-admin-manual-sumup-charge{max-width:640px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-manual-booking h2,
.tm-admin-manual-sumup-charge h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 16px;}
/* Plan 26-02 (26-UI-SPEC.md Typography): the new Add-ons screen's "Current
   add-ons"/"Add a new add-on" <h3> sections -- matches .tm-charge-card h3's
   existing 16px/600 heading style verbatim, additive only (no other screen
   inside .tm-admin-manual-booking uses an <h3> today). */
.tm-admin-manual-booking h3{font-family:var(--display);font-weight:600;font-size:15px;color:var(--ink);margin:16px 0 8px;}
/* Quick task 260828-bhe: the New-booking screen's two-column layout (left
   form column + right Quote/Create-booking rail, INDEX-04's v1.6 redesign)
   previously lived as an inline :style map inside manual_booking.cljs's
   `form`. An inline style out-specifies every rule in this file, so no
   media query could ever collapse it -- at phone widths the fixed 300px
   rail held its width and crushed the form column beside it. Moved here as
   a class pair so the SAME 768px collapse .tm-checkout-grid (above) and
   .tm-product-grid already use applies: one full-width column, with the
   rail (Quote, then Create booking) falling BELOW the four numbered form
   panels in DOM order. 768px is core.cljs's own mobile-breakpoint-px, not
   a new breakpoint. The two Desk declarations are a byte-identical port of
   the removed inline styles -- Desk rendering is unchanged by this. */
.tm-admin-manual-booking-grid{display:grid;grid-template-columns:1fr 300px;gap:20px;align-items:start;}
.tm-admin-manual-booking-rail{display:flex;flex-direction:column;gap:12px;position:sticky;top:16px;}
/* No !important here (unlike .tm-checkout-summary-rail's own mobile rule):
   the pinning above is now a class rather than an inline style, so this
   later same-specificity rule wins on document order alone. */
@media (max-width:768px){.tm-admin-manual-booking-grid{grid-template-columns:1fr;} .tm-admin-manual-booking-rail{position:static;}}
.tm-admin-manual-success{
  margin-top:16px;font-family:var(--sans);font-size:14px;color:var(--charcoal);
  background:var(--go-soft);border-radius:var(--r);padding:12px 16px;}
.tm-admin-manual-success code{
  display:inline-block;font-family:var(--mono);font-size:13px;background:#fff;
  border:1px solid var(--line-strong);border-radius:var(--r);padding:6px 10px;word-break:break-all;}

/* ============ CHECKOUT (plan 01-05, PAY-01/03/04/07) ============
   Details+photo / OTP verify / Terms acceptance / hold-confirmed interim
   panel. Spacing per UI-SPEC's 8-pt scale; --signal reserved only for the
   step's forward-progress CTA, per the exhaustive reserved-color list. */

.tm-checkout-empty{max-width:600px;margin:60px auto;text-align:center;padding:24px;}
.tm-checkout-empty h2{font-family:var(--display);font-weight:600;font-size:32px;margin:0 0 12px;color:var(--ink);}
.tm-checkout-empty p{color:var(--charcoal-70);font-size:16px;margin:0 0 20px;}

.tm-checkout-shell{max-width:1080px;margin:0 auto;padding:24px 24px 48px;}
.tm-checkout-stepper{display:flex;align-items:center;gap:8px;margin-bottom:28px;flex-wrap:wrap;}
.tm-checkout-step-dot{
  width:26px;height:26px;border-radius:100px;display:flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:12px;background:var(--bone);color:var(--charcoal-45);
  border:1px solid var(--line);}
.tm-checkout-step-dot.tm-active,.tm-checkout-step-dot.tm-done{background:var(--charcoal);color:var(--oat);border:none;}
.tm-checkout-step-label{font-family:var(--sans);font-weight:500;font-size:14px;color:var(--charcoal-45);}
.tm-checkout-step-label.tm-active{font-weight:600;color:var(--charcoal);}
.tm-checkout-step-rule{flex:0 1 40px;height:1px;background:var(--line-strong);}

.tm-checkout-grid{display:grid;gap:32px;grid-template-columns:minmax(0,1fr) minmax(300px,360px);align-items:start;}
/* WR-01 (23-REVIEW.md): matches .tm-booking-rail's own mobile treatment --
   the nav can grow to two lines at narrow widths (Phase 14, D-03 backstop),
   so a sticky rail must never stay sticky once the grid collapses to a
   single column, or it risks overlapping the nav exactly like the
   product-page bug this phase's sticky-panel fixes addressed. */
@media (max-width:768px){.tm-checkout-grid{grid-template-columns:1fr;} .tm-checkout-summary-rail{position:static !important;}}

.tm-checkout-h2{font-family:var(--display);font-weight:600;font-size:20px;margin:0 0 6px;color:var(--ink);}
.tm-checkout-sub{color:var(--charcoal-70);font-size:16px;line-height:1.5;margin:0 0 16px;}

.tm-checkout-field-grid{display:grid;gap:14px;grid-template-columns:1fr 1fr;}
@media (max-width:600px){.tm-checkout-field-grid{grid-template-columns:1fr;}}
.tm-checkout-field{display:flex;flex-direction:column;gap:8px;}
.tm-checkout-field.tm-span2{grid-column:1 / -1;}
.tm-checkout-field-err{color:var(--destructive);font-size:12px;font-family:var(--sans);}
.tm-checkout-input,.tm-checkout-textarea{
  width:100%;border:1px solid var(--line-strong);border-radius:var(--r);
  padding:12px 16px;font-family:var(--sans);font-size:16px;color:var(--charcoal);
  background:#fff;outline:none;}
.tm-checkout-textarea{min-height:72px;resize:vertical;}
.tm-checkout-input.tm-checkout-input-invalid,.tm-checkout-textarea.tm-checkout-input-invalid{border-color:var(--destructive);}

.tm-checkout-photo-drop{
  border:1.5px dashed var(--line-strong);border-radius:var(--r-lg);padding:32px 20px;
  text-align:center;background:var(--bone);cursor:pointer;display:block;}
.tm-checkout-photo-drop-title{font-family:var(--display);font-weight:600;font-size:16px;margin-bottom:4px;}
.tm-checkout-photo-drop-note{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);}
.tm-checkout-photo-preview{position:relative;border-radius:var(--r-lg);overflow:hidden;border:1px solid var(--line);cursor:pointer;}
.tm-checkout-photo-preview img{width:100%;height:200px;object-fit:cover;display:block;}

.tm-checkout-otp-input{
  width:100%;font-family:var(--mono);font-size:28px;letter-spacing:.4em;text-align:center;
  padding:16px;border:1px solid var(--line-strong);border-radius:var(--r);outline:none;}
/* Keyboard focus visibility for all form inputs above: rest border stays
   --line-strong; on keyboard focus the border darkens to the neutral ink
   token and gains a soft accent halo — both existing tokens, no new colors.
   :focus-visible (not :focus) means mouse clicks don't trigger the ring, so
   there is zero visual change for pointer users. */
.tm-admin-input:focus-visible,
.tm-checkout-input:focus-visible,
.tm-checkout-textarea:focus-visible,
.tm-checkout-otp-input:focus-visible{
  border-color:var(--charcoal);
  box-shadow:0 0 0 3px var(--signal-soft);
}
.tm-checkout-resend{
  background:none;border:none;cursor:pointer;margin-top:14px;font-family:var(--mono);
  font-size:12px;color:var(--charcoal-70);text-decoration:underline;}
.tm-checkout-otp-error{color:var(--destructive);font-size:14px;margin:12px 0 0;}

.tm-checkout-terms-panel{background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);padding:22px;box-shadow:var(--shadow);}
.tm-checkout-terms-summary{max-height:220px;overflow-y:auto;border:1px solid var(--line);border-radius:var(--r);
  padding:16px;font-size:14px;line-height:1.5;color:var(--charcoal-70);margin-bottom:16px;}
/* Quick task 260807-kfm: checkout's terms box now carries all six terms sections, so only checkout gets the taller variant -- emergency-request's Terms step keeps the base height. */
.tm-checkout-terms-summary--tall{max-height:440px;}
.tm-checkout-terms-check{display:flex;align-items:flex-start;gap:10px;font-size:14px;color:var(--charcoal);}
.tm-checkout-terms-version{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);margin-top:10px;}
/* Plan 53-01 (AIRO-16): guide/seasonal-page meta line -- byte-identical copy of .tm-checkout-terms-version's own declaration under a new selector name (UI-SPEC's "one shared style for both meta/issue and last-reviewed lines" rule), placed adjacent to it. */
.tm-guide-meta{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);margin-top:10px;}

.tm-checkout-cta-row{display:flex;gap:12px;margin-top:26px;}
.tm-checkout-btn-signal{
  flex:1;font-family:var(--sans);font-weight:600;font-size:16px;border:none;border-radius:var(--r);
  background:var(--signal);color:#fff;padding:12px 16px;cursor:pointer;}
.tm-checkout-btn-signal:disabled{opacity:.5;cursor:default;}
.tm-checkout-btn-ghost{
  font-family:var(--sans);font-weight:600;font-size:16px;border:1px solid var(--line-strong);
  border-radius:var(--r);background:transparent;color:var(--charcoal);padding:12px 16px;cursor:pointer;}
/* PAYFIX-04 (phase 46 plan 46-04): matches .tm-btn-destructive:disabled/
   .tm-checkout-btn-solid:disabled's opacity/cursor convention -- the one
   new CSS rule this fix's UI surface requires. */
.tm-checkout-btn-ghost:disabled{opacity:.5;cursor:default;}

.tm-checkout-banner{
  border:1.5px dashed var(--signal);border-radius:var(--r);background:var(--signal-soft);
  padding:14px 16px;margin-bottom:16px;color:var(--signal);font-family:var(--sans);font-size:14px;}

.tm-checkout-summary-rail{position:sticky;top:calc(var(--nav-h) + 28px);background:#fff;border:1px solid var(--line);
  border-radius:var(--r-lg);padding:22px;
  /* Phase 37 plan 37-14 Task 2 (D-04): the rail now renders BEFORE the
     main step column in DOM order (see checkout.cljs's `view`) so its own
     Special Conditions block satisfies "seen at or before booking" by
     DOM-order construction (T-37-56) — `order:2` keeps the VISUAL grid
     position (narrow right column) byte-identical to before this change;
     .tm-checkout-grid's sibling main-content div carries the matching
     `order:1` inline. */
  order:2;box-shadow:var(--shadow);}
.tm-detail-panel{background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);padding:22px;box-shadow:var(--shadow);}
.tm-checkout-summary-line{display:flex;justify-content:space-between;font-size:14px;color:var(--charcoal-70);margin-bottom:8px;}
.tm-checkout-summary-total{display:flex;justify-content:space-between;align-items:baseline;
  border-top:1px solid var(--line);margin-top:12px;padding-top:12px;}
.tm-checkout-summary-total .tm-amount{font-family:var(--mono);font-weight:700;font-size:32px;color:var(--ink);}

/* Special Conditions block (Phase 37 plan 37-14 Task 2, D-04, UI-SPEC #8) --
   ONE shared declaration, TWO render call sites (checkout.cljs's
   order-summary-rail, customer/account.cljs's booking-detail panel), via
   the ONE shared component timech.customer.ui/special-conditions-block —
   mirrors .tm-admin-blackout-ok's own bone+left-border "informational
   panel" shape (line ~457 above), but with the NEUTRAL --line-strong
   border instead of --go: this is disclosure, not a success state. No
   fixed height, no overflow scroll -- the bulleted list grows naturally. */
.tm-special-conditions{
  background:var(--bone);border-left:3px solid var(--line-strong);border-radius:var(--r);
  padding:8px 16px;margin-top:16px;font-family:var(--sans);font-size:14px;color:var(--charcoal);}
.tm-special-conditions .tm-label{margin-bottom:4px;}

.tm-checkout-confirmed{max-width:680px;margin:0 auto;padding:40px 24px 0;text-align:center;}
.tm-checkout-confirmed-badge{
  width:64px;height:64px;border-radius:100px;background:var(--go);margin:0 auto 22px;
  display:flex;align-items:center;justify-content:center;font-size:30px;color:#fff;}
.tm-checkout-confirmed h1{font-family:var(--display);font-weight:600;font-size:clamp(28px,5vw,36px);margin:0 0 12px;}
.tm-checkout-confirmed p{color:var(--charcoal-70);font-size:17px;line-height:1.55;max-width:480px;margin:0 auto 28px;}
.tm-checkout-hold-countdown{font-family:var(--mono);font-size:14px;color:var(--signal);margin-top:8px;}

/* Plan 75-04 (EXPIRY-05): generalizes the existing pay-on-delivery inline-
   style trick (checkout.cljs's confirmed-panel, `{:style {:background
   "var(--signal)"}}`) into a real modifier class -- same amber --signal
   fill, same badge shape, now also used by hold-recovery-panel's
   :refunded (reaper-race) variant. The existing inline-style call site is
   left untouched (out of scope); this class is for THIS plan's new call
   site only. */
.tm-checkout-confirmed-badge--attention{background:var(--signal);}

/* Hold status block (plan 75-02, HOLD-01/02, D-04/D-05) — the four-state
   progressive-disclosure wrapper mounted directly under the "Payment"
   heading. 8px/16px are both existing Spacing Scale tokens (sm/md), not a
   new value: 8px echoes the same gap .tm-checkout-hold-countdown's own
   margin-top already uses immediately above; 16px is the default
   element-spacing floor so the block reads correctly below the heading
   even in the :warning phase, whose own .tm-checkout-hold-countdown rule
   (unchanged, above) carries no margin-bottom of its own. No CSS
   transition on the quiet->warning text swap — this stylesheet has zero
   existing prefers-reduced-motion handling, and an instant same-position
   text swap satisfies every accessibility requirement in the
   Interaction & Accessibility Contract trivially. */
.tm-checkout-hold-status{margin:8px 0 16px;}

/* Standard screen-reader-only utility (plan 75-02) — none existed in this
   stylesheet before this phase. Carries the two D-04 aria-live milestone
   announcements (entering the warning window, entering the final minute)
   alongside the VISIBLE .tm-checkout-hold-countdown text above, which
   deliberately carries no aria-live of its own. */
.tm-visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;}

/* Payment step (plan 01-07) — same panel chrome as .tm-checkout-terms-panel;
   #tm-payment-element is the Stripe Payment Element iframe mount target,
   styled to match the INP token look per 01-UI-SPEC.md. */
.tm-checkout-payment-panel{background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);padding:22px;box-shadow:var(--shadow);}
.tm-checkout-payment-element{
  border:1px solid var(--line);border-radius:var(--r);padding:16px;background:var(--bone);min-height:52px;}

/* ============ PHASE 55 — ACCEPTANCE PAYMENT-CHOICE OPTION CARDS
   (55-UI-SPEC.md Interaction Pattern 3) ============
   Two side-by-side "Pay now"/"Pay on delivery" option cards, rendered only
   when the offer allows pay-on-delivery (ACCEPT-06). Interaction Pattern 3
   specifies a 16px gap for this exact composition; the Spacing Scale
   table's own "Exceptions" note separately lists 12px for the same pair --
   both numbers sit inside the existing 12-16px md band, so this rule
   follows Interaction Pattern 3 (the specific layout rule for this
   element) over the more general spacing-scale note. No off-scale token
   is introduced either way. */
.tm-pay-option-grid{display:flex;gap:16px;}
@media (max-width:600px){.tm-pay-option-grid{flex-direction:column;}}
.tm-pay-option{
  position:relative;flex:1 1 0;width:100%;text-align:left;cursor:pointer;
  background:transparent;border:1px solid var(--line-strong);border-radius:var(--r);
  padding:12px;font-family:inherit;font-size:inherit;color:var(--charcoal);}
.tm-pay-option:focus-visible{outline:2px solid var(--signal);outline-offset:2px;}
.tm-pay-option--selected{
  border:2px solid var(--signal);background:var(--signal-soft);
  /* one-pixel border increase (1px -> 2px) offset by a matching 1px
     padding reduction so the selected state never shifts layout */
  padding:11px;}
.tm-pay-option-title{font-family:var(--sans);font-weight:600;font-size:16px;margin:0 0 4px;color:var(--ink);}
.tm-pay-option-body{font-family:var(--sans);font-weight:400;font-size:14px;line-height:1.5;color:var(--charcoal-70);}
.tm-pay-option-check{
  position:absolute;top:10px;right:12px;color:var(--signal);
  font-family:var(--sans);font-weight:600;font-size:16px;}
.tm-pay-option-balance{
  font-family:var(--mono);font-weight:700;font-size:32px;color:var(--ink);
  /* UI-SPEC flags the balance-due figure as an unverified overflow risk at
     narrow mobile card widths (4+ digit amounts) -- these two rules are
     the explicit mitigation, not an assumption that it always fits. */
  overflow-wrap:break-word;word-break:break-word;}

/* ============ QUICK TASK 260826-op0 — OFFER ACCEPTANCE PRICE HEADLINE
   ============
   On a phone, .tm-checkout-grid collapses to a single column (:732 above)
   and .tm-checkout-summary-rail carries `order:2` (:813 above), so the
   rail's own price total renders below the entire "Your details" form.
   This headline sits OUTSIDE .tm-checkout-grid entirely, above the step
   indicator, so no column collapse can bury it -- built entirely from
   tokens already defined in this file, no new custom property. */
.tm-offer-price-header{
  display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:16px;
  background:var(--bone);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:16px 22px;margin-bottom:16px;box-shadow:var(--shadow);}
.tm-offer-price-header-item{font-family:var(--sans);font-size:14px;color:var(--charcoal-70);margin:4px 0 0;}
.tm-offer-price-header-note{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);margin-top:10px;}
.tm-offer-price-header-amount{
  font-family:var(--mono);font-weight:700;font-size:32px;color:var(--ink);
  overflow-wrap:break-word;word-break:break-word;}
@media (max-width:600px){.tm-offer-price-header{padding:14px 16px;}}

/* ============ CUSTOMER APP — ACCOUNT (plan 03-01, ACC-01) ============
   Reuses .tm-checkout-shell/-h2/-sub/-field/-input/-cta-row (sign-in gate)
   and .tm-tabs/.tm-tab/.tm-tab--active (history tabs) verbatim per
   03-UI-SPEC.md; only the booking-row card and empty state below are new. */
/* Narrow auth-form variant of .tm-checkout-shell, used only by the sign-in
   gate (quick task 260708-jdh) -- the booking history/account views below
   keep the wide .tm-checkout-shell. */
.tm-signin-shell{max-width:440px;margin:0 auto;padding:24px 24px 48px;}
.tm-account-header{margin:8px 0 4px;}
.tm-account-header h1{font-family:var(--display);font-weight:600;font-size:32px;margin:0;color:var(--ink);}

.tm-account-list{display:flex;flex-direction:column;gap:16px;}

.tm-booking-row{
  background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow);
  padding:20px 22px;display:flex;justify-content:space-between;align-items:flex-start;gap:16px;}
.tm-booking-row-item{font-family:var(--display);font-weight:600;font-size:20px;color:var(--ink);margin:0 0 6px;}
.tm-booking-row-item a{color:inherit;text-decoration:none;}
.tm-booking-row-item a:hover{text-decoration:underline;}
.tm-booking-row-meta{font-family:var(--mono);font-size:14px;color:var(--charcoal-70);margin-top:2px;}
.tm-booking-row-right{display:flex;flex-direction:column;align-items:flex-end;gap:8px;flex:0 0 auto;}
.tm-booking-row-amount{font-family:var(--mono);font-size:20px;color:var(--charcoal);}
.tm-booking-row-amount--unpaid{color:var(--signal);}
.tm-booking-row-unpaid{font-family:var(--sans);font-weight:600;font-size:12px;letter-spacing:.04em;text-transform:uppercase;color:var(--signal);margin-top:-4px;}
.tm-booking-row-cta{
  font-family:var(--sans);font-weight:600;font-size:14px;border:1px solid var(--line-strong);
  border-radius:var(--r);background:transparent;color:var(--charcoal);padding:8px 16px;
  cursor:pointer;text-decoration:none;}
@media (max-width:768px){
  .tm-booking-row{flex-direction:column;}
  .tm-booking-row-right{align-items:flex-start;width:100%;}
}

/* Quick task 260807-lxm: a wrapping peer-action row for the booking-detail
   page's Documents and Actions panels. NOT a reuse of .tm-checkout-cta-row
   above -- that class is a two-button primary/ghost checkout pair with a
   26px lead-in and no flex-wrap, which overflows once a panel holds three
   or four peer actions (Download invoice / Download hire schedule /
   Download safety information / Resend confirmation, or Reschedule /
   Extend hire / Cancel booking) on a narrow viewport. Do not modify
   .tm-checkout-cta-row/.tm-checkout-btn-ghost/.tm-booking-row-cta below --
   all three are shared with checkout and the booking-history list. */
.tm-action-group{display:flex;flex-wrap:wrap;gap:12px;margin-top:10px;}

.tm-account-empty{text-align:center;padding:48px 24px;color:var(--charcoal-70);}
.tm-account-empty h2{font-family:var(--display);font-weight:600;font-size:20px;color:var(--ink);margin:0 0 8px;}
.tm-account-empty p{font-size:16px;margin:0 0 16px;}
.tm-account-empty a{color:var(--signal);text-decoration:none;font-weight:600;}

/* Plan 34-01 (TRUST-01, D-01) — Profile tab. .tm-account-signout is a
   customer-side twin of .tm-admin-signout (byte-equivalent declaration) --
   the admin class lives in the admin-only chrome section above and must not
   be reused across the app/admin boundary. */
.tm-account-signout{
  background:transparent;border:1px solid var(--line-strong);border-radius:var(--r);
  padding:8px 16px;font-family:var(--sans);font-size:14px;font-weight:600;color:var(--charcoal);cursor:pointer;}
.tm-account-signout:disabled{opacity:.6;cursor:default;}

/* .tm-account-save-status mirrors .tm-admin-catalog-save-status's shape,
   but --error maps to --destructive instead of --signal (UX-04: --signal
   is reserved exclusively for customer booking-flow forward-progress CTAs,
   so an account-management error state may not use it). */
.tm-account-save-status{font-family:var(--sans);font-size:13px;margin-left:10px;}
.tm-account-save-status--saved{color:var(--go);}
.tm-account-save-status--error{color:var(--destructive);}

/* ============ CUSTOMER APP — CANCELLATION (plan 03-03, BOOK-07) ============
   Destructive confirmation panel + button — the FIRST rendered use of the
   --destructive/--destructive-soft tokens (declared Phase 1). Reserved
   exhaustively for this panel + .tm-btn-destructive + .tm-pill--destructive
   per 03-UI-SPEC.md — never used for reschedule/extension. Mirrors
   .tm-checkout-banner/.tm-cal-error's dashed-callout visual language,
   recolored from --signal to --destructive. */
.tm-destructive-panel{
  border:1.5px dashed var(--destructive);border-radius:var(--r-lg);background:var(--destructive-soft);
  padding:20px;margin-top:10px;}
.tm-destructive-panel h3{font-family:var(--display);font-weight:600;font-size:20px;color:var(--destructive);margin:0 0 8px;}
.tm-destructive-panel p{font-family:var(--sans);font-size:16px;color:var(--charcoal);margin:0 0 16px;line-height:1.5;}

.tm-btn-destructive{
  flex:1;font-family:var(--sans);font-weight:600;font-size:16px;border:none;border-radius:var(--r);
  background:var(--destructive);color:#fff;padding:12px 16px;cursor:pointer;}
.tm-btn-destructive:disabled{opacity:.5;cursor:default;}

/* ============ CUSTOMER APP — INCIDENT REPORTING (plan 03-06, INC-01..05) ===
   Type chooser reuses .tm-block-row/.tm-block-btn verbatim (no new rules
   needed there). Multi-photo dropzone extends .tm-checkout-photo-drop/
   -preview (unchanged above) with a thumbnail GRID for 2+ photos — the
   dropzone itself stays visible/re-clickable beneath the grid (03-UI-SPEC
   "Multi-photo upload"). Submit report is charcoal-solid (.tm-checkout-
   btn-solid, NOT signal — informational submission, matches
   .tm-admin-btn-solid's treatment of non-payment form submissions but
   sized/laid out like .tm-checkout-btn-signal so it sits naturally in a
   .tm-checkout-cta-row next to a ghost Back button). */
.tm-checkout-photo-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:8px;margin-bottom:12px;}
.tm-checkout-photo-thumb{
  position:relative;border-radius:var(--r);overflow:hidden;border:1px solid var(--line);
  aspect-ratio:1/1;background:var(--bone);}
.tm-checkout-photo-thumb img{width:100%;height:100%;object-fit:cover;display:block;}
.tm-checkout-photo-thumb-status{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;
  background:rgba(46,42,37,.55);color:#fff;font-family:var(--mono);font-size:11px;padding:4px;}

.tm-checkout-btn-solid{
  flex:1;font-family:var(--sans);font-weight:600;font-size:16px;border:none;border-radius:var(--r);
  background:var(--charcoal);color:var(--oat);padding:12px 16px;cursor:pointer;}
.tm-checkout-btn-solid:disabled{opacity:.5;cursor:default;}

.tm-report-list{display:flex;flex-direction:column;gap:16px;margin-top:10px;}
.tm-report-row{border-top:1px solid var(--line);padding-top:14px;}
.tm-report-row:first-child{border-top:none;padding-top:0;}
.tm-report-row-header{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:6px;}
.tm-report-row-type{font-family:var(--sans);font-weight:600;font-size:14px;color:var(--charcoal);}
.tm-report-row-time{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);}
.tm-report-row-desc{font-family:var(--sans);font-size:14px;color:var(--charcoal-70);margin:0 0 8px;line-height:1.5;}

/* Phase 60 (TODAY-03 success criterion 5) — Field-mode "Today's runs" card,
   sized for daylight/one-handed on-site use (44px+ tap targets, larger
   type than Desk's .tm-report-row), matching the field-tab-bar's own
   44px-minimum convention above. */
.tm-field-run-card{border:1px solid var(--line);border-radius:var(--r);padding:16px;}
.tm-field-run-card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;}
.tm-field-run-card-action{font-family:var(--sans);font-weight:700;font-size:18px;color:var(--charcoal);}
.tm-field-run-card-ref{font-family:var(--mono);font-size:15px;color:var(--charcoal-70);min-height:44px;display:flex;align-items:center;}
.tm-field-run-card-customer{font-family:var(--sans);font-weight:600;font-size:17px;color:var(--charcoal);margin:0 0 4px;}
.tm-field-run-card-item{font-family:var(--sans);font-size:15px;color:var(--charcoal-70);margin:0 0 12px;line-height:1.4;}
.tm-field-run-card-contact{display:flex;flex-direction:column;gap:8px;}
.tm-field-run-card-phone{font-family:var(--sans);font-weight:600;font-size:17px;color:var(--charcoal);min-height:44px;display:flex;align-items:center;text-decoration:underline;}
.tm-field-run-card-address{font-family:var(--sans);font-size:15px;color:var(--charcoal-70);line-height:1.4;}

/* Phase 78 (TRAVEL-01/TRAVEL-02) — Field leave-by line, 78-UI-SPEC.md
   §Surface-by-Surface Layout Contract §2. Normal state reuses
   .tm-field-run-card-action's exact declaration plus a 6px bottom margin
   (matches the header row's own margin-bottom, an intentional carry-
   forward per 78-UI-SPEC.md Spacing Scale exception). */
.tm-field-run-card-leaveby{font-family:var(--sans);font-weight:700;font-size:18px;color:var(--charcoal);margin:0 0 6px;}
/* Overdue — same size/weight, recolored to --signal, "LEAVE NOW" uppercase
   copy: recolor + case change, never a shrink (D-02). */
.tm-field-run-card-leaveby--overdue{font-family:var(--sans);font-weight:700;font-size:18px;color:var(--signal);}
/* Calculating — down-styled to .tm-field-run-card-item's exact declaration. */
.tm-field-run-card-leaveby--calculating{font-family:var(--sans);font-size:15px;color:var(--charcoal-70);}
/* Unavailable — same 15px/400 size as Calculating, recolored to --signal. */
.tm-field-run-card-leaveby--unavailable{font-family:var(--sans);font-size:15px;color:var(--signal);}

/* Phase 79 plan 79-01 Task 2 (FUELCOST-01) — Field fuel-cost line, matching
   .tm-today-run-card-fuel's Desk treatment but sized to this card's own
   15px leave-by scale (79-UI-SPEC.md Typography: 13px is the Desk figure;
   Field keeps its own existing type scale, unchanged by this addition). */
.tm-field-run-card-fuel{font-family:var(--sans);font-size:15px;color:var(--charcoal);margin:0 0 6px;}
.tm-field-run-card-fuel .tm-figure{font-family:var(--mono);}
.tm-field-run-card-fuel--calculating{font-family:var(--sans);font-size:15px;color:var(--charcoal-70);}
.tm-field-run-card-fuel--unavailable{font-family:var(--sans);font-size:15px;color:var(--signal);}
.tm-field-run-card-fuel--unavailable .tm-figure{font-family:var(--mono);}
.tm-field-run-card-detour{font-family:var(--sans);font-size:13px;color:var(--charcoal);margin:6px 0 0;}
.tm-field-run-card-detour .tm-figure{font-family:var(--mono);}

/* Phase 67 (TODAY-01) — Desk-mode "Today's Deliveries & Pickups" run-board
   card, replacing the plain divider-row .tm-report-row for THIS section
   only (every other Today section keeps .tm-report-row unchanged — see
   Handover 02's "run board" vs "waiting on a decision" distinction).
   Border-left colour distinguishes Deliver (--charcoal, matches the
   mockup's two Deliver-leg examples) from Collect (--stone, matches its
   one Collect-leg example) at a glance in a vertical stack, same intent
   as the mockup's horizontal card grid without introducing a second grid
   layout into the shared section-block container every other section
   also renders through. */
.tm-today-run-card{
  background:#fff;border:1px solid var(--line);border-left:4px solid var(--charcoal);
  border-radius:var(--r-admin-panel);padding:14px 16px;margin-bottom:10px;}
.tm-today-run-card--deliver{border-left-color:var(--charcoal);}
.tm-today-run-card--collect{border-left-color:var(--stone);}
.tm-today-run-card-header{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:6px;}
.tm-today-run-card-item{font-family:var(--display);font-weight:600;font-size:15px;color:var(--ink);margin:0 0 3px;}
.tm-today-run-card-customer{font-family:var(--sans);font-size:12.5px;color:var(--charcoal-70);margin:0 0 6px;}
.tm-today-run-card-call{font-family:var(--mono);font-size:12px;color:var(--charcoal);text-decoration:underline;}

/* Phase 78 (TRAVEL-01/TRAVEL-02) — Desk leave-by line, 78-UI-SPEC.md
   §Surface-by-Surface Layout Contract §1. Normal state reuses
   .tm-report-row-type's exact declaration; margin:0 0 6px matches
   .tm-today-run-card-header's existing margin-bottom (verified pre-
   existing non-8pt value, carried forward, not a new spacing token). */
.tm-today-run-card-leaveby{font-family:var(--sans);font-weight:600;font-size:14px;color:var(--charcoal);margin:0 0 6px;}
/* Calculating — reuses .tm-report-row-time's exact declaration. */
.tm-today-run-card-leaveby--calculating{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);}
/* Unavailable — same 12px/400 size as Calculating, recolored to --signal
   only (a data-availability problem, not a destructive-action
   confirmation, so the destructive-reserved token is never used here). */
.tm-today-run-card-leaveby--unavailable{font-family:var(--mono);font-size:12px;color:var(--signal);}

/* Phase 79 plan 79-01 (FUELCOST-01) — Desk fuel-cost line, 79-UI-SPEC.md
   Typography ("Fuel-cost / equipment-price leg line (NEW): 13px, 400,
   Space Mono via .tm-figure"). margin-top 6px matches this card's existing
   internal 6px line rhythm (79-UI-SPEC.md Spacing Scale's documented
   off-scale exception) — margin-bottom 0 so the very next line (item-name,
   which already carries its own margin) owns the following gap. */
.tm-today-run-card-fuel{font-family:var(--sans);font-size:13px;color:var(--charcoal);margin:6px 0 0;}
.tm-today-run-card-fuel .tm-figure{font-family:var(--mono);}
/* Calculating — mono/muted, matching .tm-today-run-card-leaveby--calculating's
   treatment (this line reads from the SAME cached row/state machine). */
.tm-today-run-card-fuel--calculating{font-family:var(--mono);font-size:12px;color:var(--charcoal-45);}
/* Unavailable — signal-tinted, matching .tm-today-run-card-leaveby--unavailable's
   treatment (a data-availability problem, never the destructive token). */
.tm-today-run-card-fuel--unavailable{font-family:var(--sans);font-size:13px;color:var(--signal);}
.tm-today-run-card-fuel--unavailable .tm-figure{font-family:var(--mono);}
.tm-today-run-card-detour{font-family:var(--sans);font-size:13px;color:var(--charcoal);margin:6px 0 0;}
.tm-today-run-card-detour .tm-figure{font-family:var(--mono);}

/* Phase 79 plan 79-04 (FUELCOST-02) — the Today/Tomorrow daily rollup
   strip, 79-UI-SPEC.md §Layout & Placement item 1. Echoes
   .tm-dashboard-counts/.tm-dashboard-count-tile/.tm-dashboard-count-figure
   under NEW selector names (this block is scoped to /today, not
   /dashboard's own layout context) — ONE deliberate delta from that
   verbatim reuse: gap is the standard 8-point `sm` step (8px), not
   .tm-dashboard-counts's own 10px, per 79-UI-SPEC.md's Spacing Scale. */
.tm-today-rollup{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:16px 0 32px;}
.tm-today-rollup-tile{background:#fff;border:1px solid var(--line);border-radius:var(--r-admin-panel);padding:11px 13px;}
/* 23px — matches .tm-dashboard-count-figure's existing display-figure size. */
.tm-today-rollup-figure{font-size:23px;display:block;margin-top:4px;}
/* 11px "remaining" sub-line, muted, stacked directly beneath the large
   figure (D-10 — two stacked figures, never a toggle, never side-by-side). */
.tm-today-rollup-sub{font-size:11px;color:var(--charcoal-70);margin-top:2px;}

/* Phase 79 plan 79-05 (MAP-01, ROADMAP success criteria 3/4,
   79-UI-SPEC.md §Map Container) — the small read-only stops map at the
   top of /today, directly beneath the rollup strip and above the first
   section block. Canvas height/border/radius modelled on
   .tm-dashboard-card-map/.tm-dashboard-map-empty's own existing chrome
   (see that block's comment) — 220px on desktop, 180px at/below this
   codebase's existing 768px breakpoint, per 79-UI-SPEC.md's own Map
   Container table (larger than the per-card 152px dashboard map: this is
   the ONE full-width map at the top of the page, plotting potentially
   many stops, not one of several small per-card embeds). */
.tm-today-map{margin-bottom:32px;}
.tm-today-map-canvas{height:220px;border:1px solid var(--line);border-radius:var(--r-admin-panel);overflow:hidden;}
.tm-today-map-empty,.tm-today-map-unavailable{height:220px;display:flex;align-items:center;justify-content:center;text-align:center;padding:0 16px;border:1px solid var(--line);border-radius:var(--r-admin-panel);background:var(--bone);}
.tm-today-map-empty p,.tm-today-map-unavailable p{font-family:var(--sans);font-size:12px;color:var(--charcoal-70);margin:0;max-width:240px;}
@media (max-width:768px){
  .tm-today-map-canvas{height:180px;}
  .tm-today-map-empty,.tm-today-map-unavailable{height:180px;}
}

/* InfoWindow content (D-09 — click a pin → booking info), 79-UI-SPEC.md
   §InfoWindow: sans base with .tm-figure spans for the mono elements
   (booking ref, slot label) — no new colors. The 240px max-width and the
   customer-name line's anywhere overflow-wrap are set as INLINE styles
   by info-window-node itself (so the no-DOM test suite can assert on
   them directly), not here — these selectors are typography/layout only. */
.tm-today-infowindow{font-family:var(--sans);}
.tm-today-infowindow-header{display:flex;justify-content:space-between;align-items:baseline;gap:8px;font-weight:600;font-size:12px;}
.tm-today-infowindow-customer{font-size:13px;color:var(--charcoal);margin-top:4px;}
.tm-today-infowindow-slot{font-size:12px;color:var(--charcoal-70);margin-top:4px;}

/* Phase 61 (FIELDUX-01) — Field-mode restyle of the Handover/Off-hire
   checklists (handover.cljs/off_hire.cljs). Presentation-only: every rule
   below is scoped under .tm-field-checklist (applied to the view's root
   only when the shell is in Field mode) and overrides ONLY size/spacing/
   grouping of the SAME existing .tm-admin-field/.tm-checkout-terms-check/
   .tm-admin-input/.tm-block-btn/.tm-admin-btn-solid classes both files
   already used pre-Phase-61 — no new markup structure, no changed data
   binding, so it cannot touch any computed figure or gate. Desk (no
   .tm-field-checklist class present) is completely unaffected. */
.tm-field-checklist{font-size:14.5px;}
/* Grouped cards — each existing .tm-admin-field section becomes a
   bordered, padded card instead of a bare margin-bottom block. */
.tm-field-checklist .tm-admin-field{
  border:1px solid var(--line);border-radius:var(--r-admin-panel);padding:16px;margin:0 0 12px;}
.tm-field-checklist .tm-admin-required-checklist{
  border:1px solid var(--line);border-radius:var(--r-admin-panel);padding:16px;margin:0 0 12px;}
.tm-field-checklist .tm-admin-required-checklist .tm-admin-field{
  border:none;padding:0;margin:0 0 16px;}
.tm-field-checklist .tm-admin-required-checklist .tm-admin-field:last-child{margin:0;}
/* Phase 68 (FIELDUI-01): the group-header row that pairs group-heading-style's
   h4 with a mono ticked-count badge — the extra span/div only ever renders
   when field? is true (guarded in handover.cljs), so Desk's hiccup shape
   (a bare h4) is completely unchanged, same discipline Phase 61 established. */
.tm-field-checklist .tm-field-checklist-group-header{
  display:flex;justify-content:space-between;align-items:center;margin:0 0 8px;}
.tm-field-checklist .tm-field-checklist-group-header h4{margin:0;}
.tm-field-checklist-group-count{font-size:12px;}
.tm-field-checklist-aggregate-count{font-size:12px;margin-left:8px;}
/* 51px checklist rows, 44px minimum on every other interactive control —
   no hover-only affordance, all sizing is structural (padding/min-height/
   background-on-checked), not a :hover-revealed state. Matches Handover
   04's .k-panel row spec: 5px inset-row radius (brief §6 Geometry), a
   27px checkbox (was 22px), and --go-soft fill when ticked so a completed
   row reads as "done" without needing to read the label text. */
.tm-field-checklist .tm-checkout-terms-check{
  min-height:51px;align-items:center;font-size:14.5px;gap:13px;
  padding:12px 13px;border-radius:5px;border:1px solid var(--line);}
.tm-field-checklist .tm-checkout-terms-check:has(input:checked){
  background:var(--go-soft);border-color:transparent;}
.tm-field-checklist .tm-checkout-terms-check input[type="checkbox"]{
  width:27px;height:27px;flex:none;accent-color:var(--go);}
.tm-field-checklist .tm-admin-input,
.tm-field-checklist textarea.tm-admin-input{
  min-height:44px;font-size:16px;}
.tm-field-checklist .tm-admin-btn-solid,
.tm-field-checklist .tm-block-btn,
.tm-field-checklist .tm-admin-catalog-edit-link,
.tm-field-checklist .tm-admin-catalog-add,
.tm-field-checklist .tm-admin-catalog-remove{
  min-height:44px;font-size:15px;}
.tm-field-checklist .tm-admin-catalog-edit-link,
.tm-field-checklist .tm-admin-catalog-add,
.tm-field-checklist .tm-admin-catalog-remove{
  display:inline-flex;align-items:center;}
.tm-field-checklist p,
.tm-field-checklist .tm-admin-config-hint,
.tm-field-checklist li{font-size:14.5px;line-height:1.5;}
/* Mono hour-meter/money entry, centred, 25px — .tm-field-mono-input is
   added directly on the relevant <input> in handover.cljs/off_hire.cljs
   (hour-meter, repair cost, policy excess, engine/waiver overrides). */
.tm-field-checklist .tm-field-mono-input{
  font-family:var(--mono);font-size:25px;text-align:center;}
/* Blocker sentence beside the control it blocks (§9 Blocked-actions
   pattern) — gate-hint helpers in both files render this class.
   Phase 71 (PATTERN-02) token fix: ADMIN-REDESIGN.md §6's colour table
   assigns "an incomplete-but-required checklist group, the 'still
   needed' finalize blocker" to --signal, not --destructive -- destructive
   is reserved exhaustively for Cancel/Delete/Void/Refund/Charge-card and
   their confirm modals (§6). Only 2 call sites (handover.cljs, off_hire.cljs
   gate-hint helpers), neither destructive in nature. */
.tm-field-gate-hint{
  margin:6px 0 0;font-family:var(--sans);font-size:14.5px;color:var(--signal);}
/* Phase 71 (PATTERN-02): Desk-mode combined "Missing: …" blocker readout
   — same shared .tm-admin-config-hint block used for ~140 unrelated
   neutral hints app-wide, so this is a MODIFIER applied only at genuine
   blocked-action call sites (handover.cljs/off_hire.cljs/manual_booking.cljs
   finalize/create blockers), never on the base class, to avoid recolouring
   every other hint in the app. Same --signal token as .tm-field-gate-hint
   above, for the identical "still needed" meaning per §6. */
.tm-admin-config-hint--blocker{color:var(--signal);}
/* Phase 83 (D-09): the cannot-say due state reads in words, never as a
   graded status colour — this is a MODIFIER on .tm-admin-config-hint,
   never applied to the base class. */
.tm-admin-config-hint--italic{font-style:italic;}
/* Sticky action footer for the primary Finalize/Reopen button — sits
   above the fixed Field bottom tab bar (--field-tabbar-total-h, which
   includes the safe-area inset per quick task 260828-bgc), matching the
   existing .tm-admin-catalog-actions sticky-footer convention above. */
.tm-field-checklist .tm-field-sticky-footer{
  position:sticky;bottom:var(--field-tabbar-total-h);z-index:5;
  background:var(--bone);border-top:1px solid var(--line);
  border-radius:0;margin:16px -16px 0;padding:14px 16px;}

/* ============ Phase 4 additions (plan 04-04, HAND-01/HAND-02/HAND-05) ============
   Handover Checklist fill-out view (timech.admin.handover). Reuses every
   existing token/component this file already declares — no new hex
   values. tm-admin-handover is a plain page-shell wrapper matching
   .tm-admin-manual-booking/.tm-admin-catalog's own max-width/padding
   rhythm. The numeric meter/fuel unit-row and the condition photo grid
   are this plan's two genuinely new component shapes (per 04-UI-SPEC.md
   "New Interaction Components"). */
.tm-admin-handover{max-width:640px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-handover h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 16px;}

/* Numeric meter/fuel reading input — plain .tm-admin-input plus a
   trailing inline mono unit label (e.g. "L", "hrs"), per 04-UI-SPEC.md. */
.tm-admin-input-unit-row{display:flex;align-items:center;gap:8px;}
.tm-admin-input-unit-row .tm-admin-input{margin:0;flex:1;}

/* Condition photo grid (multi-photo capture, HAND-01/HAND-05) — extends
   the existing single-slot .tm-checkout-photo-drop/-preview pair into a
   repeatable grid. Exact measurements per 04-UI-SPEC.md: 140px square
   cells, repeat(auto-fill,minmax(140px,1fr)), 16px (md) gap, 24px remove
   glyph with a 44px tap-target exception, 16px add-tile padding (a
   density reduction from the single-slot's 32px, called out explicitly
   in 04-UI-SPEC.md's Spacing Scale exceptions). */
.tm-handover-photo-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:16px;margin-top:8px;}
.tm-handover-photo-tile{
  position:relative;width:140px;height:140px;border-radius:var(--r-admin-panel);overflow:hidden;
  border:1px solid var(--line);background:var(--bone);}
.tm-handover-photo-tile img{width:100%;height:100%;object-fit:cover;display:block;}
.tm-handover-photo-placeholder{
  width:100%;height:100%;display:flex;align-items:center;justify-content:center;
  font-size:28px;color:var(--charcoal-45);}
.tm-handover-photo-remove{
  position:absolute;top:0;right:0;width:44px;height:44px;
  display:flex;align-items:center;justify-content:center;
  background:transparent;border:none;padding:0;cursor:pointer;}
.tm-handover-photo-remove span{
  width:24px;height:24px;border-radius:100px;background:rgba(22,20,15,.55);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:16px;line-height:1;}
.tm-handover-photo-add{
  width:140px;height:140px;border-radius:var(--r-admin-panel);border:1.5px dashed var(--line-strong);
  background:var(--bone);display:flex;align-items:center;justify-content:center;
  text-align:center;padding:16px;cursor:pointer;
  font-family:var(--sans);font-weight:600;font-size:14px;color:var(--charcoal);}

/* Pre/post-hire photo comparison panel (quick task 260808-l4b) —
   supersedes plan 33-04's D-12 layout. Two-up before/after pair rows
   hold at EVERY width, deliberately with no media-query collapse: this
   screen is used one-handed on a phone, and before/after adjacency on
   that exact device is the entire point of the change. Each pair cell
   wraps condition-photo-cell's own .tm-handover-photo-tile markup
   unmodified but shrinks its fixed 140px square to fit via width:100%
   + aspect-ratio, so two cells plus the row gap fit a ~375px viewport
   while the existing object-fit:cover image rule still applies
   unchanged. No new hex values — reuses this file's existing tokens. */
.tm-photo-pair-heading{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px;}
.tm-photo-pair-heading h3{margin:0;font-family:var(--display);font-weight:600;font-size:16px;color:var(--ink);}
.tm-photo-pair{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:12px;align-items:start;}
.tm-photo-pair-cell{width:100%;}
.tm-photo-pair-cell .tm-handover-photo-tile{width:100%;height:auto;aspect-ratio:1/1;}
/* comparison-photo-cell renders an interactive tile as a real <button>
   (never a bare div+on-click) when its photo has a resolved URL — this
   resets the button chrome so it reads identically to the plain-div
   case above. */
button.tm-photo-pair-cell{display:block;border:none;background:none;padding:0;margin:0;cursor:pointer;text-align:left;font:inherit;}
.tm-photo-pair-cell-empty{
  width:100%;aspect-ratio:1/1;border-radius:var(--r-admin-panel);border:1px dashed var(--line-strong);
  background:var(--bone);display:flex;align-items:center;justify-content:center;text-align:center;padding:8px;}
.tm-photo-pair-cell-empty p{margin:0;font-size:13px;color:var(--charcoal-45);}

/* Comparison-photo full-screen lightbox (260808-l4b). Scrim reuses the
   EXACT rgba tokens .tm-charge-modal-overlay/.tm-handover-photo-remove
   already declare — no new hex/rgba values. z-index sits above the
   charge modal overlay's 30, so a lightbox opened over a confirm modal
   is never hidden behind it. The close control mirrors
   .tm-handover-photo-remove's own 44px-touch-target/24px-glyph pattern. */
.tm-photo-lightbox-overlay{
  position:fixed;inset:0;background:rgba(22,20,15,.45);
  display:flex;align-items:center;justify-content:center;z-index:40;padding:24px;}
.tm-photo-lightbox-image{max-width:100%;max-height:100%;object-fit:contain;border-radius:var(--r-admin-panel);display:block;}
.tm-photo-lightbox-close{
  position:absolute;top:16px;right:16px;width:44px;height:44px;
  display:flex;align-items:center;justify-content:center;
  background:transparent;border:none;padding:0;cursor:pointer;}
.tm-photo-lightbox-close span{
  width:24px;height:24px;border-radius:100px;background:rgba(22,20,15,.55);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:16px;line-height:1;}

/* ============ Phase 4 additions (plan 04-06, HAND-03/BOOK-08) ============
   Off-Hire Checklist + early off-hire refund confirm panel. Reuses every
   existing token this file already declares — no new hex values. Two
   small modifier classes close two typographic gaps 04-UI-SPEC.md's
   Numeric Convention/Typography sections call for that the generic
   .tm-price-row-value/.tm-price-total classes don't already cover:
   Heading-size (20px) mono for computed line-item values (Waiver Excess/
   engine-hours excess/refund), and Display-size (32px, Space Mono
   Emphasis 700) mono for the amounts-to-invoice screen total — the ONLY
   Display-size figure on this screen, per the typography contract. */
.tm-price-row-value--heading{font-family:var(--mono);font-size:20px;color:var(--charcoal);}
.tm-price-total--display span:last-child{font-family:var(--mono);font-weight:700;font-size:32px;}

/* Early off-hire refund confirm panel — a plain white card, same chrome
   family as .tm-checkout-terms-panel/.tm-checkout-summary-rail, reusing
   existing tokens only (no new hex values). */
.tm-admin-offhire-panel{
  background:#fff;border:1px solid var(--line);border-radius:var(--r-admin-panel);
  padding:20px;margin:16px 0;box-shadow:var(--shadow);}
.tm-admin-offhire-panel h3{font-family:var(--display);font-weight:600;font-size:15px;color:var(--ink);margin:0 0 8px;}

/* ============ Phase 4 additions (plan 04-08, ADM-01) ============
   Unified Schedule view — Timeline (hand-rolled CSS grid) + List (reuses
   .tm-admin-config-table verbatim) + detail drawer. Every new state
   (booking block, blackout, today marker, open-incident-report badge)
   is expressed with existing tokens only — no new hex values. The
   40px date-column / 64px item-row / 88px mobile name-column measured
   values are layout-specific (04-UI-SPEC.md's spacing-exception note),
   not part of the spacing scale. */
.tm-admin-schedule{max-width:1080px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-schedule h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 16px;}
.tm-admin-schedule .tm-tabs{margin-top:0;margin-bottom:20px;}

/* Schedule Timeline — a hand-rolled CSS grid: a sticky left item-name
   column (--schedule-name-col, 160px desktop / 88px <768px per the
   responsive breakpoint) + one 40px column per day, horizontally
   scrollable; one 64px row per fleet item. */
.tm-schedule-timeline{
  --schedule-name-col:160px;
  overflow-x:auto;position:relative;border:1px solid var(--line);border-radius:var(--r-admin-panel);
  background:#fff;padding:8px;}
@media (max-width:768px){ .tm-schedule-timeline{ --schedule-name-col:88px; } }
.tm-schedule-row-label{
  position:sticky;left:0;z-index:2;background:#fff;display:flex;align-items:center;
  padding:0 12px;font-family:var(--sans);font-weight:600;font-size:13px;color:var(--charcoal);
  border-bottom:1px solid var(--line);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.tm-schedule-timeline-date{
  display:flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:11px;color:var(--charcoal-45);border-bottom:1px solid var(--line);}
.tm-schedule-block{
  position:relative;background:var(--charcoal);color:var(--oat);border-radius:var(--r);
  margin:4px 2px;padding:4px 8px;font-family:var(--sans);font-size:12px;font-weight:600;
  cursor:pointer;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
  display:flex;align-items:center;}
.tm-schedule-block--pending{border:1.5px dashed var(--line-strong);}
/* Phase 54 (plan 54-07): a 40px day column has no room for a status
   word, so the Timeline signals an unaccepted offer with a dashed
   --signal border (same weight/dash treatment as --pending above,
   differing only in colour) while the List uses a text pill instead. */
.tm-schedule-block--offer{border:1.5px dashed var(--signal);}
.tm-schedule-blackout{border-radius:var(--r);margin:4px 2px;}
.tm-schedule-today{background:var(--charcoal);width:2px;pointer-events:none;}
/* Weekend-column highlighting (ADM-10, first pass, 15-UI-SPEC.md) — --oat
   is already declared ("secondary·paper"); this is its first Timeline
   use, no new hex value. Header modifier + a parallel full-height tint
   element (positioned like .tm-schedule-today, but filling the whole
   40px column instead of a 2px line) together read as one continuous
   Sat/Sun column tint. Z-order is controlled by DOM render order
   (schedule.cljs), not by these rules. */
.tm-schedule-timeline-date--weekend{background:var(--oat);}
.tm-schedule-weekend-tint{background:var(--oat);pointer-events:none;}
.tm-schedule-badge{
  position:absolute;top:2px;right:2px;width:6px;height:6px;border-radius:100px;background:var(--signal);}

/* Schedule List — filter row (status-pill filters + search) above the
   existing .tm-admin-config-table. */
.tm-schedule-filter-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:0 0 16px;}
.tm-schedule-filter-row .tm-pill{cursor:pointer;}
.tm-th-sort{background:none;border:none;padding:0;font:inherit;letter-spacing:inherit;text-transform:inherit;color:inherit;cursor:pointer;}

/* Schedule context panel (Phase 60, RECORD-frame criterion 2) — replaces
   the old .tm-schedule-drawer fixed-overlay slide-over with an IN-FLOW
   panel below the Timeline/List, so the timeline stays visible/scrollable
   above it (a booking can be acted on "without leaving the timeline").
   Reuses the SAME white-panel box-shadow chrome family as
   .tm-checkout-summary-rail/.tm-admin-offhire-panel. */
.tm-schedule-context-panel{
  /* Phase 67 (TODAY-02): --r (4px, control-scale) -> --r-admin-panel (6px,
     panel-scale per ADMIN-REDESIGN.md §6 Geometry) -- this is a panel, not
     a control. */
  margin-top:20px;border-radius:var(--r-admin-panel);background:#fff;box-shadow:var(--shadow-lg);
  padding:24px;max-width:480px;}
.tm-schedule-context-panel h3{font-family:var(--display);font-weight:600;font-size:20px;color:var(--ink);margin:0 0 8px;}
.tm-schedule-drawer-actions{display:flex;flex-direction:column;gap:8px;margin:16px 0;}

/* ============ Phase 4 additions (plan 04-09, ADM-02/D-05/D-06) ============
   Off-session charge management (timech.admin.off-session-charge) + the
   account-deletion confirm entry point in the schedule drawer
   (timech.admin.schedule). This is the phase's — and the whole app's —
   FIRST active use of the --destructive token declared above: EXCLUSIVELY
   the "Charge card"/confirm-modal pair and the "Delete account"/confirm-
   modal pair, plus the drawer's "Delete customer account…" trigger LINK
   (Destructive-colored TEXT, per 04-UI-SPEC.md's own Task 3 action text)
   and the "Charge failed" outcome's text/border (per the Off-session
   charge status & gating section — text/border only, never a background).
   No other selector in this file uses --destructive. */
.tm-admin-charges{max-width:720px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-charges h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 16px;}

/* One charge's panel — same white-card chrome family as
   .tm-admin-offhire-panel/.tm-checkout-summary-rail. */
.tm-charge-card{
  background:#fff;border:1px solid var(--line);border-radius:var(--r-admin-panel);
  padding:20px;margin:0 0 24px;box-shadow:var(--shadow);}
.tm-charge-card h3{font-family:var(--display);font-weight:600;font-size:15px;color:var(--ink);margin:0 0 8px;}

/* Phase 44 plan 44-01 Task 3 (CHG-01): the charge-type choice row (two
   .tm-charge-card children -- "Add in-hire charge" / "Add post-hire
   charge"). Same gap idiom as .tm-charge-modal-actions/.tm-admin-blackout-
   scope; flex-basis ~260px on each child collapses the pair to a single
   column under a narrow admin viewport with no new breakpoint token. No
   new colors, radii, shadows, or font rules -- both children keep
   .tm-charge-card's own chrome verbatim. */
.tm-charge-type-row{display:flex;gap:16px;flex-wrap:wrap;}
.tm-charge-type-row .tm-charge-card{flex:1 1 260px;margin:0;}

/* Phase 66 (RECORD-01/RECORD-02): the booking record's persistent header —
   Handover 03's "the header is persistent across tabs and carries the
   four things you always need: ref and status, customer and address,
   item and hire period, outstanding balance. It does not re-fetch on tab
   change." Mounted once in booking_record.cljs's `view`, above the tab
   bar, reading the SAME already-loaded `::booking-detail/detail` every
   tab body uses — no new fetch. */
.tm-admin-record-header{
  display:flex;flex-wrap:wrap;align-items:flex-start;gap:20px;
  padding:16px 0 14px;border-bottom:1px solid var(--line);margin-bottom:16px;}
.tm-admin-record-header-main{flex:1 1 260px;min-width:220px;}
.tm-admin-record-header-main h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0;display:inline;}
.tm-admin-record-header-sub{font-size:13px;color:var(--charcoal-70);margin-top:4px;}
.tm-admin-record-header-field{text-align:right;padding-left:18px;border-left:1px solid var(--line);}
.tm-admin-record-header-field .tm-label{display:block;margin-bottom:4px;}
.tm-admin-record-header-field .tm-figure{font-size:13px;}
.tm-admin-record-header-outstanding .tm-figure{font-size:21px;}
.tm-admin-record-header-outstanding.tm-admin-record-header-field--zero .tm-figure{color:var(--charcoal);}

/* Phase 66 (RECORD-02), extended by quick task 260908-u2a: the lifecycle
   strip — five connected steps (created -> paid -> handover -> off-hire ->
   settled), derived PER-STEP from `lifecycle-step-statuses` in
   booking_record.cljs — each step answers its own done/overdue/in-
   flight/not-yet-reached question against its own booking facts, not an
   index comparison against one furthest-reached state, so (for example)
   Paid can be green while Handover is red at the same time. Four tones:
   --go = done, --signal = current (in progress), --destructive = overdue
   (an issue — the SAME admin-error precedent the comment at ~910 above
   establishes: errors use --destructive, never --signal), muted outline
   with no dot modifier class = pending (not yet reached). Connecting
   lines pick up the tone of the step they lead FROM — green once done,
   red once overdue, muted otherwise. */
.tm-record-lifecycle{display:flex;align-items:flex-start;padding:6px 4px;}
.tm-record-lifecycle-step{flex:1;text-align:center;min-width:0;}
.tm-record-lifecycle-dot{
  width:26px;height:26px;border-radius:100px;margin:0 auto 8px;
  background:var(--bone);border:2px solid var(--line-strong);}
.tm-record-lifecycle-dot--done{background:var(--go);border-color:var(--go);}
.tm-record-lifecycle-dot--current{background:var(--signal);border-color:var(--signal);}
.tm-record-lifecycle-dot--overdue{background:var(--destructive);border-color:var(--destructive);}
.tm-record-lifecycle-label{font-size:12.5px;font-weight:600;color:var(--charcoal-45);}
.tm-record-lifecycle-step--done .tm-record-lifecycle-label,
.tm-record-lifecycle-step--current .tm-record-lifecycle-label{color:var(--charcoal);}
.tm-record-lifecycle-step--current .tm-record-lifecycle-label{color:var(--signal);}
.tm-record-lifecycle-step--overdue .tm-record-lifecycle-label{color:var(--destructive);}
.tm-record-lifecycle-sub{font-family:var(--mono);font-size:11.5px;color:var(--charcoal-45);margin-top:2px;}
.tm-record-lifecycle-line{flex:0 0 40px;height:2px;background:var(--line);margin-top:12px;}
.tm-record-lifecycle-line--done{background:var(--go);}
.tm-record-lifecycle-line--overdue{background:var(--destructive);}

/* Quick task 260828-bgc: the record's 8-tab .tm-tabs strip (Overview,
   Handover, Off-hire, Money, Add-ons, Documents, Messages, History) has no
   wrap and no horizontal scroll in the base .tm-tabs rule above, so at a
   390px viewport it measured scrollWidth 704 against clientWidth 390 and
   dragged the WHOLE admin record page 704px wide — a document wider than
   the viewport is exactly what lets a viewport-fixed bottom bar (the Field
   tab bar below) drift off the visible bottom edge on a phone, because
   position:fixed resolves against the (now widened) layout viewport, not
   the visual one. .tm-admin-catalog .tm-tabs (further down this file) is
   the existing precedent for the identical remedy on the 5-tab Edit-item
   strip. Scoped here rather than on the base rule — six other screens
   share .tm-tabs and none of them overflow. */
.tm-admin-booking-record .tm-tabs{flex-wrap:wrap;}

/* Quick task 260828-bgc: .tm-admin-booking-record was one of two admin page
   roots with zero matching rules anywhere in this file — content inside the
   record measured flush at left:0 / right:390 on a 390px viewport before
   this rule. (The other, .tm-admin-bookings-index, gained its own container
   rule further down this file via the concurrently-landed quick task
   260828-bj9 — not duplicated here.) 1080px max-width and 48px bottom
   padding match .tm-admin-schedule / .tm-admin-booking-detail, the two
   widest existing admin wrappers, so this page joins the convention every
   other admin page already follows. The 16px side value is deliberately
   narrower than every Desk-first wrapper's 24px: this is a phone-primary
   Field screen the owner works from on site, and its content is already
   width-tight, so a wide Desk gutter would buy an edge margin at the cost
   of squeezing it. */
.tm-admin-booking-record{max-width:1080px;margin:0 auto;padding:0 16px 48px;}

/* The record's Handover/Off-hire, Add-ons/Record-payment and Money tab
   bodies mount .tm-admin-handover, .tm-admin-manual-booking and
   .tm-admin-charges respectively, each already carrying its own 24px of
   side padding — nested inside the record's new 16px gutter above that
   would double to 40px. Zero only the two side paddings; max-width,
   margin:0 auto centring and bottom padding all survive untouched. A
   future tab addition mounting a new wrapper needs to add it here too. */
.tm-admin-booking-record .tm-admin-handover,
.tm-admin-booking-record .tm-admin-manual-booking,
.tm-admin-booking-record .tm-admin-charges{padding-left:0;padding-right:0;}

/* Charge-failed callout — Destructive TEXT/BORDER only (never a
   background), per 04-UI-SPEC.md's explicit "not --signal, not --go"
   status-gating rule. */
.tm-charge-failed{
  color:var(--destructive);border:1px dashed var(--destructive);border-radius:var(--r);
  padding:8px 16px;font-family:var(--sans);font-size:14px;margin:8px 0;}
.tm-charge-retry{
  background:none;border:none;cursor:pointer;font-family:var(--sans);font-size:13px;
  color:var(--destructive);text-decoration:underline;padding:8px 0;}

/* The Destructive-filled button — the ONLY new background use of
   --destructive in this file: the "Charge card"/"Charge $amount" button
   pair and the "Delete account" confirm button (Task 3). Same
   :disabled{opacity:.5} convention every other CTA in this file already
   uses (.tm-checkout-btn-signal, .tm-admin-btn-solid). */
.tm-btn-destructive{
  font-family:var(--sans);font-weight:600;font-size:16px;border:none;border-radius:var(--r);
  background:var(--destructive);color:#fff;padding:12px 16px;cursor:pointer;}
.tm-btn-destructive:disabled{opacity:.5;cursor:default;}

/* Phase 71 (PATTERN-01): the shared confirm-modal (off_session_charge.cljs's
   `confirm-modal`) previously rendered EVERY confirm button as
   .tm-btn-destructive (filled --destructive), including plainly
   non-destructive actions -- Finalize, Reopen, Reschedule, Extend, Accept,
   Close/Convert offer, Remove-photo, Discard-changes, add-on Add/Reduce.
   ADMIN-REDESIGN.md §6/§9 + Handover 01's Buttons table are explicit that
   filled --destructive is used ONLY for the exhaustive list (Cancel,
   Delete account, Void, Archive, Reject, Charge card, Refund) and "never a
   CTA that is not itself destructive." Same size/shape/disabled convention
   as .tm-btn-destructive above, filled --charcoal (the Primary button
   colour, per Handover 01) instead. */
.tm-btn-primary-confirm{
  font-family:var(--sans);font-weight:600;font-size:16px;border:none;border-radius:var(--r);
  background:var(--charcoal);color:var(--oat);padding:12px 16px;cursor:pointer;}
.tm-btn-primary-confirm:disabled{opacity:.5;cursor:default;}

/* Shared confirm-modal chrome (Task 1's tm-charge-modal, reused verbatim
   by Task 3's account-deletion confirm — same overlay/panel/actions
   shape, per 04-UI-SPEC.md's "same white-panel chrome as the timeline
   detail drawer" note). */
.tm-charge-modal-overlay{
  position:fixed;inset:0;background:rgba(22,20,15,.45);
  display:flex;align-items:center;justify-content:center;z-index:30;padding:24px;}
/* Quick task 260921-hgx: the overlay is flex-centred with no overflow of
   its own, and until this fix the panel declared no height ceiling — so a
   panel taller than the viewport (holds.cljs's convert-offer/convert-booking
   forms, booking_offers.cljs's convert-confirm-modal, all passed through
   confirm-modal's `:extra` slot) overflowed EQUALLY past both viewport
   edges: the title unreachable above the top, the Cancel/Confirm row
   unreachable below the bottom, and nothing anywhere scrollable. The
   max-height below is derived from the overlay's own 24px top-plus-bottom
   padding (calc(100vh - 48px)) and is the universal safety net — it is
   what bounds the ONE panel that hand-rolls this markup instead of calling
   confirm-modal (timech.customer.addons/multi-site-trailer-modal), which
   never receives the --scroll-body modifier class below. */
.tm-charge-modal{
  background:#fff;border-radius:var(--r-lg);box-shadow:var(--shadow-lg);
  padding:24px;max-width:420px;width:100%;
  max-height:calc(100vh - 48px);overflow-y:auto;}
.tm-charge-modal h3{font-family:var(--display);font-weight:600;font-size:20px;color:var(--ink);margin:0 0 12px;}
.tm-charge-modal p{color:var(--charcoal-70);font-size:15px;line-height:1.5;margin:0 0 16px;}
.tm-charge-modal-actions{display:flex;gap:12px;justify-content:flex-end;margin-top:16px;}

/* Quick task 260921-hgx: modifier class confirm-modal opts into (see
   off_session_charge.cljs). Must stay BELOW the base .tm-charge-modal rule
   above — both are single-class selectors of equal specificity, so this
   only wins the cascade on source order. Turns the panel into a column
   flex container that clips its OWN overflow, so the inner body region
   scrolls instead of the panel itself; the h3 and actions row are given
   flex:none so they stay pinned as siblings of the scrolling body. */
.tm-charge-modal--scroll-body{
  display:flex;flex-direction:column;overflow:hidden;}
.tm-charge-modal--scroll-body > h3,
.tm-charge-modal--scroll-body > .tm-charge-modal-actions{flex:0 0 auto;}
/* min-height:0 is not optional and not cosmetic: a column flex item's
   default min-height:auto refuses to shrink below its content, so without
   this the body region grows straight past the panel's own max-height and
   nothing scrolls at all. */
.tm-charge-modal--scroll-body > .tm-charge-modal-body{
  flex:1 1 auto;min-height:0;overflow-y:auto;}
@supports (max-height:100dvh){
  .tm-charge-modal{max-height:calc(100dvh - 48px);}
}

/* Drawer entry point for D-05's account deletion (Task 3) — visually
   separated below the quick-link buttons, Destructive-colored TEXT per
   the plan's own action text. */
.tm-schedule-delete-action{margin:16px 0 0;padding-top:16px;border-top:1px solid var(--line);}
.tm-schedule-delete-link{
  background:none;border:none;cursor:pointer;font-family:var(--sans);font-size:14px;
  color:var(--destructive);text-decoration:underline;padding:0;}

/* ============ ADMIN — BOOKING-PICKER CUSTOM DISCLOSURE CHEVRON (quick 260712-s4e) ============ */
.tm-admin-field details > summary{list-style:none;}
.tm-admin-field details > summary::-webkit-details-marker{display:none;}
.tm-admin-field details > summary::before{content:"";display:inline-block;width:7px;height:7px;margin:0 10px 1px 2px;border-right:1.5px solid var(--charcoal-70);border-bottom:1.5px solid var(--charcoal-70);transform:rotate(-45deg);transition:transform .15s ease;}
.tm-admin-field details[open] > summary::before{transform:rotate(45deg);}

/* ============ Phase 14 additions (plan 14-02) ============
   Sole brand.css owner this phase (14-02-PLAN.md frontmatter) — every
   later Phase-14 plan (14-03/14-04/14-07) consumes these classes without
   editing this file, removing the cross-plan CSS merge conflict. */

/* IN-01 (25-REVIEW.md): .tm-nav-link / .tm-nav-link:hover (formerly the
   header "Catalog" nav link's plain-text style, D-03/14-UI-SPEC.md) removed
   2026-07-20 — plan 25-03 restyled that link onto .tm-nav-account-link's
   bordered-ghost chip, and a repo-wide search confirmed zero remaining
   .cljs/.cljc references to .tm-nav-link. */

/* Differentiators grid (Home, D-02/D-04) — direct port of home.jsx's
   "BENEFITS" section, hairline-divider grid trick: 1px gap + --line
   background reads as thin dividers between --bone cells. Cell padding
   28px/26px is a documented spacing exception (14-UI-SPEC.md "Spacing
   Scale exceptions"), matching home.jsx's own measured value. */
.tm-diff-grid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;}
.tm-diff-cell{background:var(--bone);padding:28px 26px;}
.tm-diff-num{font-family:var(--mono);font-size:13px;color:var(--signal);margin-bottom:0;}
.tm-diff-title{font-family:var(--display);font-weight:600;font-size:19px;color:var(--ink);margin-bottom:9px;}
.tm-diff-body{font-family:var(--sans);font-size:14px;line-height:1.55;color:var(--charcoal-70);}

/* Differentiator field marks (quick task 260728-mf2) — one bespoke 48x48
   line-art mark per card, rendered as inline Reagent hiccup in home.cljs
   (`diff-marks`/`diff-mark`) and coloured entirely through the three
   stroke tiers below: structure strokes inherit `.tm-diff-mark`'s
   `color` via `currentColor`, `.tm-mark-soft` de-emphasises secondary
   detail, and `.tm-mark-accent` (exactly one per mark) carries the
   single signal-coloured touch. `.tm-mark-fill` is the one permitted
   filled shape (card 06's shield only). No new colour value is
   introduced -- every rule below reuses an existing custom property. */
.tm-diff-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:14px;}
.tm-diff-mark{color:var(--charcoal);flex:0 0 auto;transition:color 120ms ease;}
.tm-diff-cell:hover .tm-diff-mark {color:var(--ink);}
.tm-mark-soft{stroke-width:1.25;opacity:.45;}
.tm-mark-accent{stroke:var(--signal);}
.tm-mark-fill{fill:var(--signal-soft);}
@media (max-width:600px){.tm-diff-mark svg{width:40px;height:40px;}}

/* Shared loading-dots component (ui.cljs `loading-dots`) — three pulsing
   dots rendered alongside existing "Loading…"/"Loading fleet…" copy
   (copy contract unchanged, only the animation is new). Pure CSS, no
   icon dependency, per the app's established "CSS-drawn shapes only"
   convention. */
.tm-loading-dots{display:inline-flex;align-items:center;gap:6px;vertical-align:middle;}
.tm-loading-dots span{
  width:6px;height:6px;border-radius:100px;background:var(--stone);display:inline-block;
  animation:tm-loading-dots-pulse 1.2s ease-in-out infinite;}
.tm-loading-dots span:nth-child(2){animation-delay:.15s;}
.tm-loading-dots span:nth-child(3){animation-delay:.3s;}
@keyframes tm-loading-dots-pulse{
  0%,100%{opacity:.3;}
  50%{opacity:1;}}

/* Booking-detail page loading-state UX (addon-purchase/reschedule):
   invert modifier for loading-dots on colored buttons, plus the
   page-level busy overlay shown while either action's POST is in flight. */
.tm-loading-dots--invert span{background:#fff;}
.tm-detail-busy-wrap{position:relative;}
.tm-detail-busy-overlay{position:absolute;inset:0;background:var(--oat-70);cursor:not-allowed;z-index:6;}

/* Suburb typeahead (folded todo, consumed by plan 14-03) — absolutely
   positioned dropdown anchored under the existing suburb .tm-checkout-
   input via a `position:relative` wrapper the consuming plan adds. Row
   padding 10px/16px is a documented density exception (14-UI-SPEC.md
   "Spacing Scale exceptions"). */
.tm-checkout-typeahead{
  position:absolute;top:100%;left:0;right:0;margin-top:4px;
  background:#fff;border:1px solid var(--line-strong);border-radius:var(--r);
  box-shadow:var(--shadow);max-height:220px;overflow-y:auto;z-index:5;}
.tm-checkout-typeahead-row{
  padding:10px 16px;font-family:var(--sans);font-size:14px;color:var(--charcoal);cursor:pointer;}
.tm-checkout-typeahead-row:hover{background:var(--bone);}

/* Sidebar "your details" summary (D-11, consumed by plan 14-03) —
   compact label/value list reusing .tm-checkout-summary-line's exact
   typography, rendered ABOVE the order-summary block inside the same
   .tm-checkout-summary-rail card, separated by the SAME border-top
   divider .tm-checkout-summary-total already uses. */
.tm-checkout-details-summary{
  padding-bottom:12px;margin-bottom:12px;border-bottom:1px solid var(--line);}

/* Clickable completed step-dot hover (D-09, consumed by plan 14-07) —
   .tm-done keeps its existing solid-charcoal visual; clickability is
   communicated by cursor:pointer + a subtle shadow ring using the
   existing --shadow token, never a new color. */
button.tm-checkout-step-dot.tm-done:hover{box-shadow:var(--shadow);cursor:pointer;}

/* ============ HOME — TESTIMONIALS (plan 19-05, REVIEW-07/D-05/D-06/D-08) ===
   Homepage-only published-review section, styled as a direct extension of
   the existing design system — same 1240px/24px section rhythm as
   .tm-diff-grid's differentiators, same card surface/border/shadow
   language as .tm-cc/.tm-booking-row. Reuses EXISTING custom properties
   only — no new hex/rgb literals, no new fonts. */
.tm-testimonials{max-width:1240px;margin:0 auto;padding:8px 24px 64px;}
.tm-testimonials-grid{
  display:grid;gap:24px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));}
.tm-testimonial-card{
  background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow);padding:22px 24px;}
.tm-testimonial-card p{font-size:15px;line-height:1.55;color:var(--charcoal-70);margin:12px 0 14px;}
.tm-testimonial-stars{font-family:var(--sans);font-size:16px;color:var(--signal);letter-spacing:.05em;}
.tm-testimonial-attr{
  font-family:var(--mono);font-size:12px;color:var(--charcoal-45);margin:0 !important;}
@media (max-width:768px){
  .tm-testimonials{padding:4px 24px 48px;}
  .tm-testimonial-card{padding:18px 20px;}
}

/* ============ HOME — SERVICE-AREA MAP (quick task 260818-t83) ============
   Same 1240px/24px section rhythm as .tm-diff-grid/.tm-testimonials above.
   .tm-service-map-canvas (the live-map container, Task 3) and .tm-ph
   inside .tm-service-map (the no-key fallback, Task 1) share one explicit
   height so the section never changes size when a key is later added — a
   Maps div with no height renders zero pixels and reads as a broken
   feature, so this height is load-bearing, not decoration. clamp() keeps
   it usable on a phone (320px floor) up to a roomy desktop frame (480px
   ceiling). Existing border/radius tokens (--line/--r-lg) frame both
   states identically. */
.tm-service-map{max-width:1240px;margin:0 auto;padding:56px 24px 8px;}
.tm-service-map-canvas,
.tm-service-map .tm-ph{
  height:clamp(320px,42vw,480px);
  border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;
}
.tm-service-map-fallback-content{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:12px;padding:24px;max-width:640px;max-height:100%;overflow-y:auto;text-align:center;}
.tm-service-map-caption{
  margin:0;font-family:var(--sans);font-size:15px;line-height:1.55;color:var(--charcoal-90);}
.tm-service-map-suburbs{
  margin:0;font-family:var(--sans);font-size:12.5px;line-height:1.6;color:var(--charcoal-70);}
/* Quick task 260821-5gn: CC BY 4.0 attribution for the transformed
   (simplified) ABS boundary data, rendered only in the live-map branch.
   Restyled by quick task 260821-k7y into a footer-style credit -- smaller,
   tighter and lighter than .tm-service-map-suburbs above, using --stone
   (an existing de-emphasized text-colour token, see the two uppercase-label
   rules elsewhere in this file) rather than a new colour value. The licence
   link is deliberately kept at --charcoal-45 -- a HIGHER contrast than the
   surrounding prose -- because it is the load-bearing legal element; do not
   "tidy" it back to `inherit`, which would quietly bury it as the credit
   prose recedes. */
.tm-service-map-attribution{
  margin:4px 0 0;font-family:var(--sans);font-size:10px;line-height:1.4;color:var(--stone);}
.tm-service-map-attribution a{color:var(--charcoal-45);}
@media (max-width:768px){
  .tm-service-map{padding:32px 24px 4px;}
}

/* ============ ROUTE MAP (quick task 260823-tlh) ============
   Admin + customer booking-details "hours run / route" section — the
   live-map Polyline canvas AND its unavailable-panel sibling (.tm-ph,
   route_map.cljs's own no-track state) share ONE explicit height, same
   load-bearing reason as .tm-service-map-canvas above: a Maps div with no
   height renders zero pixels and reads as a broken feature. Reuses the
   existing --line/--r-lg border/radius tokens. */
.tm-route-map-canvas{
  height:clamp(320px,42vw,480px);
  border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;
}

/* ============ Phase 20 additions (plan 20-02, ANALYTICS-05/06/07) ============
   Owner Analytics dashboard — three stacked tables (Utilization, Revenue,
   Demand Signal) sharing one month-range control (D-13/D-15). Bar-fill
   cells reuse --oat (D-14's first use as a bar-fill, not a new hex value —
   see 20-UI-SPEC.md's "Explicit non-additions" list) — no chart library,
   matching admin/schedule.cljs's own hand-rolled-CSS discipline. Tables
   compose .tm-admin-config-table verbatim (th/td rules never redeclared
   here) via `.tm-analytics-table` applied alongside it on the same
   <table> element. */
.tm-admin-analytics{max-width:1080px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-analytics h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 16px;}
.tm-analytics-range-control{display:flex;justify-content:center;align-items:center;gap:16px;margin:0 0 24px;}
.tm-analytics-range-btn{
  background:none;border:none;cursor:pointer;font-family:var(--mono);font-size:16px;
  color:var(--charcoal-70);min-width:44px;min-height:44px;
  display:inline-flex;align-items:center;justify-content:center;}
.tm-analytics-range-btn:disabled{opacity:.4;cursor:default;}
/* Phase 70 (FLEET-03, design brief §6 Type "Numbers... Space Mono 400,
   without exception" -- this month-range label and the bar/percentage
   figures below were still sans, one of the exact gaps §6 calls out. */
.tm-analytics-range-label{font-family:var(--mono);font-size:14px;color:var(--charcoal-70);}
.tm-analytics-section{margin:0 0 32px;}
.tm-analytics-section:last-child{margin-bottom:0;}
.tm-analytics-section h3{font-family:var(--display);font-weight:600;font-size:15px;color:var(--ink);margin:0 0 8px;}
.tm-analytics-table-wrap{overflow-x:auto;}
.tm-analytics-sticky-col{
  position:sticky;left:0;z-index:2;background:#fff;max-width:160px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* D-04: the fleet-wide summary row's own --oat tint extends into its
   sticky first column too, so the row reads as one continuous tinted
   band while scrolling horizontally, rather than a white sticky cell
   breaking the tint. */
.tm-analytics-summary-row td{background:var(--oat);font-weight:600;}
.tm-analytics-summary-row .tm-analytics-sticky-col{background:var(--oat);}
.tm-analytics-bar-cell{position:relative;padding:8px;}
.tm-analytics-bar-fill{position:absolute;inset:0;background:var(--oat);z-index:0;}
.tm-analytics-bar-label{position:relative;z-index:1;font-family:var(--mono);font-size:14px;color:var(--charcoal);}
/* Demand-signal table (D-09..D-12) — non-zero counts reuse
   .tm-admin-catalog-edit-link's existing typography verbatim via
   .tm-analytics-count-cell--clickable (no new declaration needed, it
   composes with the existing link class); the currently-open drill-down's
   source cell(s) get this border, reusing the same "active-item" visual
   weight the collapsed side-nav's active tile already uses (brand.css
   :362-363), never --signal. */
.tm-analytics-cell--active{border:2px solid var(--charcoal);}
/* Phase 70 (FLEET-03): the clickable non-zero demand-signal count keeps
   .tm-admin-catalog-edit-link's underline/cursor, but the figure itself
   goes mono like every other tabular number (§6). */
.tm-analytics-count-cell--clickable{font-family:var(--mono);}

/* --- Site footer (quick task 260725-dy4) -----------------------------------
   Rendered on every CUSTOMER page (ui/site-footer) — the internal admin/
   handover tool never requires timech.customer.ui, so it never picks this
   up, by construction. Reuses existing custom properties only. */
.tm-footer{border-top:1px solid var(--line);margin-top:48px;}
.tm-footer-inner{
  max-width:1240px;margin:0 auto;padding:28px 24px;
  display:flex;flex-direction:column;align-items:center;text-align:center;gap:12px;}
.tm-footer-brand{font-family:var(--mono);font-size:12px;color:var(--charcoal-70);}
.tm-footer-links{display:flex;flex-wrap:wrap;justify-content:center;gap:16px;}
.tm-footer-links a{
  font-family:var(--sans);font-size:13px;color:var(--charcoal-70);
  text-decoration:none;}
.tm-footer-links a:hover{color:var(--charcoal);text-decoration:underline;}

/* --- Static content pages: About / Contact (quick task 260725-dy4) --------
   Shared by both timech.customer.about and timech.customer.contact — do
   NOT duplicate this section for Contact. */
.tm-static-page{max-width:760px;margin:0 auto;padding:40px 24px 64px;}
.tm-static-page h1{font-family:var(--display);font-weight:600;font-size:clamp(28px,4vw,36px);color:var(--ink);margin:0 0 20px;}
.tm-static-page h2{font-family:var(--display);font-weight:600;font-size:20px;color:var(--ink);margin:36px 0 12px;}
.tm-static-page p,.tm-static-page li{font-size:16px;line-height:1.6;color:var(--charcoal-70);}
.tm-static-page ul,.tm-static-page ol{padding-left:22px;margin:0 0 16px;}
.tm-static-page a,.tm-static-page strong{color:var(--ink);}
.tm-static-page a.tm-checkout-btn-solid{color:var(--oat);}
a.tm-checkout-btn-solid{text-decoration:none;}

/* --- /free-delivery-area suburb grid + embedded map (quick task 260822-6ag)
   The `.tm-static-page ul` rule above (0,1,1) already sets padding-left:22px
   on any <ul> inside a static page -- a bare `.tm-suburb-grid` selector
   (0,1,0) would lose to it, same specificity trap `.tm-hero p.tm-hero-
   delivery` documents above, so this is qualified `.tm-static-page ul.tm-
   suburb-grid` (0,2,1) to win instead. */
.tm-static-page ul.tm-suburb-grid{
  list-style:none;padding-left:0;margin:0 0 16px;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));
  gap:2px 16px;}
/* Neutralizes the home-page section rhythm (max-width/padding/margin) so
   the embedded service-map's left edge lines up with the surrounding
   760px-wide static-page prose instead of sitting 24px inside it. The
   canvas's own height:clamp(320px,42vw,480px), set on .tm-service-map-
   canvas, is deliberately left alone. */
.tm-static-page .tm-service-map{max-width:none;padding:0;margin:0 0 8px;}

/* --- Admin "Booking details" page container (quick task 260809-k4z) ------
   This page (timech.admin.booking-detail, root .tm-admin-booking-detail)
   previously had NO container rule anywhere in this file — that missing
   rule was the literal cause of the page rendering flush to the viewport
   edges instead of centred like every sibling admin page. 1080px (not
   960px) matches .tm-admin-schedule/.tm-admin-analytics, the other two
   data-dense admin pages, because this page's related-record tables can
   run to 15 columns wide. The view-layer restructure that accompanies
   this CSS (Task 2) deliberately reuses .tm-charge-card,
   .tm-admin-catalog-section, .tm-admin-config-table and
   .tm-analytics-table-wrap from elsewhere in this file rather than
   duplicating them here — .tm-analytics-table-wrap in particular is named
   for the Analytics page but is a generic one-declaration horizontal-
   scroll wrapper, and reusing it here is the same cross-page-reuse
   discipline today.cljs already applies to .tm-charge-card and
   .tm-report-list. */
.tm-admin-booking-detail{max-width:1080px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-booking-detail h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 16px;}
.tm-admin-booking-detail h3{font-family:var(--display);font-weight:600;font-size:15px;color:var(--ink);margin:0 0 8px;}

/* --- Admin "Bookings" page container + narrow-viewport fix (quick task
   260828-bj9) --------------------------------------------------------------
   Two root causes found here. (a) .tm-admin-bookings-index had NO rule
   anywhere in this file — the same missing-container-rule symptom
   .tm-admin-booking-detail already documents above (quick task 260809-k4z),
   so this page rendered flush to the viewport edges instead of centred like
   every sibling admin page. (b) the six-column results table shares
   .tm-admin-config-table's padding:8px (line 688) — six columns x 16px
   horizontal padding is 96px of a phone's width spent on cell padding
   alone, before a single character of content.
   This page is Field-reachable (core.cljs:1046 puts it behind the "Find"
   tab, and it's absent from core.cljs's desk-only-views), so it needs both
   the Desk 25px and Field 21px page-title sizes, unlike most 25px titles
   elsewhere in this file which live on Desk-only screens. */
.tm-admin-bookings-index{max-width:1080px;margin:0 auto;padding:0 24px 48px;}
.tm-admin-bookings-index h2{font-family:var(--display);font-weight:600;font-size:25px;color:var(--ink);margin:0 0 16px;}
.tm-admin-shell--field .tm-admin-bookings-index h2{font-size:21px;}
.tm-admin-bookings-index-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:220px;}

@media (max-width:600px){
  .tm-admin-bookings-index{padding:0 12px 48px;}
  .tm-admin-bookings-index .tm-admin-config-table{font-size:12px;}
  .tm-admin-bookings-index .tm-admin-config-table th{font-size:9px;letter-spacing:.06em;padding:6px 3px;}
  .tm-admin-bookings-index .tm-admin-config-table td{padding:8px 3px;overflow-wrap:anywhere;}
  .tm-admin-bookings-index .tm-admin-bookings-index-name{white-space:normal;}
  .tm-admin-bookings-index .tm-pill{font-size:9px;letter-spacing:.06em;padding:4px 6px;}
}

/* Quick task 260828-tho: every admin address is now a clickable Google Maps
   link (timech.shared.maps-link/address-link). Colour is inherited from the
   parent element so wrapping an existing address string in this link never
   overrides a class's own muted/coloured text (e.g.
   .tm-field-run-card-address's grey) — matches the .tm-slot-warning a /
   .tm-cta-footnote a inline-link convention already used elsewhere in this
   file. */
.tm-maps-link{color:inherit;text-decoration:underline;text-underline-offset:2px;cursor:pointer;}

/* ============ Phase 73 (DASH-01..06) — /dashboard, the Fleet Status
   Dashboard ============
   73-UI-SPEC.md's transcribed values, verbatim from the mockup where
   noted. .tm-admin-schedule (already declared above) supplies the page
   shell/h2 typography for free -- this block is scoped to the screen's
   own new components only: the counts strip, the on-hire card grid (5
   fixed sections), and the Available/Off-the-road panel rows. --signal
   is reserved in this block EXCLUSIVELY for: the stale-fix counts-strip
   tile/card/map-border/freshness-strip, the over-allowance hours figure/
   bar, and the Draft handover pill (.tm-pill--signal, already shared) --
   see 73-UI-SPEC.md Color. */

/* Plan 73-02 Task 2 -- Typography conformance pass against 73-UI-SPEC.md's
   own transcribed values (re-verified directly against design/admin-
   dashboard/Dashboard Screen.dc.html's own inline styles this task):
   card title is a real Zilla Slab 17px/600 headline (was inheriting
   .tm-admin-catalog-edit-link's 14px Archivo link style verbatim, per
   Plan 73-01 Task 1's own "reused verbatim, no new link style" note --
   correct for the link BEHAVIOUR, wrong for its typography); every mono
   figure this screen renders gets its own mockup-measured size instead of
   inheriting the 13px shell baseline. */
.tm-dashboard-card-title .tm-admin-catalog-edit-link{font-family:var(--display);font-weight:600;font-size:17px;line-height:1.2;}
.tm-dashboard-card-detail-value.tm-figure{font-size:12.5px;}
.tm-dashboard-card-freshness .tm-figure{font-size:11.5px;}
.tm-dashboard-header-meta .tm-figure{font-size:11px;}
/* State 5 (tracking unavailable)'s Retry button is smaller than the
   Directions/Refresh .tm-dashboard-btn-outline default, per the Six Card
   States table. */
.tm-dashboard-map-empty .tm-dashboard-btn-outline{padding:6px 11px;font-size:11.5px;margin-top:2px;}

/* Header row + counts strip (Task 3, DASH-02) */
.tm-dashboard-header{display:flex;align-items:baseline;flex-wrap:wrap;gap:13px;}
.tm-dashboard-header-summary{font-size:13px;color:var(--charcoal-70);}
.tm-dashboard-header-meta{margin-left:auto;display:flex;align-items:center;gap:12px;}
/* Non-destructive manual-Refresh-failure banner (WR-02) -- renders ABOVE
   the counts strip while the last-known cards stay fully visible below it;
   reuses .tm-admin-login-error's --destructive color at a size that fits
   this inline slot rather than that class's own 16px bottom margin. */
.tm-dashboard-refresh-error{color:var(--destructive);font-size:13px;margin:0;}
/* CR-01 fix (79-REVIEW.md) -- today.cljs's own non-destructive
   background-refresh-failure banner, rendered as the LAST child of
   view-render's `:else` fragment while all previously-loaded page content
   stays fully visible above it (the /today mirror of this SAME
   .tm-dashboard-refresh-error rule immediately above -- same --destructive
   color at the same inline-slot size, page-scoped selector name only).
   Deliberately placed here, next to its dashboard.cljs sibling, rather
   than inside the /today Map Container block above -- that block is a
   named, marker-delimited region (today_test.cljs's own
   phase-78-brand-css-rules-never-use-destructive-token-test asserts NO
   rule between two specific comment markers ever uses --destructive) and
   this rule legitimately does. */
.tm-today-refresh-error{color:var(--destructive);font-size:13px;margin:0 0 16px;}
.tm-dashboard-counts{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:14px;}
.tm-dashboard-count-tile{background:#fff;border:1px solid var(--line);border-radius:var(--r-admin-panel);padding:11px 13px;}
.tm-dashboard-count-figure{font-size:23px;display:block;margin-top:4px;}
.tm-dashboard-count-tile--signal{border-color:rgba(192,96,43,.4);}
.tm-dashboard-count-tile--signal .tm-label,
.tm-dashboard-count-tile--signal .tm-dashboard-count-figure{color:var(--signal);}

/* Group divider rows (Task 3, DASH-02/03/04) */
.tm-dashboard-group-label{display:flex;align-items:center;gap:10px;}
.tm-dashboard-group-label-line{flex:1;height:1px;background:var(--line);}
.tm-dashboard-group-label--on-hire{margin:4px 0 0;}
.tm-dashboard-group-label--available{margin:0 0 11px;}
.tm-dashboard-group-label--off-road{margin:16px 0 11px;}
.tm-dashboard-group-label--schedule{margin:16px 0 11px;}

/* On-hire two-column card grid */
.tm-dashboard-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;}
.tm-dashboard-card{background:#fff;border:1px solid var(--line);border-radius:var(--r-admin-panel);overflow:hidden;}
/* Plan 73-02 Task 1 (stale-fix state, DASH-05): --signal reserved here
   for the stale-fix card border only -- see the exhaustive --signal
   reservation list in this block's own header comment. */
.tm-dashboard-card--stale{border-color:rgba(192,96,43,.4);}

/* Section 1 -- title row */
.tm-dashboard-card-title{padding:14px 16px 12px;display:flex;align-items:baseline;gap:10px;}
.tm-dashboard-card-ref{margin-left:auto;color:var(--charcoal-45);font-size:11px;}

/* Section 2 -- map area (152px, byte-identical structure across states) */
.tm-dashboard-card-map{height:152px;position:relative;overflow:hidden;background:var(--bone);border-top:1px solid var(--line);border-bottom:1px solid var(--line);}
.tm-dashboard-card-map--stale{border-top-color:rgba(192,96,43,.4);border-bottom-color:rgba(192,96,43,.4);}
.tm-dashboard-map-stub{position:absolute;inset:0;}
.tm-dashboard-map-note{position:absolute;left:12px;bottom:10px;font-family:var(--mono);font-size:9px;letter-spacing:.1em;text-transform:uppercase;color:var(--charcoal-45);}
.tm-dashboard-map-marker{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:13px;height:13px;border-radius:100px;background:#C0602B;box-shadow:0 0 0 4px rgba(255,255,255,.9);}
.tm-dashboard-map-marker--stale{background:rgba(46,42,37,.45);}
.tm-dashboard-map-circle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:96px;height:96px;border-radius:100px;border:2px dashed rgba(192,96,43,.5);background:rgba(192,96,43,.06);}
.tm-dashboard-map-circle--stale{border-color:rgba(46,42,37,.28);background:rgba(46,42,37,.04);}
.tm-dashboard-map-empty{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;text-align:center;padding:0 16px;}
.tm-dashboard-map-empty p:not(.tm-label){font-family:var(--sans);font-size:12px;color:var(--charcoal-70);margin:0;max-width:240px;}
.tm-dashboard-map-pin-crossed{flex:none;}

/* Section 3 -- freshness strip */
.tm-dashboard-card-freshness{padding:10px 16px;display:flex;align-items:center;gap:10px;background:var(--bone);border-bottom:1px solid var(--line);}
.tm-dashboard-card-freshness--stale{background:rgba(192,96,43,.07);border-bottom-color:rgba(192,96,43,.4);color:var(--signal);}

/* Section 4 -- detail grid, 6 fields */
.tm-dashboard-card-detail{padding:14px 16px;display:grid;grid-template-columns:1fr 1fr;gap:12px 16px;}
.tm-dashboard-card-detail-value{margin-top:4px;font-family:var(--sans);font-size:13px;color:var(--charcoal);}
.tm-dashboard-card-detail-value--signal{color:var(--signal);}
.tm-dashboard-tag{display:inline-block;margin-left:6px;font-family:var(--mono);font-size:9px;letter-spacing:.08em;text-transform:uppercase;color:var(--charcoal-70);background:var(--bone);border:1px solid var(--line);border-radius:100px;padding:2px 6px;}
.tm-dashboard-hours-bar{height:3px;background:rgba(46,42,37,.10);border-radius:3px;margin-top:6px;}
.tm-dashboard-hours-bar-fill{height:3px;border-radius:3px;background:var(--go);}
.tm-dashboard-hours-bar-fill--signal{background:var(--signal);}

/* Section 5 -- actions row */
.tm-dashboard-card-actions{padding:0 16px 15px;display:flex;gap:8px;}
.tm-dashboard-btn-outline{background:transparent;border:1px solid var(--line-strong);border-radius:var(--r);padding:10px 12px;font-family:var(--sans);font-weight:600;color:var(--charcoal);cursor:pointer;}

/* Available / Off-the-road panel rows (Task 3, DASH-04) -- absolutely no
   map area of any kind ever rendered in either group. */
.tm-dashboard-panel{background:#fff;border:1px solid var(--line);border-radius:var(--r-admin-panel);}
.tm-dashboard-row{display:flex;align-items:center;gap:12px;padding:10px 15px;border-bottom:1px solid var(--line);}
.tm-dashboard-row:last-child{border-bottom:none;}
.tm-dashboard-row--muted{color:var(--charcoal-70);font-weight:600;}

/* Overdue-service marker (Phase 83 plan 83-03, ALERT-01, D-13/D-14/D-15) --
   a solid circle, not a rounded-rect pill, and the ONLY element on this
   screen using --destructive: every one of the six existing hire-status
   states here is a .tm-pill rounded-rect uppercase-mono text pill and none
   of them uses this token, so the marker differs in SHAPE and COLOUR at
   once -- what D-14's "distinguishable by more than colour" requires on a
   phone in daylight. color:var(--oat) is load-bearing -- nav_icons.cljs's
   `icon` strokes with currentColor, so this one declaration recolours the
   wrench white-on-red with no second colour rule anywhere. */
.tm-dashboard-badge--overdue-service{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;flex:0 0 18px;border-radius:50%;background:var(--destructive);color:var(--oat);text-decoration:none;}

/* Quick task 260908-em5: the Pricing tab's "Rental-block types" table
   (timech.admin.config-forms/rental-blocks-table) is the widest editable
   table in the admin -- 11 columns inside the 960px .tm-admin-catalog
   shell. Auto table-layout crushed its money and count fields (Label, Min
   days, Rate ($), Start Price ($), Day Rate ($), Sort) below legibility,
   risking a dollars/cents mispricing the owner cannot even see. These
   per-column min-width rules are scoped to a modifier class rather than
   added to .tm-admin-config-table itself, because seven other admin
   tables (bookings index, slot definitions, coupons, reduced-excess,
   day-rate bands, FAQs, reviews) share that base class and must not
   change width. min-width lands on the .tm-admin-input INSIDE each cell,
   not on the <td> alone -- in table-layout:auto a cell's own min-width is
   only a suggestion to the column algorithm, while a child's min-content
   width genuinely raises the column's minimum; the th half of each pair
   keeps a column's header legible even when every row in it currently
   renders an em-dash (Start Price / Day Rate on a non-open-ended item).
   .tm-admin-input's existing width:100% (line 737) is untouched and
   coexists with min-width -- the input still fills a column wider than
   its minimum. The table is also wrapped in the project's generic
   .tm-analytics-table-wrap (line 1981) so it scrolls horizontally inside
   its own panel instead of forcing a page-level scrollbar.

   Quick task 260908-frp halved the Label and Min days minimums below
   (170 down to 88, 96 down to 48) once the panel gained a full-bleed
   breakout (see the .tm-admin-catalog-section--fullbleed rule at the end
   of this file) that gives the table enough room to drop its horizontal
   scrollbar entirely -- the other four column minimums are unchanged. */
.tm-admin-config-table--rental-blocks th:nth-child(3),.tm-admin-config-table--rental-blocks td:nth-child(3) .tm-admin-input{min-width:88px;}
.tm-admin-config-table--rental-blocks th:nth-child(4),.tm-admin-config-table--rental-blocks td:nth-child(4) .tm-admin-input{min-width:48px;}
.tm-admin-config-table--rental-blocks th:nth-child(5),.tm-admin-config-table--rental-blocks td:nth-child(5) .tm-admin-input{min-width:120px;}
.tm-admin-config-table--rental-blocks th:nth-child(6),.tm-admin-config-table--rental-blocks td:nth-child(6) .tm-admin-input{min-width:128px;}
.tm-admin-config-table--rental-blocks th:nth-child(7),.tm-admin-config-table--rental-blocks td:nth-child(7) .tm-admin-input{min-width:120px;}
.tm-admin-config-table--rental-blocks th:nth-child(10),.tm-admin-config-table--rental-blocks td:nth-child(10) .tm-admin-input{min-width:88px;}

/* Quick task 260908-frp: full-bleed breakout for the Pricing tab's
   "Rental-block types" panel (rental-blocks-table's 1-arg, Edit-Item
   render only). Even after halving the Label/Min days minimums above,
   the widened table still scrolled horizontally inside the centred
   960px .tm-admin-catalog shell -- this breaks the panel out of that
   shell so it spans .tm-admin-main's full available width instead.

   The derivation: let M = .tm-admin-main's width, S = .tm-admin-catalog's
   border-box width (min(960px, M)), P = the panel's containing-block
   width (S - 48px, since .tm-tab-panel adds no horizontal padding). The
   panel's left edge sits (M - S)/2 + 24px from .tm-admin-main's left
   edge, because .tm-admin-catalog is margin:0 auto. Solving for the
   margin-left that puts the panel's left edge at a gutter G from main's
   left edge gives margin-left = G - ((M - S)/2 + 24px), which simplifies
   to `G + 50% - M/2` in BOTH regimes (M >= 960 and M < 960) -- when
   M < 960, S = M so (M-S)/2 = 0 and the same expression falls out. That
   is why one rule below covers every viewport with no media query.

   M is approximated as `100vw - var(--tm-admin-rail-w)`, with two
   deliberate approximations, both absorbed by the 24px gutter: (1) 100vw
   includes the vertical scrollbar (typically 15-17px) that
   .tm-admin-main does not have, so the panel overhangs main by roughly
   scrollbar/2 (~8px) per side -- with G = 24px the real inset lands near
   16px per side, still positive, so no page-level horizontal scrollbar
   appears; (2) env(safe-area-inset-*) on .tm-admin-shell is 0 on desktop
   and only nonzero on notched mobile in landscape, where any residual
   overhang stays inside the safe-area padding band.

   --tm-admin-rail-w reads the sibling .tm-admin-sidenav's width via
   :has() (already an established pattern in this stylesheet, see line
   1383), because the collapsed-state class lives on the rail itself, a
   SIBLING of .tm-admin-main, not a descendant it could read directly.
   Three declared states plus a base: 0px with no rail (Field mode),
   200px with the expanded rail, 56px with the collapsed rail. The
   fourth, media-query rung exists because below 767px the EXPANDED rail
   switches to position:fixed and contributes 0px of flow width -- so at
   that width the base 0px value must win back over the 200px rung,
   which needs the media query's higher (0,3,0) specificity to override
   the plain expanded-rail rule's (0,2,0). Order matters for the other
   two: the --collapsed rung must come after the plain-rail rung (equal
   (0,2,0) specificity, later wins).

   The modifier is applied only on the Edit-Item (1-arg) render, never
   the standalone Settings > Pricing Rules (0-arg) render, because that
   view's .tm-admin-config wrapper sits inside .tm-admin-settings-shell
   behind a SECOND-level rail and is not centred within .tm-admin-main --
   this `50% - M/2 + G` math would be wrong there. */
.tm-admin-shell-body{--tm-admin-rail-w:0px;}
.tm-admin-shell-body:has(> .tm-admin-sidenav){--tm-admin-rail-w:200px;}
.tm-admin-shell-body:has(> .tm-admin-sidenav--collapsed){--tm-admin-rail-w:56px;}
@media (max-width:767px){.tm-admin-shell-body:has(> .tm-admin-sidenav:not(.tm-admin-sidenav--collapsed)){--tm-admin-rail-w:0px;}}
.tm-admin-catalog-section--fullbleed{margin-left:calc(50% - (100vw - var(--tm-admin-rail-w)) / 2 + 24px);margin-right:calc(50% - (100vw - var(--tm-admin-rail-w)) / 2 + 24px);}
