
/* ---------------------------------------------------------------- fonts */
/* Self-hosted, not linked from Google. Two reasons: a CDN font is a
   third-party request on every page load and a privacy footnote nobody wants
   to write, and the latin subsets are 47 KB and 15 KB, which is less than a
   fifth of what a single decorative PNG costs on a typical shop site. Both faces are
   SIL Open Font License, so self-hosting is explicitly permitted.
   font-display: swap, so text paints immediately in the fallback and never
   disappears while a font loads. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("/img/inter-var.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
/* Roman AND italic. The roman is here for one job: the wordmark, which is set
   to match the serif capitals on their actual sign. A wordmark falling through
   to whatever serif a visitor's machine happens to have would render the shop's
   name differently on every screen, which is the one place a system font stack
   is not good enough. 15 KB, OFL, self-hosted like everything else. */
@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/img/instrument-serif.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/img/instrument-serif-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}

/* ---------------------------------------------------------------- tokens */
:root {
  color-scheme: light;
  --bg:          #ffffff;
  --surface:     #f7f8f9;
  --surface-2:   #eceef1;
  --ink:         #15171b;
  --ink-2:       #4c525c;
  --ink-3:       #646b76;
  --line:        #e2e5e9;
  --line-strong: #c8ccd3;
  /* Sampled from the restored Coca-Cola machine and Tydol pump in their own
     waiting room. Measured 8.6:1 on white. */
  --brand:       #9b0a12;
  --brand-hover: #78060d;
  --brand-ink:   #ffffff;
  --brand-soft:  #f9ecec;
  --brand-edge:  #e5c0c2;
  /* Amber is the WAIT color and is used for nothing else. It never carries
     text on white: it is a rule, a dot, or a background behind dark ink. */
  --warn:        #a35a00;
  --warn-soft:   #fdf3e3;
  --warn-edge:   #edc98a;
  --good:        #1c6b3f;
  --good-soft:   #e6f4ec;
  /* The second half of red, white and blue. The red is left exactly as it was,
     because it was sampled off the Coca-Cola machine in their own waiting room
     and a brighter flag red was already tried and rejected for being too bright.
     So the blue does the work instead: it is the structural color, carrying the
     bands the page is built on, while red stays the accent. Flag blue at
     11.0:1 under the cream used on the credential strip. */
  --navy:        #0A3161;
  --navy-deep:   #0A2545;
  --navy-ink:    #ffffff;
  --shadow:      0 1px 2px rgba(13,17,23,.06), 0 8px 24px rgba(13,17,23,.06);
  --shadow-lg:   0 2px 4px rgba(13,17,23,.06), 0 18px 48px rgba(13,17,23,.12);

  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --serif: "Instrument Serif", "Iowan Old Style", Palatino, Georgia, serif;

  --wrap: 1180px;
  --gut: clamp(18px, 4vw, 40px);
  --radius: 12px;
  --radius-lg: 18px;
}


/* ---------------------------------------------------------------- base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  /* 17px base. His customers skew older and this is a shop, not a startup. */
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0 0 .5em; line-height: 1.08; letter-spacing: -0.028em; font-weight: 780; }
h1 { font-size: clamp(2.7rem, 7.4vw, 5.4rem); letter-spacing: -0.042em; font-weight: 820; line-height: 0.98; text-wrap: balance; }
h2 { font-size: clamp(2rem, 4.4vw, 3.3rem); letter-spacing: -0.036em; font-weight: 800; text-wrap: balance; }
h3 { font-size: clamp(1.2rem, 2vw, 1.5rem); letter-spacing: -0.02em; font-weight: 720; }
h4 { font-size: 1.02rem; }

/* The italic serif is the personality voice: pull quotes, the odd emphasized
   phrase. Never body text. */
.serif { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: -0.01em; }
h1 .serif, h2 .serif { font-size: 1.06em; letter-spacing: -0.02em; }

/* Numbers that are meant to be read as data line up. */
.tnum { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }
p  { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }

a { color: var(--brand); text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
a:hover { color: var(--brand-hover); }

img { max-width: 100%; height: auto; display: block; }

/* Inline icon SVGs carry a viewBox but no width/height, so with no CSS an SVG
   falls back to the replaced-element default of 300x150. That is what blew the
   mobile layout out to 470px in a 390px viewport: the phone glyph inside the
   hero button was rendering at ~300px wide. Every inline icon gets an explicit
   box, and the catch-all keeps a future icon from doing it again. */
/* Inline icons are sized to the text around them. The exclusions matter:
   .ch is the analytics chart, which sets its own 200px height and was being
   squashed to 1.15em by this rule (equal-ish specificity, but :not() adds
   enough to win), so both graphs rendered as a thin smear with their captions
   still in place. .logo-mark is kept for the day a real logo replaces the
   typographic wordmark. */
svg:not(.logo-mark):not(.ch) { width: 1.15em; height: 1.15em; flex: 0 0 auto; }
.btn svg { width: 18px; height: 18px; }
.btn-lg svg { width: 19px; height: 19px; }
/* <picture> is an inline wrapper by default, so an image whose intrinsic width
   is narrower than its column just sits there at natural size instead of
   filling it. Several of his source photos are only 508px wide, which is how
   one row ended up with an undersized image. Make the wrapper
   a block and let the images fill. */
picture { display: block; }
.row img, .hero-media img, .card img, figure img { width: 100%; }
hr { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* Focus that is actually visible, on both themes. The overlay widget on his
   current site is the kind that gets shops sued; real focus states are the
   thing that actually helps somebody navigating by keyboard. */
:focus-visible {
  outline: 3px solid var(--brand);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip {
  position: absolute; left: 8px; top: -60px; z-index: 200;
  background: var(--brand); color: var(--brand-ink);
  padding: 12px 18px; border-radius: 0 0 10px 10px; font-weight: 650;
  transition: top .16s ease;
}
.skip:focus { top: 0; }

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gut); }
.narrow { max-width: 760px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------- header */
.hdr {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(12px);
  -webkit-backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: 1px solid var(--line);
}
@supports not (backdrop-filter: blur(1px)) { .hdr { background: var(--bg); } }

.hdr-in { display: flex; align-items: center; gap: 14px; min-height: 74px; }
.brand { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; text-decoration: none; }

/* ---------------------------------------------------------------- logo */
/* The shop's real mark, replacing the typographic imitation. Sized in px rather
   than em so it does not drift with the surrounding type, and given explicit
   width/height so the header does not reflow while it loads. */
.logo { display: block; width: 190px; height: auto; }
.ftr .logo { width: 210px; }
@media (max-width: 560px) { .logo { width: 158px; } }
@media (max-width: 379px) { .logo { width: 140px; } }

/* ---------------------------------------------------------------- header */
.hdr {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(12px);
  -webkit-backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: 1px solid var(--line);
}
@supports not (backdrop-filter: blur(1px)) { .hdr { background: var(--bg); } }

.hdr-in { display: flex; align-items: center; gap: 14px; min-height: 74px; }
.brand { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; text-decoration: none; }

/* ---------------------------------------------------------------- wordmark */
/* Set to MATCH THEIR SIGN, not to invent one.
   The fascia at 340-B reads FRAMES AUTOMOTIVE in cream serif capitals on dark
   brown, FRAMES larger than AUTOMOTIVE, both on one line. An earlier version
   here was a heavy sans stacked in two rows, which was a guess made before any
   photograph of the building existed. Instrument Serif is already loaded for
   the display voice, so matching the real sign costs nothing. */
.wm {
  display: flex; align-items: baseline; gap: .3em; line-height: 1;
  font-family: var(--serif); font-style: normal; white-space: nowrap;
}
.wm b {
  font-weight: 400; font-size: 1.62rem; letter-spacing: .045em;
  text-transform: uppercase; color: var(--ink);
}
.wm i {
  font-style: normal; font-weight: 400; font-size: 1.02rem;
  letter-spacing: .09em; text-transform: uppercase; color: var(--ink-2);
}
.hdr .wm b { font-size: 1.5rem; }
.hdr .wm i { font-size: .95rem; }
@media (max-width: 560px) {
  .wm b { font-size: 1.3rem; }
  .wm i { font-size: .82rem; letter-spacing: .07em; }
}
/* Below 380px the two words together are wider than the space the header can
   give them, and a squashed sign is worse than a short one. */
@media (max-width: 379px) { .wm i { display: none; } }
.menu { flex: 0 0 auto; }

.nav { display: flex; gap: 4px; margin-left: auto; align-items: center; }
.nav a {
  color: var(--ink-2); text-decoration: none; font-size: .93rem; font-weight: 550;
  padding: 9px 9px; border-radius: 8px; white-space: nowrap;
}
.nav a:hover { color: var(--ink); background: var(--surface); }
.nav a[aria-current="page"] { color: var(--brand); background: var(--brand-soft); }

.hdr-cta { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }

/* Open / closed. Computed server-side in America/New_York and corrected on the
   client, so it is right for a visitor in another timezone too. */
.status {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: .79rem; font-weight: 600; color: var(--ink-2);
  padding: 5px 10px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--bg); white-space: nowrap;
}
.status .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ink-3); flex: 0 0 auto; }
.status.is-open { color: var(--good); border-color: color-mix(in srgb, var(--good) 34%, transparent); background: var(--good-soft); }
.status.is-open .dot { background: var(--good); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  font: inherit; font-weight: 650; font-size: .97rem;
  padding: 13px 22px; border-radius: 10px; border: 1px solid transparent;
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background .15s ease, border-color .15s ease, transform .12s ease;
  /* 44px minimum touch target. His current site has tap targets under 24px. */
  min-height: 46px;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--brand); color: var(--brand-ink); border-color: var(--brand); }
.btn-primary:hover { background: var(--brand-hover); border-color: var(--brand-hover); color: var(--brand-ink); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line-strong); }
.btn-ghost:hover { background: var(--surface); color: var(--ink); border-color: var(--ink-3); }
.btn-lg { padding: 16px 28px; font-size: 1.05rem; min-height: 54px; }
.btn-block { width: 100%; }

.tel { font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
/* A phone number inside a sentence is technically exempt from the 24px target
   floor, but it is the single thing a customer is most likely to tap. Give the
   inline ones a real target. */
p > a.tel { display: inline-block; min-height: 24px; padding-block: 2px; }


/* Mobile nav: a details/summary disclosure, so it works with zero JS. */
.menu { display: none; }
.menu > summary {
  list-style: none; cursor: pointer; width: 46px; height: 46px; flex: 0 0 46px; border-radius: 10px;
  border: 1px solid var(--line-strong); display: grid; place-items: center; color: var(--ink);
}
.menu > summary::-webkit-details-marker { display: none; }
.menu[open] > summary { background: var(--surface); }
.menu-panel {
  position: absolute; left: 0; right: 0; top: 100%;
  background: var(--bg); border-bottom: 1px solid var(--line);
  padding: 10px var(--gut) 20px; box-shadow: var(--shadow-lg);
}
.menu-panel a {
  display: block; padding: 14px 8px; color: var(--ink); text-decoration: none;
  font-weight: 600; border-bottom: 1px solid var(--line);
}
.menu-panel a:last-of-type { border-bottom: 0; }

/* ---------------------------------------------------------------- hero */
.hero { position: relative; background: var(--surface); border-bottom: 1px solid var(--line); overflow: hidden; }
.hero-grid {
  display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(28px, 5vw, 68px);
  align-items: center; padding-block: clamp(46px, 7vw, 92px);
}
.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: .8rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--brand); margin-bottom: 20px;
}
.eyebrow::before { content: ""; width: 26px; height: 2px; background: var(--brand); }
.hero h1 { margin-bottom: 20px; }
.hero .lede { font-size: clamp(1.08rem, 1.7vw, 1.24rem); color: var(--ink-2); max-width: 46ch; margin-bottom: 30px; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 30px; }

.hero-media { position: relative; }
.hero-media img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}
/* A caption, because the photo is of HIS shop and saying so is the point. */
.hero-media figcaption {
  margin-top: 12px; font-size: .84rem; color: var(--ink-3); text-align: right;
}

/* ---------------------------------------------------------------- hero, full bleed */
/* The old hero was text-left, image-right: the most default layout there is,
   and it used his best photograph as a thumbnail. His shop pictures are the
   whole emotional argument, so one of them now fills the screen and the words
   sit on top of it. */
.hero-full {
  position: relative;
  min-height: min(78vh, 720px);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: #14161a;
  isolation: isolate;
}
.hero-full > picture, .hero-full > picture img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: -2;
}
/* THREE layers, tuned to this photograph rather than inherited.
   The sibling build's scrim was made for a dark interior bay. This hero is a
   sunlit brick storefront, which is a much brighter and much less even
   picture: its left-to-right gradient ran out at 62% and left a visible
   vertical seam down the middle of the wall, with the AAA sign and the brick
   glaring on the far side of it.
   So: a flat base tint that covers the whole frame evenly and kills the seam,
   then the vertical carry for the text, then a gentle left weighting. Warm
   brown rather than blue-black, because the building is brown and a cold scrim
   over warm brick reads as a color cast. */
.hero-full::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(to top, rgba(16,18,22,.93) 0%, rgba(16,18,22,.78) 30%, rgba(16,18,22,.55) 68%, rgba(16,18,22,.5) 100%),
    linear-gradient(to right, rgba(16,18,22,.42) 0%, rgba(16,18,22,.12) 78%, rgba(16,18,22,.06) 100%);
}
.hero-full .wrap { padding-block: clamp(40px, 7vw, 76px); position: relative; }
.hero-full h1 { color: #fff; max-width: 15ch; margin-bottom: 22px; text-wrap: balance; }
.hero-full .lede { color: rgba(255,255,255,.86); font-size: clamp(1.08rem, 1.7vw, 1.3rem); max-width: 50ch; margin-bottom: 30px; }
.hero-full .eyebrow { color: #f0ece7; }
.hero-full .eyebrow::before { background: #f0ece7; }
.hero-full .credit {
  position: absolute; right: var(--gut); bottom: 12px;
  font-size: .76rem; color: rgba(255,255,255,.5);
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; }
/* On a photo, the secondary button needs its own surface to stay readable. */
.hero-full .btn-ghost {
  color: #fff; border-color: rgba(255,255,255,.42);
  background: rgba(255,255,255,.08); backdrop-filter: blur(6px);
}
.hero-full .btn-ghost:hover { background: rgba(255,255,255,.18); border-color: #fff; color: #fff; }

/* ---------------------------------------------------------------- dark section */
/* Rhythm. Every section being white made the whole page read as one long
   scroll. One hard dark band gives the page a spine and it is where the
   argument about why the shop is slow lives, which is the whole differentiator. */
.dark {
  background: var(--navy-deep); color: #eef1f5;
  --ink: #eef1f5; --ink-2: #aebbcd; --ink-3: #90a0b6;
  --line: #1b3555; --line-strong: #2b4a70;
  --brand: #f0ece7; --brand-ink: #17120d; --brand-hover: #ffffff;
  --brand-soft: #241016; --brand-edge: #4b2430;
  --warn: #e8a54a; --warn-soft: #241a08; --warn-edge: #5a4318;
  --bg: var(--navy-deep); --surface: #10304f;
}
.dark .panel, .dark .card, .dark .quote { background: #10304f; border-color: #1b3555; }
/* The primary button inherits --brand, which on a dark ground is the lightened
   accent: a salmon pink block that read as washed out and cheap, and was the
   least polished thing on the page. On dark, the button is cream with dark
   brown text instead. Measured 14.6:1. */
.dark .btn-primary {
  background: #eef1f5; color: #14161a; border-color: #eef1f5;
}
.dark .btn-primary:hover {
  background: #fff; border-color: #fff; color: #1a1208;
}

/* ---------------------------------------------------------------- stat row */
/* The ratings were a four-cell table. They are the strongest thing he has, so
   they are set as display type. */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(16px, 2.6vw, 34px); }
.stat { border-top: 2px solid var(--brand); padding-top: 16px; }
.stat b {
  display: block; font-size: clamp(2.1rem, 4.4vw, 3.2rem); font-weight: 820;
  letter-spacing: -0.045em; line-height: 1; color: var(--ink);
}
.stat b .u { font-size: .44em; font-weight: 700; letter-spacing: -0.02em; color: var(--ink-3); margin-left: 3px; }
.stat > span { display: block; margin-top: 9px; font-size: .89rem; color: var(--ink-2); line-height: 1.42; }
.stat .src { display: block; margin-top: 2px; color: var(--ink-3); font-size: .82rem; }

/* ---------------------------------------------------------------- photo strip */
.strip { position: relative; height: clamp(260px, 42vw, 460px); overflow: hidden; background: var(--surface-2); }
.strip picture, .strip img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* ---------------------------------------------------------------- page head */
/* Every page other than the home page opened with a bare heading on white, so
   clicking out of the home page felt like leaving the site. This gives the
   inner pages a consistent, quieter version of the same treatment. */
.page-head {
  background: var(--surface); border-bottom: 1px solid var(--line);
  padding-block: clamp(44px, 6.5vw, 84px);
}
.page-head h1 { max-width: 17ch; margin-bottom: 18px; }
/* A headline short enough to run on one line, held to 17ch, was broken over two
   lines and left a tall block against an empty right half. Widening the measure
   lets it sit on one line at desktop and still wrap on its own on narrow
   screens, which is a line of height saved and a much less lopsided head. */
.page-head h1.h1-wide { max-width: 26ch; }
.page-head .lede { font-size: clamp(1.06rem, 1.6vw, 1.22rem); color: var(--ink-2); max-width: 58ch; }
.page-head .hero-actions { margin-top: 28px; }
.page-head-img { display: grid; grid-template-columns: 1.15fr .85fr; gap: clamp(28px, 5vw, 60px); align-items: center; }
.page-head-img img { border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); }
@media (max-width: 860px) { .page-head-img { grid-template-columns: 1fr; } .page-head-img figure { order: -1; } }

/* ---------------------------------------------------------------- anchors */
/* The header is sticky, so an in-page link like /services#transmission used to
   scroll the target underneath it and land the reader mid-paragraph. */
[id] { scroll-margin-top: 96px; }
@media (max-width: 620px) { [id] { scroll-margin-top: 132px; } }

/* ---------------------------------------------------------------- faq */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  list-style: none; cursor: pointer; padding: 22px 44px 22px 0; position: relative;
  font-weight: 680; font-size: 1.06rem; color: var(--ink); letter-spacing: -0.012em;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; position: absolute; right: 8px; top: 50%; width: 11px; height: 11px;
  border-right: 2px solid var(--ink-3); border-bottom: 2px solid var(--ink-3);
  transform: translateY(-70%) rotate(45deg); transition: transform .18s ease;
}
.faq details[open] summary::after { transform: translateY(-30%) rotate(225deg); }
.faq summary:hover { color: var(--brand); }
.faq .a { padding: 0 44px 24px 0; color: var(--ink-2); max-width: 76ch; }
.faq .a p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- details */
::selection { background: var(--brand); color: var(--brand-ink); }
.lead-in::first-letter {
  float: left; font-family: var(--serif); font-style: italic; font-size: 3.6em;
  line-height: .82; padding: .06em .08em 0 0; color: var(--brand);
}

/* ---------------------------------------------------------------- trust */
.trust { border-bottom: 1px solid var(--line); background: var(--bg); }
.trust-in {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: var(--line); border-inline: 1px solid var(--line);
}
.trust-cell { background: var(--bg); padding: 24px clamp(14px, 2vw, 26px); text-align: center; }
/* Three of these four are links now. The resting state is deliberately
   IDENTICAL to the div it replaced: the anchor would otherwise inherit brand
   color and draw an underline across the figure and its label. Hover is the
   only difference, and it exists because a link with no affordance is one
   nobody finds. */
a.trust-cell { display: block; color: inherit; text-decoration: none; transition: background .16s ease; }
a.trust-cell:hover { background: var(--surface); }
.trust-num { font-size: clamp(1.5rem, 2.6vw, 2rem); font-weight: 750; letter-spacing: -0.03em; line-height: 1.1; color: var(--ink); }
.trust-num .stars { color: var(--brand); }
.trust-lbl { font-size: .84rem; color: var(--ink-3); margin-top: 4px; line-height: 1.4; }

/* ---------------------------------------------------------------- sections */
.sec { padding-block: clamp(52px, 8vw, 96px); }
.sec-alt { background: var(--surface); border-block: 1px solid var(--line); }
/* Wide enough that a 3.3rem heading takes two lines, not six. An earlier pass
   set this to 24ch, which is a sane measure for BODY copy and a disaster for
   display type. text-wrap: balance does the rag. */
.sec-head { max-width: 66ch; margin-bottom: clamp(30px, 4vw, 48px); }
.sec-head h2 { max-width: 20ch; }
.sec-head p { max-width: 58ch; }
.sec-head .eyebrow { margin-bottom: 14px; }
.sec-head p { color: var(--ink-2); font-size: 1.08rem; }

.grid { display: grid; gap: clamp(18px, 2.4vw, 28px); }
.g-2 { grid-template-columns: repeat(2, 1fr); }
.g-3 { grid-template-columns: repeat(3, 1fr); }
.g-4 { grid-template-columns: repeat(4, 1fr); }

.card {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-lg);
  overflow: hidden; display: flex; flex-direction: column;
  transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.sec-alt .card { background: var(--bg); }
.card:hover { border-color: var(--brand-edge); box-shadow: var(--shadow); transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .card:hover { transform: none; } }
.card img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; }
.card-body { padding: 24px; flex: 1; display: flex; flex-direction: column; }
.card-body h3 { margin-bottom: 8px; }
.card-body p { color: var(--ink-2); font-size: .98rem; }
.card-more { margin-top: auto; padding-top: 16px; font-weight: 650; font-size: .95rem; color: var(--brand); }
.card-more a { display: inline-block; min-height: 24px; padding-block: 3px; }

/* ---------------------------------------------------------------- quotes */
.quote {
  background: var(--bg); border: 1px solid var(--line); border-left: 3px solid var(--brand);
  border-radius: var(--radius); padding: 26px 28px;
}
.quote blockquote { margin: 0 0 16px; font-size: 1.04rem; line-height: 1.56; color: var(--ink); }
.quote cite { font-style: normal; font-weight: 650; font-size: .93rem; color: var(--ink); }
.quote .meta { font-size: .84rem; color: var(--ink-3); margin-top: 2px; }

/* The inherited .pull set the serif face and a display size on the FIGURE, so
   the attribution under the quote inherited both and rendered as small italic
   serif. The quote itself carries its own type below; this rule now only owns
   the box. Same class of defect as .note-warn: a base rule reaching further
   than intended, invisible unless you look at what actually rendered.

   The 24ch measure was also inherited, and it was written for a sidebar. In a
   full-width container it broke a three-line quote into eight lines of three
   words. Widening it on the FIGURE did not help either, because ch resolves
   against that element's own font-size, which is body size: the 34px quote
   inside was still being measured in 8.5px units. The measure belongs on the
   blockquote, where the display type actually is. */
.pull { color: var(--ink); }

/* ---------------------------------------------------------------- feature rows */
.row { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 5vw, 64px); align-items: center; }
.row + .row { margin-top: clamp(48px, 7vw, 86px); }
.row img { border-radius: var(--radius-lg); aspect-ratio: 4/3; object-fit: cover; box-shadow: var(--shadow); }
.row-flip > figure { order: 2; }

.ticks { list-style: none; padding: 0; margin: 22px 0 0; display: grid; gap: 12px; }
.ticks li { display: grid; grid-template-columns: 22px 1fr; gap: 12px; align-items: start; color: var(--ink-2); }
.ticks svg { width: 20px; height: 20px; color: var(--brand); margin-top: 3px; }
.ticks b { color: var(--ink); font-weight: 650; }

/* The dealer-alternative points are the objections somebody has while deciding
   whether to call, so they get more room than a footnote list. */
.ticks-lg li { grid-template-columns: 24px 1fr; gap: 14px; font-size: 1.04rem; }
.ticks-lg li + li { margin-top: 4px; }
.ticks-lg svg { width: 22px; height: 22px; }

/* ---------------------------------------------------------------- call bar */
/* This business has exactly one funnel: a driver has a problem, decides
   they trust the shop, and calls. On a phone the header scrolls away, so the
   two actions that matter live at the bottom of the screen instead. Desktop
   never sees it; the header is always visible there. */
.callbar { display: none; }
@media (max-width: 620px) {
  .callbar {
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
    background: color-mix(in srgb, var(--bg) 94%, transparent);
    backdrop-filter: saturate(1.6) blur(12px);
    -webkit-backdrop-filter: saturate(1.6) blur(12px);
    border-top: 1px solid var(--line);
  }
  @supports not (backdrop-filter: blur(1px)) { .callbar { background: var(--bg); } }
  .callbar .btn { width: 100%; padding-inline: 10px; font-size: .95rem; }
  /* Room so the bar never covers the last line of the footer. */
  body { padding-bottom: 76px; }
}
/* ================================================================
   FRAMES-SPECIFIC. Everything below exists because this shop has no
   photographs. The Silver Star rebuild next door mined thirteen usable
   images off the owner's own live site; framesautomotive.com has served a
   Network Solutions frameset since 2016 whose target has been 404 since
   2018, so there is nothing to mine. No stock garage, no generated bays,
   no customer snapshots lifted off Yelp. The page carries its weight in
   type, rules and space instead.
   ================================================================ */

/* ---------------------------------------------------------------- type hero */
/* A photo hero borrows its drama from the photograph. With no photograph the
   drama has to come from scale and from the amount of quiet around it, so the
   measure is tight, the leading is closed up, and the whole block sits on a
   soft ground with a heavy brand rule down the left. */
.hero-type {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding-block: clamp(56px, 9vw, 118px);
}
.hero-type .wrap { position: relative; }
.hero-type h1 { max-width: 15ch; margin-bottom: .34em; }
.hero-type .lede {
  max-width: 54ch; font-size: clamp(1.06rem, 1.7vw, 1.24rem);
  color: var(--ink-2); margin-bottom: 34px;
}
.hero-type .eyebrow { margin-bottom: 20px; }
.hero-note {
  margin-top: 26px; padding-left: 16px; border-left: 3px solid var(--warn);
  max-width: 52ch; font-size: .96rem; color: var(--ink-2);
}
@media (min-width: 900px) {
  .hero-type .wrap::before {
    content: ""; position: absolute; left: calc(var(--gut) - 22px); top: 6px; bottom: 6px;
    width: 4px; border-radius: 4px; background: var(--brand);
  }
}

/* ---------------------------------------------------------------- hero card */
/* REMOVED. There was a bordered facts panel here, a dl of Where / When / What
   we take / The wait, sitting beside the headline. It was the single most
   template-looking thing on the site: a boxed table is what every builder-made
   shop page puts in that slot, and it made a page whose whole argument is
   "somebody actually built this" look generated.
   The hero is now full-bleed on their own storefront, the way the sibling
   build is, and those four facts live where they are actually useful: the
   address in the hero credit and the footer, the hours on /visit, the wait in
   the headline and in the How to get in section that follows it. */

/* ---------------------------------------------------------------- captions */
/* Photographs get real space here rather than being thumbnails apologizing for
   themselves, so they need a caption style that works on white and on the dark
   band without being restated in each place it appears. */
/* .cap removed: the photograph captions under the feature-row images were
   dropped at Ben's request. The rule is gone rather than left orphaned. */
.row figure { min-width: 0; }
.row figcaption { text-align: left; }

/* A pull quote given the full column instead of a narrow sidebar. At display
   size the serif is the loudest thing on the page and it should not be
   squeezed into a third of it. */
.pull-wide { margin-bottom: clamp(34px, 4.6vw, 52px); }
/* Centered variant, for a quote standing alone across the full measure rather
   than sitting beside something. The left rule and the left-aligned attribution
   read as a sidebar when there is nothing to its right, so both are dropped and
   the measure is centered. */

/* ================================================================
   STRUCTURE THAT IS DELIBERATELY NOT THE SIBLING BUILD'S.
   Peter Fuchs and Bill Frames are in the same building. Recoloring one
   skeleton and calling it two sites is exactly what would destroy the
   pitch if they ever compared. These four components exist so the pages
   have different silhouettes, not just different palettes.
   ================================================================ */

/* ---------------------------------------------------------------- split hero */
/* Type on a solid ground BESIDE a full-height photograph, rather than type
   sitting on top of a full-bleed image. Different silhouette at a glance, and
   it suits a 990px source better: the picture never has to span the viewport,
   so it is asked for half the width and stays sharp. */
.hero-split {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  background: var(--surface); border-bottom: 1px solid var(--line);
  align-items: stretch;
  /* The section owns the vertical rhythm, not the text column.
     Measured before this change: the photograph sat 0px below the header while
     the headline started 94px below it. The image looked like it was crashing
     into the nav and the two halves looked unrelated. Padding here insets BOTH
     columns by the same amount, so they start on the same line. */
  padding-block: clamp(30px, 3.6vw, 52px);
  /* The tinted band still spans the window, but the CONTENT is held to the same
     measure as every other section. The photograph used to run off the right
     edge of the screen, which made the hero the one place on the site that did
     not line up with anything below it. */
  padding-inline: max(var(--gut), calc((100% - var(--wrap)) / 2 + var(--gut)));
  gap: clamp(26px, 3.4vw, 52px);
}
.hero-split-text { display: flex; align-items: center; padding-block: 0; }
.hero-split-in { width: 100%; }
/* The global h1 clamp is sized for a full-width measure. In a half-width
   column it broke the headline into four ragged lines, so this one is scaled
   to the column it actually sits in rather than to the viewport. */
.hero-split h1 {
  max-width: 16ch; margin-bottom: .34em;
  font-size: clamp(2.4rem, 4.4vw, 3.9rem);
}
.hero-split .lede {
  max-width: 44ch; font-size: clamp(1.04rem, 1.5vw, 1.18rem);
  color: var(--ink-2); margin-bottom: 30px;
}
.hero-split .eyebrow { margin-bottom: 20px; }
.hero-addr { margin: 26px 0 0; font-size: .92rem; color: var(--ink-3); }
.hero-addr b { color: var(--ink-2); }
/* Rounded on the left, flush to the right edge. Bleeding off one side keeps
   the editorial split; rounding the side that faces the text stops it reading
   as a rectangle somebody forgot to finish. */
.hero-split-img {
  margin: 0; position: relative; overflow: hidden; background: var(--surface-2);
  border-radius: var(--radius-lg);
  min-height: clamp(340px, 38vw, 540px);
}
.hero-split-img picture, .hero-split-img img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
@media (max-width: 900px) {
  .hero-split {
    grid-template-columns: minmax(0, 1fr); gap: clamp(24px, 5vw, 36px);
    padding-block: clamp(22px, 5vw, 34px) clamp(34px, 6vw, 48px);
    padding-inline: var(--gut);
  }
  /* Full bleed on a phone: an inset panel with rounded corners wastes the only
     width there is, and the picture is the first thing worth seeing. */
  .hero-split-img {
    order: -1; position: relative; border-radius: var(--radius-lg); min-height: 0;
    height: clamp(230px, 54vw, 360px);
  }

}

/* ---------------------------------------------------------------- marks strip */
/* Six issued credentials, as a strip. NOT a row of four big numbers, which is
   the sibling's signature move. This shop's windows and walls are covered in
   marks somebody else issued, so listing them is both distinctive and true. */
.marks { background: var(--navy); color: #f3ece1; padding-block: clamp(20px, 2.4vw, 26px); }
/* ONE line, centered, no sub-notes.
   The first version was a six-column grid with a caption under each name. Two
   of the six wrapped to two lines and four did not, so the baselines were
   ragged and the captions sat at three different heights: fussy rather than
   confident, and the first thing the eye caught after the hero. A single row of
   names with thin separators is the classic accreditation strip and it reads as
   settled. The sourcing for each mark lives on /about, where it has room. */
.marks ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 10px clamp(16px, 2.2vw, 30px);
}
.marks li {
  position: relative; font-size: .76rem; font-weight: 640;
  letter-spacing: .095em; text-transform: uppercase; white-space: nowrap;
  color: rgba(243,236,225,.9);
}
.marks li + li::before {
  content: ""; position: absolute; left: calc(-1 * clamp(16px, 2.2vw, 30px) / 2);
  top: 50%; width: 3px; height: 3px; margin-top: -1.5px; border-radius: 50%;
  background: rgba(240,236,231,.7);
}
/* The review score sits ABOVE the strip, not in it, and is deliberately not
   dressed as a seventh accreditation.
   As a seventh item it pushed CERTIFIED EMISSIONS onto a second line on its
   own, which is the ragged wrap the note below this one was written about. On
   its own line the six marks keep the single row they were designed for and the
   score reads as the lead rather than as an orphan. The other six are things a third party awarded the shop; this
   is what its customers said, it is the strongest number the business has, and
   until now it appeared nowhere on the home page. Brighter than the marks
   beside it, and the star is amber rather than the brand red, which does not
   carry on a near-black bar. */
.marks-score {
  margin: 0 0 clamp(12px, 1.4vw, 16px); text-align: center; color: #fff;
  font-weight: 700; font-size: clamp(.92rem, 1.5vw, 1.06rem); letter-spacing: .01em;
}
.marks-star { color: #f0b429; font-size: 1.08em; }

/* 12.2px, not 11.5. rem resolves against the 16px root, so .72rem lands under
   the 12px floor. Third time this exact trap has been hit in this build. */
@media (max-width: 700px) {
  .marks li { font-size: .765rem; letter-spacing: .06em; }
  .marks ul { gap: 9px 16px; }
}

/* ---------------------------------------------------------------- posted list */
/* Services as a posted list of numbered rows with rules, echoing the hand-set
   board on their own wall. Replaces a three-card grid, which is what the
   sibling uses and what every template uses. */
.listing {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: clamp(18px, 3vw, 38px); align-items: baseline;
  padding-block: clamp(26px, 3.2vw, 36px); border-top: 1px solid var(--line);
}
.listing:last-of-type { border-bottom: 1px solid var(--line); }
/* The number is a marker, not a heading. It was competing with the title at
   the same weight, and the whole row read thin because the title was set at
   body scale with a lot of rule around it. */
.listing-n {
  font-size: .8rem; font-weight: 700; color: var(--ink-3);
  letter-spacing: .08em; line-height: 2.4;
}
.listing-b h3 { margin-bottom: 7px; font-size: clamp(1.28rem, 1.9vw, 1.55rem); }
.listing-b p { margin: 0; color: var(--ink-2); max-width: 62ch; font-size: 1.02rem; }
.listing-a a { font-weight: 650; font-size: .93rem; white-space: nowrap; }
@media (max-width: 640px) {
  .listing { grid-template-columns: auto minmax(0, 1fr); row-gap: 10px; }
  .listing-a { grid-column: 2; }
}

/* The full-bleed photo band was REMOVED. It cropped a portrait photograph of
   the waiting room to 21:9, which cut the Coca-Cola machine and the gas pump
   off at the knees to make a banner out of a picture that is not banner-shaped.
   The lobby now sits at its own 3:4 in a feature row where the whole scene is
   visible. If a genuinely landscape photograph ever arrives, this component is
   in the git history.
   The .band .btn-primary override went with it; .dark .btn-primary still
   covers every dark ground that remains. */

/* ---------------------------------------------------------------- ways in */
/* An ordered list with its own numerals, not three floating cards. */
.ways { list-style: none; margin: 0; padding: 0; counter-reset: w; }
.ways li {
  counter-increment: w; position: relative;
  padding: 20px 0 20px 44px; border-top: 1px solid var(--line);
}
.ways li:first-child { border-top: 0; padding-top: 0; }
.ways li:first-child::before { top: 0; }
.ways li::before {
  content: counter(w); position: absolute; left: 0; top: 20px;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--brand); color: var(--brand-ink);
  font-size: .82rem; font-weight: 750; display: grid; place-items: center;
}
.ways h3 { font-size: 1.06rem; margin-bottom: 4px; }
.ways p { margin: 0 0 8px; color: var(--ink-2); font-size: .98rem; }
.ways a { font-weight: 650; font-size: .93rem; display: inline-block; padding-block: 4px; margin-block: -4px; min-height: 24px; }

/* ---------------------------------------------------------------- flat cards */
/* The card component was built around a 3:2 image at the top. Without one the
   remaining box is all padding and no anchor, so the flat variant gets a rule
   across the top instead, which is the same job the photograph was doing:
   telling the eye where the card starts. */
.card-flat { border: 1px solid var(--line); border-top: 3px solid var(--brand); box-shadow: none; }
.card-flat:hover { box-shadow: var(--shadow); }
.card-flat .card-body { padding-top: 24px; }

/* Numbered steps. The number is decorative and must not be read out, so it is
   a CSS-generated glyph rather than markup. */
.card-num .card-body { position: relative; padding-top: 26px; }
.card-num .card-body::before {
  content: var(--n); display: block; font-size: .84rem; font-weight: 800;
  letter-spacing: .16em; color: var(--brand); margin-bottom: 10px;
}

/* ---------------------------------------------------------------- makes row */
/* THIRTY-THREE names, not six. Set as type rather than as manufacturer logos:
   thirty-three carmakers' marks on an independent shop's site is real trademark
   exposure, and the sibling build removed the Mercedes star for exactly that
   reason. At this count the list makes the argument on its own, which six pills
   never did. Slightly smaller and tighter than the six-item version so the
   block reads as a set rather than as thirty-three separate buttons. */
/* A LOGO WALL, centered.
   Full-color marks need room: at the 15px the text chips used they were mush.
   One sprite, img/marks.webp, 30 cells of 200x64 shown at 100x32, so the whole
   wall is a single request and no third-party call. The custom property --i is
   the cell index.
   All 33 have a mark now. */
.makes {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(6px, 1vw, 12px);
  margin-top: clamp(26px, 3.4vw, 40px); padding-top: clamp(26px, 3vw, 34px);
  border-top: 1px solid var(--line);
}
.makes .mk {
  width: 100px; height: 32px; flex: 0 0 auto;
  background-image: url("/img/marks.webp");
  background-repeat: no-repeat;
  background-size: 3300px 32px;                 /* 33 cells x 100px */
  background-position: calc(var(--i) * -100px) 0;
  filter: saturate(.92);
}
.makes .mk-name {
  width: 100px; height: 32px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .8rem; font-weight: 650; color: var(--ink-3);
  text-align: center; line-height: 1.15;
}
@media (max-width: 560px) {
  .makes .mk, .makes .mk-name { width: 84px; height: 27px; }
  .makes .mk { background-size: 2772px 27px; background-position: calc(var(--i) * -84px) 0; }
  /* 12.2px. .72rem is 11.5px against the 16px root, under the floor. */
  .makes .mk-name { font-size: .765rem; letter-spacing: -.01em; }
}
.makes .makes-more { border-style: dashed; color: var(--ink-3); font-weight: 550; }

/* ---------------------------------------------------------------- credentials */
.creds { list-style: none; padding: 0; margin: 0; display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; }
.creds li { background: var(--bg); padding: 24px clamp(20px, 3vw, 30px); }
.creds h3 { margin-bottom: 6px; }
.creds p { color: var(--ink-2); margin-bottom: 8px; font-size: .99rem; max-width: 68ch; }
.creds .src { font-size: .82rem; color: var(--ink-3); }
@media (min-width: 860px) { .creds { grid-template-columns: 1fr 1fr; } }

/* ---------------------------------------------------------------- warn note */
/* Amber is reserved for the wait and for nothing else on this site, so it
   reads as one idea rather than as decoration. Dark ink on a pale amber
   ground; the amber never carries text itself. */
/* .note-warn moved: it used to sit HERE, 146 lines before the .note rule it
   was meant to override. Equal specificity, so .note won on source order and
   the amber "this is about the wait" box has been rendering in brand pink the
   whole time. The one-color-one-idea rule documented at the top of this file
   was therefore never true on screen. Found by sampling the rendered pixel
   rather than by reading the stylesheet. */

/* ---------------------------------------------------------------- pull quote */
.pull { margin: 0; }
.pull blockquote {
  margin: 0; font-family: var(--serif); font-style: italic;
  font-size: clamp(1.5rem, 3vw, 2.15rem); line-height: 1.32; color: var(--ink);
  border-left: 3px solid var(--brand); padding-left: clamp(18px, 2.4vw, 28px);
  /* ch here resolves against the display size, so this is roughly characters
     per line. 21 was too tight: a comfortable display measure is low 30s. */
  max-width: 32ch;
}
.pull-wide blockquote { font-size: clamp(1.7rem, 3.6vw, 2.7rem); max-width: 26ch; }
.pull figcaption {
  margin-top: 18px; padding-left: clamp(21px, 2.4vw, 31px);
  font-family: var(--sans); font-style: normal; font-size: .86rem;
  line-height: 1.45; color: var(--ink-3);
}
/* CENTERED VARIANT. Must sit AFTER the .pull rules above: equal specificity,
   so source order decides, and placed before them the base rule put the left
   bar and the 32ch measure straight back. That is the fifth time in this build
   a modifier landed above its base; tools/content.js now checks for it. */
.pull-center { margin-block: clamp(44px, 6vw, 72px) 0; text-align: center; }
.pull-center blockquote {
  border-left: 0; padding-left: 0; max-width: 30ch;
  margin-inline: auto; text-wrap: balance;
}
.pull-center figcaption { padding-left: 0; margin-top: 22px; text-align: center; }


/* ---------------------------------------------------------------- splits */
.sec-head-wide { max-width: 100%; }
.sec-head-wide h2 { max-width: 24ch; }

/* ---------------------------------------------------------------- evidence */
/* The /evidence page. Rows are labeled by how each one can be checked, which
   is the whole argument: none of it is an opinion about design. */
.ev { list-style: none; padding: 0; margin: 0; display: grid; gap: 18px; }
/* min-width:0 is load-bearing. A grid item defaults to min-width:auto, so the
   widest <pre> inside a finding refused to shrink and pushed the whole document
   to 686px in a 640px viewport at 200% text. Same root cause as the .split
   fix above, found by the reflow check rather than by eye. */
.ev li { min-width: 0; border: 1px solid var(--line); border-left: 3px solid var(--warn); border-radius: var(--radius); padding: 22px clamp(20px, 2.6vw, 28px); }
.ev li.ev-good { border-left-color: var(--good); }
.ev h3 { margin-bottom: 8px; }
.ev p { color: var(--ink-2); margin-bottom: 10px; max-width: 74ch; }
.ev p:last-child { margin-bottom: 0; }
.ev .tag {
  display: inline-block; font-size: .79rem; font-weight: 750; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 10px;
}
.ev code, .mono {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: .87em; background: var(--surface-2); border-radius: 5px; padding: 2px 6px;
  overflow-wrap: anywhere;
}
.ev pre {
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px;
  padding: 14px 16px; overflow-x: auto; font-size: .84rem; line-height: 1.55; margin: 0 0 12px;
  max-width: 100%;
}
/* font-size MUST be reset here. .ev code sets .87em, which compounds against
   the pre's own size and lands the text at 11.4px.
   overflow-wrap MUST be reset too. .ev code sets it to anywhere, which is right for
   a domain name in a sentence and wrong inside a <pre>: the code element then
   grows to its unwrapped width and pokes 81px past a 390px screen, because the
   pre scrolls but the child was never told it could not. Resetting to normal keeps the
   command output on its own lines and lets the pre do the scrolling. */
.ev pre code {
  background: none; padding: 0; font-size: 1em;
  overflow-wrap: normal; word-break: normal; display: block; min-width: 0;
}

/* A rendered stand-in for what a browser shows at their domain today. */
.deadbox {
  border: 1px solid var(--line-strong); border-radius: var(--radius); overflow: hidden;
  background: var(--bg); max-width: 520px;
}
.deadbox-bar {
  display: flex; align-items: center; gap: 8px; padding: 10px 12px;
  background: var(--surface-2); border-bottom: 1px solid var(--line);
  font-size: .8rem; color: var(--ink-3);
}
.deadbox-url {
  flex: 1; background: var(--bg); border: 1px solid var(--line); border-radius: 999px;
  padding: 5px 12px; color: var(--ink-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .78rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.deadbox-body { padding: 34px 26px; text-align: center; }
.deadbox-body h4 { font-size: 1.02rem; margin-bottom: 8px; color: var(--ink); }
.deadbox-body p { font-size: .89rem; color: var(--ink-3); margin: 0; }

/* ---------------------------------------------------------------- numbered rows */
/* The services page was three image cards. With no images it is three numbered
   rows instead, which suits a short list of broad capabilities better than
   cards did: the number carries the rhythm and the text gets full measure. */
/* Raised cards, matching the four on the home page rather than inventing a
   second treatment for the same four services. Rules between rows became a
   border and a shadow; the numbers and the covers lists are unchanged. */
.row-plain {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(20px, 4vw, 46px);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: clamp(26px, 3.4vw, 40px);
  transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.row-plain + .row-plain { margin-top: clamp(18px, 2.2vw, 26px); }
.row-plain:hover {
  border-color: var(--brand-edge);
  box-shadow: var(--shadow-lg);
  transform: translateY(-2px);
}
@media (prefers-reduced-motion: reduce) { .row-plain:hover { transform: none; } }
.row-plain-num { font-size: clamp(1.5rem, 3vw, 2.3rem); font-weight: 830; letter-spacing: -0.04em; color: var(--brand); line-height: 1; padding-top: .18em; }
.row-plain-body h2 { max-width: 20ch; }
.row-plain-body .lede { font-size: clamp(1.06rem, 1.5vw, 1.18rem); color: var(--ink-2); max-width: 56ch; }
.row-plain-body p { max-width: 70ch; }
@media (max-width: 620px) { .row-plain { grid-template-columns: minmax(0, 1fr); gap: 10px; } }
.row-plain + .makes { margin-top: clamp(34px, 4.5vw, 54px); }

.chips { list-style: none; padding: 0; margin: 22px 0 0; display: flex; flex-wrap: wrap; gap: 9px; }
.chips li { font-size: .9rem; color: var(--ink-2); background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 7px 13px; }
.sec-alt .chips li { background: var(--bg); }

/* An answer we have not confirmed is flagged rather than quietly polished.
   The whole argument of this site is that it says only what can be checked. */
.faq-flag { margin-top: 10px; font-size: .88rem; font-weight: 620; color: var(--warn); }

/* ---------------------------------------------------------------- hours table */
.hrs { width: 100%; border-collapse: collapse; margin-top: 6px; }
.hrs th, .hrs td { text-align: left; padding: 14px 0; border-bottom: 1px solid var(--line); font-weight: 500; }
.hrs th { font-weight: 650; color: var(--ink); }
.hrs td { color: var(--ink-2); text-align: right; }
.hrs .hrs-off th, .hrs .hrs-off td { color: var(--ink-3); }
.hrs tr:last-child th, .hrs tr:last-child td { border-bottom: 0; }

.kv-plain { background: none; border: 0; padding: 0; }

/* Fact cards on the visit page: hours, and how to find the place. Raised like
   the service cards rather than a heading over open space and a gray box. */
.fact-card {
  background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
  padding: clamp(22px, 2.6vw, 30px);
}
.fact-card + .fact-card { margin-top: clamp(18px, 2.2vw, 24px); }
.fact-head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 10px 16px;
  margin-bottom: 6px;
}
.fact-head h2 { margin: 0; font-size: clamp(1.3rem, 2.2vw, 1.72rem); }
/* The live status belongs beside the heading, where somebody checking whether
   they can turn up right now is already looking. */
.pill {
  font-size: .8rem; font-weight: 650; color: var(--ink-2);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 999px; padding: 5px 12px; white-space: nowrap;
}
.pill-open { color: var(--good); background: var(--good-soft); border-color: var(--good); }
/* Label above value. Side by side, the labels were a narrow column of small
   gray words squeezing the addresses next to them onto three lines each. */
.facts { display: grid; gap: clamp(15px, 1.8vw, 19px); margin: clamp(14px, 1.6vw, 18px) 0 0; }
.facts dt {
  /* .765rem, not .74. rem resolves against the 16px root, so .74 lands at
     11.8px and under the 12px floor. FOURTH time this exact trap has been hit
     in this build; the sweep caught it again. */
  font-size: .765rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 3px;
}
.facts dd { margin: 0; color: var(--ink); font-size: 1.02rem; line-height: 1.5; }
.facts dd a { display: inline-block; padding-block: 3px; margin-block: -3px; min-height: 24px; }

/* ---------------------------------------------------------------- tap floor */
/* Bare links inside definition lists and running text measured 19-20px tall,
   under the 24px touch target floor: a text link is only as tall as its line
   box. Padding rather than a height, so nothing on the page moves, and the
   negative margin keeps the list rhythm identical to before. */
/* Bare text links measure only as tall as their line box, which is 18-20px,
   under the 24px touch floor. Padding rather than a height, so nothing on the
   page moves, and the negative margin keeps the surrounding rhythm identical.
   The list grew every time a new component added a bare link; the audit has
   caught it three separate times now, which is the check earning its keep. */
.kv dt a, .kv dd a, .res-route a, .creds a, .ev a, .panel p > a,
.listing-a a, .sec p > a, .cap a {
  display: inline-block; padding-block: 4px; margin-block: -4px; min-height: 24px;
}
/* .res-route's link sits at the end of a sentence, so padding alone leaves it
   19px tall: the line box, not the padding, was the constraint. An explicit
   line-height gets it over 24 without moving the sentence around it. */
.res-route a { line-height: 1.5; padding-block: 5px; margin-block: -5px; }

@media print { .callbar { display: none !important; } }

/* ---------------------------------------------------------------- forms */
.form { display: grid; gap: 18px; }
.field { display: grid; gap: 7px; }
.field label { font-weight: 650; font-size: .93rem; color: var(--ink); }
.field .hint { font-size: .85rem; color: var(--ink-3); font-weight: 400; }
.field input, .field select, .field textarea {
  font: inherit; font-size: 1rem; color: var(--ink); background: var(--bg);
  border: 1px solid var(--line-strong); border-radius: 10px; padding: 13px 14px;
  width: 100%; min-height: 50px;
}
.field textarea { min-height: 128px; resize: vertical; line-height: 1.55; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--brand); }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-3); }
.field-err input, .field-err select, .field-err textarea { border-color: #c0392b; }
.err { color: #c0392b; font-size: .87rem; font-weight: 600; }
.f-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }

.note {
  background: var(--brand-soft); border: 1px solid var(--brand-edge);
  border-radius: var(--radius); padding: 18px 20px; font-size: .95rem; color: var(--ink-2);
}
.note b { color: var(--ink); }
/* Amber is reserved for one idea, the wait, and appears nowhere else. This
   must stay AFTER .note: equal specificity means source order decides. */
.note-warn { background: var(--warn-soft); border-color: var(--warn-edge); }
.note-warn p:last-child { margin-bottom: 0; }
.note + .note, .grid + .note, .split + .note { margin-top: clamp(26px, 3.4vw, 38px); }

.ok {
  background: var(--good-soft); border: 1px solid color-mix(in srgb, var(--good) 34%, transparent);
  border-radius: var(--radius); padding: 22px 24px;
}
.ok h3 { color: var(--good); margin-bottom: 8px; }

/* ---------------------------------------------------------------- splits */
/* Two-column layouts that actually collapse. Inline grid-template-columns had
   no breakpoint, and because a 1fr track is min-width:auto by default the
   columns refused to shrink and forced the whole document wider than the
   phone. minmax(0, Nfr) plus a real media query fixes both halves of that. */
.split { display: grid; gap: clamp(28px, 5vw, 64px); align-items: start; }
.split-6-5 { grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); align-items: center; }
/* Must stay BELOW the rule it overrides. Moving .split-6-5 down to fix an
   earlier cascade-order bug left this media query 150 lines ABOVE it, so the
   two-column base won and the evidence page's Google-result cards never
   stacked on a phone. Fixing one ordering bug created another; the gate only
   looked at top-level rules and could not see it. */
@media (max-width: 900px) { .split-6-5 { grid-template-columns: minmax(0, 1fr); } }
.split-form { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); }
.split-cta { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 40px; align-items: center; }
@media (max-width: 900px) {
  .split-form, .split-cta { grid-template-columns: minmax(0, 1fr); }
  .split-form aside, .split-cta dl { position: static !important; }
}

/* ---------------------------------------------------------------- panels */
/* Shadowed, like every other card on the site. Border and radius alone left
   the panels reading as flatter, older boxes beside the service, review and
   hours cards, which all sit on the same page as one of these. */
.panel {
  background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
  padding: clamp(24px, 3.4vw, 38px);
}
.sec-alt .panel { background: var(--bg); }

.kv { display: grid; grid-template-columns: auto 1fr; gap: 10px 20px; font-size: .98rem; }
.kv dt { color: var(--ink-3); }
.kv dd { margin: 0; color: var(--ink); font-weight: 550; }

/* A figure we could not open the source for says so, in the same place the
   figure is. The FAQ already flags an unconfirmed answer this way. */
.kv-flag {
  display: block; margin-top: 3px; font-size: .8rem; font-weight: 600;
  color: var(--warn); letter-spacing: 0;
}

/* ---------------------------------------------------------------- compare */
/* A fake Google result. Deliberately plain: the moment it looks designed it
   stops reading as "this is what Google shows" and starts reading as a slide. */
.serp {
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
  padding: 20px 22px; font-family: arial, sans-serif;
}
.serp-bad { border-color: color-mix(in srgb, #c0392b 40%, var(--line)); }
.serp-url { font-size: .82rem; color: var(--ink-2); margin-bottom: 4px; }
.serp-title {
  font-size: 1.22rem; line-height: 1.3; color: #1a0dab; font-weight: 400;
  letter-spacing: 0; margin-bottom: 5px;
}
.serp-desc { font-size: .88rem; line-height: 1.58; color: var(--ink-2); }
.serp-rating { margin-top: 7px; font-size: .84rem; color: var(--ink-2); }
.serp-stars { color: #b85a00; letter-spacing: -1px; }

.cmp-tag {
  display: inline-block; font-size: .8rem; font-weight: 750; letter-spacing: .09em;
  text-transform: uppercase; padding: 5px 11px; border-radius: 6px; margin-bottom: 12px;
}
.cmp-tag-bad { background: #fbe9e7; color: #a02c1c; }
.cmp-tag-good { background: var(--brand-soft); color: var(--brand); }
.cmp-note { font-size: .95rem; color: var(--ink-2); margin-top: 16px; }

/* The comparison table. A real <table> would be the semantic choice, but this
   has to collapse to a readable stack on a phone and carry a "why it matters"
   line under every row, which a table fights. Grid with explicit labels. */
.cmp { border-top: 2px solid var(--ink); }
.cmp-head {
  display: grid; grid-template-columns: 1.15fr 1fr 1fr;
  gap: 20px; padding: 14px 0; font-size: .78rem; font-weight: 750;
  letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3);
  border-bottom: 1px solid var(--line);
}
.cmp-row {
  display: grid; grid-template-columns: 1.15fr 1fr 1fr;
  gap: 8px 20px; padding: 20px 0; border-bottom: 1px solid var(--line);
  align-items: start;
}
.cmp-what { font-weight: 680; color: var(--ink); }
.cmp-kind {
  display: block; margin-top: 6px; font-size: .78rem; font-weight: 600;
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3);
}
.cmp-old, .cmp-new { display: grid; grid-template-columns: 20px 1fr; gap: 9px; color: var(--ink-2); font-size: .97rem; }
.cmp-new { color: var(--ink); font-weight: 550; }
.mark { font-weight: 800; line-height: 1.5; }
.mark-bad { color: #c0392b; }
.mark-ok { color: var(--good); }
.cmp-why {
  grid-column: 1 / -1; margin-top: 10px; font-size: .93rem; color: var(--ink-3);
  line-height: 1.55; max-width: 84ch;
}
.cmp-row.is-tie .cmp-what { font-weight: 600; color: var(--ink-2); }
.cmp-row.is-tie { background: color-mix(in srgb, var(--good) 5%, transparent); }

.big-num {
  font-size: clamp(2.6rem, 6vw, 4.4rem); font-weight: 830; letter-spacing: -0.05em;
  line-height: 1; color: var(--ink); margin-bottom: 14px;
}
.big-num .u { font-size: .34em; font-weight: 700; letter-spacing: -0.01em; color: var(--ink-3); margin-left: 5px; }

@media (max-width: 780px) {
  .cmp-head { display: none; }
  .cmp-row { grid-template-columns: 1fr; gap: 10px; padding: 22px 0; }
  .cmp-old::before { content: "Today: "; font-weight: 700; color: var(--ink-3); }
  .cmp-new::before { content: "New: "; font-weight: 700; color: var(--ink-3); }
  .cmp-old, .cmp-new { grid-template-columns: 20px auto 1fr; }
  .cmp-why { margin-top: 4px; }
}

/* ---------------------------------------------------------------- offer page */
.step { position: relative; padding-top: 30px; }
.step-n {
  position: absolute; top: -18px; left: clamp(24px, 3.4vw, 38px);
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--brand); color: var(--brand-ink);
  display: grid; place-items: center; font-weight: 820; font-size: 1.16rem;
}
.step h3 { margin-top: 6px; }
.step-who {
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: .9rem; color: var(--ink-3);
}
.step-who b { color: var(--ink-2); }

.price { background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: clamp(24px, 3vw, 34px); }
.price-row { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.price-row span { color: var(--ink-2); font-size: 1rem; }
.price-row b { font-size: clamp(1.9rem, 3.4vw, 2.5rem); font-weight: 820; letter-spacing: -0.04em; color: var(--ink); }
.price-row .per { font-size: .42em; font-weight: 700; color: var(--ink-3); letter-spacing: -0.01em; }
.price-note { margin-top: 8px; font-size: .92rem; color: var(--ink-3); line-height: 1.5; max-width: 46ch; }

.reason-stat { text-align: left; }
.reason-stat .big-num { color: var(--brand); margin-bottom: 6px; }
.reason-lbl { font-size: .96rem; color: var(--ink-3); max-width: 22ch; line-height: 1.42; }

/* ---------------------------------------------------------------- results */
.res-row {
  display: grid; grid-template-columns: 1fr 1.5fr auto; gap: 10px 24px;
  padding: 18px 14px; border-bottom: 1px solid var(--line); align-items: start;
}
.res-row.is-after { background: var(--brand-soft); }
.res-name { font-weight: 700; color: var(--ink); }
.res-meta { font-size: .9rem; color: var(--ink-3); margin-top: 2px; }
.res-problem { color: var(--ink-2); font-size: .97rem; }
.res-when { font-size: .87rem; color: var(--ink-3); text-align: right; white-space: nowrap; }
.res-tag {
  display: block; margin-top: 6px; font-size: .78rem; font-weight: 750;
  letter-spacing: .06em; text-transform: uppercase; color: var(--brand);
}
@media (max-width: 780px) {
  .res-row { grid-template-columns: 1fr; gap: 6px; }
  .res-when { text-align: left; }
  .res-tag { display: inline-block; margin-top: 4px; }
}

/* ---------------------------------------------------------------- services */
/* Compact rows, not full-bleed bands.
   The bands were a mistake: adding a six-item list made the text column tall,
   the band stretched to match, and a 4:3 photograph got forced into a 720x500
   box. A close-up of an engine at that size stops being informative and becomes
   an abstract, and three of them in a row shout at the reader.
   The photograph is now a fixed 300px thumbnail: small enough to stay sharp
   from an 800px source, small enough not to dominate, and the content, which is
   the actual point of a services page, gets the room. */
.svcs { list-style: none; margin: 0; padding: 0; border-top: 2px solid var(--ink); }
.svc {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr) minmax(0, 15rem);
  gap: clamp(22px, 3vw, 44px);
  padding: clamp(26px, 3vw, 40px) 0;
  border-bottom: 1px solid var(--line);
  /* Center, not start: the covers column is shorter than the text beside it, so
     top-aligning left it hanging off the top of the row. */
  align-items: center;
}
.svc-shot { margin: 0; }
/* The inherited .svc / .svc-shot / .svc-covers block was REMOVED. It styled a
   services layout this build does not have, and two of its selectors collided
   by NAME with the new home-page component: its .svc-covers li carried a
   padding-left and a red ::before dot, which painted a bullet inside every
   chip, and its .svc-n set display:block. Same class of defect as .note-warn
   and .pull: an inherited rule reaching a component written later, invisible
   until you look at what actually rendered. */

@media (max-width: 440px) { .svc-covers { grid-template-columns: 1fr; } }

.shot-cap { margin-top: 9px; font-size: .84rem; color: var(--ink-3); }

/* ---------------------------------------------------------------- findings */
/* Each finding shows evidence first, then explains. The two-column footer is
   the part that matters: "what is wrong" and "why it matters to you" side by
   side, so the second is never skipped. A defect without a consequence is
   trivia, and trivia is what a shop owner has learned to tune out. */
.find { border-top: 2px solid var(--ink); padding-top: 26px; margin-top: clamp(38px, 5vw, 58px); }
.find:first-of-type { margin-top: 0; }
.find-head { display: grid; grid-template-columns: 4rem 1fr; gap: clamp(12px, 2vw, 24px); align-items: start; margin-bottom: 24px; }
.find-n { font-size: 1.7rem; font-weight: 830; letter-spacing: -0.04em; color: var(--brand); line-height: 1; }
.find-head h3 { font-size: clamp(1.35rem, 2.3vw, 1.85rem); margin: 0 0 8px; max-width: 26ch; }
.find-check { display: flex; align-items: center; gap: 8px; margin: 0; font-size: .88rem;
  font-weight: 650; letter-spacing: .02em; color: var(--good); }
.find-check svg { width: 15px; height: 15px; flex: 0 0 auto; }
.find-show { margin-bottom: 26px; }
.find-why { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 3vw, 40px);
  padding-top: 22px; border-top: 1px solid var(--line); }
.find-why h4 { font-size: .76rem; font-weight: 750; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3); margin: 0 0 8px; }
.find-why p { margin: 0; color: var(--ink-2); font-size: .99rem; line-height: 1.6; }
.find-why > div:last-child p { color: var(--ink); }

/* Evidence blocks: a plain fact table, deliberately unstyled-looking, because
   the moment it looks designed it starts reading as a claim again. */
.evidence { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.evidence-row { display: grid; grid-template-columns: 14rem 1fr; gap: 18px;
  padding: 14px 18px; border-bottom: 1px solid var(--line); font-size: .95rem; }
.evidence-row:last-child { border-bottom: 0; }
.evidence-row > b { color: var(--ink-3); font-weight: 650; font-size: .88rem; }
.evidence-row span, .evidence-row code { color: var(--ink-2); }
.evidence-row code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .86rem; word-break: break-all; }
.evidence-note { margin-top: 16px; font-size: .95rem; color: var(--ink-2); max-width: 66ch; }

/* The misspelling, shown at something like the size he actually ships it at.
   Describing this one is far weaker than showing it: a driver reads the
   headline and draws their own conclusion in about a second. */
.misspell { border: 1px solid var(--line-strong); border-radius: var(--radius); overflow: hidden; }
.misspell-lbl {
  padding: 10px 18px; background: var(--surface); border-bottom: 1px solid var(--line);
  font-size: .78rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3);
}
.misspell-h1 {
  margin: 0; padding: clamp(24px, 4vw, 44px) clamp(18px, 3vw, 32px);
  font-size: clamp(1.7rem, 4.6vw, 3.1rem); font-weight: 500; line-height: 1.14;
  letter-spacing: -0.02em; color: var(--ink);
}
.misspell-word {
  position: relative; color: #b3261e; font-weight: 700;
  text-decoration: underline wavy #b3261e; text-underline-offset: 6px; text-decoration-thickness: 2px;
}
.misspell-foot {
  display: flex; flex-wrap: wrap; gap: 6px 28px;
  padding: 12px 18px; border-top: 1px solid var(--line); background: var(--surface);
  font-size: .86rem; color: var(--ink-2);
}
.misspell-foot b { color: var(--ink-3); font-weight: 650; margin-right: 5px; }
.misspell-foot code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .84rem; }

/* The "what happens instead" block. Only one finding has an answer worth
   showing rather than describing, and this is it: two real emails, rendered by
   the same code that sends them. */
.answer { margin-top: 26px; padding-top: 24px; border-top: 1px solid var(--line); }
.answer-head { margin-bottom: 20px; }
.answer-head p { margin: 10px 0 0; color: var(--ink-2); font-size: .99rem; max-width: 66ch; }
.shot { margin: 0; }
.shot-when {
  font-size: .82rem; color: var(--ink-3); margin-bottom: 9px;
  padding-bottom: 8px; border-bottom: 1px solid var(--line);
}
.shot-when b { color: var(--ink); font-weight: 700; margin-right: 6px; }
.shot img {
  width: 100%; height: auto; border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.shot figcaption { margin-top: 11px; font-size: .9rem; color: var(--ink-2); line-height: 1.5; }
.answer-note {
  margin-top: 22px; padding: 15px 18px; background: var(--brand-soft);
  border: 1px solid var(--brand-edge); border-radius: var(--radius);
  font-size: .94rem; color: var(--ink-2); line-height: 1.55;
}
.answer-note b { color: var(--ink); }
/* The two shots are very different heights, so top-align them rather than
   letting the shorter one float in the middle of its column. */
.answer .grid.g-2 { align-items: start; }

/* The week, as a bar. 45 open hours against 123 with no letterbox. */
.clock-bar { display: flex; height: 58px; border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--line-strong); font-size: .85rem; font-weight: 650; }
.clock-open { flex: 0 0 var(--open-share, 26.8%); background: var(--good-soft); color: var(--good);
  display: grid; place-items: center; text-align: center; padding: 0 6px; }
.clock-shut { flex: 1; background: var(--brand-soft); color: var(--brand);
  display: grid; place-items: center; text-align: center; padding: 0 10px; }
.clock-lbl { margin-top: 9px; font-size: .84rem; color: var(--ink-3); }

.ok-panel { border-left: 3px solid var(--good); }

@media (max-width: 780px) {
  .find-head { grid-template-columns: 1fr; gap: 6px; }
  .find-why { grid-template-columns: 1fr; gap: 20px; }
  .evidence-row { grid-template-columns: 1fr; gap: 4px; }
  /* 26.8% of a phone is 105px, which cannot hold "45 hours open" at a legible
     size. Stack the two bars and keep the proportion in the heights instead. */
  .clock-bar { flex-direction: column; height: auto; font-size: .86rem; }
  .clock-open { flex: 0 0 auto; padding: 12px 10px; }
  .clock-shut { flex: 0 0 auto; padding: 26px 10px; }
}

/* ---------------------------------------------------------------- side by side */
.race { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px, 2.4vw, 30px); }
.race-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.race-head .cmp-tag { margin-bottom: 0; }
.race-time {
  font-size: .92rem; font-weight: 750; color: var(--ink-3);
  font-variant-numeric: tabular-nums; min-width: 4.5em; text-align: right;
}
.race-time.is-done { color: var(--ink); }
/* A fixed-height window onto each site, scaled down so a desktop layout is
   recognizable at half width. transform, not zoom: zoom is not in the spec and
   Firefox ignores it, which would show one site at half scale and the other at
   full and make the comparison a lie. */
.race-frame {
  position: relative; height: clamp(320px, 46vw, 520px);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  overflow: hidden; background: var(--surface-2);
}
.race-frame iframe {
  position: absolute; top: 0; left: 0; border: 0;
  width: 200%; height: 200%;
  transform: scale(.5); transform-origin: 0 0;
}
.race-note { margin-top: 9px; font-size: .84rem; color: var(--ink-3); }

@media (max-width: 820px) {
  .race { grid-template-columns: 1fr; }
  .race-frame { height: 62vw; }
}

/* ---------------------------------------------------------------- reviews */
.rev-head { display: grid; grid-template-columns: 1.5fr auto; gap: clamp(28px, 5vw, 60px); align-items: end; }
.rev-score { text-align: right; flex: 0 0 auto; }
.rev-score-n { font-size: clamp(3.4rem, 8vw, 5.6rem); font-weight: 830; letter-spacing: -0.05em; line-height: .9; color: var(--ink); }
.rev-score-s { color: var(--brand); font-size: 1.34rem; letter-spacing: 1px; margin-top: 6px; }
.rev-score-l { font-size: .88rem; color: var(--ink-3); margin-top: 6px; }

.srcs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; }
.src-cell { background: var(--bg); padding: 22px clamp(14px, 2vw, 24px); }
/* The whole cell is the link, so the figure and the service name are one target
   rather than a small word at the bottom. The b, span and em inside all set
   their own color, so nothing turns brand red, but text-decoration is drawn by
   the anchor across its descendants and has to be turned off here. The tint on
   hover is the affordance: without it a cell reads as a static statistic and
   nobody discovers it is clickable. */
a.src-cell {
  display: block; color: inherit; text-decoration: none;
  transition: background .16s ease;
}
a.src-cell:hover { background: var(--surface); }
a.src-cell:hover em { color: var(--brand); }
.src-cell b { display: block; font-size: clamp(1.6rem, 3vw, 2.2rem); font-weight: 820;
  letter-spacing: -0.04em; line-height: 1; color: var(--ink); }
.src-cell b .u { font-size: .42em; font-weight: 700; color: var(--ink-3); }
/* CHILD combinator, not descendant. Written as a bare element selector this
   rule also matched the .u unit nested inside the b, so the /5 and the % were
   turned into blocks and dropped onto their own line under the number. The .u
   rule above sets size, weight and color but never display, so the general rule
   won despite being the less specific of the two. Same shape as the stat rule a
   few hundred lines up, which is a child selector for exactly this reason. */
.src-cell > span { display: block; margin-top: 7px; font-size: .88rem; color: var(--ink-2); line-height: 1.4; }
.src-cell em { display: block; margin-top: 5px; font-style: normal; font-size: .76rem;
  font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }

.rev-feature { display: grid; grid-template-columns: 1.35fr .65fr; gap: clamp(28px, 5vw, 64px); align-items: center; }
.rev-attr b { display: block; font-size: 1.02rem; color: var(--ink); }
.rev-attr span { font-size: .88rem; color: var(--ink-3); }

.theme + .theme { margin-top: clamp(44px, 6vw, 72px); }
/* Three lines of near-equal weight stacked with nothing between them read as
   three orphans. The number and the mention count now sit in their own column
   against a rule, the claim is the only thing at heading weight, and the note
   below it is visibly a footnote rather than a second claim. */
.theme-head {
  display: grid; grid-template-columns: 7.5rem 1fr; gap: clamp(18px, 3vw, 36px);
  align-items: start; padding-bottom: 20px; margin-bottom: 24px;
  border-bottom: 1px solid var(--line-strong);
}
.theme-mark { border-top: 3px solid var(--brand); padding-top: 10px; }
.theme-n { display: block; font-size: 1.5rem; font-weight: 830; letter-spacing: -0.03em; color: var(--brand); line-height: 1; }
.theme-count { display: block; margin-top: 6px; font-size: .78rem; font-weight: 650;
  letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3); }
.theme-text h3 { margin: 0 0 10px; font-size: clamp(1.3rem, 2.2vw, 1.7rem); max-width: 24ch; }
.theme-note {
  margin: 0; padding-left: 15px; border-left: 2px solid var(--line-strong);
  color: var(--ink-3); font-size: .95rem; line-height: 1.55; max-width: 62ch;
}
.theme-q { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: clamp(16px, 2vw, 24px); }

.rev { margin: 0; padding: 22px 24px; background: var(--bg);
  border: 1px solid var(--line); border-left: 3px solid var(--brand); border-radius: var(--radius); }
.rev-pull { margin: 0 0 22px; font-family: var(--serif); font-style: italic; font-weight: 400;
  font-size: clamp(1.5rem, 3.2vw, 2.4rem); line-height: 1.3; letter-spacing: -0.018em; color: var(--ink); }
.sec-alt .rev, .dark .rev { background: var(--bg); }
.rev blockquote { margin: 0 0 14px; font-size: 1.02rem; line-height: 1.55; color: var(--ink); }
.rev figcaption { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.rev-who { font-weight: 700; font-size: .95rem; color: var(--ink); }
.rev-src { font-size: .82rem; color: var(--ink-3); }

@media (max-width: 900px) {
  .rev-head { grid-template-columns: 1fr; }
  .rev-score { text-align: left; }
  .rev-feature { grid-template-columns: 1fr; }
  .rev-feature figure { order: -1; }
  .srcs { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .srcs { grid-template-columns: 1fr; }
  .theme-head { grid-template-columns: 1fr; gap: 14px; }
  .theme-mark { display: flex; align-items: baseline; gap: 12px; }
  .theme-count { margin-top: 0; }
}

/* ---------------------------------------------------------------- footer */
/* Navy, so the page is bookended in blue: the credential strip near the top and
   the footer at the bottom, with white between them and red carrying the
   accents. On a light gray footer the blue appeared exactly once on the whole
   page and the scheme did not read. Token overrides rather than new rules, so
   every child that already asks for ink or line picks up the light values. */
.ftr {
  background: var(--navy-deep); border-top: 1px solid var(--navy);
  padding-block: clamp(44px, 6vw, 72px) 30px;
  color: #eef1f5;
  --ink: #eef1f5; --ink-2: #c2cddb; --ink-3: #9fb0c4;
  --line: #1b3555; --line-strong: #2b4a70;
  --brand: #ffffff; --brand-hover: #ffffff;
}
.ftr-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1.25fr; gap: clamp(28px, 4.5vw, 60px); }
.ftr h4 { font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 14px; font-weight: 700; }
.ftr a { color: var(--ink-2); text-decoration: none; }
.ftr a:hover { color: var(--brand); text-decoration: underline; }
.ftr ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; font-size: .96rem; }
/* Footer links are navigation, not prose, so WCAG 2.5.8's inline-link exception
   does not cover them. Padding takes each one to a 24px target. */
.ftr ul a, .ftr ul li { display: inline-block; min-height: 24px; padding-block: 3px; }
.ftr .wm b { font-size: 1.72rem; }
.ftr .wm i { font-size: 1.08rem; }
.ftr-btm {
  margin-top: 40px; padding-top: 22px; border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: 18px; justify-content: space-between;
  align-items: center; font-size: .87rem; color: var(--ink-3);
}
/* The card marks are his own "we accept" strip, carrying the genuine network
   logos. Native is 308px and it is shown at 210, so it stays sharp. This
   replaced five text pills that wrapped badly and clipped off a phone. */
.pay { display: flex; }
.pay img { width: 210px; height: auto; display: block; }

/* Two separate statements get two lines, rather than running together into one
   long sentence that then wraps at an arbitrary point. */
.ftr-legal { display: grid; gap: 3px; line-height: 1.5; }

/* ---------------------------------------------------------------- map */
.map-embed { border: 0; width: 100%; height: 380px; border-radius: var(--radius-lg); background: var(--surface-2); }

/* ---------------------------------------------------------------- demo banner */
/* This is a demonstration built for Bill Frames, and it says so on every page.
   It is not pretending to be a live site, and it is noindex at the server.
   The bar matters more here than it did on the Silver Star build: this shop's
   real domain currently forwards to an unregistered one, so an unmarked copy
   would be indistinguishable from the takeover the site warns about. */
.demo-bar {
  background: #1d2027; color: #dfe4ea; font-size: .86rem; text-align: center;
  padding: 9px var(--gut); line-height: 1.45;
}
.demo-bar b { color: #ffffff; }
.demo-bar a { color: #ffffff; display: inline-block; min-height: 24px; padding-block: 4px; }

/* No scroll-reveal animation, deliberately.
   An earlier version faded content in on scroll. The audit then reported 18
   nodes sitting at opacity:0 on load, which is precisely the defect this
   rebuild criticizes on the current site. A subtle fade is not worth handing
   back the strongest point in the pitch, so the content is simply visible. */

/* ---------------------------------------------------------------- responsive */
@media (max-width: 1180px) {
  .status { display: none; }
}
@media (max-width: 1100px) {
  .nav { display: none; }
  .menu { display: block; margin-left: auto; }
  .hdr-cta .btn span.long { display: none; }
  .ftr-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-media { order: -1; }
  .hero-media img { aspect-ratio: 16/10; }
  .row, .row-flip > figure { grid-template-columns: 1fr; order: 0; }
  .g-3, .g-4 { grid-template-columns: repeat(2, 1fr); }
  .trust-in { grid-template-columns: repeat(2, 1fr); }
}
/* Below 620px the header cannot fit the logo, the phone number, the toggle and
   the menu on one line: everything in it is flex: 0 0 auto, so the row forced a
   474px minimum and the whole document scrolled sideways. Wrap it into two
   rows and give the call button the full width of the second one. For a repair
   shop that is the better mobile layout regardless: the phone number is the
   primary action and it becomes a full-width tap target. */
@media (max-width: 620px) {
  /* The fixed Call / Request bar covers both actions on every screen, so every
     other instance of them is noise. Hiding the header's phone button also lets
     the mobile header collapse back to a single row: logo and menu. */
  .hdr-cta { display: none; }
  .hero-actions, .cta-pair { display: none; }

  body { font-size: 16.5px; }
  .g-2, .g-3, .g-4 { grid-template-columns: 1fr; }
  .f-2 { grid-template-columns: 1fr; }
  .hdr-in { min-height: 66px; gap: 12px; }
  .status { display: none; }
  .hero-actions .btn { width: 100%; }

  /* Centered footer on a phone. Four left-aligned columns stacked into one
     narrow column left everything hugging the edge with no visual close to the
     page, and the payment marks ran off the right. */
  .ftr { text-align: center; }
  .ftr-grid { grid-template-columns: 1fr; gap: 30px; }
  .ftr .brand { justify-content: center; }
  .ftr h4 { margin-bottom: 10px; }
  .ftr ul { justify-items: center; }
  .ftr p { margin-inline: auto; max-width: 34ch; }
  .ftr-btm { flex-direction: column; align-items: center; gap: 16px; text-align: center; }
  .pay { display: flex; justify-content: center; }
}

/* ---------------------------------------------------------------- sheet */
/* Designed for the printer first. Sized so the whole thing lands on one side of
   US Letter, because a second page does not get read. */
.sheet {
  max-width: 7.1in; margin: clamp(24px, 4vw, 48px) auto; padding: clamp(20px, 3vw, 34px);
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-lg);
  color: var(--ink);
}
.sheet-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 24px;
  border-bottom: 2px solid var(--ink); padding-bottom: 14px; margin-bottom: 16px; }
.sheet-kicker { font-size: .78rem; font-weight: 750; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-3); }
.sheet h1 { font-size: 1.72rem; margin: 3px 0 2px; letter-spacing: -0.03em; }
.sheet-sub { font-size: .8rem; color: var(--ink-3); }
.sheet-score { display: flex; gap: 16px; text-align: right; flex: 0 0 auto; }
.sheet-score b { display: block; font-size: 1.75rem; font-weight: 820; line-height: 1; letter-spacing: -0.04em; }
.sheet-score span { font-size: .76rem; color: var(--ink-3); text-transform: uppercase; letter-spacing: .06em; }
.sheet-lede { font-size: .88rem; color: var(--ink-2); margin-bottom: 14px; line-height: 1.5; }

.sheet-list { list-style: none; counter-reset: f; margin: 0; padding: 0; }
.sheet-list li {
  counter-increment: f; position: relative; padding: 9px 0 9px 27px;
  border-bottom: 1px solid var(--line);
}
.sheet-list li::before {
  content: counter(f) "."; position: absolute; left: 0; top: 9px;
  font-weight: 800; font-size: .84rem; color: var(--brand);
}
.sheet-list h2 { font-size: .95rem; margin: 0 0 3px; letter-spacing: -0.014em; line-height: 1.3; }
.sheet-list p { font-size: .82rem; color: var(--ink-2); margin: 0; line-height: 1.48; }
.sheet-v {
  display: inline-block; margin-top: 4px; font-size: .76rem; font-weight: 750;
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3);
}

.sheet-fine { margin-top: 14px; padding: 11px 14px; border: 1px solid var(--line); border-radius: 8px; }
.sheet-fine h3 { font-size: .8rem; letter-spacing: .09em; text-transform: uppercase; color: var(--good); margin: 0 0 6px; }
.sheet-fine ul { margin: 0; padding-left: 16px; }
.sheet-fine li { font-size: .78rem; color: var(--ink-2); line-height: 1.5; }

.sheet-foot { display: grid; grid-template-columns: 1.5fr 1fr; gap: 22px; margin-top: 16px;
  padding-top: 14px; border-top: 2px solid var(--ink); }
.sheet-foot h3 { font-size: .95rem; margin: 0 0 5px; }
.sheet-foot p { font-size: .82rem; color: var(--ink-2); margin: 0 0 6px; line-height: 1.48; }
.sheet-url { font-size: .84rem !important; color: var(--ink) !important; }
.sheet-sign { border-left: 1px solid var(--line); padding-left: 18px; font-size: .8rem; color: var(--ink-3); }
.sheet-by { font-weight: 750; color: var(--ink); font-size: .92rem; }
.sheet-note { margin-top: 10px; font-style: italic; line-height: 1.45; }

.sheet-actions { display: flex; gap: 10px; justify-content: center; padding: 0 var(--gut) clamp(40px, 6vw, 70px); flex-wrap: wrap; }

@media (max-width: 620px) {
  .sheet-head { flex-direction: column; gap: 12px; }
  .sheet-score { text-align: left; }
  .sheet-foot { grid-template-columns: 1fr; }
  .sheet-sign { border-left: 0; padding-left: 0; border-top: 1px solid var(--line); padding-top: 12px; }
}

/* ---------------------------------------------------------------- print */

/* ================================================================
   PRIVATE DASHBOARD AND FIRST-PARTY ANALYTICS
   Ported from ~/silverstar-demo on 2026-08-31 with the palette rebased.
   Appended at the END of the sheet deliberately: the .note-warn bug in this
   same file was a block landing before the base rule it meant to override, and
   these are all leaf components with no base rules of their own to fight.
   ================================================================ */
/* ---------------------------------------------------------------- results */
.res-row {
  display: grid; grid-template-columns: 1fr 1.5fr auto; gap: 10px 24px;
  padding: 18px 14px; border-bottom: 1px solid var(--line); align-items: start;
}

.res-row.is-after { background: var(--brand-soft); }

.res-name { font-weight: 700; color: var(--ink); }

.res-meta { font-size: .9rem; color: var(--ink-3); margin-top: 2px; }

.res-problem { color: var(--ink-2); font-size: .97rem; }

.res-when { font-size: .87rem; color: var(--ink-3); text-align: right; white-space: nowrap; }

.res-tag {
  display: block; margin-top: 6px; font-size: .78rem; font-weight: 750;
  letter-spacing: .06em; text-transform: uppercase; color: var(--brand);
}

@media (max-width: 780px) {
  .res-row { grid-template-columns: 1fr; gap: 6px; }
  .res-when { text-align: left; }
  .res-tag { display: inline-block; margin-top: 4px; }
}

/* ------------------------------------------------- private dashboard
   Four server-rendered tabs at /results, one page load each, addressed by
   ?tab=. No JavaScript anywhere in it: this is the page Bill opens from an
   email on a phone that may be several years old, and a settings screen that
   half-loads is worse than one that takes an extra second. */
.dash-head {
  padding-block: clamp(26px, 3.6vw, 44px) 0;
  background: var(--surface); border-bottom: 1px solid var(--line);
}

/* No rule to the left of it here. The little dash is a section marker on the
   public pages, where an eyebrow introduces the band under it. On the dashboard
   the eyebrow is naming the whole screen, not decorating a section. */
.dash-eyebrow::before { content: none; }

.dash-head h1 { font-size: clamp(1.7rem, 4vw, 2.6rem); letter-spacing: -0.035em; margin: 10px 0 0; }

.dash-tabs {
  display: flex; gap: 2px; margin-top: clamp(18px, 2.4vw, 26px);
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.dash-tabs::-webkit-scrollbar { display: none; }

.dash-tabs a {
  flex: 0 0 auto; padding: 13px 18px; min-height: 48px;
  font-weight: 650; font-size: .97rem; color: var(--ink-2); text-decoration: none;
  border-bottom: 3px solid transparent; white-space: nowrap;
}

.dash-tabs a:hover { color: var(--ink); background: var(--bg); }

.dash-tabs a.is-on { color: var(--brand); border-bottom-color: var(--brand); background: var(--bg); }

/* The same list as a dropdown, for phones. Hidden above 780px; the row of tabs
   is hidden below it. A <details>, so it needs no JavaScript, matching the
   site's main mobile menu. */
.dash-pick { display: none; margin-top: 18px; position: relative; }

.dash-pick > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center;
  justify-content: space-between; gap: 12px; min-height: 52px; padding: 13px 16px;
  background: var(--bg); border: 1px solid var(--line-strong); border-radius: 10px;
  font-weight: 700; font-size: 1.02rem; color: var(--ink);
}

.dash-pick > summary::-webkit-details-marker { display: none; }

/* A chevron, drawn rather than an icon file, that flips when it opens. */
.dash-pick > summary::after {
  content: ""; width: 9px; height: 9px; flex: 0 0 auto; margin-right: 3px;
  border-right: 2px solid var(--ink-3); border-bottom: 2px solid var(--ink-3);
  transform: rotate(45deg) translate(-2px, -2px);
}

.dash-pick[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }

.dash-pick[open] > summary { border-color: var(--brand); border-radius: 10px 10px 0 0; }

.dash-pick-panel {
  position: absolute; left: 0; right: 0; z-index: 20;
  background: var(--bg); border: 1px solid var(--brand); border-top: 0;
  border-radius: 0 0 10px 10px; overflow: hidden;
  box-shadow: 0 14px 32px rgba(9, 20, 34, .14);
}

.dash-pick-panel a {
  display: block; padding: 14px 16px; min-height: 48px; text-decoration: none;
  font-weight: 600; color: var(--ink); border-top: 1px solid var(--line);
}

.dash-pick-panel a.is-on { color: var(--brand); font-weight: 750; background: var(--surface); }

/* The overview stats sit inside a tab panel rather than their own band, so they
   need their own bottom margin where the section used to provide it. */
.dash-stats { margin-bottom: 26px; }

.pt-call { margin: 0; }

.pt-call a {
  font-size: clamp(1.5rem, 4vw, 2.1rem); font-weight: 800; letter-spacing: -0.03em;
  color: var(--brand); text-decoration: none;
}

/* The two away controls, as buttons that open into their own form. Closed they
   read as a pair of buttons; open, the one that was tapped shows its fields and
   the other stays a button. <details>, so no JavaScript is involved. */
.ov-away { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(14px, 2vw, 20px); margin-top: 28px; }

/* No overflow:hidden here. It was only ever rounding the summary's corners,
   and it clips anything a form control wants to draw outside the box, which on
   a phone includes the native date control. The summary rounds its own corners
   instead. */
.ov-opt {
  background: var(--bg); border: 1px solid var(--line-strong); border-radius: var(--radius-lg);
  align-self: start; min-width: 0;
}

.ov-opt > summary { border-radius: calc(var(--radius-lg) - 1px); }

.ov-opt[open] > summary { border-radius: calc(var(--radius-lg) - 1px) calc(var(--radius-lg) - 1px) 0 0; }

.ov-opt > summary {
  list-style: none; cursor: pointer; display: flex; flex-direction: column; gap: 3px;
  padding: clamp(16px, 2.2vw, 22px) clamp(18px, 2.4vw, 24px); min-height: 76px;
  justify-content: center; position: relative;
}

.ov-opt > summary::-webkit-details-marker { display: none; }

.ov-opt > summary b { font-size: 1.1rem; letter-spacing: -0.015em; color: var(--ink); }

.ov-opt > summary span { font-size: .92rem; color: var(--ink-3); }

.ov-opt > summary::after {
  content: ""; position: absolute; right: 20px; top: 50%; width: 9px; height: 9px;
  border-right: 2px solid var(--ink-3); border-bottom: 2px solid var(--ink-3);
  transform: translateY(-70%) rotate(45deg);
}

.ov-opt[open] > summary::after { transform: translateY(-30%) rotate(-135deg); }

.ov-opt:hover { border-color: var(--brand-edge); }

.ov-opt[open] { border-color: var(--brand); grid-column: 1 / -1; }

.ov-opt[open] > summary { border-bottom: 1px solid var(--line); }

.ov-opt .pt-form { padding: clamp(18px, 2.4vw, 24px); }

/* Away is a state, not a control, so it stops looking like a pair of buttons
   and becomes one panel that says what is happening and how to end it. */
.ov-away.is-on {
  grid-template-columns: minmax(0, 1fr) auto; align-items: center;
  background: var(--warn-soft); border: 1px solid var(--warn-edge); border-left: 4px solid var(--warn);
  border-radius: var(--radius-lg); padding: clamp(20px, 2.8vw, 28px);
}

.ov-away.is-on b { display: block; font-size: 1.15rem; letter-spacing: -0.02em; color: var(--ink); }

.ov-away.is-on span { display: block; margin-top: 6px; color: var(--ink-2); font-size: .96rem; max-width: 62ch; }

/* ------------------------------------------------- analytics tab
   Hand-drawn SVG and CSS bars from server-rendered numbers. No charting
   library, for the same reason there is no analytics script: the page that
   argues his site is heavy cannot ship 90 KB to draw thirty rectangles. */
.ch-wrap { overflow-x: auto; color: var(--ink-3); }

/* The chart element itself. The extractor matched selectors containing the
   wanted class names and ".ch" alone is a prefix of nothing, so this one rule
   was silently left behind and both charts rendered at zero height with their
   captions still in place: a graph that looks like it has no data rather than
   one that is missing. */
.ch { display: block; width: 100%; height: 200px; min-width: 460px; }
.ch-bar { fill: var(--brand); }

/* Wrapped in a scroller so a four-column table cannot push the whole document
   sideways on a 320px phone. The page body must never scroll horizontally; a
   table inside its own box may. */
.an-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.an-tbl { width: 100%; border-collapse: collapse; font-size: .95rem; }

/* Long addresses are one unbreakable token and will otherwise set the width of
   everything above them. */
.an-tbl td, .an-tbl th { overflow-wrap: anywhere; }

.an-tbl th {
  text-align: left; font-size: .76rem; font-weight: 750; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3); padding: 0 10px 9px 0;
  border-bottom: 2px solid var(--ink);
}

.an-tbl th.num, .an-tbl td.num { text-align: right; }

.an-tbl td { padding: 10px 10px 10px 0; border-bottom: 1px solid var(--line); color: var(--ink-2); }

.an-tbl td b { color: var(--ink); }

.an-tbl tr:last-child td { border-bottom: 0; }

.an-share { width: 40%; }

.an-bar { display: block; height: 9px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }

.an-bar span { display: block; height: 100%; background: var(--brand); border-radius: 999px; }

.an-hours { display: flex; align-items: flex-end; gap: 2px; height: 96px; }

.an-hours-lbl {
  display: flex; justify-content: space-between; margin-top: 6px;
  font-size: .76rem; color: var(--ink-3);
}

.an-dev { display: flex; height: 34px; border-radius: 8px; overflow: hidden; border: 1px solid var(--line); }

.an-dev span { display: block; height: 100%; }

.an-dev-0 { background: var(--brand); }

/* A SEQUENTIAL ramp, not four unrelated hues. This is an ordered share bar, so
   the segments step down in lightness from the brand to the page surface:
   measured relative luminance 0.05 / 0.16 / 0.39 / 0.79. Stepping by lightness
   rather than by hue means it still reads in grayscale and for a color-blind
   viewer, which four differently-hued blocks would not. Rebased off the
   sibling build's blues, which do not exist in this palette. */
.an-dev-1 { background: #b8535a; }

.an-dev-2 { background: #d99ba0; }

.an-dev-3 { background: var(--surface-2); }

.an-key { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px 18px; }

.an-key li { display: flex; align-items: center; gap: 7px; font-size: .9rem; color: var(--ink-2); }

.an-key i { width: 11px; height: 11px; border-radius: 3px; flex: 0 0 auto; }

.an-key b { color: var(--ink); }

/* ------------------------------------------------- history feed */
.hist { list-style: none; margin: 0; padding: 0; border-top: 2px solid var(--ink); }

.hist-row {
  display: grid; grid-template-columns: 8.5rem minmax(0, 1fr) auto; gap: 10px 22px;
  padding: 16px 2px; border-bottom: 1px solid var(--line); align-items: start;
}

.hist-row.is-after { background: var(--brand-soft); }

.hist-row.is-change { color: var(--ink-3); }

.hist-when b { display: block; font-weight: 700; color: var(--ink); font-size: .94rem; }

.hist-when span { display: block; font-size: .88rem; color: var(--ink-3); }

.hist-kind {
  display: block; font-size: .78rem; font-weight: 750; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 3px;
}

/* A change line carries a full email address, which is one unbreakable token
   and was setting the width of the whole document at 320px. */
.hist-row > * { min-width: 0; }

.hist-what { overflow-wrap: anywhere; }

.hist-what > b { font-size: 1.04rem; color: var(--ink); }

.hist-what p { margin: 5px 0 0; color: var(--ink-2); font-size: .96rem; line-height: 1.5; }

.hist-meta { color: var(--ink-3) !important; font-size: .89rem !important; }


/* Deliberately not flex. A flex container makes the <b> its own item and puts
   a gap on both sides of it, which reads as a space before the comma. */
.res-route { margin-top: 18px; font-size: .96rem; color: var(--ink-2); max-width: 60ch; }

.res-route b { color: var(--ink); }

.res-route a { margin-left: 10px; white-space: nowrap; }

.pt-msg {
  margin: 0 0 22px; padding: 14px 18px; border-radius: 10px; font-weight: 600;
  border: 1px solid var(--brand-edge); background: var(--brand-soft); color: var(--ink);
}

.pt-msg.is-error { border-color: #e2b3ac; background: #fdf1ef; color: #8f2c1e; }

/* Roomier than it was. The analytics tab put eight dense panels on one screen
   and every one of them was cramped against the next: tables ran to the card
   edge, and a chart, a legend and a paragraph shared a box with 20px around
   the lot. Padding is the whole difference between a dashboard and a printout,
   and this one is read on a phone at arm's length. */
.pt-cols {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(18px, 2.4vw, 28px); margin-bottom: clamp(18px, 2.4vw, 28px);
}

.pt-card {
  background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: clamp(22px, 3vw, 34px);
}

.pt-card > h3 { margin-bottom: 16px; }

.pt-cols + .pt-cols, .stats + .pt-card, .stats + .pt-cols {
  margin-top: clamp(18px, 2.4vw, 28px);
}

/* The last thing in a card should not sit flush against its floor. */
.pt-card > *:last-child { margin-bottom: 0; }

/* The dashboard uses h3 inside cards, since the page title is the h1 and the
   status line is the h2. h4 kept so nothing that still uses it jumps size. */
.pt-card h3, .pt-card h4 { font-size: 1.06rem; letter-spacing: -0.01em; margin: 0 0 8px; }

.pt-card > p { color: var(--ink-2); font-size: .95rem; margin: 0 0 18px; max-width: 46ch; }

.pt-form { display: grid; gap: 12px; justify-items: start; }

.pt-form > .btn { margin-top: 4px; }

.pt-lbl {
  font-weight: 650; font-size: .88rem; color: var(--ink);
  display: block; margin-bottom: 6px;
}

.pt-form input, .pt-form select, .pt-form textarea {
  font: inherit; font-size: 1rem; color: var(--ink); background: var(--bg);
  border: 1px solid var(--line-strong); border-radius: 10px; padding: 12px 14px;
  width: 100%; max-width: 100%; min-width: 0; min-height: 48px;
}

/* iOS gives input[type=date] a native control with its own intrinsic width and
   its own padding, and that width does not shrink to its container: the
   Vacation Mode fields ran off the side of a phone while every desktop browser
   and the headless audit showed them fitting. Stripping the native appearance
   puts the box back under this stylesheet's control. The value still opens the
   system date wheel on tap, which is the part that matters.
   min-width:0 on the grid cell as well, because a grid item defaults to
   min-width:auto and will not shrink below its content either. */
.pt-form input[type="date"] {
  -webkit-appearance: none; appearance: none; background-clip: padding-box;
}

.pt-two > * { min-width: 0; }

.pt-form textarea { line-height: 1.55; resize: vertical; min-height: 132px; }

.pt-form input:focus, .pt-form select:focus, .pt-form textarea:focus { border-color: var(--brand); outline: none; }

.pt-form input::placeholder, .pt-form textarea::placeholder { color: var(--ink-3); }

.pt-form select, .pt-form > label + select { max-width: 100%; }

.pt-form > select, .pt-form > input { width: 100%; }

.pt-two { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; width: 100%; }

.pt-form :disabled { opacity: .5; cursor: not-allowed; }

.pt-people { list-style: none; margin: 0 0 6px; padding: 0; border-top: 1px solid var(--line); }

.pt-people li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 10px 20px;
  align-items: center; padding: 15px 2px; border-bottom: 1px solid var(--line);
}

.pt-who b { display: block; color: var(--ink); font-weight: 700; }

.pt-who span { display: block; font-size: .9rem; color: var(--ink-3); word-break: break-all; }

/* The main recipient has no buttons, so its third cell is an empty placeholder.
   It has to hold the same width as a row of buttons, or the badge above the
   buttons sits further right than the one beside them. */
.pt-people li > span:empty { min-width: 11.5rem; }

.pt-acts { display: flex; gap: 6px; align-items: center; justify-content: flex-end; min-width: 11.5rem; }

.pt-link {
  font: inherit; font-size: .92rem; font-weight: 650; cursor: pointer;
  background: none; border: 1px solid transparent; border-radius: 8px;
  color: var(--brand); padding: 10px 12px; min-height: 44px; white-space: nowrap;
}

.pt-link:hover { background: var(--surface-2); }

.pt-link.is-danger { color: #a33224; }

.pt-note { font-size: .88rem; color: var(--ink-3); margin: 10px 0 0; max-width: 52ch; line-height: 1.5; }

.pt-add { margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--line); }

.pt-add .pt-note { margin-top: 2px; }

.pt-log { list-style: none; margin: 0; padding: 0; }

.pt-log li {
  display: flex; gap: 14px; font-size: .93rem; color: var(--ink-2);
  padding: 9px 0; border-bottom: 1px solid var(--line);
}

.pt-log li:last-child { border-bottom: 0; }

.pt-log span { color: var(--ink-3); flex: 0 0 auto; min-width: 11.5rem; }

.pt-hist { background: transparent; }


/* Six more rules the extractor missed: its selector match required the class
   name to appear in the selector text, so rules whose only selector is a
   descendant of a wanted class fell through. Found by diffing the class names
   the rendered portal actually uses against what the sheet defines. */
.ov-dest {
  background: var(--bg); border: 1px solid var(--line); border-left: 4px solid var(--brand);
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
  padding: clamp(20px, 2.8vw, 28px); margin-bottom: 22px;
}
.ov-dest.is-away { border-left-color: #c8791f; background: #fff8ee; }
.ov-dest-lbl {
  display: block; font-size: .8rem; font-weight: 750; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px;
}
.ov-dest b {
  display: block; font-size: clamp(1.5rem, 3.4vw, 2.1rem); font-weight: 820;
  letter-spacing: -0.035em; color: var(--ink); line-height: 1.1;
}
.ov-dest-mail { display: block; margin-top: 6px; color: var(--ink-2); font-size: .98rem; word-break: break-all; }
.ov-dest-cc, .ov-dest-tag {
  display: inline-block; margin-top: 10px; margin-right: 8px; font-size: .8rem; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3);
  border: 1px solid var(--line-strong); border-radius: 999px; padding: 4px 12px;
}
.ov-dest-tag { color: #8a5310; border-color: #e2c79b; background: #fdf3e3; }
.pt-status {
  background: var(--bg); border: 1px solid var(--line);
  border-left: 4px solid var(--brand); border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: clamp(22px, 3vw, 30px); margin-bottom: 22px;
}
.pt-status h2, .pt-status h3 {
  font-size: clamp(1.15rem, 2.1vw, 1.42rem); letter-spacing: -0.02em; margin: 0;
}
.pt-status p { margin: 8px 0 0; color: var(--ink-2); max-width: 60ch; }
.pt-status form { margin-top: 18px; }
.pt-status.is-away { border-left-color: #c8791f; background: #fff8ee; }

/* The portal header: the wordmark and nothing else. */
.hdr-portal .hdr-in { justify-content: flex-start; }
.hdr-portal .brand { display: inline-flex; }

/* The outgoing-mail hold notice. Amber, because it is the same idea as every
   other amber on this site: something the reader needs to know before they
   trust what is in front of them. */
.pt-msg.is-hold { border-color: var(--warn-edge); background: var(--warn-soft); color: #7a4a0f; font-weight: 400; }
.pt-msg.is-hold b { color: #6a3f0c; }

/* The overview stat row and its "What this counts" disclosure, taken from the
   sibling's CURRENT stylesheet. The markup for this changed there after the
   snapshot this portal was ported from, so the new markup arrived without the
   rules that lay it out and the summary rendered as a stray circle beside four
   stacked words. */
/* Sits under both count tiles now rather than inside the second one, so it is
   left aligned with everything else on the dashboard instead of centered under
   a single figure. */
.ov-info { display: block; margin: 0 0 clamp(18px, 2.4vw, 26px); }
.ov-info > summary {
  list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px; margin: 0 auto;
  color: var(--ink-3); font-size: .86rem; font-weight: 650;
}
.ov-info > summary::-webkit-details-marker { display: none; }
.ov-info > summary i {
  width: 20px; height: 20px; border-radius: 50%; flex: 0 0 auto;
  border: 1.5px solid currentColor; display: grid; place-items: center;
  /* The sans stack, not the display serif: at this size the serif italic "i"
     reads as a stray mark rather than a letter. */
  font: 800 .76rem/1 var(--sans); font-style: normal;
}
.ov-info > summary:hover, .ov-info[open] > summary { color: var(--brand); }
.ov-info-panel {
  margin-top: 12px; text-align: left;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: 14px 16px;
}
.ov-info-panel p {
  margin: 0 0 8px; font-size: .9rem; line-height: 1.55; color: var(--ink-2); font-weight: 400;
}
.ov-info-panel p:last-child { margin-bottom: 0; }

/* Google result mockups, ported from the sibling build. Same job here as
   there: show the owner what a stranger sees when they look him up. */
.serp {
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
  padding: 20px 22px; font-family: arial, sans-serif;
}
.serp-bad { border-color: color-mix(in srgb, #c0392b 40%, var(--line)); }
.serp-url { font-size: .82rem; color: var(--ink-2); margin-bottom: 4px; }
.serp-title {
  font-size: 1.22rem; line-height: 1.3; color: #1a0dab; font-weight: 400;
  letter-spacing: 0; margin-bottom: 5px;
}
.serp-desc { font-size: .88rem; line-height: 1.58; color: var(--ink-2); }
.serp-rating { margin-top: 7px; font-size: .84rem; color: var(--ink-2); }
.serp-stars { color: #b85a00; letter-spacing: -1px; }

/* ---------------------------------------------------------------- what we do */
/* Each service carries a covers array in data.js, which is the real content a
   driver wants: not "Repair" but brakes, suspension, cooling, driveline. The
   card leads with the number and title on one line, the blurb under it, and the
   covers as a wrapped list of what is included. Two columns at desktop so four
   services do not become a long scroll.
   These were rules and type until now, deliberately, so the page would not read
   like the shop next door. Cards were asked for, so the separation has to come
   from somewhere else: the numbering, the covers lists and the two-column block
   are all still ours, and the shadow here is the token every other raised
   surface on the site already uses rather than a heavier one invented for this
   section. */
.svc-grid { display: grid; gap: clamp(16px, 2vw, 22px); }
.svc-row {
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: clamp(22px, 2.6vw, 30px);
  transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.svc-row:hover {
  border-color: var(--brand-edge);
  box-shadow: var(--shadow-lg);
  transform: translateY(-2px);
}
@media (prefers-reduced-motion: reduce) { .svc-row:hover { transform: none; } }
.svc-head { display: flex; align-items: baseline; gap: 14px; margin-bottom: 8px; }
.svc-n {
  font-size: .78rem; font-weight: 750; letter-spacing: .1em;
  color: var(--brand); flex: 0 0 auto;
}
.svc-head h3 { margin: 0; font-size: clamp(1.22rem, 1.8vw, 1.46rem); flex: 1 1 auto; }
.svc-link {
  flex: 0 0 auto; font-weight: 650; font-size: .9rem; white-space: nowrap;
  display: inline-block; padding-block: 4px; margin-block: -4px; min-height: 24px;
}
.svc-blurb { margin: 0 0 14px; color: var(--ink-2); max-width: 60ch; }
/* Chips follow the blurb rather than being pushed to the card foot. Bottom
   aligning them looked deliberate only when every blurb ran the same number of
   lines; with a short one it opened a gap mid-card that read as a bug. Equal
   height cards with trailing space at the bottom read as padding instead. */
.svc-covers {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 7px 8px;
}
.svc-covers li {
  font-size: .86rem; color: var(--ink-2);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 7px; padding: 5px 11px;
}
.sec-alt .svc-covers li { background: var(--bg); }

@media (min-width: 900px) {
  /* Two columns once there is room for four cards without each one squeezing
     its covers list into a narrow column. */
  .svc-grid { grid-template-columns: 1fr 1fr; column-gap: clamp(20px, 2.4vw, 28px); }
}

/* Themed review groups. Each is a heading, a line of argument, and its quotes,
   with enough space between groups that the page reads as four short sections
   rather than one long wall of praise. */
.rev-group + .rev-group { margin-top: clamp(38px, 5vw, 62px); }
.rev-group h3 {
  font-size: clamp(1.24rem, 2.1vw, 1.6rem); letter-spacing: -0.02em;
  margin: 0 0 6px; max-width: 30ch;
}
.rev-group-note {
  margin: 0 0 clamp(18px, 2.2vw, 24px); color: var(--ink-2);
  max-width: 62ch; font-size: 1rem;
}
.rev-group .rev { box-shadow: var(--shadow); }

/* ---------------------------------------------------------------- info card */
/* The address, phone and neighborhood sit under the hours in the same column,
   but they are a different kind of thing from opening times and were reading as
   more rows of the table. A card separates them without moving them. */
.info-card {
  margin-top: clamp(28px, 3.6vw, 40px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: clamp(22px, 2.6vw, 28px);
}
.sec-alt .info-card { background: var(--bg); }
.info-card .kv { margin: 0; }

/* ---------------------------------------------------------------- dashboard, part 2 */
/* Ten rules the first port missed, taken from the sibling's CURRENT stylesheet.
   The extractor matched by class-name substring and these are the ones whose
   selectors it never reached, so the overview's two big count cards rendered as
   two lines of plain text: "2 today" and "2 this week so far", where the whole
   point of that panel is that the number is the first thing seen. Found by
   diffing rule DECLARATIONS between the two sheets rather than checking which
   class names existed, which had reported everything fine. */
.ov-counts {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(16px, 2.4vw, 26px); margin-bottom: clamp(12px, 1.6vw, 16px);
}
@media (max-width: 780px) {
  /* Five tabs in a row on a phone either scroll sideways behind an edge nobody
     drags, or wrap into a block that pushes the content off the first screen.
     The dropdown replaces them and names the section you are on. */
  .dash-tabs { display: none; }
  .dash-pick { display: block; }

  .ov-counts { grid-template-columns: 1fr; }
  .ov-away { grid-template-columns: 1fr; }
  .ov-away.is-on { grid-template-columns: 1fr; align-items: start; gap: 16px; }
  .ov-away.is-on .btn { width: 100%; justify-content: center; }
  .an-share { width: 30%; }
  .an-tbl { font-size: .9rem; }
  .hist-row { grid-template-columns: 1fr; gap: 4px; }
  .hist-when { display: flex; gap: 8px; align-items: baseline; }
  .hist-when b, .hist-when span { display: inline; }
}

/* Left aligned and tighter. A 5rem numeral centered in a tall box gave the
   first screen of the dashboard two big digits and a lot of nothing, and it was
   the only centered thing on a page where the destination card, the history and
   the tabs all start at the left edge. */
.ov-count {
  background: var(--bg); border: 1px solid var(--line); border-top: 3px solid var(--brand);
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
  padding: clamp(18px, 2.4vw, 24px) clamp(20px, 2.6vw, 26px);
}

.ov-count b {
  display: block; font-size: clamp(2.4rem, 6vw, 3.4rem); font-weight: 820;
  letter-spacing: -0.045em; line-height: 1; color: var(--ink);
}

.ov-count span {
  display: block; margin-top: 10px; font-size: 1rem; font-weight: 650; color: var(--ink-2);
}

.ov-note { margin: 22px 0 0; color: var(--ink-3); font-size: .95rem; line-height: 1.6; max-width: 64ch; }

.an-h {
  flex: 1 1 0; height: max(2px, var(--h, 0%)); border-radius: 2px 2px 0 0;
  background: var(--surface-2); border: 1px solid var(--line);
}

.an-h.is-open { background: var(--brand); border-color: var(--brand); }

@media (max-width: 780px) {
  /* Five tabs in a row on a phone either scroll sideways behind an edge nobody
     drags, or wrap into a block that pushes the content off the first screen.
     The dropdown replaces them and names the section you are on. */
  .dash-tabs { display: none; }
  .dash-pick { display: block; }

  .ov-counts { grid-template-columns: 1fr; }
  .ov-away { grid-template-columns: 1fr; }
  .ov-away.is-on { grid-template-columns: 1fr; align-items: start; gap: 16px; }
  .ov-away.is-on .btn { width: 100%; justify-content: center; }
  .an-share { width: 30%; }
  .an-tbl { font-size: .9rem; }
  .hist-row { grid-template-columns: 1fr; gap: 4px; }
  .hist-when { display: flex; gap: 8px; align-items: baseline; }
  .hist-when b, .hist-when span { display: inline; }
}

.res-route a { margin-left: 10px; white-space: nowrap; }

.pt-tag {
  font-size: .78rem; font-weight: 750; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3); border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 4px 11px; white-space: nowrap;
}
@media (max-width: 780px) {
  .pt-cols { grid-template-columns: 1fr; }
  .pt-two { grid-template-columns: 1fr; }
  .pt-form > .btn, .pt-form button { width: 100%; justify-content: center; }
  /* Name, badge, then the buttons on their own full-width row: at this size a
     three-column row squeezes an email address to two characters a line. */
  .pt-people li { grid-template-columns: minmax(0, 1fr) auto; }
  .pt-tag { min-width: 0; }
  .pt-people li > span:empty { display: none; }
  .pt-acts { grid-column: 1 / -1; justify-content: flex-start; margin-left: -12px; min-width: 0; }
  .pt-log li { flex-direction: column; gap: 2px; }
  .pt-log span { min-width: 0; }
}

.pt-tag.is-main { color: var(--brand); border-color: var(--brand-edge); background: var(--brand-soft); }

.pt-tag { min-width: 9.5rem; text-align: center; }

.pt-foot { margin: 24px 0 0; font-size: .92rem; color: var(--ink-3); max-width: 62ch; line-height: 1.6; }

@media (max-width: 780px) {
  .pt-cols { grid-template-columns: 1fr; }
  .pt-two { grid-template-columns: 1fr; }
  .pt-form > .btn, .pt-form button { width: 100%; justify-content: center; }
  /* Name, badge, then the buttons on their own full-width row: at this size a
     three-column row squeezes an email address to two characters a line. */
  .pt-people li { grid-template-columns: minmax(0, 1fr) auto; }
  .pt-tag { min-width: 0; }
  .pt-people li > span:empty { display: none; }
  .pt-acts { grid-column: 1 / -1; justify-content: flex-start; margin-left: -12px; min-width: 0; }
  .pt-log li { flex-direction: column; gap: 2px; }
  .pt-log span { min-width: 0; }
}

@media print {
  .hdr, .ftr, .demo-bar, .menu, .sheet-actions { display: none !important; }
  /* Flatten to black on white for the printer. */
  :root {
    --bg: #fff; --surface: #fff; --ink: #000; --ink-2: #222; --ink-3: #555;
    --line: #bbb; --line-strong: #888; --brand: #000; --good: #000;
  }
  /* Tuned until tools/pagecount.sh reports one page. At 10.5pt with the
     original spacing it ran to two, and a second page does not get read. */
  .sheet { max-width: none; margin: 0; padding: 0; border: 0; border-radius: 0; }
  .sheet h1 { font-size: 17pt; }
  .sheet-lede { font-size: 8.6pt; margin-bottom: 8pt; line-height: 1.4; }
  .sheet-list li { padding: 5.5pt 0 5.5pt 18pt; }
  .sheet-list li::before { top: 5.5pt; font-size: 8pt; }
  .sheet-list h2 { font-size: 9.4pt; margin-bottom: 1.5pt; }
  .sheet-list p { font-size: 8.2pt; line-height: 1.36; }
  .sheet-v { font-size: 6.2pt; margin-top: 2pt; }
  .sheet-head { padding-bottom: 8pt; margin-bottom: 9pt; }
  .sheet-score b { font-size: 16pt; }
  .sheet-fine { margin-top: 8pt; padding: 7pt 10pt; }
  .sheet-fine li { font-size: 7.8pt; line-height: 1.4; }
  .sheet-foot { margin-top: 9pt; padding-top: 8pt; gap: 16pt; }
  .sheet-foot p { font-size: 8.2pt; line-height: 1.38; margin-bottom: 4pt; }
  .sheet-sign { font-size: 7.8pt; }
  .sheet-list li { break-inside: avoid; page-break-inside: avoid; }
  .sheet-foot, .sheet-fine { break-inside: avoid; page-break-inside: avoid; }
  @page { margin: 0.5in; }
  body { font-size: 11pt; color: #000; background: #fff; }
  a { color: #000; text-decoration: none; }
  .card, .panel, .quote { border: 1px solid #999; break-inside: avoid; }
}
