
/* ---------------------------------------------------------------- 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 ONE of the three unresized iPhone photographs the current /About ships.
   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;
}
@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:     #f5f7fa;
  --surface-2:   #e9eef4;
  --ink:         #10161d;
  --ink-2:       #47535f;
  --ink-3:       #59677a;
  --line:        #dde4ec;
  --line-strong: #c4cfdb;
  /* Deep navy. 9.96:1 on white, so it can carry body links, buttons and
     headings without a second thought. */
  --brand:       #14456f;
  --brand-hover: #0e3253;
  --brand-ink:   #ffffff;
  --brand-soft:  #e9eff6;
  --brand-edge:  #b6c9dc;
  /* Their gold. 5.62:1 on the navy above, 1.77:1 on white. DARK GROUNDS AND
     RULES ONLY. If it ever appears as text on a light background, that is a
     bug, and tools/a11y.js is what catches it. */
  --accent:      #fcb627;
  --accent-ink:  #3d2a00;
  /* NAPA'S OWN COLORS, and they are not the site's. Kept separate on purpose.
     The warranty callout is the one component on this site that is speaking for
     somebody else -- it is NAPA's program, NAPA's 24/24, honored at NAPA's
     14,000 locations -- and it earns NAPA's blue and yellow rather than PT's
     navy and gold. Everything else on the page stays PT's.
     Blue is 11.4:1 on white and carries the figure and the shield. Yellow is
     1.67:1 on white and is a RULE AND A GROUND ONLY, never text on light, same
     rule as --accent above and caught by tools/a11y.js either way. */
  --napa-blue:   #0033a0;
  --napa-yellow: #ffc72c;
  --napa-soft:   #eef1fa;
  --good:        #1c6b3f;
  --good-soft:   #e6f4ec;
  --warn:        #8a5a00;
  --warn-soft:   #fdf4e3;
  --shadow:      0 1px 2px rgba(16,22,29,.06), 0 8px 24px rgba(16,22,29,.06);
  --shadow-lg:   0 2px 4px rgba(16,22,29,.06), 0 18px 48px rgba(16,22,29,.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; }
/* The ceiling came down from 5.4rem. It was set for a three-word headline
   ("Mercedes-Benz. That is all we do.") and this shop's pages carry longer,
   plainer ones. At 5.4rem "Fifteen brands, fitted and aligned here" ran to four
   lines and swallowed the whole first screen for a line that is not the point
   of the page. 4.2rem keeps the hero emphatic and gives the sentence under it
   room to be read. */
h1 { font-size: clamp(2.4rem, 5.6vw, 4.2rem); letter-spacing: -0.04em; font-weight: 820; line-height: 1.0; text-wrap: balance; }
h2 { font-size: clamp(1.7rem, 3.4vw, 2.6rem); letter-spacing: -0.032em; 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; }

/* RANK IS NOT SIZE. Five pages ran h1 straight to h3, which is a skipped level
   for anybody navigating by heading, and the headings in question are top-level
   sections of their page so h2 is the correct rank. But a bare h2 here is
   2.6rem against h3's 1.5rem, and promoting them would have blown up five
   layouts to fix a structural problem nobody can see. This carries the old
   size at the new rank. */
.h-sub, .steps li h2 {
  font-size: clamp(1.2rem, 2vw, 1.5rem); letter-spacing: -0.02em; font-weight: 720;
  text-wrap: initial;
}

/* 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. On an earlier
   build that blew the mobile layout out to 470px in a 390px viewport, because
   the phone glyph inside the hero button was rendering ~300px wide. Every
   inline icon gets an explicit box, and the catch-all keeps a future icon from
   doing it again.

   AND THE EXCLUSION LIST IS LOAD-BEARING. The catch-all selector is specificity
   (0,1,1) and a bare class is (0,1,0), so the catch-all WINS against a plain
   class rule. It sized the tire tread illustrations to 1.15em and
   they rendered as an empty gray box, with nothing anywhere reporting an error.
   Any SVG here that is a real drawing rather than an icon has to be named in
   this selector.

   (This comment used to quote the selectors with backticks. It lives inside a
   JavaScript template literal, so that ended the string and the whole module
   stopped parsing. No backticks in this file.) */
/* Every inline SVG on this site is an ICON, so they get icon dimensions by
   default. Anything that is a real drawing has to be excluded by name: the
   analytics chart inherited 1.15em square and rendered as a 15px smudge with
   its bars technically present and completely invisible. Add new drawings to
   this list rather than fighting the specificity from the other end. */
svg:not(.ch):not(.tread) { 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; }
/* THE WORDMARK, set in type rather than shipped as a file.
   Their site's logo slot holds /Portals/103/logo.png, which is the NAPA
   AutoCare Center badge, with alt="PT Auto Experts" on it. So there is no
   wordmark to inherit and nothing to trace. Their storefront lettering reads
   "PT" large with "AUTO EXPERTS" set out beside it, and this is that: zero
   bytes, sharp at any resolution, and real text to a screen reader. The whole
   lockup is aria-hidden with an aria-label on the anchor, so it is announced
   once as the shop's name rather than letter-strings. */
.brand {
  display: inline-flex; align-items: center; gap: 9px;
  flex: 0 0 auto; text-decoration: none; color: var(--brand);
}
.menu { flex: 0 0 auto; }
.brand-pt {
  font-size: 1.72rem; font-weight: 900; letter-spacing: -0.055em; line-height: 1;
  font-style: italic;
}
.brand-words {
  display: grid; gap: 1px;
  /* 12px is a floor, not a preference. tools/sweep.sh fails any text under it,
     and it caught this at 11px when the lockup was set in rem. Explicit px so a
     future change to the 17px body size cannot quietly drag it back under. */
  font-size: 12px; font-weight: 750; letter-spacing: .15em;
  line-height: 1.1; text-transform: uppercase; color: var(--ink-2);
  padding-left: 9px; border-left: 2px solid var(--accent);
}
.hdr .brand:hover .brand-pt { color: var(--brand-hover); }

.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: #0b0f14;
  isolation: isolate;
}
.hero-full > picture, .hero-full > picture img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: -2;
}
/* Two overlays, not one. A vertical gradient carries the text at the bottom,
   and a horizontal one keeps the left column legible over the bright
   fluorescent patches in the bay.
   THE STOPS HERE WERE WRONG FOR TWO YEARS' WORTH OF CONFIDENCE. The comment
   used to claim "measured at 8.9:1 for the h1", and tools/hero-contrast.js --
   which reads the composited pixels behind the type rather than a token pair --
   put the real desktop numbers at 2.99:1 for the h1 (needs 3.0) and 3.90:1 for
   the eyebrow (needs 4.5). Nothing caught it because tools/a11y.js skips text
   over a background image entirely. The mobile scrim had already been
   strengthened by hand; the desktop one had never been checked at all. */
.hero-full::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(to top, rgba(6,9,13,.94) 0%, rgba(6,9,13,.88) 30%, rgba(6,9,13,.60) 58%, rgba(6,9,13,.40) 100%),
    linear-gradient(to right, rgba(6,9,13,.62) 0%, rgba(6,9,13,0) 68%);
}
.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: #9ec6ff; }
.hero-full .eyebrow::before { background: #9ec6ff; }
/* THE PHOTO CREDIT WAS UNREADABLE, at 1.04:1 on a phone and 1.96:1 on a desktop
   -- measured, and 1.0 is the floor of the scale. It is 50% white sitting in
   the corner the scrim lightens, so it faded into the picture entirely. A
   credit nobody can read is not restraint, it is a line of text that failed.
   It keeps its quiet size and its corner, and gets a ground of its own so the
   contrast no longer depends on which part of the photograph it lands on. */
.hero-full .credit {
  position: absolute; right: var(--gut); bottom: 12px;
  font-size: .76rem; color: rgba(255,255,255,.82);
  background: rgba(6,9,13,.55); padding: 3px 9px; border-radius: 999px;
  backdrop-filter: blur(4px);
}
.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; }

/* A SPLIT HERO. Type on its own ground, photograph shown whole beside it.
   See the note in home.js: the storefront is lettered edge to edge and an
   overlaid headline collides with it wherever you put it. */
.hero-split {
  background: var(--surface); border-bottom: 1px solid var(--line);
  padding-block: clamp(34px, 5vw, 72px);
}
.hero-split-in {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(28px, 5vw, 64px); align-items: center;
}
@media (max-width: 900px) {
  .hero-split-in { grid-template-columns: 1fr; }
  .hero-shot { order: -1; }
}
.hero-copy h1 { margin: 10px 0 18px; }
.hero-copy .lede { margin-bottom: 26px; }
.hero-shot { margin: 0; }
.hero-shot img {
  width: 100%; border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); background: var(--surface-2);
}
/* THE ADDRESS CARD in the finding-us section.
   It sits beside a photograph carrying --shadow-lg and used to be a flat box
   with a hard border, so it read as a form field next to a picture. It now
   takes the same lift as the photograph and a hairline border instead of the
   strong one, because the shadow is doing the separating.
   Rows are stacked rather than a two-column label/value grid: the address is
   two lines, the phone is one, and each set of hours is three, so a shared
   column has to be as wide as the widest value and leaves the short rows
   stranded. Stacked, the label is a quiet header and the value gets the width.
   The hours are their own little day/time grid with the times in tabular
   figures and right-aligned, so the colons line up and the eye can compare
   Saturday to the weekday without reading. */
.info-card {
  margin: 22px 0 0; padding: 4px 24px;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--bg); box-shadow: var(--shadow);
}
.info-row { display: grid; gap: 4px; padding: 16px 0; border-top: 1px solid var(--line); }
.info-row:first-child { border-top: 0; }
/* max(12px, ...) because .72rem is 11.5px and the floor here is 12. Caught by
   sweep at both widths, which is the third time a micro-label has tried to go
   out under 12px in this build. */
.info-lbl {
  font-size: max(12px, .72rem); font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3);
}
.info-val { display: grid; gap: 2px; color: var(--ink); font-weight: 550; font-size: 1rem; }
/* The phone is the action in this card, so it is the only thing in it set at
   heading weight. min-height keeps it a real 24px tap target; sweep caught the
   old one at 19px and it would catch this one too. */
.info-tel {
  justify-self: start; text-decoration: none; color: var(--brand);
  font-size: 1.32rem; font-weight: 800; letter-spacing: -0.02em;
  min-height: 24px; padding-block: 2px;
}
.info-tel:hover { color: var(--brand-hover); text-decoration: underline; }
.info-hours {
  display: grid; grid-template-columns: auto 1fr; gap: 3px 18px;
  margin: 0; font-weight: 500;
}
.info-hours dt { color: var(--ink-2); }
.info-hours dd { margin: 0; text-align: right; color: var(--ink); }
.info-hours .is-shut { color: var(--ink-3); font-weight: 450; }
.info-note { margin: 8px 0 0; font-size: .84rem; color: var(--ink-3); }
.dark .info-card { background: rgba(255,255,255,.03); border-color: var(--line-strong); }

/* Actions that belong to the photograph sit under it and share its width.
   Two full-width buttons read as one decision; the same pair trailing off the
   end of a paragraph reads as afterthoughts. */
/* A photograph with things stacked under it, sharing its width. */
.shot-stack { display: grid; gap: 14px; }
.shot-stack .warranty-note { margin-top: 0; }

.shot-actions { display: grid; gap: 10px; margin-top: 14px; }
@media (min-width: 560px) { .shot-actions { grid-template-columns: 1fr 1fr; } }

.hero-shot figcaption {
  margin-top: 12px; font-size: .88rem; color: var(--ink-3); text-align: right;
}
/* THE CAPTION STOPS HUGGING THE RIGHT once the layout stacks.
   Right-aligned under a photograph in a two-column layout, it reads as a
   caption tucked against the column edge. Stacked full width it is the only
   right-aligned line on the page, so it stops looking like a caption and starts
   looking like a mistake: prose that does not line up with the prose above or
   below it. /about and the home page both use this layout, so one rule fixes
   both.
   IT HAS TO SIT AFTER THE BASE RULE, not inside the stacking media query
   further up. Both selectors are (0,2,0), so the later one wins whatever the
   media query says, and the first attempt at this changed nothing at all --
   measured at 390px, still computing text-align: right. A media query does not
   raise specificity. */
@media (max-width: 900px) {
  .hero-shot figcaption { text-align: left; }
}

/* ---------------------------------------------------------------- dark section */
/* Rhythm. Every section being white made the whole page read as one long
   scroll. Hard dark bands give the page a spine, and they are where the
   arguments that need weight live: why people end up here, and what actually
   makes a repair painless.

   The brand navy cannot survive on this ground: #14456f measures about 1.7:1
   against #0b0f14, which is invisible. So --brand is redefined inside .dark to
   a light blue, the same move the tokens block describes for the gold. Every
   component that reads var(--brand) follows automatically. */
.dark {
  background: #0b0f14; color: #e9eef4;
  --ink: #e9eef4; --ink-2: #a9b6c3; --ink-3: #8896a3;
  --line: #1e2933; --line-strong: #2c3945;
  --brand: #7fb2ff; --brand-ink: #06111f; --brand-hover: #a3c9ff;
  --brand-soft: #10203a; --brand-edge: #26456e;
  --bg: #0b0f14; --surface: #121820;
}
.dark .panel, .dark .card, .dark .quote { background: #121820; border-color: #1e2933; }

/* ---------------------------------------------------------------- stat row */
/* The ratings were a four-cell table. They are the strongest thing he has, so
   they are set as display type. */
/* Four across when there is room, fewer when there is not, and NEVER wider
   than the screen. This was a flat repeat(4, 1fr) with no breakpoint: at 320px
   the "32 yrs" stat could not fit its own label, so the row pushed the document
   to 337px and every page scrolled sideways. On a phone that reads as the right
   edge of the content being sliced off, which is exactly what it was.
   min() is what makes it safe: a column can never demand more than the full
   width, so the track collapses instead of overflowing. */
.stats {
  display: grid; gap: clamp(16px, 2.6vw, 34px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11.5rem), 1fr));
}
.stat { min-width: 0; }
.stat { border-top: 2px solid var(--brand); padding-top: 16px; }

/* THE THREE RATING STATS ARE LINKS AND MUST NOT LOOK LIKE IT.
   Every element inside a stat already sets its own color, so nothing turns
   brand blue. text-decoration is the exception: it is drawn by the anchor
   across all its descendants and has to be turned off here, or the whole cell
   arrives underlined. display:block is what a <div class="stat"> already was,
   so the linked cells and the unlinked years cell render identically. The only
   difference on screen is the cursor, which the UA stylesheet supplies. */
a.stat { display: block; color: inherit; text-decoration: none; }
.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: max(12px, .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; }

/* THE FOOTNOTE PARAGRAPH, which had no rule at all.
   The class is used two ways on this site: as a <span> inside a stat, styled just
   above, and as a <p> carrying a sourcing note under a section. Only the first
   was ever written. The six <p class="src"> notes on /tires, /about, /financing,
   /service-area and /reviews were therefore rendering at full body size in full
   body color, competing with the copy they were meant to sit quietly beneath.
   Scoped to p.src so the span keeps its own smaller treatment. */
p.src { margin: 20px 0 0; color: var(--ink-3); font-size: .88rem; line-height: 1.55; max-width: 82ch; }

/* THE SIDE-BY-SIDE ON /compare.
   Two live pages cannot go here: their site sends X-Frame-Options: SAMEORIGIN,
   so it cannot be framed at all, and framing it would load 32 MB of somebody
   else's page inside the page arguing about weight. So: two screenshots taken
   at the same window size, each in its own scroll window.

   A FIXED-HEIGHT SCROLLER RATHER THAN THE WHOLE IMAGE. Their capture is 2151px
   tall at this width and ours is 3656px. Laid out in full the section is nine
   thousand pixels of page and the two are impossible to compare, because you
   can never see both at once. Both windows are the same height and start at the
   top, so the first screen of each sits side by side, and either can be
   scrolled on its own from there. */
.shots { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px, 2vw, 26px); }
.shots figure { margin: 0; min-width: 0; }
.shots figcaption {
  display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline;
  margin-bottom: 10px; padding-bottom: 8px; border-bottom: 2px solid var(--line-strong);
}
.shots figcaption b { font-size: 1.02rem; color: var(--ink); }
.shots figcaption span { font-size: .86rem; color: var(--ink-3); }
.shot-win {
  height: min(74vh, 720px); overflow-y: auto; overflow-x: hidden;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg); overscroll-behavior: contain;
}
.shot-win img { display: block; width: 100%; height: auto; }
.shot-note { margin: 10px 0 0; font-size: .88rem; }

@media (max-width: 820px) {
  /* Stacked, the two are read one after the other rather than compared, so a
     tall window stops earning its height. */
  .shots { grid-template-columns: 1fr; }
  .shot-win { height: min(58vh, 460px); }
}

/* ---------------------------------------------------------------- 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; }
.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; }
.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; }

.pull {
  font-family: var(--serif); font-size: clamp(1.4rem, 2.8vw, 2rem); line-height: 1.4;
  color: var(--ink); max-width: 24ch;
}

/* ---------------------------------------------------------------- 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: somebody has a warning light or an
   inspection due, 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 {
    /* minmax(0, 1fr), NOT 1fr. A bare 1fr is minmax(auto, 1fr), and that auto
       minimum is the item's min-content width, which here is a nowrap button
       label. The two tracks resolved to 186px each, so the bar came to 404px
       inside a 390px viewport and scrolled the whole document sideways. Setting
       min-width:0 on the buttons does not help: the blowout is in the TRACK,
       not the item. */
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 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); } }
  /* min-width:0 for the same reason as .finds: these are grid items, their
     default min-width is auto, and "Request appointment" refused to shrink. The
     bar measured 404px inside a 390px viewport, which is the entire reason the
     whole page scrolled sideways. It is fixed-position, so it widened the
     document without visibly breaking its own layout. */
  .callbar .btn { width: 100%; min-width: 0; padding-inline: 10px; font-size: .95rem; }
  .callbar > * { min-width: 0; }
  /* Room so the bar never covers the last line of the footer. */
  body { padding-bottom: 76px; }
}
@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; }
/* AN INPUT AND A SELECT DO NOT AGREE ON HEIGHT unless you tell them to.
   Given identical font, padding, border and min-height, an <input> lays out a
   26px line box and a <select> a 24px one, so a pair sitting side by side ends
   up 50px and 48px. It is invisible in a stacked form and obvious the moment
   two of them share a row, which is what Plate and State do on /tires.
   Setting line-height explicitly makes the content box the same for both, so
   every pair on the site lines up rather than just the one that was noticed. */
.field input, .field select, .field textarea {
  font: inherit; font-size: 1rem; line-height: 1.5; color: var(--ink); background: var(--bg);
  border: 1px solid var(--line-strong); border-radius: 10px; padding: 13px 14px;
  width: 100%; min-height: 50px;
}
/* AND AN EXPLICIT HEIGHT, because line-height alone does not settle it: a
   <select>'s closed box is laid out by the engine and still came out a pixel
   short of the input beside it (50/48 before the line-height, 48/47 after).
   One height on both ends the argument. textarea is deliberately not in this
   selector -- it is the one control here that must grow.
   The file input for the VIN scan is not in a .field and is .sr-only, so it is
   untouched; it is a label that is the real target, which sweep already checks. */
.field input, .field select { 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); }

.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-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 */
.panel { background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-lg); 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); }
/* A link in a definition term is 19px tall at this font size, under the WCAG 2.2
   24px minimum. Inline links in running prose are exempt; these are not in
   prose, they are a list of targets, and the exemption is a defense rather than
   a design. Padding the block axis is enough and costs 6px of row height. */
.kv dt a { display: inline-block; padding-block: 3px; }
.kv dd { margin: 0; color: var(--ink); font-weight: 550; }

/* ---------------------------------------------------------------- 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: max(12px, .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: max(12px, .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; }
}

/* ------------------------------------------------- private dashboard
   Four server-rendered tabs at /results, one page load each, addressed by
   ?tab=. No JavaScript anywhere in it: this is the page Peter 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; }

/* The portal header: the logo, a label, and nothing else. No nav, no phone
   button, no open/closed pill, no hamburger. Those belong to the website; this
   is the tool. */
.hdr-portal .hdr-in { justify-content: flex-start; }
.hdr-portal .brand { display: inline-flex; }
.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; }

/* ------------------------------------------------- overview
   Three facts, sized so the two numbers are readable across a shop. */
.ov-dest {
  background: var(--bg); border: 1px solid var(--line); border-left: 4px solid var(--brand);
  border-radius: var(--radius-lg); 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; }

/* The bottom margin is not optional. The counts used to be the LAST thing on
   the overview and did not need one; once they moved above the destination
   card the two were touching. */
.ov-counts {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(16px, 2.4vw, 26px); margin-bottom: clamp(18px, 2.4vw, 26px);
}
.ov-count {
  background: var(--bg); border: 1px solid var(--line); border-top: 3px solid var(--brand);
  border-radius: var(--radius-lg); padding: clamp(20px, 3vw, 30px); text-align: center;
}
.ov-count b {
  display: block; font-size: clamp(3rem, 9vw, 5rem); font-weight: 820;
  letter-spacing: -0.05em; line-height: .95; 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; }

/* The week explanation, behind an "i". Worth having; not worth three lines of
   gray text under the number every single time he opens this.
   IT EXPANDS IN FLOW, INSIDE THE CARD. It was a floating popover first, and a
   popover has to be positioned against something: against the little round
   button it ran off the side of a phone, and against the card it hung over the
   panel below and read as a rendering fault. A box that simply pushes the card
   taller cannot be in the wrong place at any width, on any screen. */
/* The control centers under the number like everything else in the card; the
   panel it opens is left-aligned, because prose is. */
.ov-info { display: block; margin-top: 14px; text-align: center; }
.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;
  /* 24px minimum. At .86rem this measured 22px tall and failed WCAG 2.5.8 in
     tools/a11y.js. Padding rather than a larger font, because the label is
     deliberately quiet and making it louder would fix the wrong thing. */
  min-height: 24px; padding-block: 2px;
}
.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; }

.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: #fff8ee; border: 1px solid #e2c79b; border-left: 4px solid #c8791f;
  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); }
.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-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); }
.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); }
.an-dev-1 { background: #6d93cc; }
.an-dev-2 { background: #adc3e0; }
.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; }

@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; }
}

/* ------------------------------------------------- recipients portal
   The settings at the bottom of /results. Opened perhaps twice a year, on a
   phone, by somebody who has not seen it since the last time, so it is sized
   for a thumb rather than for a mouse: nothing is smaller than 44px, every
   control is labeled with a verb, and there is no icon standing in for a word.
   Everything is a real form POST, so none of it depends on JavaScript. */
/* 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; }
.pt-msg.is-hold { border-color: #e2c79b; background: #fdf3e3; color: #7a4a0f; font-weight: 400; }
.pt-msg.is-hold b { color: #6a3f0c; }

.pt-status {
  background: var(--bg); border: 1px solid var(--line);
  border-left: 4px solid var(--brand); border-radius: var(--radius-lg);
  padding: clamp(22px, 3vw, 30px); margin-bottom: 22px;
}
/* h2 in the dashboard, h3 when it was a section. Both, so a markup change
   cannot silently leave this heading at page-title size, which it did. */
.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; }
/* Away is the state that matters, so it is the one that looks different. */
.pt-status.is-away { border-left-color: #c8791f; background: #fff8ee; }

/* 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-wide marks a card that spans the full width of the dashboard rather than
   sharing a row. It is on ten cards and had NO RULE, so it was a comment in the
   markup: the cards happened to be full width already because none of them sits
   inside .pt-cols. Given the name is already used consistently, the fix is to
   make it true rather than to strip it from ten call sites -- so if one is ever
   moved into a two-column row it spans, instead of silently becoming a half. */
.pt-wide { grid-column: 1 / -1; }
.pt-cols + .pt-card, .pt-card + .pt-card,
.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; }
/* .78rem, not .74: below 12px tools/audit.js flags it, and it is a label a man
   in his sixties has to read on a phone. */
.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;
}
.pt-tag.is-main { color: var(--brand); border-color: var(--brand-edge); background: var(--brand-soft); }
/* Each row is its own grid, so the columns do not line up on their own. Fixed
   widths on the two right-hand columns put the badges and the buttons in a
   straight line down the list, which is the whole point of a list. */
.pt-tag { min-width: 9.5rem; text-align: center; }
/* 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; }

.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; }
}

/* ---------------------------------------------------------------- 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; }
.svc-shot img { border-radius: var(--radius); box-shadow: var(--shadow); }
.svc-n { display: block; font-size: .82rem; font-weight: 800; letter-spacing: .1em; color: var(--brand); margin-bottom: 10px; }
.svc h2 { font-size: clamp(1.35rem, 2.1vw, 1.75rem); letter-spacing: -0.026em; margin-bottom: 10px; max-width: 18ch; }
.svc p { color: var(--ink-2); font-size: .99rem; margin: 0; }
.svc-covers { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; align-content: center; }
.svc-covers li { position: relative; padding-left: 15px; font-size: .92rem; color: var(--ink-2); line-height: 1.4; }
.svc-covers li::before { content: ""; position: absolute; left: 0; top: .55em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--brand); }

@media (max-width: 1080px) {
  /* Once the list wraps under the text it is no longer beside anything, so it
     goes back to flowing from the top. */
  .svc { grid-template-columns: 240px minmax(0, 1fr); align-items: start; }
  .svc-covers { grid-column: 2; grid-template-columns: repeat(2, 1fr); gap: 8px 20px; padding-top: 14px; align-content: start; }
}
@media (max-width: 720px) {
  .svc { grid-template-columns: 1fr; gap: 18px; }
  .svc-shot { max-width: 320px; }
  .svc-covers { grid-column: 1; }
}
@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; }
/* THE 390px SIDEWAYS SCROLL LIVED HERE. This is a flex row holding three things
   ("Check it:", the claim, and how to verify it), flex-wrap defaults to nowrap,
   and flex items default to min-width:auto, so none of the three would shrink
   and the row ran 13px past the edge. That widened the layout viewport, which in
   turn stretched the fixed call bar to 404px, so the bar and the menu panel both
   showed up as offenders while being only symptoms. Proved by hiding this one
   element: the document went from 404px back to 390px. */
.find-check { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin: 0;
  font-size: .88rem; font-weight: 650; letter-spacing: .02em; color: var(--good); }
.find-check > * { min-width: 0; }
.find-check svg { width: 15px; height: 15px; flex: 0 0 auto; }
/* break-word is belt and braces for the longest of these, tools/footer-pixels.sh
   at 23 characters. It was NOT the cause of the overflow above: that was the
   flex row refusing to wrap. */
.find-show { margin-bottom: 26px; overflow-wrap: break-word; }
.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; }

/* Kept from the Silver Star build. Nothing on this site uses it, because their
   copy has no misspelling in it to show. Left in place because the pattern
   (quote the defect at the size it actually ships at, rather than describing
   it) is the right one and costs nothing until it is needed. */
.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); }

/* The observed load-time range, drawn as a span rather than an average.
   An average would be the wrong picture: 1.5 and 27 seconds do not describe a
   site that is "about fourteen seconds", they describe a site that is a
   lottery, and the width between the two ends is the thing to look at. */
.clock-range {
  margin-top: 26px; padding: clamp(22px, 3vw, 32px);
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-lg);
}
.clock-range h3 { font-size: clamp(1.06rem, 1.9vw, 1.26rem); letter-spacing: -0.02em; margin: 0 0 20px; }
.clock-range p { color: var(--ink-2); font-size: .98rem; margin: 14px 0 0; max-width: 68ch; }
.clock-range p b { color: var(--ink); }

.range-bar { display: flex; align-items: center; gap: 14px; }
.range-fast, .range-slow { display: grid; justify-items: center; gap: 2px; flex: 0 0 auto; }
.range-fast b, .range-slow b {
  font-size: clamp(1.5rem, 3.4vw, 2.15rem); font-weight: 820; letter-spacing: -0.04em; line-height: 1;
}
.range-fast b { color: var(--good); }
.range-slow b { color: var(--brand); }
/* .78rem, not .74: below 12px tools/audit.js flags it, and correctly. */
.range-fast span, .range-slow span {
  font-size: .78rem; font-weight: 750; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3);
}
/* Left-to-right green into blue, so the eye reads the distance traveled
   rather than two numbers sitting next to each other. */
.range-track {
  flex: 1 1 auto; height: 12px; border-radius: 999px; min-width: 40px;
  background: linear-gradient(to right, var(--good-soft), var(--brand-soft));
  border: 1px solid var(--line-strong);
}
.range-note { font-size: .9rem !important; color: var(--ink-3) !important; }

.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; }
  /* The gradient track needs room to read as a distance. On a phone the two
     numbers carry it on their own. */
  .range-bar { gap: 10px; }
  .range-track { min-width: 24px; height: 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); text-align: center; }

/* The whole cell is the link, so the figure and the platform 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 blue, but text-decoration is drawn by
   the anchor across its descendants and has to be turned off here or every cell
   arrives underlined. The tint on hover is then the only affordance left:
   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: max(12px, .42em); font-weight: 700; color: var(--ink-3); margin-left: 2px; }
/* DIRECT CHILD. As a descendant selector this also caught <span class="u">, the
   small "/5" and "%" suffix that lives INSIDE the <b>, and display:block put it
   on its own line under the figure. "5.0" with "/5" beneath it reads as two
   facts rather than one number. */
.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-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); }
.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); }

/* A grid row is as tall as its tallest cell, so a two-line quote beside an
   eight-line one leaves a hole under the short one. Laying the card out as a
   column and pushing the attribution down with margin-top:auto puts every name
   on the bottom edge of its card, which reads as a decision rather than as a
   gap. */
.rev { margin: 0; padding: 22px 24px; background: var(--bg);
  border: 1px solid var(--line); border-left: 3px solid var(--brand); border-radius: var(--radius);
  display: flex; flex-direction: column; }
.rev figcaption { margin-top: auto; }
.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); }
/* The platform name in an attribution is a link out to the review list, and at
   .82rem it is 13px tall -- half the WCAG 2.2 24px minimum. Inline links in
   running prose are exempt; a name in a caption is not running prose, and the
   exemption is a defense rather than a design. Padding the block axis costs
   nothing because the caption line has room above and below it. */
.rev-src a, .rev-attr a { display: inline-block; padding-block: 6px; }
.rev-attr a { color: var(--brand); }
.dark .rev-attr a { color: var(--ink-2); }

/* A GROUP ON /reviews. Deliberately NOT a section of its own: the version that
   gave each group its own full-bleed band with an eyebrow, a heading, a note
   and an alternating background was the thing that made this page too long.
   Four of those cost more vertical space than the twelve quotes they held. This
   is a rule, a heading with its count set into it, one line, and the grid. */
/* EACH GROUP IS ITS OWN CARD, on the tinted ground of the section, so the four
   findings read as four things rather than as one long column with rules in it.
   The quotes inside go FLAT -- no border, no background of their own -- because
   a bordered card inside a bordered card is two frames arguing, and the group
   card is already the frame. What is left of a quote is the brand rule down its
   left edge, which is enough to separate three of them in a row and still reads
   as a list when they stack on a phone. */
.rev-grp {
  margin-top: clamp(20px, 2.4vw, 30px);
  background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
  padding: clamp(22px, 3vw, 34px);
}
.rev-grp:first-of-type { margin-top: 0; }
.rev-grp h3 {
  margin: 0 0 8px;
  font-size: clamp(1.15rem, 1.9vw, 1.42rem); letter-spacing: -0.02em;
  display: flex; gap: 12px; align-items: baseline;
}
/* EACH REVIEW IS ITS OWN CARD, and the card is what separates it from the next
   one -- no rule, no divider. It carries its own attribution, so a quote and
   the person who wrote it are one object rather than two things a reader has to
   pair up by proximity.
   The card takes the section's tint on the white group card, which is enough
   separation without a second shadow: the group card already casts one, and a
   shadow inside a shadow reads as clutter rather than as depth.
   figcaption keeps margin-top:auto from the base .rev rule, so on a row of
   unequal quotes every name still sits on its card's bottom edge. */
.rev-grp .rev {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px 22px;
}
.rev-grp-n { color: var(--brand); font-weight: 830; flex: 0 0 auto; }
.rev-grp-note {
  margin: 0 0 22px; max-width: 68ch; color: var(--ink-3);
  font-size: .93rem; line-height: 1.55;
}
@media (max-width: 900px) { .rev-grp .g-3 { grid-template-columns: 1fr; } }


@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; }
}



/* INLINE LINKS IN PROSE, given a real tap target.
   WCAG 2.5.8 exempts a link inside a sentence, on the reasoning that the
   sentence positions it. The exemption is a defense, not a design: on a phone
   these are still 19 or 20 pixels tall and still missed. Vertical padding on an
   inline element grows the hit box without changing the line box, so the
   paragraph does not re-flow and the target reaches 24px. Costs nothing.

   Scoped to running text. Links that are already buttons, nav, cards or footer
   items have their own sizing and must not inherit this. */
.sec p a, .note a, .panel p a, .lede a, .steps p a, .src-list a,
.disclosures a, .answer-note a, .find-why a, .ftr-blurb a {
  padding-block: 4px;
}

/* ------------------------------------------------- PT Auto Experts components
   Everything below is new for this build rather than inherited. Grouped in one
   block so it is obvious what belongs to this shop and what is shared. */

/* THE WARRANTY CALLOUT.
   Its own component because the single most embarrassing defect on the current
   site is a home-page badge advertising 12 months / 12,000 miles that links to
   their own page saying 24/24. Every mention of the warranty on this site
   renders this one component from one number in data.js, so the two can never
   drift apart again. It is a link, so it always goes to the terms. */
.warranty-note {
  display: flex; gap: 14px; align-items: flex-start;
  margin-top: 26px; padding: 16px 20px;
  border: 1px solid #c9d3ec; border-left: 4px solid var(--napa-yellow);
  border-radius: var(--radius);
  background: var(--napa-soft); color: var(--ink);
  text-decoration: none; font-size: .97rem; line-height: 1.55;
}
.warranty-note:hover { border-color: var(--napa-blue); color: var(--ink); }
.warranty-note svg { width: 24px; height: 24px; color: var(--napa-blue); margin-top: 1px; }
.warranty-note b { color: var(--napa-blue); }
.warranty-note.is-wide { margin-top: 0; font-size: 1.04rem; padding: 20px 24px; }

/* ON A DARK BAND THE ACCENT FLIPS TO THE YELLOW, and it has to.
   NAPA blue is #0033a0, which is 1.6:1 on this site's near-black and unreadable.
   The yellow is the other half of the same two-color mark and reads at 11:1
   there, so the callout still says NAPA on a dark ground without inventing a
   third color or dropping to the site's own brand blue. */
.dark .warranty-note { background: rgba(255,199,44,.07); border-color: rgba(255,199,44,.26); }
.dark .warranty-note b, .dark .warranty-note svg { color: var(--napa-yellow); }
.dark .warranty-note:hover { border-color: var(--napa-yellow); }

/* THE BIG WARRANTY FIGURE on the NAPA warranty page. The number is the page. */
.warranty-hero {
  border: 1px solid var(--line-strong); border-radius: var(--radius-lg);
  padding: clamp(24px, 4vw, 40px); background: var(--surface); margin-bottom: 40px;
}
.warranty-figure {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin-bottom: 16px;
}
.wf-num { font-size: clamp(2.6rem, 7vw, 4.4rem); font-weight: 850; letter-spacing: -.045em;
  line-height: 1; color: var(--brand); }
.wf-unit { font-size: 1.05rem; font-weight: 650; color: var(--ink-2); }
.wf-sep { width: 2px; align-self: stretch; min-height: 44px; background: var(--accent); margin-inline: 10px; }
@media (max-width: 520px) { .wf-sep { display: none; } .warranty-figure { gap: 8px 12px; } }

/* SERVICE PAGE ADDITIONS. The inspection-hours line is the single most useful
   operational fact this shop has and their site states it once, mid-paragraph. */
.svc-hours {
  display: flex; gap: 9px; align-items: flex-start;
  margin: 14px 0 0; font-size: .95rem; color: var(--ink-2);
}
.svc-hours svg { width: 18px; height: 18px; color: var(--brand); margin-top: 3px; }
.svc-hours b { color: var(--ink); }
.svc-wait {
  display: inline-block; margin: 12px 0 0; padding: 4px 12px;
  font-size: .85rem; font-weight: 650; color: var(--good);
  background: var(--good-soft); border-radius: 999px;
}

/* THE TEAM. Five people in a shop of five is the whole story, and their site
   puts it two clicks down behind an About menu. Portraits are 3:4 to match the
   source frames, so nothing is cropped through anybody's face. */
.team {
  display: grid; gap: clamp(26px, 3.5vw, 40px);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  /* Five people. auto-fit put four across with one orphan underneath, which
     reads as somebody having been forgotten. Three across gives 3 + 2, which
     looks deliberate, and it also buys each biography a wider column: Tony's is
     three times the length of Asael's and was setting the row height on its own. */
  align-items: start;
}
@media (min-width: 900px) { .team { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.person figure { margin: 0 0 16px; }
.person img {
  width: 100%; border-radius: var(--radius); object-fit: cover;
  background: var(--surface-2);
}
.person h3 { margin-bottom: 2px; }
.person-role {
  margin: 0 0 12px; font-size: .82rem; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase; color: var(--brand);
}
.person p { color: var(--ink-2); font-size: .97rem; }
.dark .person-role { color: var(--brand); }
.cred-note { margin-top: 10px; font-size: .92rem; color: var(--ink-3); }

/* THE SUCCESSION PAIR. Tony and Brianna at a larger size than the bench,
   because they are the answer to the question a customer is really asking:
   who will I be dealing with in five years. */
.pair {
  display: grid; gap: clamp(20px, 3vw, 36px);
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}
.pair-person {
  display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 22px;
  align-items: start;
}
@media (max-width: 520px) { .pair-person { grid-template-columns: 1fr; } }
.pair-person figure { margin: 0; }
.pair-person img { width: 100%; border-radius: var(--radius); background: var(--surface-2); }
.pair-person h3 { margin-bottom: 2px; font-size: 1.4rem; }
.pair-person p { color: var(--ink-2); font-size: .97rem; }

/* CREDENTIALS as a numbered list rather than four flat panels. They are four
   different KINDS of thing - a state license, a program membership, a
   per-technician certification and a public rating - and a grid of identical
   boxes said they were interchangeable. */
.creds { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.creds li {
  display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 18px;
  padding: 22px 0; border-top: 1px solid var(--line); align-items: start;
}
.creds li:last-child { border-bottom: 1px solid var(--line); }
.creds-n {
  font-size: 1rem; font-weight: 800; color: var(--brand);
  padding-top: 3px; letter-spacing: -.01em;
}
.creds h3 { margin-bottom: 5px; font-size: 1.15rem; }
.creds p { margin: 0; color: var(--ink-2); max-width: 72ch; }

/* The about hero uses the shared split, but its photograph is a room rather
   than a building, so it wants a little less shadow. */
.about-hero .hero-shot img { box-shadow: var(--shadow); }

/* PHOTO GRID. Three of their photographs at a size their own source files
   comfortably cover, rather than one stretched across the top of the page. */
.photo-grid {
  display: grid; gap: clamp(14px, 2vw, 22px);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.photo-grid figure { margin: 0; }
.photo-grid img { border-radius: var(--radius); }
.photo-grid figcaption {
  margin-top: 10px; font-size: .9rem; color: var(--ink-3); line-height: 1.45;
}

/* TIRE BRANDS, as text. Fifteen brand logo files would be fifteen requests
   saying nothing a crawler or a screen reader can use. */
.brand-list {
  display: flex; flex-wrap: wrap; gap: 9px;
  list-style: none; margin: 22px 0 0; padding: 0;
}
.brand-list li {
  border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 7px 16px; font-weight: 620; font-size: .95rem;
  background: var(--bg);
}

/* HOURS TABLE. A real <table> because it is real tabular data, which means a
   screen reader announces "Saturday, 8:30 AM to 1:00 PM" rather than reading
   two disconnected columns. */
.hours-table { width: 100%; border-collapse: collapse; font-size: 1rem; }
.hours-table th, .hours-table td {
  text-align: left; padding: 11px 0; border-bottom: 1px solid var(--line);
}
.hours-table th { font-weight: 650; }
.hours-table td { text-align: right; color: var(--ink-2); }
.hours-table tr.is-closed th, .hours-table tr.is-closed td { color: var(--ink-3); }

/* NUMBERED STEPS on /visit. */
.steps { list-style: none; counter-reset: s; margin: 0; padding: 0; display: grid; gap: 26px; }
.steps li { counter-increment: s; padding-left: 56px; position: relative; }
.steps li::before {
  content: counter(s); position: absolute; left: 0; top: 0;
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--brand); color: var(--brand-ink);
  font-weight: 750; font-size: 1rem; font-variant-numeric: tabular-nums;
}
.steps h2 { margin-bottom: 6px; }
.steps p { color: var(--ink-2); margin: 0; }

/* SERVICE AREA CARDS. */
.area-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.area-card {
  display: block; padding: 20px 22px; text-decoration: none;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg); color: var(--ink);
}
.area-card:hover { border-color: var(--brand-edge); box-shadow: var(--shadow); color: var(--ink); }
.area-card h2 { margin-bottom: 4px; font-size: 1.12rem; }
.area-card p { margin: 0; color: var(--ink-3); font-size: .93rem; }
.area-note { margin-top: 8px !important; color: var(--ink-2) !important; }

/* SOURCE LISTS. Every rating on this site is attributed, so the list of where
   they came from is a real part of the argument rather than a footnote. */
.src-list, .disclosures {
  list-style: none; margin: 22px 0 0; padding: 0;
  display: grid; gap: 12px; font-size: .97rem; color: var(--ink-2);
}
.src-list li, .disclosures li {
  padding-left: 18px; position: relative; line-height: 1.55;
}
.src-list li::before, .disclosures li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 7px; height: 2px; background: var(--accent);
}
.src-list b { color: var(--ink); }
.disclosures { font-size: .95rem; }

/* FINANCING. The apply and manage buttons go to Synchrony, and the account
   token in the apply URL is the shop's merchant identifier. See data.js. */
.fin-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 12px; }

/* FIELDSETS. Used by the tire quote form, which groups "what size" and "how to
   reach you" into named sections: grouping them is the difference between a
   form that explains itself and one that looks like an interrogation.

   These rules were deleted with the reminder form on 2026-09-01 and restored
   the same day. The reminder form used them too, and the grep that checked for
   other users was piped through head, which cut off the four tire-quote hits.
   Route and dead-end gates cannot see a missing CSS rule, so nothing caught it. */
.fs {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px 20px 6px; margin: 0 0 22px;
}
.fs legend { padding: 0 8px; font-weight: 700; font-size: .98rem; }
.fs > .hint { margin: 0 0 14px; }

/* THE SEARCH-MODE PICKER ON /tires/quote, which had no CSS whatsoever.
   The markup shipped with .picker, .picker-row, .picker-opt, .picker-lbl and
   .picker-hint and not one rule for any of them, on a page linked from the
   home page, /tires, /tires/all, /tires/cart and /services. Three bare radios
   20px tall -- under the WCAG 24px minimum, and the only failure in the whole
   accessibility sweep -- with the selected option indistinguishable from the
   other two, because .is-on styled nothing.
   Each option is a card, so the whole thing is the target rather than the
   12px radio dot, and the selected one carries the brand border and ground
   that the rest of this site uses for a chosen state. */
.picker-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: 10px; margin-top: 4px;
}
.picker-opt {
  display: grid; gap: 3px; cursor: pointer;
  padding: 14px 16px; min-height: 48px;
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--bg); transition: border-color .14s ease, background .14s ease;
}
.picker-opt:hover { border-color: var(--brand-edge); }
/* The radio itself stays in the accessibility tree and keeps its focus ring;
   it is simply not the thing being aimed at. */
.picker-opt input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.picker-opt:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.picker-opt.is-on { border-color: var(--brand); background: var(--brand-soft); }
.picker-lbl { font-weight: 700; font-size: .97rem; color: var(--ink); }
.picker-opt.is-on .picker-lbl { color: var(--brand); }
.picker-hint { font-size: .85rem; color: var(--ink-3); line-height: 1.4; }
.dark .picker-opt { background: #121820; border-color: var(--line-strong); }
.dark .picker-opt.is-on { background: rgba(127,178,255,.10); border-color: var(--brand); }

/* A success notice. .pt-msg had is-error and is-hold and no is-ok, so the
   portal's confirmations rendered in the neutral default and read like
   information rather than like something having worked. */
.pt-msg.is-ok { border-color: #a9d3ba; background: var(--good-soft); color: var(--good); }

/* The home page review grid has one fewer real review than it has slots, and
   says so in the empty one rather than padding it out with something invented. */
.quote-cta {
  display: flex; flex-direction: column; justify-content: center;
  background: var(--surface); border: 1px dashed var(--line-strong);
}
.quote-cta p { color: var(--ink-2); }
.dark .quote-cta { background: rgba(255,255,255,.03); }

/* A SERVICE CARD WITH NO PHOTOGRAPH.
   They own four pictures and there are seven services. The first draft filled
   the gap by repeating the same shot of the bay five times, which read as
   padding. A card with nothing to illustrate it says what the service covers
   instead: more useful than a stock-feeling repeat, and it stops the grid from
   looking like a mistake. */
.card-plain { background: var(--surface); border-color: var(--line-strong); }
.card-plain .card-body { padding-top: 24px; }
.card-covers {
  list-style: none; margin: 14px 0 0; padding: 0;
  display: grid; gap: 5px; font-size: .92rem; color: var(--ink-2);
}
.card-covers li { padding-left: 15px; position: relative; }
.card-covers li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 6px; height: 2px; background: var(--accent);
}

/* Same idea on the services page. The row is a three-column grid of
   image / text / covers, so a row with no image collapses to two columns rather
   than leaving a 300px hole where the picture would have been. */
.svc-noshot { grid-template-columns: minmax(0, 1fr) minmax(0, 18rem); }


/* ------------------------------------------------- the vehicle header
   One card carrying the identification, the facts and the size control.
   It replaced a title, a lede, a size bar and a note stacked as four separate
   blocks, which pushed the first tire below the fold on a laptop. */
.veh-head {
  background: var(--surface); border-bottom: 1px solid var(--line);
  padding-block: clamp(22px, 3vw, 34px) clamp(26px, 3.4vw, 40px);
}
.veh-back {
  display: inline-block; min-height: 24px; padding-block: 3px; margin-bottom: 14px;
  font-size: .92rem; font-weight: 620; color: var(--ink-2); text-decoration: none;
}
.veh-back:hover { color: var(--brand); }
.veh-card {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(250px, 300px);
  gap: clamp(22px, 3vw, 40px); align-items: start;
  background: var(--bg); border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg); padding: clamp(22px, 3vw, 32px);
  box-shadow: var(--shadow);
}
@media (max-width: 820px) { .veh-card { grid-template-columns: 1fr; } }
/* On a phone this whole block sat between the customer and the tires they came
   for, so it gives up its generous desktop spacing below 560px. Nothing is
   removed, it is only tightened. */
@media (max-width: 560px) {
  .veh-head { padding-block: 14px 18px; }
  .veh-card { padding: 16px; gap: 16px; }
  .veh-back { margin-bottom: 9px; }
  .veh-main h1 { font-size: clamp(1.55rem, 7vw, 1.9rem); margin: 3px 0 12px; }
}
.veh-main h1 { font-size: clamp(1.9rem, 4vw, 3rem); margin: 6px 0 18px; }

/* The facts, as a definition row rather than a sentence. A customer scanning
   this wants to confirm we understood them, which is a glance, not a read. */
.veh-facts {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 10px 28px;
}
.veh-facts li { display: grid; gap: 1px; }
.veh-facts span {
  /* 12px, the same floor as every other small label here. At .72rem this came
     out 11.5px and tools/sweep.sh failed it. */
  font-size: 12px; font-weight: 750; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3);
}
.veh-facts b { font-size: 1rem; font-weight: 650; }
.veh-sensed {
  display: flex; gap: 8px; align-items: flex-start;
  margin: 18px 0 0; padding: 11px 14px;
  background: var(--good-soft); border-radius: var(--radius);
  font-size: .9rem; color: var(--ink-2); line-height: 1.5;
}
.veh-sensed svg { width: 17px; height: 17px; color: var(--good); margin-top: 2px; }
.veh-note { margin: 16px 0 0; font-size: .93rem; color: var(--ink-2); }

/* The size control, pulled into the header so the thing that changes every
   price on the page sits beside the vehicle it belongs to. */
.veh-size {
  border: 1px solid var(--brand-edge); border-left: 4px solid var(--accent);
  border-radius: var(--radius); background: var(--brand-soft);
  padding: 18px 20px;
}
.veh-size > label {
  display: block; font-weight: 700; font-size: .95rem; margin-bottom: 10px;
}
.veh-size-row { display: flex; gap: 9px; }
.veh-size-row select {
  flex: 1; font: inherit; font-size: 1rem; min-height: 46px; padding: 11px 12px;
  border: 1px solid var(--line-strong); border-radius: 10px;
  background: var(--bg); color: var(--ink);
}
.veh-size-hint { margin: 11px 0 0; font-size: .85rem; color: var(--ink-2); line-height: 1.5; }
.veh-fine {
  margin: 16px 0 0; font-size: .87rem; color: var(--ink-3);
  max-width: 84ch; line-height: 1.55;
}

/* THE HOME PAGE TIRE FINDER. The shortest useful version of the picker: the two
   inputs that need no dropdowns at all, and a link to the rest. */
.finder {
  display: grid; gap: clamp(24px, 4vw, 48px); align-items: center;
  grid-template-columns: 1.05fr .95fr;
  border: 1px solid var(--line-strong); border-radius: var(--radius-lg);
  padding: clamp(26px, 3.6vw, 44px); background: var(--surface);
}
@media (max-width: 860px) { .finder { grid-template-columns: 1fr; } }
.finder-txt h2 { margin-bottom: 10px; }
.finder-txt p { color: var(--ink-2); margin: 0; max-width: 46ch; }
.finder-form { display: grid; gap: 14px; }
.finder-form .field label { font-size: .86rem; }
.finder-or {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: 12px; align-items: center;
  color: var(--ink-3); font-size: .85rem; margin: -2px 0;
}
.finder-or::before, .finder-or::after {
  content: ""; height: 1px; background: var(--line-strong);
}
.finder-alt { margin: 0; font-size: .9rem; text-align: center; }

/* THE PICKER. Three or four cards, each a self-contained form with its own
   submit, because a customer knows exactly one of these things and should not
   have to work out which part of a long form applies to them. Separate <form>
   elements rather than one form with a mode switch: each posts only its own
   fields, and each works with scripting off. */
.pick-cards {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
/* Four across on a desktop, explicitly. auto-fit with a 280px minimum was
   giving two rows of two at 1180px, which reads as two pairs of alternatives
   rather than four equal ways in. They are four equal ways in. */
@media (min-width: 1060px) { .pick-cards { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 700px) and (max-width: 1059px) { .pick-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.pick { padding: 22px; }
.pick h2 { font-size: 1.1rem; gap: 9px; }
.pick-ico { width: 34px; height: 34px; }
.pick-ico svg { width: 19px !important; height: 19px !important; }
.pick > p { font-size: .88rem; }
.pick {
  display: flex; flex-direction: column; gap: 14px;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 26px; background: var(--bg); box-shadow: var(--shadow);
}
.pick:hover { border-color: var(--brand-edge); }
.pick:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.pick h2 {
  font-size: 1.2rem; margin: 0; letter-spacing: -0.02em;
  display: flex; align-items: center; gap: 11px;
}
/* An icon per method, so the four cards are scannable before they are read.
   Drawn to the same 24-grid and stroke weight as the rest of the set. */
.pick-ico {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 38px; height: 38px; border-radius: 10px;
  background: var(--brand-soft); color: var(--brand);
}
.pick-ico svg { width: 22px !important; height: 22px !important; }
.dark .pick-ico { background: rgba(127,178,255,.12); }
.pick > p { color: var(--ink-2); font-size: .93rem; margin: 0; }
.pick .field { gap: 6px; }
.pick .field label { font-size: .86rem; }
.pick .field input, .pick .field select { min-height: 46px; height: 48px; padding: 11px 12px; }
/* Three selects inside a card this narrow clipped their own "Select" text to
   "Selec". Tighter padding and a slightly smaller face fit the word; the touch
   target is unchanged because min-height carries it. */
.pick .f-2, .pick .f-3 { gap: 8px; }
.pick .f-3 select { padding-inline: 8px; font-size: .93rem; }
.pick button { margin-top: auto; }
.pick .hint { margin: 0; font-size: .85rem; color: var(--ink-3); }
/* The "where do I find it" helper. A <details> rather than a modal or a
   tooltip: it works with no JavaScript, it is a real disclosure to a screen
   reader, and somebody who knows their size never sees it. */
/* The scan control. Ships hidden; the script reveals it only where the browser
   can actually decode a barcode. */
.vinscan { display: grid; gap: 8px; }
.vinscan label.btn { cursor: pointer; }
.vinscan .hint { margin: 0; font-size: .82rem; }

.wheremini { margin: -4px 0 0; }
.wheremini > summary {
  cursor: pointer; font-size: .88rem; font-weight: 650; color: var(--brand);
  min-height: 24px; padding-block: 3px; list-style: none;
  text-align: center;
}
/* Only the control centers. What it opens is prose and stays left, because
   centered body copy is harder to read down and these are two instructions
   somebody follows while standing at a wheel. */
.wheremini p { text-align: left; }
.wheremini > summary::-webkit-details-marker { display: none; }
/* NO "? " PREFIX. It used to prepend one as a poor man's disclosure marker,
   which rendered as "? Where do I find it?" -- a stray question mark in front
   of a sentence that already ends in one. The summary is brand-colored,
   underlined on hover and cursor:pointer, which is affordance enough. */
.wheremini > summary:hover { color: var(--brand-hover); text-decoration: underline; }
.wheremini p { font-size: .88rem; color: var(--ink-2); margin: 8px 0 0; line-height: 1.5; }

.pick-alt { margin-top: 26px; color: var(--ink-2); font-size: .96rem; }
.dark .pick { background: #121820; }

/* TREAD ILLUSTRATIONS. Drawn, not photographed: see the note at the top of
   treads.js. They recolor with the theme, which is the other thing a JPEG of a
   tire cannot do. */
.tire-shot {
  position: relative; border-radius: var(--radius) var(--radius) 0 0; overflow: hidden;
  aspect-ratio: 16 / 9; background: var(--surface-2);
  display: grid; place-items: center;
}
/* A real product photograph. They are square studio shots on white, so they are
   CONTAINED rather than cropped: slicing a tire in half to fill a 16:9 window
   looks like a mistake. Padding keeps them off the edges. */
.tire-shot img, .product-shot img {
  width: auto; height: 100%; max-width: 100%; object-fit: contain;
  padding: 10px; mix-blend-mode: multiply;
}
.dark .tire-shot img, .dark .product-shot img { mix-blend-mode: normal; }
.tread { width: 100%; height: 100%; display: block; }
.tread-bg { fill: #2b3238; }
.tread-block { fill: #4a545c; }
.tread-lug { fill: #525d66; }
.tread-sipe { stroke: #2b3238; stroke-width: 2.2; fill: none; stroke-linecap: round; }
.dark .tread-bg { fill: #171d24; }
.dark .tread-block { fill: #333d46; }
.dark .tread-lug { fill: #3a444e; }
.dark .tread-sipe { stroke: #171d24; }
.product-shot {
  position: relative; max-width: 420px; aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg); overflow: hidden; background: var(--surface-2);
  margin: 26px 0 18px; display: grid; place-items: center;
}
.product-price { margin: 0 0 22px; display: flex; gap: 8px; flex-wrap: wrap; align-items: baseline; }
.product-price b { font-size: 1.5rem; letter-spacing: -0.025em; }
.product-price span { color: var(--ink-3); font-size: .95rem; }
.tire-tier {
  position: absolute; top: 10px; right: 10px;
  background: rgba(255,255,255,.92); color: #3d4650;
  box-shadow: 0 1px 3px rgba(16,22,29,.16);
  /* 12px floor, same rule as the wordmark. At .72rem this measured 11.5px and
     tools/sweep.sh failed it on all three pages that show a tire. */
  font-size: 12px; font-weight: 750; letter-spacing: .05em; text-transform: uppercase;
  padding: 4px 9px; border-radius: 999px;
}

/* The price band. A RANGE, captioned as one. See the pricing block in
   tires.js for where the numbers come from and why showing them is right. */
/* Badges and text pills share this row, and the artwork is a mix of wide
   horizontal logos and tall portrait signs. Normalising on HEIGHT alone made
   the two Virginia signs about 30px wide and unreadable, so each badge gets a
   fixed box and sits inside it, which keeps every mark the same visual weight
   whatever its aspect ratio. White plate because the NAPA and DEQ artwork both
   assume a light background. */
.ftr-creds li.has-badge{background:none;border:0;border-radius:0;
  display:flex;align-items:center;justify-content:center;
  height:76px;width:118px;box-sizing:border-box;padding:7px}
.ftr-creds li.has-badge img{display:block;max-height:100%;max-width:100%;width:auto;
  height:auto;object-fit:contain}
/* The two Virginia signs are portrait documents rather than wordmarks. Fitted
   to the same box as the NAPA lozenge they came out about 30px wide, which is
   not a badge, it is a smudge. They get the full height of the box. */
.ftr-creds li.has-badge.is-tall{width:64px}
.ftr-creds li.has-badge.is-tall img{max-height:100%}
@media (max-width:560px){
  .ftr-creds li.has-badge{height:64px;width:100px;padding:6px}
  .ftr-creds li.has-badge.is-tall{width:54px}
}
.tire-warranty{display:block;color:var(--ink);font-weight:700;font-size:max(12px,.92rem);
  margin-bottom:2px}
.qbar{display:flex;flex-wrap:wrap;gap:10px 14px;align-items:center;justify-content:space-between;
  background:var(--napa-blue);color:#fff;border-radius:12px;padding:12px 15px;margin-bottom:12px}
.qbar-txt{margin:0;font-size:max(12px,.95rem);line-height:1.45}
.qbar-txt b{font-weight:750}
.qbar .btn{background:var(--napa-yellow);color:#1a1a1a;border-color:var(--napa-yellow);
  min-height:44px;flex:0 0 auto}
@media (max-width:560px){.qbar{padding:11px 12px}.qbar .btn{width:100%}}
.tfilter{background:var(--napa-soft);border:1px solid rgba(0,51,160,.14);border-radius:12px;
  padding:14px 15px}
.tfilter-row{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end}
.tfilter-f{display:flex;flex-direction:column;gap:5px;flex:1 1 165px;min-width:0}
.tfilter-q{flex:2 1 260px}
.tfilter-f > span{font-size:max(12px,.74rem);font-weight:700;letter-spacing:.02em;
  text-transform:uppercase;color:var(--ink-2)}
.tfilter-f input,.tfilter-f select{height:50px;line-height:1.5;width:100%;box-sizing:border-box;
  padding:0 12px;border:1px solid var(--line);border-radius:9px;background:#fff;
  color:var(--ink);font:inherit;font-size:max(12px,.95rem)}
.tfilter-f input:focus-visible,.tfilter-f select:focus-visible{outline:3px solid var(--napa-blue);
  outline-offset:1px}
.tfilter .btn{height:50px;flex:0 0 auto;padding-inline:22px}
.tfilter-count{margin:11px 0 0;font-size:max(12px,.86rem);color:var(--ink-2)}
.tfilter-count b{color:var(--ink)}
.tfilter-count a{color:var(--napa-blue);min-height:24px;display:inline-block;padding:2px 0}
.tfilter-empty{text-align:center;padding:26px 0 8px;max-width:56ch;margin-inline:auto}
.tfilter-empty h2{margin:0 0 8px}
.tfilter-empty p{color:var(--ink-2);margin:0 0 14px}
@media (max-width:560px){
  /* Stacked full-width, this bar ran 733px on a 390px screen and was the single
     biggest thing between the customer and a tire. Two across, with the field
     labels carried by the first option ("Any brand") instead of a heading above
     each control. The labels stay in the DOM for screen readers. */
  .tfilter{padding:11px 12px}
  .tfilter-row{display:grid;grid-template-columns:1fr 1fr;gap:8px;align-items:end}
  .tfilter-q{grid-column:1 / -1}
  .tfilter .btn{grid-column:1 / -1;width:100%}
  .tfilter-f > span{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
  .tfilter-count{margin-top:9px}
}
.group-band{margin:10px 0 0;font-size:max(12px,.86rem);line-height:1.5;color:var(--ink-2);
  background:var(--napa-soft);border:1px solid rgba(0,51,160,.14);border-radius:10px;
  padding:10px 13px;max-width:62ch}
.group-band b{color:var(--ink);font-size:1.06em}
.tire-price {
  margin: 10px 0 0 !important; display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
}
.tire-price b { font-size: 1.24rem; color: var(--ink); letter-spacing: -0.028em; font-weight: 780; }
.tire-price span { font-size: .84rem; color: var(--ink-3); }


/* ------------------------------------------------------- the tire catalog
   Filters are LINKS with their own URLs, so this is a real browsable catalog
   rather than a JavaScript widget: every view can be bookmarked, sent, and
   crawled, and it all works with scripting off. */
.cat-search { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 22px; }
.cat-search input[type="search"] {
  flex: 1 1 260px; font: inherit; font-size: 1rem; min-height: 50px;
  padding: 13px 14px; border: 1px solid var(--line-strong); border-radius: 10px;
  background: var(--bg); color: var(--ink);
}
.filters { display: grid; gap: 12px; margin-bottom: 20px; }
.filter-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.filter-lbl {
  font-size: .78rem; font-weight: 750; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3); margin-right: 4px; flex: 0 0 auto;
}
.chip {
  display: inline-block; text-decoration: none;
  border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 7px 14px; min-height: 24px;
  font-size: .92rem; font-weight: 620; color: var(--ink-2); background: var(--bg);
}
.chip:hover { border-color: var(--brand-edge); color: var(--ink); }
.chip.is-on {
  background: var(--brand); border-color: var(--brand); color: var(--brand-ink);
}
.cat-blurb { color: var(--ink-2); max-width: 68ch; margin: 0 0 14px; }
/* The brand and category links in a product page's eyebrow are navigation back
   into the catalog, not prose, so they get real targets too. */
.eyebrow a { display: inline-block; min-height: 24px; padding-block: 2px; color: inherit; }
.cat-count { font-size: .9rem; color: var(--ink-3); margin: 0 0 18px; }

.tire-grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
}
.tire {
  display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--bg); overflow: hidden;
}
.tire-body { display: flex; flex-direction: column; gap: 8px; padding: 20px 22px 22px; flex: 1; }
.tire:hover { border-color: var(--brand-edge); box-shadow: var(--shadow); }
.tire-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.tire-brand {
  font-size: .76rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--brand);
}
.tire-cat { font-size: .78rem; color: var(--ink-3); }
.tire h2, .tire h3 { font-size: 1.16rem; margin: 0; letter-spacing: -0.018em; }
/* The product name is the main way into a tire's page, so it is a real target
   rather than a 22px line of text. inline-block plus padding gets it over the
   24px minimum without changing where the card's text sits. */
.tire h2 a, .tire h3 a {
  color: var(--ink); text-decoration: none;
  display: inline-block; min-height: 24px; padding-block: 2px;
}
.tire h2 a:hover, .tire h3 a:hover { color: var(--brand); }
.tire p { color: var(--ink-2); font-size: .93rem; margin: 0; flex: 1; }
.tire form { margin-top: 6px; }
.tire button[disabled] { opacity: 1; color: var(--good); border-color: var(--good); cursor: default; }
.dark .tire { background: #121820; border-color: var(--line-strong); }

/* The quote cart. Their flow ends at "We will send you a quote on the
   following"; so does this one. */
.cart-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.cart-list li {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  justify-content: space-between;
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 20px; background: var(--bg);
}
.cart-list b { display: block; }
.cart-list span { font-size: .87rem; color: var(--ink-3); }
/* h2, not h3: this panel is only rendered for a returning visitor whose vehicle
   is remembered, so it never appeared in a plain fetch of the page and the
   heading jump it caused (h1 straight to h3) was invisible to any check that
   reads HTML rather than a rendered DOM. Size held at the old value. */
.knownveh h2 { font-size: 1.05rem; letter-spacing: -0.02em; font-weight: 720; text-wrap: initial; }
.knownveh p { margin: 0; font-size: .92rem; color: var(--ink-2); }

.picked ul { list-style: none; margin: 0 0 10px; padding: 0; display: grid; gap: 4px;
  font-size: .95rem; color: var(--ink-2); }
.picked p { margin: 0; font-size: .9rem; }

/* Findings list on /compare. */
.finds { list-style: none; margin: 0; padding: 0; display: grid; gap: clamp(24px, 3vw, 36px); }
/* GRID BLOWOUT. A grid item's default min-width is auto, not zero, so anything
   inside it that refuses to shrink widens the track past its own container
   rather than wrapping. Measured at 390px: ol.finds sat correctly at 354px wide
   while every li.find inside it was 385px, and the page scrolled 14px sideways.
   min-width:0 lets the item shrink to its track, which is what a reader wants;
   the nested grids need the same, because each of them is an item of the one
   above it. */
.finds > li,
.find-head > *,
.find-why > * { min-width: 0; }


/* ------------------------------------------------------------- polish pass
   Shared refinements, applied in one place rather than per component, so the
   whole site moves together. Nothing here changes layout; it is weight,
   transition and edge treatment, which is most of what separates a page that
   works from one that looks finished. */

/* Motion. One duration and one curve everywhere, and all of it surrendered
   under prefers-reduced-motion, which is not decoration: vestibular disorders
   are common and a hover that lifts is exactly the kind of thing that triggers
   them. */
:root { --ease: cubic-bezier(.2, .7, .3, 1); --fast: .16s; }
.btn, .card, .tire, .area-card, .panel, .pick, .rev-links a, .chip,
.field input, .field select, .field textarea, .cat-search input {
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease),
              background-color var(--fast) var(--ease), transform var(--fast) var(--ease),
              color var(--fast) var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .btn, .card, .tire, .area-card, .panel, .pick, .rev-links a, .chip,
  .field input, .field select, .field textarea, .cat-search input { transition: none; }
  .card:hover, .tire:hover, .area-card:hover { transform: none; }
}

/* Buttons. A press that actually presses, and a primary that reads as the
   thing to click without shouting. */
.btn { will-change: transform; }
.btn-primary { box-shadow: 0 1px 2px rgba(16,22,29,.14); }
.btn-primary:hover { box-shadow: 0 3px 10px rgba(20,69,111,.28); }
.btn:active { transform: translateY(1px); box-shadow: none; }
.btn-ghost:hover { border-color: var(--brand); color: var(--brand); }

/* Cards lift a little on hover. Two pixels: enough to say "this is one thing
   and it is clickable", not enough to make a grid of them feel restless. */
.tire:hover, .area-card:hover { transform: translateY(-2px); }
.tire:hover { box-shadow: var(--shadow); border-color: var(--brand-edge); }

/* Focus inside a card should light the card, not just the link, or keyboard
   users get a 2px outline floating in the middle of a box. */
.tire:focus-within, .area-card:focus-visible {
  border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft);
}

/* Form fields: a real focus ring rather than a color change nobody notices. */
.field input:focus, .field select:focus, .field textarea:focus,
.cat-search input:focus, .veh-size-row select:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

/* The note box appears on nearly every page, so it had to stop looking like a
   warning. A quiet left rule in the accent, and type that sits with the page
   instead of interrupting it. */
.note {
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  background: var(--surface); border-radius: var(--radius);
  padding: 16px 20px; font-size: .95rem; line-height: 1.6; color: var(--ink-2);
}
.note b { color: var(--ink); }
.dark .note { background: rgba(255,255,255,.04); border-color: var(--line-strong); }

/* Section headings breathe a little more, and the lede under them is capped so
   it never runs the full width of a 1180px container. */
.sec-head { margin-bottom: clamp(24px, 3vw, 38px); }
.sec-head p { color: var(--ink-2); max-width: 64ch; }
.lede { max-width: 62ch; }

/* The eyebrow rule is the one place the gold earns its keep on a light ground:
   it is a graphic element, not text, so contrast rules do not apply to it. */
.eyebrow::before { background: var(--accent); width: 22px; height: 3px; border-radius: 2px; }

/* ---------------------------------------------------------------- footer */
.ftr { background: var(--surface); border-top: 1px solid var(--line); padding-block: clamp(44px, 6vw, 72px) 30px; }

/* The call bar is fixed to the bottom, so the last thing on the page sits under
   it. Measured at 390px: the bar's top edge was 770 while the AAA badge and the
   BBB pill ran to 792 and 775, both underneath it and unreadable at the point
   someone has scrolled all the way down to look at exactly those. The footer
   reserves the bar's own height plus the safe area.

   This has to sit AFTER the .ftr base rule, which sets padding-block and would
   otherwise reset the bottom padding no matter what this asked for. */
@media (max-width: 620px) {
  .ftr { padding-bottom: calc(92px + env(safe-area-inset-bottom, 0px)); }
}
.ftr-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1.25fr; gap: clamp(28px, 4.5vw, 60px); }
/* .78rem is 12.5px, above the 12px floor. Kept exactly as the h4 rule was so
   the rank change is invisible on screen and only real to a screen reader. */
.ftr h2 { 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 .brand-pt { font-size: 1.9rem; }
.ftr-blurb { margin-top: 16px; color: var(--ink-2); font-size: .96rem; max-width: 36ch; }
.ftr .dim { color: var(--ink-3); }
/* The dashboard footer's one link. It sits in a paragraph and so missed the
   prose-link padding rule, which is scoped to .sec and .note. */
.ftr-portal p a { display: inline-block; min-height: 24px; padding-block: 3px; }

/* The current page in the footer: present, but not a link to nowhere. */
.ftr-here { color: var(--ink-3); display: inline-block; min-height: 24px; padding-block: 3px; }
.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);
}

/* EVERYTHING IN THE FOOTER IS CENTERED, at every width rather than only on a
   phone. The columns stay four across on a desktop; it is their contents that
   center, so the structure is unchanged and only the alignment moves. */
.ftr { text-align: center; }
.ftr .brand { justify-content: center; }
.ftr ul { justify-items: center; }
.ftr p { margin-inline: auto; }
.ftr-blurb { margin-inline: auto; }
.ftr-btm { flex-direction: column; align-items: center; gap: 16px; text-align: center; }
.ftr-legal { justify-items: center; }
.pay { display: flex; justify-content: center; flex-wrap: wrap; }
/* Credentials as text, not as a row of logo files.
   Their current site puts the NAPA, ASE and BBB marks in the footer as four
   PNGs with title= attributes and no alt, which is 4 requests that say nothing
   to a screen reader or a crawler. The same four facts are set in type here,
   and the machine-readable version rides along in the JSON-LD hasCredential
   array, which is the form that actually earns anything. */
/* .ftr ul sets display:grid and outranks a bare .ftr-creds (0,1,1 beats 0,1,0),
   so this was silently a one-badge-per-row column no matter what it asked for.
   Qualified to win rather than nudged with !important. */
.ftr ul.ftr-creds {
  /* Its own full-width line. Sharing the bottom bar with the legal text left
     roughly 200px, and once these were badges rather than text pills they
     wrapped into a tall vertical stack. */
  flex: 1 0 100%; order: -1; justify-content: center;
  /* center, not stretch: a text pill next to 76px badges was being pulled to
     the full row height, and a 999px radius on that turned "BBB A+" into a
     large circle. */
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  list-style: none; margin: 0; padding: 0;
  font-size: .8rem; font-weight: 620; color: var(--ink-2);
}
.ftr-creds li {
  border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 5px 12px; min-height: 24px; background: var(--bg);
}

/* 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 PT Auto Experts, and it says so. It is not
   pretending to be the live site, and it is noindex at the server. */
.demo-bar {
  background: #10233a; color: #dce9ff; font-size: .86rem; text-align: center;
  padding: 9px var(--gut); line-height: 1.45;
}
.demo-bar b { color: #ffffff; }
.demo-bar a { color: #9ec8ff; 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; }

  /* THE HERO COPY MOVES TO THE TOP OF THE PICTURE, and the scrim flips with it.
     Bottom-aligned is right on a wide screen: the hero is short, the type sits
     on the gradient's dark end, and the whole thing is visible at once. On a
     phone the hero is 658px of a 844px viewport and the buttons are hidden, so
     bottom-aligned left 247 PIXELS OF IMAGE above the first word -- measured --
     and the headline arrived near the fold on a page whose job is to say what
     this shop is in the first second.
     THE GRADIENT HAS TO TURN OVER TOO. It runs dark-at-the-bottom, so moving
     white type to the top without flipping it would drop the headline onto the
     lightest part of the scrim, over the bright fluorescent patches this
     overlay exists to defeat. tools/a11y.js does NOT catch that: text sitting
     on a background image has no single background color to sample, so it is
     listed for a human rather than counted, and it would have passed. Measured
     by hand instead, off the composited pixels behind the type.
     The bottom stays partly dark so the photo credit in that corner survives.
     THE FIRST FLIP FAILED AND THE MEASUREMENT IS WHY THE STOPS LOOK LIKE THIS.
     Lightening at 66% put the LEDE, which runs to 58% of the hero on a 390px
     phone, over a backdrop of rgb(116,121,124) -- 3.15:1 against its own color,
     against a 4.5 requirement. The dark band now holds to 62% and eases from
     there. Centering the headline afterwards pushed the lede down again, to 76%
     of the hero, and it came back at 4.55:1 -- passing by five hundredths, which
     is not passing, it is landing on the line. The dark band was extended a
     second time to hold .70 out to 78%. Every figure here was taken off the
     composited screenshot with the copy hidden, not estimated. */
  /* THE EYEBROW HOLDS THE TOP AND THE REST CENTERS IN WHAT IS LEFT.
     Moving the whole block up left the type in the top half and 277px of dead
     image under it. Stretching the wrap to the full height and letting the
     headline take auto margins above and below floats the h1 and the lede in
     the space beneath the eyebrow, so the picture is framed by type at the top
     and open below rather than being bottom-heavy with nothing in it. */
  /* THE PHOTO CREDIT IS COVERED BY THE STICKY CALL BAR HERE, so it goes.
     Measured: the credit occupies y793-819 in an 844px viewport and
     elementFromPoint at its center returns the bar's button, not the credit.
     It was text rendered underneath a solid control -- unreadable, and counted
     as a contrast failure because there was nothing to read it against. A
     photograph credit is the one thing on this hero that can be dropped on a
     phone; the alternative is lifting it above a bar it has no relationship
     with. */
  .hero-full .credit { display: none; }
  .hero-full { align-items: stretch; }
  .hero-full .wrap { display: flex; flex-direction: column; }
  .hero-full h1 { margin-top: auto; }
  .hero-full .lede { margin-bottom: auto; }
  .hero-full::after {
    background:
      linear-gradient(to bottom,
        rgba(6,9,13,.94) 0%, rgba(6,9,13,.88) 38%,
        rgba(6,9,13,.78) 58%, rgba(6,9,13,.70) 78%,
        rgba(6,9,13,.48) 90%, rgba(6,9,13,.60) 100%);
  }

  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; }
  .brand svg, .brand img { width: 148px; }
  .status { display: none; }
  .hero-actions .btn { width: 100%; }

  /* The rest of the footer centering is unconditional now, see below the
     .ftr-btm rule. Only the single-column collapse belongs to a phone. */
  .ftr-grid { grid-template-columns: 1fr; gap: 30px; }
  .ftr h2 { margin-bottom: 10px; }
}

/* ---------------------------------------------------------------- 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 */
@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; }

}
