/* ==========================================================================
   CURBSIDE MOBILE REPAIR — DEMONSTRATION SITE
   Design direction: DISPATCH BOARD.
   A cool near-black board, lighter row surfaces, tabular mono for anything
   structural, plain sans for prose. Status color is STATUS, never decoration:
   green = done, amber = en route / waiting, red = declined / referred out.
   ⛔ No card grid. The layout is a narrow left rail of job rows and a wide
   right detail pane, and it stacks to one column below 900px.
   ⛔ Zero external requests. System font stacks only. No @import, no CDN.
   ========================================================================== */

:root{
  --board:#0b1016;        /* deep blue-gray, near black */
  --board2:#0f151d;       /* section ground */
  --row:#151e28;          /* row surface */
  --row-hi:#1c2833;       /* selected / hovered row */
  --rule:#25333f;         /* hairline */
  --rule-soft:#1a242e;
  --ink:#e8eef4;
  --ink2:#b6c6d4;
  --dim:#7f95a7;
  --dimmer:#5d7183;

  --done:#43c08a;         /* green  — finished */
  --wait:#e2a63f;         /* amber  — en route / waiting */
  --no:#e2604f;           /* red    — declined / referred out */

  /* STEEL is the only non-status color, and it has exactly one job:
     STRUCTURE. Selection, keylines, diagram rules, focus, the primary
     action. It is never allowed to mean "done", "waiting" or "declined",
     and green/amber/red are never allowed to mean "this is important".  */
  --steel:#5b93c4;
  --steel-dim:#3d6a92;
  --steel-glow:rgba(91,147,196,.22);

  /* ⭐ HI-VIS is the BRAND accent, added 11 Sep 2026, and it has exactly four
     jobs: the mark, the offer strip, one phrase of the home page h1, and the
     primary button. Nothing else.
     🔴 READ THIS BEFORE USING IT ANYWHERE ELSE. --wait (#e2a63f) is a STATUS
     and it is also amber. The two are told apart by WHERE they appear, not by
     hue: --wait only ever fills a status pill or a row flag inside the board;
     --hivis only ever appears on brand furniture, and NEVER inside a board
     row. ⛔ Put hi-vis on a row and the row reads as "en route". That rewrites
     the steel rule below: the primary action is now hi-vis, but the rest of
     the rule stands — green/amber/red still never mean "this is important",
     and steel still owns selection, keylines, diagram rules and focus. */
  --hivis:#ffb000;
  --hivis-lo:#d99500;
  --hivis-glow:rgba(255,176,0,.22);

  /* depth — a board is a lit screen, not a flat fill */
  --lift:rgba(255,255,255,.045);   /* hairline that catches the light */
  --lift2:rgba(255,255,255,.022);  /* alternating row value */
  --sink:rgba(0,0,0,.34);
  --ease:cubic-bezier(.22,.61,.36,1);

  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Monaco, Consolas,
          "Liberation Mono", "Courier New", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
          Arial, "Noto Sans", sans-serif;

  --shell: 1180px;
}

*,*::before,*::after{ box-sizing:border-box; }

html{ -webkit-text-size-adjust:100%; }

body{
  margin:0;
  background:var(--board);
  background-image:
    radial-gradient(1100px 520px at 50% -160px, #16202b 0%, rgba(22,32,43,0) 70%),
    linear-gradient(180deg, #0d131b 0%, var(--board) 420px);
  background-repeat:no-repeat;
  background-attachment:scroll;
  color:var(--ink);
  font-family:var(--sans);
  font-size:1rem;
  line-height:1.62;
  overflow-wrap:break-word;
}

img,svg{ max-width:100%; }

a{ color:#8fd0ff; text-decoration:none; transition:color .16s var(--ease); }
a:hover{ text-decoration:underline; color:#bce2ff; }
:focus-visible{ outline:2px solid var(--steel); outline-offset:2px; }

.shell{ width:100%; max-width:var(--shell); margin:0 auto; padding:0 22px; }

/* ---------- the demonstration strip -------------------------------------
   ⛔ Not decoration and not optional. Every page opens with it, above the
   header, un-dismissable. These files are reachable outside the viewer that
   frames them, and standing alone every page reads as a real repair business
   with a phone number on it.                                              */
.demostrip{
  display:flex; align-items:flex-start; gap:10px;
  background:#1a1206;
  border-bottom:1px solid #43300e;
  color:#f0d9ae;
  font-family:var(--mono);
  font-size:.78125rem; line-height:1.5;
  padding:9px 22px;
}
.demostrip b{ color:#ffdf9e; }
.demostrip a{ color:#ffcf7a; text-decoration:underline; white-space:nowrap; }
.demostrip__dot{
  flex:0 0 auto; width:8px; height:8px; margin-top:7px; border-radius:50%;
  background:var(--wait); box-shadow:0 0 0 3px rgba(226,166,63,.16);
}

/* ---------- header ------------------------------------------------------ */
.top{
  border-bottom:1px solid var(--rule); position:relative; z-index:5;
  background:linear-gradient(180deg,#131c25 0%,var(--board2) 100%);
  box-shadow:inset 0 1px 0 var(--lift), 0 1px 0 rgba(0,0,0,.5);
}
.top__in{ display:flex; flex-wrap:wrap; align-items:center; gap:14px 26px; padding-top:14px; padding-bottom:14px; }
.mark{ display:flex; align-items:baseline; gap:10px; }
.mark__name{ font-family:var(--mono); font-size:1rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--ink); }
.mark__sub{ font-family:var(--mono); font-size:.65625rem; letter-spacing:.16em; text-transform:uppercase; color:var(--dimmer); }
.mark a{ color:inherit; text-decoration:none; }

.nav{ display:flex; flex-wrap:wrap; gap:4px 16px; margin-left:auto; }
.nav a{
  font-family:var(--mono); font-size:.71875rem; letter-spacing:.11em;
  text-transform:uppercase; color:var(--ink2); text-decoration:none;
  padding:4px 0; border-bottom:1px solid transparent;
  transition:color .16s var(--ease), border-color .16s var(--ease);
}
.nav a:hover{ color:#fff; border-bottom-color:var(--steel); text-decoration:none; }
.nav a[aria-current="page"]{ color:#fff; border-bottom-color:var(--steel); }

.callbar{
  font-family:var(--mono); font-size:.75rem; letter-spacing:.06em;
  color:var(--ink); border:1px solid var(--rule); white-space:nowrap;
  background:linear-gradient(180deg,#1b2632,#141d26);
  box-shadow:inset 0 1px 0 var(--lift);
  padding:7px 12px;
  transition:border-color .18s var(--ease), box-shadow .18s var(--ease), color .18s var(--ease);
}
.callbar:hover{
  border-color:var(--steel); text-decoration:none; color:#fff;
  box-shadow:inset 0 1px 0 var(--lift), 0 0 0 3px var(--steel-glow);
}
.callbar b{ color:#fff; }

/* ---------- ruled section bars ------------------------------------------ */
.rulebar{
  display:flex; align-items:center; gap:13px;
  font-family:var(--mono); font-size:.6875rem; font-weight:700;
  letter-spacing:.18em; text-transform:uppercase; color:var(--ink2);
  margin:66px 0 22px;
}
.rulebar::before{
  content:""; flex:0 0 auto; width:7px; height:7px; background:var(--steel);
  box-shadow:0 0 0 3px var(--steel-glow);
}
.rulebar::after{
  content:""; flex:1 1 auto; height:1px;
  background:linear-gradient(90deg,var(--rule) 0%,var(--rule) 55%,rgba(37,51,63,0) 100%);
}
.rulebar--first{ margin-top:38px; }
.rulebar--done::before{ background:var(--done); box-shadow:0 0 0 3px rgba(67,192,138,.16); }
.rulebar--wait::before{ background:var(--wait); box-shadow:0 0 0 3px rgba(226,166,63,.16); }
.rulebar--no::before{ background:var(--no); box-shadow:0 0 0 3px rgba(226,96,79,.16); }

/* ---------- headings & prose -------------------------------------------- */
h1,h2,h3{ margin:0 0 14px; }
h1{
  font-size:clamp(1.9375rem,5.1vw,3.25rem); font-weight:700;
  line-height:1.04; letter-spacing:-.025em; color:#fff;
  max-width:20ch; text-wrap:balance;
}
h2{ font-size:clamp(1.375rem,2.9vw,1.9375rem); font-weight:700; line-height:1.14; letter-spacing:-.018em; color:#fff; }
h3{ font-size:1.09375rem; font-weight:700; line-height:1.25; letter-spacing:-.008em; }
p{ margin:0 0 15px; }
.lede{ font-size:clamp(1.0625rem,2.05vw,1.25rem); line-height:1.55; color:var(--ink2); max-width:62ch; }
.prose{ max-width:70ch; }
.prose h2{ margin-top:34px; }
.prose h3{ margin-top:26px; color:#fff; }
.prose ul,.prose ol{ margin:0 0 16px; padding-left:20px; }
.prose li{ margin-bottom:8px; }
.small{ font-size:.84375rem; color:var(--dim); }
.stamp{ font-family:var(--mono); font-size:.6875rem; letter-spacing:.14em; text-transform:uppercase; color:var(--dim); }

/* ---------- the board: narrow left rail + wide right pane ---------------- */
.board{
  display:grid;
  grid-template-columns:minmax(0,318px) minmax(0,1fr);
  gap:0;
  border:1px solid var(--rule);
  background:
    radial-gradient(760px 340px at 82% 0%, rgba(91,147,196,.055) 0%, rgba(91,147,196,0) 68%),
    linear-gradient(180deg,#111a23 0%,#0c1219 62%,#0a1017 100%);
  box-shadow:inset 0 1px 0 var(--lift), 0 18px 44px -28px rgba(0,0,0,.9);
}
.board__rail{
  border-right:1px solid var(--rule); min-width:0;
  background:linear-gradient(180deg,rgba(0,0,0,.22),rgba(0,0,0,0) 220px);
}
.board__pane{ min-width:0; padding:20px 22px 26px; }

.railhead,.panehead{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  font-family:var(--mono); font-size:.65625rem; font-weight:700;
  letter-spacing:.15em; text-transform:uppercase; color:var(--dim);
  padding:11px 14px; border-bottom:1px solid var(--rule);
  background:linear-gradient(180deg,#141d27,#0c131a);
  box-shadow:inset 0 1px 0 var(--lift);
}
.railhead b,.panehead b{ color:var(--steel); font-weight:700; }
.panehead{ margin:-20px -22px 18px; padding-left:22px; padding-right:22px; }

/* job rows in the rail */
.jobrow{
  position:relative;
  display:grid; grid-template-columns:11px minmax(0,1fr); gap:11px;
  align-items:start;
  padding:12px 15px 12px 16px;
  border-bottom:1px solid var(--rule-soft);
  border-top:1px solid transparent;
  font-family:var(--mono); font-size:.75rem; line-height:1.45;
  color:var(--ink2);
  transition:background-color .17s var(--ease), color .17s var(--ease);
}
/* alternating value — a board is ruled, and ruled paper is never one tone */
.jobrow:nth-of-type(even){ background:var(--lift2); }
/* the hairline that catches the light: dark rule below, lit rule above */
.jobrow + .jobrow{ border-top-color:var(--lift); }
.jobrow:last-child{ border-bottom:0; }

/* the SELECTED row. Steel, not amber — selection is structure, not status,
   and the row's own pip is still free to say what the job is doing.       */
.jobrow--on{
  background:linear-gradient(90deg,rgba(91,147,196,.13) 0%,rgba(91,147,196,.03) 46%,rgba(255,255,255,.028) 100%);
  color:var(--ink);
  box-shadow:inset 0 1px 0 var(--lift), 0 6px 18px -14px rgba(0,0,0,.9);
}
.jobrow--on::before{
  content:""; position:absolute; left:0; top:-1px; bottom:-1px; width:3px;
  background:var(--steel); box-shadow:0 0 12px 1px var(--steel-glow);
}
.jobrow__id{ color:#fff; font-weight:700; letter-spacing:.04em; }
.jobrow--on .jobrow__id{ color:#fff; }
.jobrow__meta{ color:var(--dimmer); font-size:.6875rem; display:block; }
.jobrow--on .jobrow__meta{ color:var(--ink2); }
.jobrow__st{ font-size:.65625rem; letter-spacing:.11em; text-transform:uppercase; }

/* status pips read as lit indicators, not printed dots */
.pip{
  width:9px; height:9px; margin-top:5px; border-radius:50%;
  background:var(--dim); box-shadow:0 0 0 3px rgba(127,149,167,.12);
}
.pip--done{ background:var(--done); box-shadow:0 0 0 3px rgba(67,192,138,.13), 0 0 9px rgba(67,192,138,.5); }
.pip--wait{ background:var(--wait); box-shadow:0 0 0 3px rgba(226,166,63,.14), 0 0 9px rgba(226,166,63,.5); }
.pip--no{   background:var(--no);   box-shadow:0 0 0 3px rgba(226,96,79,.14),  0 0 9px rgba(226,96,79,.5); }
.st--done{ color:var(--done); }
.st--wait{ color:var(--wait); }
.st--no{ color:var(--no); }

/* ---------- the work order ---------------------------------------------- */
.wo{
  border:1px solid var(--rule);
  background:linear-gradient(180deg,#18222d 0%,#141d26 34%,#121a23 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.055), 0 22px 40px -30px rgba(0,0,0,1);
}
.wo__head{
  display:flex; flex-wrap:wrap; gap:6px 24px; align-items:baseline;
  padding:15px 16px; border-bottom:1px solid var(--rule);
  background:linear-gradient(180deg,#1a2531,#101922);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06);
  font-family:var(--mono); font-size:.71875rem; letter-spacing:.08em; color:var(--dim);
}
.wo__no{ font-size:.9375rem; font-weight:700; color:#fff; letter-spacing:.06em; }
.wo__facts{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,180px),1fr));
  gap:2px 22px; padding:14px 16px; border-bottom:1px solid var(--rule);
  font-family:var(--mono); font-size:.75rem;
}
.wo__facts dt{ color:var(--dimmer); font-size:.65625rem; letter-spacing:.14em; text-transform:uppercase; }
.wo__facts dd{ margin:0 0 10px; color:var(--ink); }

.woline{
  padding:15px 16px; border-bottom:1px solid var(--rule-soft);
  border-top:1px solid transparent;
  transition:background-color .18s var(--ease);
}
.woline + .woline{ border-top-color:var(--lift); }
.woline:nth-of-type(even){ background:var(--lift2); }
.woline:hover{ background:rgba(255,255,255,.038); }
.woline:last-of-type{ border-bottom:0; }
.woline__top{
  display:grid; grid-template-columns:minmax(0,1fr) auto; gap:4px 16px;
  align-items:baseline;
  font-family:var(--mono); font-size:.78125rem; letter-spacing:.03em;
}
.woline__title{ color:#fff; font-weight:700; text-transform:uppercase; }
.woline__price{ color:var(--ink); font-variant-numeric:tabular-nums; white-space:nowrap; }
.woline__st{ grid-column:1/-1; font-size:.65625rem; letter-spacing:.13em; text-transform:uppercase; }
.woline__note{ margin:8px 0 0; font-size:.90625rem; color:var(--ink2); max-width:64ch; }
/* the $0.00 declined line. It is the best line on the site and it is lit
   like one — red is the status, and the status is "we did not touch it".  */
.woline--no,
.woline--no:nth-of-type(even){
  background:linear-gradient(90deg,rgba(226,96,79,.115) 0%,rgba(226,96,79,.045) 55%,rgba(226,96,79,.02) 100%);
  box-shadow:inset 3px 0 0 var(--no), inset 0 1px 0 rgba(255,255,255,.05);
}
.woline--no:hover{ background:linear-gradient(90deg,rgba(226,96,79,.155) 0%,rgba(226,96,79,.06) 55%,rgba(226,96,79,.03) 100%); }
.woline--no .woline__title{ color:#ffd9d2; }
.woline--no .woline__price{ color:var(--no); }
.woline--free .woline__price{ color:var(--dim); }

.wo__total{
  display:grid; grid-template-columns:minmax(0,1fr) auto; gap:4px 16px;
  padding:14px 16px; border-top:1px solid var(--rule);
  background:linear-gradient(180deg,#16202a,#101922);
  box-shadow:inset 0 1px 0 var(--lift);
  font-family:var(--mono); font-size:.8125rem; letter-spacing:.06em;
}
.wo__total b{ color:#fff; font-size:1rem; font-variant-numeric:tabular-nums; }
.wo__total span:first-child{ text-transform:uppercase; color:var(--dim); font-size:.6875rem; }
.wo__foot{
  padding:12px 16px; border-top:1px solid var(--rule);
  font-family:var(--mono); font-size:.6875rem; color:var(--dimmer); letter-spacing:.05em;
}

/* ---------- queue rows (services, areas, anything tabular) --------------- */
.queue{
  border:1px solid var(--rule);
  background:linear-gradient(180deg,#101923 0%,#0c1219 100%);
  box-shadow:inset 0 1px 0 var(--lift);
}
.queue__head{
  display:grid; grid-template-columns:minmax(0,2.1fr) minmax(0,1fr) minmax(0,1.4fr);
  gap:14px; padding:10px 16px; border-bottom:1px solid var(--rule);
  background:linear-gradient(180deg,#141d27,#0c131a); box-shadow:inset 0 1px 0 var(--lift);
  font-family:var(--mono); font-size:.625rem; font-weight:700; letter-spacing:.16em;
  text-transform:uppercase; color:var(--dim);
}
.qrow{
  position:relative;
  display:grid; grid-template-columns:minmax(0,2.1fr) minmax(0,1fr) minmax(0,1.4fr);
  gap:4px 14px; padding:15px 16px; border-bottom:1px solid var(--rule-soft);
  border-top:1px solid transparent;
  align-items:baseline;
  transition:background-color .18s var(--ease);
}
.qrow + .qrow{ border-top-color:var(--lift); }
.qrow:nth-of-type(even){ background:var(--lift2); }
.qrow:last-child{ border-bottom:0; }
.qrow:hover{ background:rgba(91,147,196,.075); }
.qrow:hover::before{
  content:""; position:absolute; left:0; top:-1px; bottom:-1px; width:2px;
  background:var(--steel); box-shadow:0 0 10px 1px var(--steel-glow);
}
/* a queue whose rows are JOB TYPES carries a drawn mark; a queue whose rows
   are something else (the mileage rings) does not, and must not get a
   phantom 34px column. Opt in with .queue--marked.                       */
.queue--marked .queue__head,
.queue--marked .qrow{ grid-template-columns:34px minmax(0,2.1fr) minmax(0,1fr) minmax(0,1.4fr); }
.queue--marked .qrow__note{ grid-column:2/-1; }
.qrow__mark{ grid-row:1/3; align-self:start; margin-top:1px; }
.qrow__name{ font-family:var(--mono); font-size:.8125rem; font-weight:700; letter-spacing:.04em; text-transform:uppercase; }
.qrow__name a{ color:#fff; }
.qrow__name a:hover{ color:var(--steel); text-decoration:none; }
.qrow__dur,.qrow__where{ font-family:var(--mono); font-size:.71875rem; color:var(--ink2); }
.qrow__note{ grid-column:1/-1; margin:6px 0 0; font-size:.90625rem; color:var(--ink2); max-width:74ch; }
.qrow__label{ display:none; font-family:var(--mono); font-size:.59375rem; letter-spacing:.16em; text-transform:uppercase; color:var(--dimmer); }

/* ---------- the "when we will tell you no" list ------------------------- */
.nolist{
  border:1px solid var(--rule); border-left:3px solid var(--no);
  background:
    linear-gradient(90deg,rgba(226,96,79,.07) 0%,rgba(226,96,79,0) 340px),
    linear-gradient(180deg,#111923 0%,#0c1219 100%);
  box-shadow:inset 0 1px 0 var(--lift);
}
.noitem{
  padding:17px 19px; border-bottom:1px solid var(--rule-soft);
  border-top:1px solid transparent;
  transition:background-color .18s var(--ease);
}
.noitem + .noitem{ border-top-color:var(--lift); }
.noitem:hover{ background:rgba(255,255,255,.03); }
.noitem:last-child{ border-bottom:0; }
.noitem__head{ display:flex; align-items:center; gap:10px; margin:0 0 8px; }
.noitem__head h3{ margin:0; }
.noitem h3{
  font-family:var(--mono); font-size:.75rem; font-weight:700; letter-spacing:.1em;
  text-transform:uppercase; color:var(--no); margin:0 0 7px;
}
.noitem p{ margin:0; font-size:.9375rem; color:var(--ink2); max-width:76ch; }

/* ---------- plain ruled blocks ------------------------------------------ */
.slab{
  border:1px solid var(--rule); padding:21px 23px;
  background:linear-gradient(180deg,#111923 0%,#0c1219 100%);
  box-shadow:inset 0 1px 0 var(--lift);
}
.slab + .slab{ border-top:0; }
.slab h3{ color:#fff; }
.slab p:last-child{ margin-bottom:0; }

.kv{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr)); gap:0;
  border:1px solid var(--rule);
  background:linear-gradient(180deg,#111923,#0c1219);
  box-shadow:inset 0 1px 0 var(--lift);
}
.kv > div{
  padding:15px 16px; border-right:1px solid var(--rule); border-bottom:1px solid var(--rule);
  transition:background-color .18s var(--ease);
}
.kv > div:hover{ background:rgba(91,147,196,.06); }
.kv > div:last-child{ border-right:0; }
.kv dt,.kv .k{ font-family:var(--mono); font-size:.625rem; letter-spacing:.16em; text-transform:uppercase; color:var(--dimmer); margin-bottom:5px; }
.kv .v{ font-family:var(--mono); font-size:.8125rem; color:#fff; }

/* ---------- the empty frame where photographs will go ------------------- */
.frame{
  border:1px dashed #3a4b59;
  background:repeating-linear-gradient(135deg,#0e151d 0 12px,#111922 12px 24px);
  padding:34px 24px; text-align:center;
}
.frame__label{ font-family:var(--mono); font-size:.65625rem; letter-spacing:.18em; text-transform:uppercase; color:var(--dim); }
.frame p{ margin:11px auto 0; max-width:64ch; color:var(--ink2); font-size:.90625rem; text-align:left; }

/* ---------- the hero ----------------------------------------------------- */
.hero,
.showcase{ padding:36px 0 0; }
.hero__kick{
  display:inline-flex; align-items:center; gap:9px;
  font-family:var(--mono); font-size:.6875rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--steel); margin-bottom:16px;
}
.hero__kick::before{
  content:""; width:22px; height:1px; background:var(--steel); flex:0 0 auto;
}
.hero__grid{ display:grid; grid-template-columns:minmax(0,1fr); gap:26px; align-items:start; }
.illo{
  border:1px solid var(--rule); padding:15px;
  background:
    radial-gradient(620px 300px at 26% 8%, rgba(91,147,196,.075) 0%, rgba(91,147,196,0) 70%),
    linear-gradient(180deg,#111a24 0%,#0a1017 100%);
  box-shadow:inset 0 1px 0 var(--lift), 0 20px 44px -34px rgba(0,0,0,1);
}
.illo svg{ display:block; width:100%; height:auto; }
.illo--tight{ padding:0; }
.illo--tight svg{ padding:12px 12px 0; }
.illo__cap{
  font-family:var(--mono); font-size:.71875rem; letter-spacing:.02em;
  color:var(--dimmer); margin-top:12px; line-height:1.7; max-width:92ch;
}

/* ---------- buttons ------------------------------------------------------ */
.btnrow{ display:flex; flex-wrap:wrap; gap:10px; margin-top:20px; }
.btn{
  display:inline-flex; align-items:center; gap:9px;
  font-family:var(--mono); font-size:.75rem; font-weight:700;
  letter-spacing:.1em; text-transform:uppercase; padding:13px 19px;
  border:1px solid var(--rule); color:var(--ink);
  background:linear-gradient(180deg,#1c2733,#141d26);
  box-shadow:inset 0 1px 0 var(--lift);
  text-decoration:none; cursor:pointer;
  transition:border-color .18s var(--ease), color .18s var(--ease),
             box-shadow .18s var(--ease), transform .18s var(--ease);
}
.btn:hover{
  border-color:var(--steel); color:#fff; text-decoration:none; transform:translateY(-1px);
  box-shadow:inset 0 1px 0 var(--lift), 0 0 0 3px var(--steel-glow);
}
.btn:active{ transform:translateY(0); }
/* the primary action is STEEL. Amber is a status and it is not for sale. */
.btn--go{
  background:linear-gradient(180deg,#6ea6d6,#4b81b1);
  border-color:#79b0dd; color:#07121b;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3), 0 0 0 0 var(--steel-glow);
}
.btn--go:hover{
  background:linear-gradient(180deg,#83b8e4,#5a91c1);
  border-color:#96c8f0; color:#07121b;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35), 0 0 0 4px var(--steel-glow);
}

/* ---------- form --------------------------------------------------------- */
.form{ border:1px solid var(--rule); background:var(--board2); }
.form__row{ padding:14px 16px; border-bottom:1px solid var(--rule-soft); }
.form__row:last-child{ border-bottom:0; }
label{ display:block; font-family:var(--mono); font-size:.65625rem; letter-spacing:.15em; text-transform:uppercase; color:var(--dim); margin-bottom:7px; }
input,select,textarea{
  width:100%; max-width:100%; background:#0b1016; border:1px solid var(--rule);
  color:var(--ink); font-family:var(--mono); font-size:.875rem; padding:10px 12px;
}
input,select,textarea{ transition:border-color .16s var(--ease), box-shadow .16s var(--ease); }
input:hover,select:hover,textarea:hover{ border-color:var(--steel-dim); }
input:focus,select:focus,textarea:focus{
  outline:2px solid var(--steel); outline-offset:-1px;
  box-shadow:0 0 0 4px var(--steel-glow);
}
textarea{ min-height:110px; font-family:var(--sans); line-height:1.55; }
fieldset{ border:0; padding:0; margin:0; }

/* ---------- footer ------------------------------------------------------- */
.foot{
  border-top:1px solid var(--rule); margin-top:70px; padding:30px 0 42px;
  background:linear-gradient(180deg,#0e151d 0%,#080d13 100%);
  box-shadow:inset 0 1px 0 var(--lift);
}
.foot__grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr)); gap:24px; }
.foot h4{ font-family:var(--mono); font-size:.625rem; letter-spacing:.17em; text-transform:uppercase; color:var(--dim); margin:0 0 10px; }
.foot ul{ list-style:none; margin:0; padding:0; }
.foot li{ margin-bottom:6px; font-size:.875rem; }
.foot a{ color:var(--ink2); }
.foot a:hover{ color:var(--steel); }
.foot__note{ margin-top:26px; padding-top:18px; border-top:1px solid var(--rule); font-family:var(--mono); font-size:.6875rem; color:var(--dimmer); line-height:1.7; }

/* ---------- chat launcher (bottom LEFT — the host page owns bottom right) - */
.chatlaunch{
  position:fixed; left:16px; bottom:16px; z-index:60;
  display:flex; align-items:center; gap:9px;
  font-family:var(--mono); font-size:.71875rem; font-weight:700; letter-spacing:.11em;
  text-transform:uppercase; color:#07121b;
  background:linear-gradient(180deg,#6ea6d6,#4b81b1);
  border:0; padding:13px 16px; cursor:pointer;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3), 0 8px 26px rgba(0,0,0,.55);
  transition:background .18s var(--ease), box-shadow .18s var(--ease), transform .18s var(--ease);
}
.chatlaunch:hover{
  background:linear-gradient(180deg,#83b8e4,#5a91c1); transform:translateY(-1px);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35), 0 10px 30px rgba(0,0,0,.6);
}
.chatpanel{
  position:fixed; left:16px; bottom:16px; z-index:61;
  width:min(340px,calc(100vw - 32px)); max-height:min(560px,calc(100vh - 32px));
  display:none; flex-direction:column;
  background:var(--board2); border:1px solid var(--rule); box-shadow:0 10px 40px rgba(0,0,0,.6);
}
.chatpanel[data-open="1"]{ display:flex; }
.chatpanel__head{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:11px 13px; border-bottom:1px solid var(--rule); background:#0d141c;
  font-family:var(--mono); font-size:.6875rem; letter-spacing:.13em; text-transform:uppercase; color:var(--dim);
}
.chatpanel__x{ background:none; border:0; color:var(--dim); font-size:1.125rem; line-height:1; cursor:pointer; padding:0 2px; }
.chatpanel__x:hover{ color:#fff; }
.chatlog{ padding:13px; overflow-y:auto; flex:1 1 auto; }
.msg{ font-size:.875rem; line-height:1.55; margin-bottom:11px; }
.msg--bot{ color:var(--ink2); border-left:2px solid var(--rule); padding-left:10px; }
.msg--you{ color:#fff; font-family:var(--mono); font-size:.78125rem; text-align:right; }
.chatopts{ padding:0 13px 13px; display:flex; flex-wrap:wrap; gap:7px; }
.chatopt{
  font-family:var(--mono); font-size:.6875rem; letter-spacing:.06em; text-transform:uppercase;
  background:var(--row); border:1px solid var(--rule); color:var(--ink);
  padding:8px 11px; cursor:pointer;
}
.chatopt{ transition:border-color .16s var(--ease), color .16s var(--ease), background-color .16s var(--ease); }
.chatopt:hover{ border-color:var(--steel); color:#fff; background:rgba(91,147,196,.11); }
.chatfoot{ padding:9px 13px; border-top:1px solid var(--rule); font-family:var(--mono); font-size:.625rem; color:var(--dimmer); letter-spacing:.06em; }

/* ---------- responsive ---------------------------------------------------
   ⚠️ The failure mode for a dispatch board is a dense table that overflows at
   375px. Every multi-column grid below collapses to one column and the mono
   column labels turn back on so a stacked row still says what each value is. */
@media (max-width:900px){
  .board{ grid-template-columns:minmax(0,1fr); }
  .board__rail{ border-right:0; border-bottom:1px solid var(--rule); }
  .board__pane{ padding:18px 16px 22px; }
  .panehead{ margin:-18px -16px 16px; padding-left:16px; padding-right:16px; }
}
@media (max-width:700px){
  .queue__head{ display:none; }
  .qrow{ grid-template-columns:minmax(0,1fr); padding:14px 14px; }
  .qrow__label{ display:block; margin-top:8px; }
  .nav{ margin-left:0; width:100%; }
  .callbar{ width:100%; text-align:center; }
  .wo__total{ grid-template-columns:minmax(0,1fr); }
}
@media (max-width:480px){
  body{ font-size:.96875rem; }
  .shell{ padding:0 14px; }
  .demostrip{ padding:9px 14px; font-size:.71875rem; }
  .woline__top{ grid-template-columns:minmax(0,1fr); }
  .woline__price{ color:#fff; }
  .wo__facts{ grid-template-columns:minmax(0,1fr); }
  .kv{ grid-template-columns:minmax(0,1fr); }
  .kv > div{ border-right:0; }
  .jobrow{ font-size:.71875rem; }
  .illo{ padding:8px; }
  .chatlaunch{ left:12px; bottom:12px; font-size:.6875rem; padding:11px 13px; }
  .chatpanel{ left:12px; bottom:12px; width:calc(100vw - 24px); }
}

/* ==========================================================================
   PART TWO — DEPTH, ILLUSTRATION AND MOTION
   Added in the enrichment pass. Everything below is ADDITIVE: nothing here
   is required for a page to be readable, and nothing here is hidden by
   default and switched on by script.
   ========================================================================== */

/* ---------- inline marks (.sym) -----------------------------------------
   A hand-drawn glyph per job type. currentColor throughout so a mark takes
   the color of whatever row it sits in — it is never given a status color
   of its own, because a drawing of a door ding is not a status.          */
.sym{
  display:inline-block; width:24px; height:24px; flex:0 0 auto;
  vertical-align:-5px; color:var(--dimmer);
  transition:color .18s var(--ease), transform .18s var(--ease);
}
.sym svg{ display:block; width:100%; height:100%; }
.sym--lg{ width:40px; height:40px; vertical-align:-11px; }
.sym--xl{ width:56px; height:56px; }
.qrow:hover .sym{ color:var(--steel); transform:translateY(-1px); }
.qrow__mark .sym{ width:26px; height:26px; }
.noitem__head .sym{ width:27px; height:27px; color:var(--no); }
.rulebar .sym{ width:18px; height:18px; color:var(--dim); }

/* a mark set beside a page title */
.titlemark{ display:flex; align-items:center; gap:16px; margin:0 0 6px; }
.titlemark .sym{ color:var(--steel-dim); }
.titlemark h1{ margin:0; }

/* ---------- diagrams (.dgm) ---------------------------------------------
   A drawn explanation, framed like a plate in a manual. Steel keylines,
   mono labels, status color only where the drawing is stating a status.  */
.dgm{
  border:1px solid var(--rule); margin:0;
  background:
    radial-gradient(680px 320px at 30% 0%, rgba(91,147,196,.07) 0%, rgba(91,147,196,0) 72%),
    linear-gradient(180deg,#101923 0%,#0a1017 100%);
  box-shadow:inset 0 1px 0 var(--lift), 0 18px 40px -32px rgba(0,0,0,1);
}
.dgm svg{ display:block; width:100%; height:auto; padding:16px 16px 4px; }
.dgm__cap{
  display:block; padding:12px 16px 14px; margin:0;
  border-top:1px solid var(--rule); background:rgba(0,0,0,.26);
  font-family:var(--mono); font-size:.75rem; letter-spacing:.015em;
  color:var(--dim); line-height:1.75; max-width:96ch;
}
.dgm__cap b{ color:var(--steel); font-weight:700; }

/* ---------- designed photograph slots (.slot) ----------------------------
   Photographs are coming. Until they do, the space they will occupy is
   BUILT, at the aspect ratio the real frame will have, filled with line
   art and named in the caption so the shoot list writes itself.
   ⛔ There is no before/after slot here and one must never be added. In
   this trade a before/after pair IS the result, so an empty one would be
   a promise, and a filled one would be a fabricated repair.              */
.slotgrid{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));
  gap:16px; align-items:start;   /* ⛔ never stretch: a 16:9 frame beside a 4:3
                                    one would grow dead space under the short one */
}
.slot{
  position:relative; min-width:0;
  /* ⛔ a lone slot in an auto-fit grid absorbs the whole row: a 4:3 frame
     1134px wide is 850px tall and reads as a hero, not as a plate.        */
  max-width:440px;
  border:1px solid var(--rule);
  background:linear-gradient(158deg,#141d27 0%,#0c1219 58%,#0f1822 100%);
  box-shadow:inset 0 1px 0 var(--lift);
  transition:border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.slot:hover{ border-color:var(--steel-dim); box-shadow:inset 0 1px 0 var(--lift), 0 0 0 3px var(--steel-glow); }
.slot__art{ display:block; width:100%; height:auto; }
.slot--wide .slot__art{ aspect-ratio:16/9; }
.slot--box  .slot__art{ aspect-ratio:4/3; }
.slot--tall .slot__art{ aspect-ratio:3/2; }
/* corner ticks — a registration frame, so the slot reads as deliberate */
.slot::before,.slot::after{
  content:""; position:absolute; width:13px; height:13px; pointer-events:none;
  border:1px solid var(--steel-dim); opacity:.55;
}
.slot::before{ top:7px; left:7px; border-right:0; border-bottom:0; }
.slot::after{ top:7px; right:7px; border-left:0; border-bottom:0; }
.slot__cap{
  display:flex; flex-wrap:wrap; align-items:baseline; gap:4px 10px;
  padding:10px 13px; border-top:1px solid var(--rule); background:rgba(0,0,0,.3);
  font-family:var(--mono); font-size:.65625rem; letter-spacing:.13em;
  text-transform:uppercase; color:var(--dimmer);
}
.slot__tag{ color:var(--steel); font-weight:700; }
.slot__what{ color:var(--ink2); }
.slot__ratio{ margin-left:auto; color:var(--dimmer); }
.slotnote{
  margin:12px 0 0; font-family:var(--mono); font-size:.6875rem; line-height:1.7;
  letter-spacing:.04em; color:var(--dimmer);
}

/* the existing honesty block, tightened */
.frame{ box-shadow:inset 0 1px 0 var(--lift); }

/* ---------- the pane swap ------------------------------------------------
   The work order for job 4417 is IN THE HTML and is on screen with no
   script running at all. The script only adds the ability to look at a
   different row, and it transitions rather than snapping.                */
.paneswap{ transition:opacity .19s var(--ease), transform .19s var(--ease); }
.paneswap[data-out="1"]{ opacity:0; transform:translateY(6px); }
.jobrow[data-pick]{ cursor:pointer; }
.jobrow[data-pick]:hover{ background:rgba(91,147,196,.085); color:var(--ink); }
.jobrow[data-pick]:hover .jobrow__meta{ color:var(--ink2); }
.jobrow[data-pick]:focus-visible{ outline:2px solid var(--steel); outline-offset:-2px; }
.jobcard{ border:1px solid var(--rule); background:linear-gradient(180deg,#16202a,#111a23); box-shadow:inset 0 1px 0 var(--lift); }
.jobcard__head{
  display:flex; flex-wrap:wrap; gap:6px 20px; align-items:baseline;
  padding:15px 16px; border-bottom:1px solid var(--rule);
  background:linear-gradient(180deg,#1a2531,#101922);
  font-family:var(--mono); font-size:.71875rem; letter-spacing:.08em; color:var(--dim);
}
.jobcard__no{ font-size:.9375rem; font-weight:700; color:#fff; letter-spacing:.06em; }
.jobcard__body{ padding:15px 16px; }
.jobcard__body p{ font-size:.90625rem; color:var(--ink2); max-width:62ch; }
.jobcard__body p:last-child{ margin-bottom:0; }
.jobcard__back{
  display:inline-block; margin-top:4px; font-family:var(--mono); font-size:.6875rem;
  letter-spacing:.11em; text-transform:uppercase;
}

/* ==========================================================================
   MOTION
   Rules: the DEFAULT STATE IS VISIBLE. Entrance animations are attached to
   an .is-in class the script adds when the board scrolls into view — if the
   script never runs, every row and the whole work order is simply there.
   One thing pulses, not everything: the amber pip on the row that is
   actually moving right now.
   ========================================================================== */
@keyframes rowIn{
  from{ opacity:0; transform:translateX(-10px); }
  to  { opacity:1; transform:none; }
}
@keyframes paneIn{
  from{ opacity:0; transform:translateY(9px); }
  to  { opacity:1; transform:none; }
}
@keyframes pipPulse{
  0%,100%{ box-shadow:0 0 0 3px rgba(226,166,63,.14), 0 0 8px rgba(226,166,63,.42); }
  50%    { box-shadow:0 0 0 6px rgba(226,166,63,.05), 0 0 16px rgba(226,166,63,.85); }
}
@keyframes rodSweep{
  from{ transform:translateX(0); }
  to  { transform:translateX(150px); }
}
@keyframes lineDraw{
  from{ stroke-dashoffset:var(--dash,300); }
  to  { stroke-dashoffset:0; }
}

/* rows arriving in sequence, like a queue populating */
.board.is-in .jobrow{ animation:rowIn .44s var(--ease) backwards; }
.board.is-in .jobrow:nth-of-type(1){ animation-delay:.03s }
.board.is-in .jobrow:nth-of-type(2){ animation-delay:.09s }
.board.is-in .jobrow:nth-of-type(3){ animation-delay:.15s }
.board.is-in .jobrow:nth-of-type(4){ animation-delay:.21s }
.board.is-in .jobrow:nth-of-type(5){ animation-delay:.27s }
.board.is-in .jobrow:nth-of-type(6){ animation-delay:.33s }
.board.is-in .jobrow:nth-of-type(7){ animation-delay:.39s }
.board.is-in .jobrow:nth-of-type(8){ animation-delay:.45s }
.board.is-in .board__pane{ animation:paneIn .5s var(--ease) .26s backwards; }

.queue.is-in .qrow{ animation:rowIn .4s var(--ease) backwards; }
.queue.is-in .qrow:nth-of-type(1){ animation-delay:.03s }
.queue.is-in .qrow:nth-of-type(2){ animation-delay:.08s }
.queue.is-in .qrow:nth-of-type(3){ animation-delay:.13s }
.queue.is-in .qrow:nth-of-type(4){ animation-delay:.18s }
.queue.is-in .qrow:nth-of-type(5){ animation-delay:.23s }
.queue.is-in .qrow:nth-of-type(6){ animation-delay:.28s }
.queue.is-in .qrow:nth-of-type(7){ animation-delay:.33s }
.queue.is-in .qrow:nth-of-type(8){ animation-delay:.38s }
.queue.is-in .qrow:nth-of-type(9){ animation-delay:.43s }

.nolist.is-in .noitem{ animation:rowIn .4s var(--ease) backwards; }
.nolist.is-in .noitem:nth-of-type(1){ animation-delay:.04s }
.nolist.is-in .noitem:nth-of-type(2){ animation-delay:.11s }
.nolist.is-in .noitem:nth-of-type(3){ animation-delay:.18s }
.nolist.is-in .noitem:nth-of-type(4){ animation-delay:.25s }
.nolist.is-in .noitem:nth-of-type(5){ animation-delay:.32s }

/* ONE pip pulses: the van that is on the road right now. Not the waiting
   row, not the demo strip, not the chat launcher. One thing moving.     */
.pip--live{ animation:pipPulse 2.9s ease-in-out infinite; }

/* the line-board diagram's traveling reflection — the one piece of motion
   that is actually explaining something: this is what the tech is doing. */
.dgm__sweep{ animation:rodSweep 5.5s ease-in-out infinite alternate; }
.dgm__draw{ animation:lineDraw 1.6s var(--ease) backwards; }

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  .board.is-in .jobrow,
  .queue.is-in .qrow,
  .nolist.is-in .noitem,
  .board.is-in .board__pane{ animation:none; opacity:1; transform:none; }
  .pip--live{ animation:none; }
  .dgm__sweep{ animation:none; }
  .btn:hover{ transform:none; }
  .chatlaunch:hover{ transform:none; }
}

/* ---------- responsive additions for the new pieces --------------------- */
@media (max-width:700px){
  .queue--marked .qrow{ grid-template-columns:26px minmax(0,1fr); }
  .queue--marked .qrow__mark{ grid-row:1; }
  .queue--marked .qrow__name{ grid-column:2; }
  .queue--marked .qrow__dur,
  .queue--marked .qrow__where,
  .queue--marked .qrow__note{ grid-column:1/-1; }
  .slotgrid{ grid-template-columns:minmax(0,1fr); }
  .titlemark{ gap:12px; }
}
@media (max-width:480px){
  .rulebar{ margin:46px 0 18px; letter-spacing:.14em; }
  .dgm svg{ padding:10px 10px 2px; }
  .dgm__cap{ padding:10px 12px; letter-spacing:.09em; }
  .slot__cap{ letter-spacing:.09em; font-size:.625rem; }
  .slot__ratio{ margin-left:0; }
  .sym--xl{ width:42px; height:42px; }
  .titlemark{ gap:11px; }
}

/* ---------- the four cases where paintless repair gets a no -------------
   Four small drawn cases rather than one wide diagram, so a phone stacks
   them instead of shrinking a single plate into illegibility.            */
.nogrid{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));
  border:1px solid var(--rule); border-left:3px solid var(--no);
  background:linear-gradient(180deg,#111923 0%,#0b1118 100%);
  box-shadow:inset 0 1px 0 var(--lift);
}
.nocase{
  min-width:0; padding:16px 18px 18px;
  border-right:1px solid var(--rule); border-bottom:1px solid var(--rule);
  transition:background-color .18s var(--ease);
}
.nocase:hover{ background:rgba(226,96,79,.05); }
.nocase__art{
  border:1px solid var(--rule); background:linear-gradient(170deg,#131c26,#090e15);
  box-shadow:inset 0 1px 0 var(--lift);
}
.nocase__art svg{ display:block; width:100%; height:auto; }
.nocase__cap{
  display:flex; align-items:baseline; gap:9px; margin-top:12px;
  font-family:var(--mono); font-size:.71875rem; font-weight:700; letter-spacing:.09em;
  text-transform:uppercase; color:var(--no); line-height:1.4;
}
.nocase__n{ color:var(--dimmer); font-weight:700; }
.nocase__note{ margin:8px 0 0; font-size:.875rem; color:var(--ink2); }
.nogrid.is-in .nocase{ animation:rowIn .42s var(--ease) backwards; }
.nogrid.is-in .nocase:nth-of-type(1){ animation-delay:.04s }
.nogrid.is-in .nocase:nth-of-type(2){ animation-delay:.12s }
.nogrid.is-in .nocase:nth-of-type(3){ animation-delay:.20s }
.nogrid.is-in .nocase:nth-of-type(4){ animation-delay:.28s }

/* a slot grid arriving with the section */
.slotgrid.is-in .slot{ animation:paneIn .5s var(--ease) backwards; }
.slotgrid.is-in .slot:nth-of-type(2){ animation-delay:.11s }
.slotgrid.is-in .slot:nth-of-type(3){ animation-delay:.22s }
.dgm.is-in{ animation:paneIn .55s var(--ease) backwards; }

@media (prefers-reduced-motion: reduce){
  .nogrid.is-in .nocase,
  .slotgrid.is-in .slot,
  .dgm.is-in{ animation:none; opacity:1; transform:none; }
}


/* ═══ 📱 MOBILE MENU — added 8 Sep 2026. See tools/navfix notes.
   ⛔ Do not give this a colour. The panel IS this site's own <nav>, so it
   keeps this site's own paper and rules; the button rides on currentColor.
   ⛔ Do not raise the breakpoint without re-measuring — 860 is where these
   nav rows start wrapping, which is the thing being fixed. */
.navbtn { display: none; }
.navq { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
        overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
@media (max-width: 860px) {
  .navbtn {
    display: inline-flex; align-items: center; gap: .55rem;
    padding: .5rem .8rem; border-radius: .5rem; cursor: pointer;
    font: inherit; font-size: .82rem; letter-spacing: .06em; text-transform: uppercase;
    color: currentColor;
    border: 1px solid currentColor;
    background: transparent;
    opacity: .85;
  }
  .navbtn__ico { position: relative; width: 15px; height: 2px; background: currentColor; }
  .navbtn__ico::before, .navbtn__ico::after {
    content: ""; position: absolute; left: 0; width: 15px; height: 2px; background: currentColor;
  }
  .navbtn__ico::before { top: -5px; }
  .navbtn__ico::after  { top:  5px; }
  .navq:focus-visible + .navbtn { outline: 2px solid currentColor; outline-offset: 2px; }

  /* the demo's own nav, closed */
  nav[aria-label="Main"], nav[aria-label="Primary"] { display: none; }
  .navq:checked ~ nav[aria-label="Main"],
  .navq:checked ~ nav[aria-label="Primary"] { display: block; width: 100%; }

  /* ⚠️ the lists inside are flex rows on every one of these sites; they have to
     stack, and the row gap has to become a tap target. */
  nav[aria-label="Main"] ul, nav[aria-label="Primary"] ul {
    display: block; margin: 0; padding: 0; list-style: none;
  }
  nav[aria-label="Main"] li, nav[aria-label="Primary"] li { display: block; }
  nav[aria-label="Main"] li a, nav[aria-label="Primary"] li a,
  nav[aria-label="Main"] > a, nav[aria-label="Primary"] > a {
    display: block; padding: .7rem .2rem; line-height: 1.2;
  }
  nav[aria-label="Main"] li + li, nav[aria-label="Primary"] li + li {
    border-top: 1px solid currentColor;
  }
  nav[aria-label="Main"] li + li, nav[aria-label="Primary"] li + li { border-top-color: color-mix(in srgb, currentColor 18%, transparent); }
}


/* ═══ 🔤 NAV TYPE PASS 9 Sep 2026 — size and tracking only.
   ⛔ Do not add colour, family, case or weight here: those are what keep these
   twelve sites from converging, and converging is the thing that was fixed
   once already. Measured before: 11–12.5px with tracking wide enough that
   the label read as separate letters rather than a word. */
nav[aria-label="Main"] a,
nav[aria-label="Primary"] a {
  font-size: .8125rem;
  letter-spacing: .1em;
}

/* ═══ 🖼️ THE HERO ART, A LITTLE HIGHER — 9 Sep 2026.
   Measured at 1440x900: the van drawing began at y=547 and 353px of its 555
   were already above the fold, so this one was the mildest of the three and
   needed a nudge rather than a rebuild. The gap above it closes and the
   drawing is capped so it finishes inside the first screen.
   ⛔ Its own numbers, its own layout — see the note in the roofing and
   auto-detailing sheets. These twelve must not converge. */
@media (min-width: 900px) {
  .hero .illo, .showcase .illo { margin-top: 14px !important; }
  .hero .illo svg, .showcase .illo svg { max-height: 44vh; width: 100%; height: auto; }
  .hero h1 { margin-bottom: .6rem; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ⭐ THE PROFESSIONAL PASS — 11 Sep 2026.
   Measured against the reference client rebuild, this demo was missing four things:
     1. no brand MARK — "CURBSIDE" set in mono is a wordmark, not a mark
     2. no colour anywhere in the headline
     3. no offer strip, so nothing said what you actually get before scroll
     4. the primary button was steel, the same blue as every keyline, rule and
        focus ring on the page — a colour that is everywhere points at nothing
   ⛔ No photograph closes this gap. Every illustration here is drawn, and the
   captions say so. the reference site's own instrument is a rendered graphic, not a photo.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── the mark ─────────────────────────────────────────────────────────── */
/* A high-roof panel van with a roof rack, in side profile on a dashed road.
   ⚠️ It was a beacon first, and the beacon was WRONG: a dome with radial rays
   reads as a SUNRISE at 26px, which is what a blind look at it showed. A
   rotating-sweep version read as a wifi symbol. The van is the only one of the
   three that is unmistakable at mark size, and the rack is what stops it
   reading as a delivery van. ⭐ Blind-test a mark at its real size before
   shipping it — every one of these was obvious once rendered at 26px. */
.mark{align-items:center}
.mark__name{display:inline-flex;align-items:center;gap:9px}
.nav__mark{
  width:26px;height:26px;flex:0 0 auto;color:var(--hivis);
  transition:transform .2s var(--ease);
}
.mark__name:hover .nav__mark{transform:translateY(-1px)}

/* ── the headline carries the colour ──────────────────────────────────── */
/* <em> so it still reads as emphasis with styles off; the slant comes off
   because the display face leans on weight, not italics. */
h1 .hl{font-style:normal;color:var(--hivis)}

/* ── the offer strip ──────────────────────────────────────────────────── */
/* ⭐ the reference site's coupon bar in this shop's own words — both clauses lifted off the
   home page hero. ⛔ It must never carry a price, a rating or a count this
   demo has not published elsewhere. */
.offerbar{
  border-bottom:1px solid var(--rule);
  background-image:linear-gradient(180deg,var(--row),var(--board2));
  box-shadow:inset 0 1px 0 var(--lift2);
}
.offerbar__in{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding-top:10px;padding-bottom:10px}
.offerbar__tag{
  font-family:var(--mono);font-size:.65625rem;text-transform:uppercase;letter-spacing:.14em;
  color:var(--hivis);
  border:1px solid color-mix(in srgb, var(--hivis) 40%, transparent);
  border-radius:999px;padding:3px 9px;flex:0 0 auto;
}
.offerbar__msg{margin:0;font-size:.84375rem;line-height:1.45;color:var(--ink2);flex:1 1 340px;min-width:0}
.offerbar__msg b{color:#fff;font-weight:700}
.offerbar__go{
  flex:0 0 auto;font-family:var(--mono);font-size:.71875rem;text-transform:uppercase;
  letter-spacing:.09em;color:var(--ink);text-decoration:none;white-space:nowrap;
  border-bottom:1px solid color-mix(in srgb, var(--hivis) 60%, transparent);padding-bottom:2px;
}
.offerbar__go:hover{color:var(--hivis);border-bottom-color:var(--hivis)}
@media (max-width:640px){
  .offerbar__go{display:none}        /* the hero button is a screen below it */
  .offerbar__msg{font-size:.78125rem}
}

/* ── depth on the drawn hero ──────────────────────────────────────────── */
/* ⭐ What separates the reference site's instrument from a flat vector is one light and a
   real cast shadow. The frame had a 34px-inset shadow that never reached the
   page; this one lands on it. */
.hero .illo,
.showcase .illo{
  box-shadow:inset 0 1px 0 var(--lift), 0 36px 64px -30px rgba(0,0,0,1);
}
.hero .illo svg,
.showcase .illo svg{filter:contrast(1.05) saturate(1.05)}

@media (prefers-reduced-motion:reduce){
  .mark__name:hover .nav__mark{transform:none}
}

/* ── the primary button is the accent, not steel ──────────────────────── */
/* 🔴 THE ORDER IN THIS BLOCK IS INVERTED RELATIVE TO THE ROOFING TEMPLATE,
   AND ON PURPOSE. On roofing, `.btn` is the primary and `.btn--ghost` is the
   modifier, so the ghost is restated LAST. Here it is the other way round:
   `.btn` is the secondary and `.btn--go` is the primary modifier — so an
   appended bare `.btn` rule is what would eat the primary, since `.btn` and
   `.btn--go` are the SAME specificity in an unlayered file and a `.btn--go`
   element carries BOTH classes. Two primaries is no primary, and so is none.
   ⭐ So the secondary is restated with `:not(.btn--go)`, which cannot match a
   primary at all. ⛔ Any future rule appended below this point must keep that
   guard, or source order decides which button is loud. */
.btn:not(.btn--go){
  border-color:var(--rule); color:var(--ink);
  background:linear-gradient(180deg,#1c2733,#141d26);
  box-shadow:inset 0 1px 0 var(--lift);
}
.btn:not(.btn--go):hover{
  border-color:var(--steel); color:#fff;
  box-shadow:inset 0 1px 0 var(--lift), 0 0 0 3px var(--steel-glow);
}
.btn--go{
  background:linear-gradient(180deg,var(--hivis),var(--hivis-lo));
  border-color:#ffc44d; color:#0b0f14; font-weight:700;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35), 0 0 0 0 var(--hivis-glow);
}
.btn--go:hover{
  background:linear-gradient(180deg,#ffc02e,var(--hivis));
  border-color:#ffd580; color:#0b0f14;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4), 0 0 0 4px var(--hivis-glow);
}

/* ── 🚐 THE DAY, AS THE CUSTOMER HAS IT — 11 Sep 2026 ─────────────────────
   Owner: "make mobile detail van be creative with pictures build a story that
   our customer will want".
   ⭐ The old hero led with the VAN, which is our fact, not the customer's. The
   thing a person actually buys from a mobile trade is the day they do not lose
   — no drop-off, no rental, no afternoon in a waiting room. The van is how; the
   day is why. So the headline says the town and the trade, the accent carries
   the hook, and this section walks the day hour by hour.
   ⛔ Every beat is something this company could really do. Nothing here claims
   a booking is held or confirmed, and 09:05 is a REFUSAL — the one beat a real
   customer repeats to someone else. */
.sec--day .day{list-style:none;margin:1.75rem 0 0;padding:0;display:grid;gap:0}
.day__i{
  /* ⭐ 5.5rem, not 84px: the track has to grow when a reader turns their text
     size up, or the timestamp outgrows a fixed column. minmax(0,1fr) so the
     prose column can actually shrink instead of pushing the row wide. */
  display:grid;grid-template-columns:5.5rem minmax(0,1fr);gap:0 1.25rem;
  padding:1.15rem 0;border-top:1px solid var(--hair,rgba(255,255,255,.1));
  align-items:start;
}
.day__i:first-child{border-top:0}
/* 🔴 THE THREE CHILDREN MUST BE PLACED, NOT AUTO-FLOWED. A grid with two
   columns and three children puts the THIRD one back in column 1 — so the
   paragraph lands under the timestamp and wraps at about ten characters,
   breaking words in half ("appointmen/t", "photograph/s"). It looks like a
   rendering fault and it is only visible once you actually open the page: the
   markup is correct, the CSS is short, and every gate passes.
   ⛔ Never leave these three rules implicit. */
.day__t{
  grid-column:1;grid-row:1 / span 2;
  font-family:var(--mono,ui-monospace),monospace;font-size:.8125rem;letter-spacing:.06em;
  color:var(--hivis,#FFB000);padding-top:.15rem;white-space:nowrap;
}
.day__i h3{grid-column:2;grid-row:1;margin:0 0 .3rem;font-size:1.02rem;line-height:1.25}
.day__i p{grid-column:2;grid-row:2;margin:0;font-size:.9375rem;line-height:1.55;color:var(--ink-2,#b2bcc6);max-width:62ch}
/* ⭐ one beat is marked, and it is the ARRIVAL — the moment the promise in the
   headline actually happens. ⛔ Not the sale; the sale is not the story. */
.day__i--live{position:relative}
.day__i--live .day__t::after{
  content:"";display:inline-block;width:6px;height:6px;border-radius:50%;
  background:var(--hivis,#FFB000);margin-left:6px;vertical-align:middle;
}
.day__foot{
  margin:1.5rem 0 0;padding-top:1.15rem;border-top:1px solid var(--hair,rgba(255,255,255,.1));
  font-size:.9375rem;line-height:1.6;color:var(--ink-2,#b2bcc6);
}
.day__foot b{color:var(--ink,#f2f5f8)}
@media (max-width:560px){
  .day__i{grid-template-columns:1fr;gap:.35rem}
  /* ⛔ and release the explicit placement with it, or all three children stack
     into one cell */
  .day__t{grid-column:1;grid-row:auto;padding-top:0}
  .day__i h3,.day__i p{grid-column:1;grid-row:auto}
}

/* ── 📷 A REAL DENT — 11 Sep 2026 ─────────────────────────────────────────
   Owner supplied real shop photography and said to use it: crop the branded
   banner out, then use the photos.
   🔴 CROPPED, AND THE CROP IS THE POINT. The original frame carried a real
   licensee's branded banner across the back wall. On a site for a FICTIONAL
   company that is another shop's brand on somebody else's page — a defect this
   estate has shipped before — and a reverse image search would land a prospect
   on the wrong business. The top 30% is gone; what is left is the door panel,
   which was the subject anyway.
   ⛔ AND THE BRAND IS NOT NAMED HERE EITHER. The first version of this comment
   spelled the licensee out, and check-demo-polish.mjs refused the build — a CSS
   comment is served to the browser, so naming a private client in one is the
   same leak as putting it on the page. The gate was right and I was the one who
   wrote it in.
   ⭐ It earns its place here because Curbside IS paintless dent repair, and the
   caption says the one thing the photograph actually proves: the paint is
   unbroken. ⛔ Do not caption it as this company's own job. */
.photoband{position:relative;margin:0;line-height:0}
.photoband img{width:100%;height:clamp(200px,24vw,320px);object-fit:cover;display:block}
.photoband__cap{
  position:absolute;left:0;right:0;bottom:0;
  padding:10px 14px;font-size:.78125rem;line-height:1.45;
  color:rgba(255,255,255,.92);
  background:linear-gradient(180deg,rgba(11,15,20,0),rgba(11,15,20,.86));
}


/* 🔴 THE TIMELINE'S THIRD CHILD FELL INTO COLUMN ONE — found 11 Sep 2026 by the
   agent porting this template to four other demos, and it was in MY original.
   `.day__i` is a two-column grid holding THREE children (time, h3, p), so
   auto-placement wrapped the paragraph back under the timestamp and rendered it
   84px wide at 1280 — measured, not guessed. Each beat stood ~387px tall for no
   reason. ⛔ Both the heading and the paragraph have to be pinned to column 2,
   and the pin has to be undone inside the phone breakpoint or it invents an
   implicit column there. */
.day__i > h3, .day__i > p { grid-column: 2; }
@media (max-width:560px){
  .day__i > h3, .day__i > p { grid-column: 1; }
}

/* ── 📷 PHOTOGRAPHS ───────────────────────────────────────────────────────
   🔴 11 Sep 2026. Owner: "need photos!!" and "no stick diagrams". This demo
   shipped with none, and a page of line drawings reads as a prototype rather
   than as a business's site.

   ⭐ PORTABLE ON PURPOSE. Thirteen demos, thirteen different token names —
   --soil/--panel/--hair here, --paper/--rule/--gr there, light and dark both.
   A component written against one demo's variables is a component that has to
   be rewritten twelve times and will be wrong in four of them. So this uses
   `currentColor` and plain rgba, and inherits the page's own ink.

   ⛔ Every CC BY / CC BY-SA frame carries its credit IN the frame. Attribution
   is a licence term, not a courtesy, and "we'll add the credits later" is
   exactly how a licence gets breached. */
.photo{position:relative;margin:0;line-height:0;border-radius:4px;overflow:hidden;
  border:1px solid rgba(128,128,128,.28)}
.photo img{width:100%;display:block;object-fit:cover;filter:saturate(1.03) contrast(1.02)}
.photo--hero img{height:clamp(260px,34vw,430px)}
.photo--band img{height:clamp(190px,26vw,320px)}
.photo--tall img{height:clamp(240px,30vw,380px)}
/* ⚠️ the badge carries its OWN scrim rather than the frame carrying a gradient.
   A gradient tuned for a dark ground turns a light photo muddy along the bottom,
   and half these demos are light. */
.photo__cr{position:absolute;right:8px;bottom:8px;z-index:2;
  font-size:.59375rem;letter-spacing:.04em;line-height:1.45;font-weight:500;
  color:rgba(255,255,255,.88);background:rgba(0,0,0,.52);padding:3px 7px;border-radius:2px;
  text-shadow:0 1px 2px rgba(0,0,0,.5)}
.photo__cr a{color:inherit;text-decoration:underline;text-underline-offset:2px}
.photo__cap{line-height:1.55;font-size:.78125rem;opacity:.72;padding-top:9px}

/* ── 🚪 THE WAY OUT STAYS ON SCREEN ───────────────────────────────────────
   🔴 11 Sep 2026, owner: "need to be able and x out of all the demo sites if
   you view on mobile dont let people get stuck somewher with out easy exit."

   This banner is the only route from a demo back to us, and it sat at the top
   of the document as a static block. On a phone, two swipes down a service page
   and it is gone — a visitor who arrived on a shared link has no way back and
   no reason to think one exists. ⚠️ The link was always there and was always
   unreachable, which is the same shape as the embed's close button being parked
   off-screen above the iframe.

   ⭐ Sticky on phones only. On a desktop the banner is in view at the top of a
   page people can see all of, and pinning it would just spend vertical room. */
@media (max-width: 640px) {
  .demostrip {
    position: sticky;
    top: 0;
    z-index: 90;
  }
  /* ⚠️ AND THE LINK HAS TO BE HITTABLE, NOT MERELY PRESENT. It is inline text
     inside a sentence, so on a 375px screen it wrapped into two fragments 15px
     tall — measured, both genuinely tappable, and both far under the 44px a
     thumb needs. ⭐ Make it a control: one line, real padding, no wrap. */
  .demostrip a {
    display: inline-block;
    margin-top: 4px;
    padding: 11px 12px;
    white-space: nowrap;
    font-weight: 700;
  }
}


/* 🔴 INSIDE OUR OWN FRAME THE BANNER IS DUPLICATE — 11 Sep 2026. Owner, looking
   at the embed on the home page: "take all of this off this is awfull they know
   that". He is right about that surface: our own chrome prints a disclosure
   directly under the frame, in our voice, so the demo's banner made two stacked
   notices — which reads as nervous rather than as honest.
   ⛔ A STANDALONE PAGE KEEPS IT. There the banner is the ONLY notice, and these
   pages carry a live telephone line: an invented business with a working number
   and nothing saying so is a trap, not a demo.
   ⚠️ Fails in the honest direction — with JavaScript off, nothing is hidden.
   ⛔ If the note under the frame is ever removed, delete this rule first. */
html[data-embedded] .demostrip { display: none !important; }


/* ── 🧭 THE UTILITY BAR — 15 Sep 2026 ─────────────────────────────────
   Written by tools/demo-utilbar.mjs. See that file for why the disclosure
   banner became a chip and why hours are absent on the demos that publish none.
   ⛔ Self-contained colour on purpose: every demo means something different by
   --ink, and borrowing it painted this a different thing on each site. */
.utilbar{background:#0f1b2a;color:rgba(255,255,255,.92);
  border-bottom:1px solid rgba(255,255,255,.14);font-size:.78rem;line-height:1.4;
  font-family:system-ui,-apple-system,"Segoe UI",sans-serif}
.utilbar__in{display:flex;align-items:center;justify-content:space-between;
  gap:.9rem;min-height:38px;padding:.3rem 20px;flex-wrap:wrap;
  max-width:1180px;margin:0 auto}
.utilbar__hours{margin:0;display:flex;align-items:center;gap:.45rem;min-width:0}
.utilbar__hours b{font-weight:600;color:#fff}
.utilbar__sep{opacity:.45}
.utilbar__hours>span:last-child{opacity:.72}
.utilbar__right{display:flex;align-items:center;gap:.9rem;flex-wrap:wrap;min-width:0}
.utilbar__lnk{color:rgba(255,255,255,.88);text-decoration:none;
  border-bottom:1px solid rgba(255,255,255,.26);padding-bottom:1px}
.utilbar__lnk:hover{color:#fff;border-bottom-color:#fff}
/* ⭐ colour is never the only carrier — the words say Open or Closed outright */
.utilbar__dot{width:8px;height:8px;border-radius:50%;flex:0 0 auto;background:#7fe0a8}
.utilbar__hours[data-state="open"] .utilbar__dot{background:#7fe0a8;animation:utilpulse 3s ease-out infinite}
.utilbar__hours[data-state="soon"] .utilbar__dot{background:#ffc861}
.utilbar__hours[data-state="shut"] .utilbar__dot{background:#9aa6b1}
@keyframes utilpulse{0%{box-shadow:0 0 0 0 rgba(127,224,168,.5)}
  70%{box-shadow:0 0 0 6px rgba(127,224,168,0)}100%{box-shadow:0 0 0 0 rgba(127,224,168,0)}}
@media (prefers-reduced-motion:reduce){.utilbar__dot{animation:none !important}}
.utilbar .demostrip{display:inline-flex;align-items:center;gap:.4rem;
  padding:.16rem .55rem;border-radius:999px;background:rgba(255,255,255,.10);
  border:1px solid rgba(255,255,255,.22);font-size:.72rem;color:#fff;
  text-decoration:none;cursor:pointer}
.utilbar .demostrip:hover{background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.38)}
.utilbar .demostrip b{text-transform:uppercase;letter-spacing:.08em;font-size:.68rem;font-weight:700}
.utilbar .demostrip__dot{width:7px;height:7px;border-radius:50%;background:#ff6a55;display:block}
@media (max-width:860px){
  /* ⛔ the TAIL hides, never the notice — and the chip becomes the link to it */
  .utilbar__demotail{display:none}
  .utilbar__in{gap:.55rem}
  .utilbar__right{gap:.7rem}
  .utilbar .demostrip{min-height:30px}
}
@media (max-width:560px){
  .utilbar{font-size:.72rem}
  .utilbar__hours>span:last-child,.utilbar__sep{display:none}
  .utilbar .demostrip{min-height:34px;padding-inline:.7rem}
}
/* ⛔ Inside our own iframe the surrounding chrome carries the disclosure, so the
   chip is hidden there and ONLY there. A standalone page always keeps it. */
html[data-embedded] .utilbar .demostrip{display:none !important}

/* 🔴 NO STATUS LIGHT WITHOUT A STATUS — 15 Sep 2026. Six of these demos publish
   no hours at all, and one publishes "by appointment". The dot is a status
   light: green, beside a company name with nothing behind it, it silently says
   OPEN NOW about a business whose hours nobody ever wrote. It only appears once
   the script has decided a real state from real published hours.
   ⚠️ This shipped for one sync because the fix was written into a script that
   died on an assertion BEFORE the file was saved — the edit was reported and
   never landed. Verify the artefact, not the log line. */
.utilbar__hours:not([data-state]) .utilbar__dot{display:none}


/* ── 🖼️ THE PHOTOGRAPH IS THE HERO — 15 Sep 2026 ─────────────────────────
   Written by tools/demo-photo-hero.mjs; the reasoning lives there. */
.lanaihero{position:relative;isolation:isolate;display:flex;flex-direction:column;justify-content:center;
  min-height:clamp(330px,62vh,600px);overflow:hidden;background:#07182a}
.lanaihero>img{position:absolute;inset:0;z-index:0;width:100%;height:100%;
  object-fit:cover;object-position:center 58%}
/* 🔴 TWO GRADIENTS, BOTH LOAD-BEARING. The horizontal one carries the headline;
   the vertical one holds the eyebrow and the buttons, which sit where the
   horizontal scrim has already thinned out. */
.lanaihero__scrim{position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(90deg, rgba(5,18,32,.93) 0%, rgba(5,18,32,.86) 38%,
                           rgba(5,18,32,.46) 70%, rgba(5,18,32,.24) 100%),
    linear-gradient(0deg,  rgba(5,18,32,.42) 0%, rgba(5,18,32,.30) 50%,
                           rgba(5,18,32,.14) 100%)}
/* ⛔ padding-block, never the shorthand — a `padding: X 0 Y` here wipes the
   horizontal gutter the wrap class contributes and every line goes flush to the
   edge of the screen. That shipped once. */
.lanaihero__in{position:relative;z-index:2;
  padding-block:clamp(2rem,5vw,3.4rem) clamp(1.9rem,4.5vw,3rem)}
.lanaihero h1{color:#fff;max-width:20ch;text-wrap:balance}
.lanaihero .h1__where{color:#fff}
.lanaihero .hl{color:rgba(255,255,255,.74)}
.lanaihero .eyebrow,.lanaihero .lbl,.lanaihero .kicker{color:rgba(255,255,255,.88)}
.lanaihero .btnrow,.lanaihero .hero__act{margin-top:1.4rem;display:flex;flex-wrap:wrap;gap:.7rem}
/* ⛔ A ghost/outline button is a hairline on paper; over a photograph it
   disappears. WCAG 2.2 asks 3:1 for the control's own boundary, not just its
   label. */
.lanaihero .btn--ghost,.lanaihero .btn--line,.lanaihero .btn--out{
  border-color:rgba(255,255,255,.62);color:#fff;background:rgba(7,22,38,.42);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.lanaihero .btn--ghost:hover,.lanaihero .btn--line:hover,.lanaihero .btn--out:hover{
  background:rgba(7,22,38,.66);border-color:#fff}
.lanaihero .photo__cr{position:absolute;right:10px;bottom:9px;z-index:3;
  font-size:.625rem;color:rgba(255,255,255,.8);background:rgba(0,0,0,.5);
  padding:3px 7px;border-radius:3px}
.lanaihero .photo__cr a{color:inherit}
@media (max-width:640px){
  /* ⚠️ At phone width the headline spans the full column, so a left-weighted
     gradient leaves its right-hand words over bright sky. Mostly vertical here. */
  .lanaihero{min-height:clamp(300px,52vh,420px)}
  .lanaihero__scrim{background:
    linear-gradient(0deg, rgba(5,18,32,.80) 0%, rgba(5,18,32,.72) 50%,
                          rgba(5,18,32,.55) 100%),
    linear-gradient(90deg, rgba(5,18,32,.55) 0%, rgba(5,18,32,.30) 100%)}
  .lanaihero h1{max-width:none}
}




/* 🔴 THE HERO BUTTONS — 15 Sep 2026. Owner: "make sure the buttons are spread
   out and even across heros", "not sqished into the tiltles".
   Measured at 1280 before touching anything: rv-powersports had its buttons
   touching the headline at a gap of ZERO, because its row is `.hero__cta` and
   the rule only named `.btnrow` and `.hero__act`. The rest sat at 22px with an
   11px gap between them and heights running 40 to 53.
   ⭐ One rule, all three row names, and a floor under the height so a row of
   buttons reads as a row rather than as two different controls. */
.lanaihero .btnrow,
.lanaihero .hero__act,
.lanaihero .hero__cta{
  margin-top:clamp(1.6rem,2.6vw,2.2rem);
  display:flex; flex-wrap:wrap; align-items:center;
  gap:.85rem;
}
.lanaihero .btn{
  min-height:48px;
  display:inline-flex; align-items:center; justify-content:center;
  padding-inline:1.25rem;
}
@media (max-width:560px){
  /* ⚠️ Full width and stacked on a phone — two half-width buttons side by side
     put both under the 48px the thumb needs in the direction that matters. */
  .lanaihero .btnrow,.lanaihero .hero__act,.lanaihero .hero__cta{gap:.65rem}
  .lanaihero .btn{width:100%}
}


/* ── 👥 THE SOCIAL MARKS — 15 Sep 2026. Owner: "put fake no link social on the
   headers", after twice being told there is nowhere honest to point them.
   ⛔ THEY ARE NOT LINKS, AND THAT IS THE POINT. These companies are invented,
   so a social icon could only lead to an invented profile, to somebody else's
   real account, or to nothing — and a control that goes nowhere is worse than
   no control. They are `<span>` marks, `aria-hidden`, not focusable and not
   clickable: an illustration of where a real client's profiles sit in the bar,
   on a page that already says it is a demonstration.
   ⛔ Do not turn these into <a> on a real build without real profiles behind
   them. Bots On Staff's own Facebook and Instagram have never published once. */
.utilbar__social{display:inline-flex;align-items:center;gap:.55rem;opacity:.62}
.utilbar__social svg{width:15px;height:15px;display:block}
@media (max-width:560px){ .utilbar__social{display:none} }


/* 🔴 THE GHOST BUTTON, RESTATED BELOW `.btn` — 15 Sep 2026.
   The polish gate refused four demos for this and it was right: adding a
   `.lanaihero .btn` block after the ghost rules puts the outline variant at the
   mercy of source order in unlayered CSS. It happens that the block above sets
   no background, so nothing rendered wrong — but "it happens to be fine" is not
   a property anyone can rely on while editing this file later.
   ⛔ Any new `.btn` rule goes ABOVE this, or this moves below it. */
.lanaihero .btn--ghost,
.lanaihero .btn--line,
.lanaihero .btn--out{
  border-color:rgba(255,255,255,.62);
  color:#fff;
  background:rgba(7,22,38,.42);
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
}
.lanaihero .btn--ghost:hover,
.lanaihero .btn--line:hover,
.lanaihero .btn--out:hover{background:rgba(7,22,38,.66);border-color:#fff}

.lanaihero .btn--ghost{
  border-color:rgba(255,255,255,.62);
  color:#fff;
  background:rgba(7,22,38,.42);
}


/* ── 📣 THE OFFER BAND, ON THE PHOTOGRAPH — 15 Sep 2026 ──────────────────────
   Owner: "i dont think it needs the white section evry vist", then "figure it
   out in a great spot dont just throw it somewhere be creative".
   🔴 IT CANNOT SIMPLY GO. The polish gate requires an offer strip on every page
   and it is right to — it is the one line on a demonstration site that says what
   the shop actually promises. But as a white slab wedged between the header and
   the hero it interrupted the only picture on the page before anyone had seen it.
   ⭐ So it is pinned to the FOOT of the hero, over the photograph, on the same
   dark glass as the scrim. The promise now reads as part of the image instead of
   as an announcement above it, and the page opens header -> photograph -> story
   with nothing cutting across.
   ⛔ Its own backdrop is near-opaque on purpose: type over a photograph is the
   one thing on this estate that has been measured wrong twice, and a band that
   carries its own ground cannot drift when the picture changes. */
.lanaihero{padding-bottom:0}
.lanaihero .offerbar{
  position:absolute; left:0; right:0; bottom:0; z-index:3;
  background:rgba(6,19,34,.86);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  border-top:1px solid rgba(255,255,255,.16);
  border-bottom:0;
}
.lanaihero .offerbar__in{
  display:flex; align-items:center; gap:1rem; flex-wrap:wrap;
  padding-block:.7rem;
}
.lanaihero .offerbar__tag{
  color:#fff; border-color:rgba(255,255,255,.45); background:rgba(255,255,255,.10);
}
.lanaihero .offerbar__msg{color:rgba(255,255,255,.92); margin:0}
.lanaihero .offerbar__msg b{color:#fff}
.lanaihero .offerbar__go{color:#fff; border-color:rgba(255,255,255,.5)}
/* ⚠️ the hero's own content must clear the band, or the buttons sit under it */
.lanaihero__in{padding-bottom:clamp(5.5rem,9vw,7rem)}
@media (max-width:860px){
  /* ⛔ On a phone the band would eat the picture. It goes back into the flow
     directly beneath the hero — still out from between the header and the photo,
     which is the thing that was wrong. */
  .lanaihero .offerbar{position:static;backdrop-filter:none;-webkit-backdrop-filter:none}
  .lanaihero__in{padding-bottom:clamp(1.9rem,4.5vw,3rem)}
}


/* ══ 🧭 THE HEADER, 2026 — 15 Sep 2026 ══════════════════════════════════════
   Owner: "the header need to be way better on each site look like proper 2026
   header trends", "make sure everyting looks as goos as outr customer sites".
   🔴 MEASURED FIRST, ALL TWELVE AT 1280: heights ran from 62px to 223px, only
   one was sticky, and eleven carried a telephone number that the new utility bar
   was already showing a few pixels above it.
   ⭐ This layer is keyed on the `header` ELEMENT, not on a class, because these
   demos call it .site, .top, .mast, .nav and .masthead — five names for one
   thing. Anything that needs a class name is done per demo.
   ⛔ It is deliberately visual-only: sticky, glass, a hairline that appears on
   scroll, and honest focus rings. It does not re-order anybody's markup. */
header{
  position:sticky; top:0; z-index:60;
  -webkit-backdrop-filter:saturate(1.3) blur(10px);
  backdrop-filter:saturate(1.3) blur(10px);
  transition:box-shadow .22s ease, border-color .22s ease;
}
/* ⭐ The rule under the header only appears once you have scrolled — a border
   that is always there is chrome, a border that arrives is depth. */
header::after{
  content:""; position:absolute; left:0; right:0; bottom:-1px; height:1px;
  background:currentColor; opacity:0; transition:opacity .22s ease;
  pointer-events:none;
}
html[data-scrolled] header::after{opacity:.16}
html[data-scrolled] header{box-shadow:0 10px 30px -22px rgba(0,0,0,.55)}

/* ⛔ 44px is not decoration. WCAG 2.2 §2.5.8, and on a phone this is the only
   navigation there is. */
@media (max-width:900px){
  header nav a{min-height:44px;display:flex;align-items:center}
}
/* a focus ring that is visible on both a light and a dark header */
header a:focus-visible, header button:focus-visible, header label:focus-visible{
  outline:2px solid currentColor; outline-offset:3px; border-radius:6px;
}


/* 🔴 STICKY WAS LOSING ON SPECIFICITY — 15 Sep 2026. `header{position:sticky}`
   is (0,0,1) and these demos set `.top{position:relative}` at (0,1,0), so five
   of twelve silently stayed put while the other seven pinned. Measured, not
   assumed: auto-detailing, drain-cleaning, mobile-repair, plumbing-hvac and
   rv-powersports all read `relative` after the layer went in.
   ⭐ `header[class]` is (0,1,1) and beats a single class without reaching for
   !important, which would then have to be fought later. */
header[class]{position:sticky;top:0;z-index:60}

/* 🔴 THE OFF-CANVAS MENU WAS WIDENING THE PAGE. Parked at translateX(102%) the
   panel still counted toward scrollWidth — 700px against a 371px viewport — so
   the whole site scrolled sideways on a phone with nothing visible to scroll to.
   ⛔ `overflow-x:hidden` would fix it and break `position:sticky` in the same
   stroke; `clip` does not create a scroll container, so the header still pins. */
html{overflow-x:clip}


/* 🔴 THE NAV WAS WRAPPING ONTO ITS OWN ROW — 15 Sep 2026, measured at 1280.
   These headers are flex rows that ran out of width, so the navigation dropped
   beneath the brand and the header doubled in height: 134, 138, 104, 223.
   A sticky header that tall eats a quarter of a laptop screen, and it is the
   clearest difference between these and the client sites.
   ⭐ One row, and the NAV is the part allowed to give — `min-width:0` lets it
   shrink, and if it still will not fit it scrolls sideways within itself rather
   than pushing the whole header down. ⛔ `scrollbar-width:none` hides the bar,
   not the ability to scroll; the items remain reachable by wheel, trackpad,
   touch and keyboard. */
@media (min-width:901px){
  header .top__in,
  header .masthead__row,
  header .brandline{flex-wrap:nowrap}
  header nav{min-width:0}
}
@media (min-width:901px){
  header nav ul{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}
  header nav ul::-webkit-scrollbar{display:none}
  header nav a{white-space:nowrap}
}

@media (min-width:901px){
  header .mark{flex:0 1 auto;min-width:0}
  header nav.nav{flex:1 1 auto;min-width:0}
  header .callbar{flex:0 0 auto}
}



/* 🔴 ONE HERO WAS 83vh BECAUSE ITS HEADLINE WAS 104px — 15 Sep 2026.
   Owner: "make sure desktop hero are proper sixe". Measured at 1280: nine
   heroes sat at 62-66vh and auto-detailing at 83vh, and the cause was not the
   hero box at all — its <h1> renders at 104px over three lines, 306px of type.
   That size was tuned for a hero made ONLY of words; over a photograph it is
   shouting. ⭐ Capped to the size the rest already use, so the set reads as one
   family. ⛔ Still large text for contrast purposes (>=24px), so the 3:1
   threshold the probe applies is unchanged. */
.lanaihero h1{font-size:clamp(2rem,4.4vw,3.5rem);line-height:1.06}


/* ══════════════════════════════════════════════════════════════════════════
   ⚠️ HAND-EDITED — THIS SHEET NOW DIVERGES FROM ITS GENERATOR. 23 Sep 2026.
   The header at the top of this file says this demo is written out of
   ~/Desktop/demo-mobile/dist by tools/sync-demo.mjs and must not be edited by
   hand. Everything below this line was written BY HAND anyway, on the owner's
   instruction, and the generator knows nothing about it.
   ⛔ DO NOT RUN tools/sync-demo.mjs OR build.py FOR THIS DEMO. A sync would
   revert every rule below without printing a word — the exact failure the
   estate has already paid for once ("a hand-edit to a generated file reverts
   silently — build green, fix gone").
   ⭐ WHY THIS IS THE RIGHT WAY ROUND ANYWAY: the generator source lives outside
   this repo, is untracked and unbacked, and at least one of these demos
   provably no longer reproduces its published copy. public/demo IS in git. So
   public/demo is the authority now. If the generator is ever restored, port
   these blocks into it FIRST and diff its output before syncing anything.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1. ONE HERO, NOT TWO ─────────────────────────────────────────────────
   🔴 This page opened with <section class="lanaihero"> and then a SECOND
   <section class="hero"> immediately underneath. Ten of the thirteen demos
   did. Two hero bands is a stack, and a stack has no first thing to look at —
   the same defect the Cut Above home page was rebuilt six times for.
   ⭐ The second band is now `.showcase`: a content band that keeps its ground,
   its drawing and its photograph, and has no headline, no eyebrow and no lede
   restating what the h1 already said. The rules it needs were added to the
   `.hero` selectors above rather than duplicated, so the two cannot drift. */

/* ── 2. THE HEADLINE IS AT LEAST 3.0x BODY AT EVERY WIDTH ─────────────────
   🔴 Measured before this pass: the hero headline fell to **1.88x** body on a
   phone. `.lanaihero h1` capped it at 2rem — correctly, because 104px over
   three lines had made one hero 83vh — but the floor went with the ceiling.
   A headline under 2x body is not a headline, it is a bold paragraph.
   ⭐ THE FIX IS ARITHMETIC, NOT TASTE, and it is this pair:
        body  1rem (16px) up to 740px, 1rem above it
        h1    clamp(3rem, 7vw, …)
   The worst point is 741px, where body jumps to 16px while 7vw is only
   51.87px — 3.05x, the tightest the whole range gets. At 320px it is 48/16 =
   3.00x exactly. ⛔ Do not lower either number without recomputing 741px.
   ⚠️ The 3.5rem ceiling on the hero headline is deliberately unchanged: that
   number was measured, and raising it is how a hero became 83vh tall. */
@media (max-width:740px){ body{font-size:1rem} }

/* ── 3. THE HERO IS THE DOCUMENT ──────────────────────────────────────────
   ⭐ The most persuasive object this business has is a job it turned DOWN: one
   real line on a real document, at $0.00, with a reason a customer can go and
   check. It was buried mid-page behind two hundred words of lede. It is now
   the offer strip itself, at the fold, and **$0.00 is a literal in the
   markup** — not a badge, not a rounded claim, not a rating. There are no
   ratings, stars or review counts anywhere on this site and there never will
   be; this is the honest version of the same job.
   ⛔ THE WRAPPER KEEPS `offerbar` IN ITS CLASS LIST ON PURPOSE.
   tools/check-demo-polish.mjs requires an offer strip on every page of every
   demo. Renaming the class here would strip it from the gate's view.
   ⚠️ COLOUR, AND WHY NOTHING COLOURED CARRIES TEXT. This band is
   rgba(6,19,34,.86) over a photograph, so with a white photo behind it it
   composites to roughly #293340 — dark, but not as dark as it looks in a
   screenshot of a dark picture. Every foreground below is white or near-white
   against that. The one coloured thing is the 3px flag rule, which carries no
   glyphs and so answers to the 3:1 non-text floor, not 4.5:1. */
.lanaihero .herodoc{ box-shadow:inset 0 3px 0 var(--doc-flag); }
.herodoc__in{
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  align-items:center;
  column-gap:clamp(.8rem,2vw,1.5rem);
  row-gap:.5rem;
  padding-block:clamp(.8rem,1.7vw,1.1rem);
}
.herodoc__tag{
  grid-column:1; grid-row:1;
  font-family:var(--mono); font-size:.625rem; font-weight:700;
  letter-spacing:.2em; text-transform:uppercase; white-space:nowrap;
  color:#fff; background:rgba(255,255,255,.12);
  border:1px solid rgba(255,255,255,.42); border-radius:2px;
  padding:.3rem .55rem; align-self:center;
}
.herodoc__it{
  grid-column:2; grid-row:1;
  font-weight:600; line-height:1.25; color:#fff;
  font-size:clamp(.9375rem,1.5vw,1.0625rem);
  text-shadow:0 1px 2px rgba(0,0,0,.70);
}
/* ⛔ Not a muted grey. Over a picture the picture is already doing the
   de-emphasising, and a dimmed foreground on a busy ground is just an
   unreadable foreground. Near-full ink, plus a shadow that travels with the
   glyphs rather than a panel that darkens the photograph. */
.herodoc__why{
  display:block; margin-top:.22rem; max-width:52ch;
  font-family:var(--mono); font-style:normal; font-weight:400;
  font-size:.75rem; line-height:1.5; letter-spacing:.01em;
  color:rgba(255,255,255,.93);
  text-shadow:0 1px 2px rgba(0,0,0,.70);
}
/* ⭐ tabular figures, so the amount reads as money in a column rather than as
   a word in a sentence. That is what makes it look like a document. */
.herodoc__amt{
  grid-column:3; grid-row:1;
  font-family:var(--mono); font-weight:700; color:#fff; white-space:nowrap;
  font-size:clamp(1.25rem,2.4vw,1.6rem); letter-spacing:-.01em;
  font-variant-numeric:tabular-nums;
  text-shadow:0 1px 2px rgba(0,0,0,.70);
}
/* ⛔ At 640px three columns stop fitting and the reason column collapses to a
   word per line. The flag and the amount stay together on the first row —
   they are the two things that must be read as one statement — and the line
   itself wraps underneath at full width. Nothing is lost at 320px. */
@media (max-width:640px){
  .herodoc__in{ grid-template-columns:auto minmax(0,1fr); }
  .herodoc__amt{ grid-column:2; grid-row:1; justify-self:end; }
  .herodoc__it{ grid-column:1 / -1; grid-row:2; }
}

/* ── 4. ONE MEASURE ───────────────────────────────────────────────────────
   🔴 Two prose blocks on this site ran to **92ch and 96ch**. At 16px that is
   roughly 800 and 840 pixels of unbroken line, and a reader loses the start of
   the next line somewhere around 75. One rail, one measure: 64ch for body
   copy. ⛔ These two were set on the ELEMENT, so a `.prose` cap could never
   reach them — capping the container is not capping the line. */
.frame p,
.qrow__note,
.noitem p,
.prose{ max-width:64ch; }
h1{ font-size:clamp(3rem,7vw,3.5rem); }
.lanaihero h1{ font-size:clamp(3rem,7vw,3.5rem); line-height:1.04; }

/* the flag rule's colour: --no, which this site already defines as 'red — declined / referred out'. It is exactly the semantic this row carries */
:root{ --doc-flag:#e2604f; }

/* ── 5. THE WORDMARK IS THE LOGO ──────────────────────────────────────────
   There is no icon any more. The type is the mark and the hi-vis kerb between
   CURB and SIDE is the one element doing the work.
   ⛔ The literal word "Curbside" was removed from the anchor beside it — a
   wordmark plus the same word set in HTML is the name twice. The <svg> carries
   role="img" and aria-label="Curbside", so the accessible name is unchanged.
   ⚠️ width:auto — the old rule was a 26px SQUARE and would have crushed a
   132x26 lockup into a letterform-and-a-half. */
.nav__mark--word{width:auto;height:23px;flex:0 0 auto}
@media (max-width:420px){ .nav__mark--word{height:20px} }

/* ── 6. GLASS — A SOFT PANEL ──────────────────────────────────────────────
   Owner, 23 Sep 2026: "use glass buttons all the newest elements".
   ⛔ See the long note in the auto-detailing sheet. The alpha below clears
   4.5:1 with NO blur. Measured by tools/check-hero-button-contrast.mjs.

   ⭐ THE MATERIAL IS THE SOFTEST OF THE FOUR: a 12px radius panel, the widest
   blur, and one inset line of light along the top edge — a lit control on a
   dark board, which is what this whole site is. ⛔ The hi-vis stays hi-vis:
   it is the only saturated thing in the hero and the one action in it. */
.lanaihero .btn--go{
  border-radius:12px;
  background:color-mix(in srgb, var(--hivis) 88%, transparent);
  border:1px solid color-mix(in srgb, #fff 40%, var(--hivis));
  color:#0b0f14;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45);
  -webkit-backdrop-filter:blur(20px) saturate(1.15);
  backdrop-filter:blur(20px) saturate(1.15);
}
.lanaihero .btn--go:hover{
  background:color-mix(in srgb, var(--hivis) 96%, transparent);
  border-color:#fff; box-shadow:inset 0 1px 0 rgba(255,255,255,.6);
}
.lanaihero .btn:focus-visible{
  outline:2px solid #fff; outline-offset:3px; box-shadow:0 0 0 5px rgba(11,16,22,.78);
}
