/* ============================================================================
   tire.css — TireFit's site-local layer. Loads AFTER datasite.css, adds only
   what the ring's Identity A does not already own.

   THE HAND (AAA+++ §5 — every site in the ring draws in a different one)
   ---------------------------------------------------------------------
   watts draws a switchboard. lux draws a ceiling plan. cook draws a probe.
   TireFit draws a DIMENSIONED ENGINEERING ELEVATION — the drawing a tyre
   engineer would staple to a fitment report:

     · 1.1px hairlines for geometry, 1.6px for the subject outline
     · dimension lines with 45° tick terminals, never arrowheads
     · extension lines that stop 3px short of what they measure
     · every label in --mono, uppercase, +.06em, never in the serif
     · the tolerance band drawn as a shaded ring, so the ±3% convention is a
       thing you can SEE the second tyre sitting inside or outside of

   Nothing here is an image and nothing here needs JS: the plate is emitted
   server-side as inline SVG and is complete with scripting off. calc.js only
   ever re-labels an already-drawn plate.

   MOTION (added 2026-08-04, §10). This file used to say "nothing here
   animates". The guarantee that mattered was never "no motion" — it was that
   the OUTPUT is a finished drawing: correct with JavaScript off, correct in
   print, correct to a crawler. That is unchanged. §10 animates the act of
   drawing the hero plate and nothing else, purely in CSS, with every
   element's final state identical to its natural state — so if the animation
   never runs, the plate is simply there. It lives inside
   `prefers-reduced-motion: no-preference`, the same opt-in the ring uses for
   .reveal, so for a reader who has asked for less motion it does not exist —
   and inside a further `@media screen`, because print applies an animation's
   backwards fill without ever running the animation, which would have printed
   every plate as an empty frame.
   ========================================================================== */

body[data-site="tire"] {
  --tf-line: color-mix(in srgb, var(--ink) 34%, transparent);
  --tf-line-2: color-mix(in srgb, var(--ink) 16%, transparent);
  --tf-subject: var(--ink-2);
  --tf-ok: #2F6B3F;
  --tf-marginal: #8A5A14;
  --tf-no: #A3352A;
}
:root[data-theme="dark"] body[data-site="tire"] {
  --tf-line: color-mix(in srgb, var(--ink) 44%, transparent);
  --tf-line-2: color-mix(in srgb, var(--ink) 20%, transparent);
  --tf-ok: #6FBF86;
  --tf-marginal: #D6A94F;
  --tf-no: #E1857C;
}

/* ============================================================ 1. THE PLATE
   The frame the drawing sits in. A drawing plate, not a card: it has a title
   block along the top and a border that is a drawn rule rather than a UI
   stroke, and it never floats (§3.2 — the one shadow on this site belongs to
   the calculator, nothing else). */
.tf-plate {
  margin: var(--s4) 0 0;
  border: 1px solid var(--tf-line-2);
  background: var(--surface);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.tf-plate-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px 18px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--tf-line-2);
  background: var(--paper-2);
}
.tf-plate-t {
  font-family: var(--mono); font-size: .78rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-2); font-weight: 600;
}
.tf-plate-m {
  font-family: var(--mono); font-size: .74rem; letter-spacing: .06em;
  color: var(--muted); margin-left: auto;
}
.tf-plate-body { padding: 20px 18px 8px; }
.tf-plate svg { display: block; width: 100%; height: auto; }
.tf-plate figcaption { padding: 0 18px 14px; }

/* The drawing hand itself, applied to every plate SVG. */
.tf-draw .geo    { fill: none; stroke: var(--tf-line);   stroke-width: 1.1; }
.tf-draw .faint  { fill: none; stroke: var(--tf-line-2); stroke-width: 1.1; }
.tf-draw .subject{ fill: none; stroke: var(--tf-subject);stroke-width: 1.6; }
.tf-draw .rim    { fill: none; stroke: var(--tf-subject);stroke-width: 1.3; opacity: .75; }
.tf-draw .dim    { fill: none; stroke: var(--tf-line);   stroke-width: 1;   }
.tf-draw .ext    { fill: none; stroke: var(--tf-line-2); stroke-width: 1; stroke-dasharray: 2 3; }
.tf-draw .accent { fill: none; stroke: var(--accent);    stroke-width: 1.8; }
.tf-draw .band   { fill: var(--accent); opacity: .08; stroke: none; }
.tf-draw .hatch  { fill: none; stroke: var(--tf-line-2); stroke-width: 1; }
.tf-draw text {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .05em;
  fill: var(--muted); text-transform: uppercase;
}
.tf-draw text.val { fill: var(--ink-2); font-size: 11.5px; letter-spacing: .02em; text-transform: none; }
.tf-draw text.key { fill: var(--accent); font-weight: 600; }
.tf-draw .cl { stroke: var(--tf-line-2); stroke-width: 1; stroke-dasharray: 9 3 2 3; }

/* ========================================================= 2. THE VERDICT
   The single most useful thing on the site and the thing no competitor
   prints: not a table of two diameters, but an answer, on a rail, with the
   convention it is judged against drawn around it. */
.tf-verdict {
  margin: var(--s4) 0 0;
  border-top: 2px solid var(--vc, var(--accent));
  background: var(--surface);
  padding: 20px 22px 22px;
}
.tf-verdict[data-v="ok"]       { --vc: var(--tf-ok); }
.tf-verdict[data-v="marginal"] { --vc: var(--tf-marginal); }
.tf-verdict[data-v="no"]       { --vc: var(--tf-no); }
.tf-v-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 14px; }
.tf-v-word {
  font-size: 1.34rem; font-weight: 600; letter-spacing: -.02em; color: var(--vc);
}
.tf-v-band {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
  border: 1px solid var(--tf-line-2); border-radius: 999px; padding: 3px 9px;
}
.tf-v-stat { margin: 12px 0 0; }
.tf-v-stat .stat-display { color: var(--ink); display: inline-block; }
.tf-v-line { margin-top: 10px; color: var(--ink-2); font-size: .95rem; line-height: 1.62; max-width: 62ch; }

/* ================================================ 2b. THE TOLERANCE CHART
   The set piece. Two rules stacked on ONE axis, drawn as different shapes
   because they ARE different things:

     · the ±3% fitment convention is symmetric — industry practice about
       geometry, so both its edges are DASHED and of equal weight;
     · UN ECE R39's speedometer margin is asymmetric — it runs a long way to
       the left and then stops dead at 0.00%, so its far edge is DASHED (the
       +4 km/h term moves it with speed) and its near edge is a SOLID 2.2px
       rule that does not move and has nothing behind it.

   Everything past that solid edge is 45° hatch: the drawing convention for
   a region with no material in it. A symmetric ± band — which is what this
   block used to render, and what every competitor renders — would have
   misrepresented the regulation, so the asymmetry is load-bearing, not
   decorative.

   Colour lives on the gate alone (the verdict's own tint). The rules are
   drawn in ink, so the argument survives greyscale, print and colour
   blindness — which is the test a legality claim has to pass. */
.tf-tol { margin-top: 20px; --vc: var(--accent); }
.tf-tol[data-v="ok"]       { --vc: var(--tf-ok); }
.tf-tol[data-v="marginal"] { --vc: var(--tf-marginal); }
.tf-tol[data-v="no"]       { --vc: var(--tf-no); }

/* the tolerated field, and the field with nothing in it */
.tf-tol .tf-draw .band  { fill: var(--ink); opacity: .055; }
.tf-tol .tf-draw .nogo  { fill: url(#tf-nogo); opacity: .5; }

/* the two KINDS of edge — the whole argument is that these differ */
.tf-tol .tf-draw .edge-soft {
  fill: none; stroke: var(--tf-line); stroke-width: 1.1; stroke-dasharray: 4 4;
}
.tf-tol .tf-draw .edge-hard {
  fill: none; stroke: var(--ink); stroke-width: 2.2; stroke-linecap: butt;
}
.tf-tol .tf-draw text.hi   { fill: var(--ink); font-weight: 600; letter-spacing: .07em; }
/* --faint was the obvious choice for a secondary annotation and it fails:
   ~3.3:1 on warm paper at 9.5px. This label carries the number that makes the
   asymmetry legible, so it holds --muted, which contrast-check clears. */
.tf-tol .tf-draw text.lo   { fill: var(--muted); font-size: 9.5px; }
.tf-tol .tf-draw text.ok-t,
.tf-tol .tf-draw text.nogo-t { fill: var(--muted); font-size: 9.5px; letter-spacing: .09em; }

/* the substitution itself: the one coloured mark on the plate */
.tf-tol .tf-draw .gate { fill: none; stroke: var(--vc); stroke-width: 2.2; }
.tf-tol .tf-gate-g .dim { stroke: var(--vc); stroke-width: 1.6; }
.tf-tol .tf-draw text.val { fill: var(--vc); font-weight: 600; font-size: 12px; }

/* ====================================================== 3. THE SPEC STRIP
   Key/value pairs in the mono voice — the register the ring reserves for
   dates, units, codes and specifications (AAA+++ §3.1's third voice). */
.tf-specs {
  margin: var(--s4) 0 0;
  border-top: 1px solid var(--line);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
}
.tf-spec {
  padding: 14px 18px 15px 0;
  border-bottom: 1px solid var(--line);
}
.tf-spec dt {
  font-family: var(--mono); font-size: .68rem; letter-spacing: .11em;
  text-transform: uppercase; color: var(--muted);
}
.tf-spec dd {
  margin: 6px 0 0; font-size: 1.16rem; font-weight: 600; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums lining-nums; color: var(--ink);
}
.tf-spec dd em { font-style: normal; font-weight: 400; font-size: .84rem; color: var(--muted); margin-left: 5px; }

/* ==================================================== 4. SIDEWALL DECODER
   The "what do these numbers mean" block. The size is set large in the mono
   voice with each field tinted and a leader dropping to its explanation — a
   callout drawing done in HTML so it reflows on a phone instead of scaling a
   diagram down to nothing. */
.tf-decode { margin: var(--s4) 0 0; }
.tf-code {
  font-family: var(--mono); font-weight: 600;
  font-size: clamp(1.5rem, 6vw, 2.4rem); letter-spacing: .02em;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 2px;
}
.tf-code b { font-weight: 600; padding: 0 3px; border-bottom: 3px solid var(--accent); color: var(--ink); }
.tf-code b.d2 { border-bottom-color: color-mix(in srgb, var(--accent) 55%, var(--paper)); }
.tf-code b.d3 { border-bottom-color: color-mix(in srgb, var(--accent) 30%, var(--paper)); }
.tf-code i { font-style: normal; color: var(--muted); padding: 0 3px; }
.tf-legend { margin-top: var(--s3); border-top: 1px solid var(--line); }
.tf-legend div {
  display: grid; grid-template-columns: 4.5rem 1fr; gap: 4px 16px;
  padding: 13px 0; border-bottom: 1px solid var(--line); align-items: baseline;
}
.tf-legend dt {
  font-family: var(--mono); font-size: .95rem; font-weight: 600; color: var(--ink);
}
.tf-legend dd { margin: 0; color: var(--ink-2); font-size: .93rem; line-height: 1.6; }
.tf-legend dd b { color: var(--ink); font-weight: 600; }

/* ====================================================== 5. THE CALCULATOR
   The one floating object on the site (§3.2). Inputs sit in sunken wells;
   the result is drawn by the same plate the static pages use, so the
   calculator is not a different product from the pages. */
.tf-calc {
  margin: var(--s4) 0 0;
  border: 1px solid var(--line-2); border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--shadow-lift);
  padding: 22px;
}
:root[data-theme="dark"] .tf-calc { box-shadow: none; background: var(--surface); border-color: var(--line-2); }
.tf-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 18px; }
.tf-field > span {
  display: block; font-family: var(--mono); font-size: .68rem; letter-spacing: .11em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 8px;
}
.tf-in {
  display: flex; gap: 6px; align-items: center;
  background: var(--paper-2); border: 1px solid var(--line-2);
  border-radius: var(--radius-sm); padding: 6px 8px;
}
.tf-in select, .tf-in input {
  flex: 1; min-width: 0; height: 38px;
  border: 0; background: transparent; color: var(--ink);
  font-family: var(--mono); font-size: 1rem; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.tf-in select:focus, .tf-in input:focus { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
.tf-in i { font-style: normal; color: var(--faint); font-family: var(--mono); font-size: .9rem; }
.tf-note { font-family: var(--mono); font-size: .74rem; letter-spacing: .04em; color: var(--muted); margin-top: 14px; }
.tf-note.live { color: var(--accent); }

/* ============================================== 6. SPEEDOMETER ERROR TABLE
   Small, dense, unmistakably a reference table rather than a marketing
   graphic. Tabular numerals are non-negotiable here — the whole value is
   that the columns line up so the drift is visible down the page. */
.tf-speedo td, .tf-speedo th { font-variant-numeric: tabular-nums lining-nums; }
.tf-speedo .over  { color: var(--tf-no); font-weight: 600; }
.tf-speedo .under { color: var(--tf-ok); font-weight: 600; }

/* =========================================================== 7. SIZE INDEX
   A dense typeset index, closer to the back of a parts catalogue than to a
   card grid: on a rim hub there can be 167 sizes and cards would make that
   five screens of nothing. */
.tf-index {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  border-top: 1px solid var(--line);
}
.tf-index a {
  padding: 11px 14px 11px 0; border-bottom: 1px solid var(--line);
  text-decoration: none; color: var(--ink); display: block;
}
.tf-index a:hover { color: var(--accent); }
.tf-index a b { font-family: var(--mono); font-weight: 600; font-size: .93rem; letter-spacing: .01em; }
.tf-index a small { display: block; color: var(--muted); font-size: .76rem; margin-top: 2px; font-variant-numeric: tabular-nums; }
.tf-index a.tail b { color: var(--muted); font-weight: 500; }

/* ======================================================== 8. THE SEARCH
   The one control every visitor touches first, so it earns real work. The
   behaviour lives in TF_SEARCH_JS (build.mjs); this is only its dress.
   Grouped headings, a pinned exact hit, a highlighted match and a visible
   keyboard legend — the point is that a reader can see the size they typed
   being recognised, rather than guessing whether the box understood them. */
.tf-search input { padding-right: 44px; }
.tf-search .tf-slash {
  position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
  font-family: var(--mono); font-size: .72rem; line-height: 1;
  color: var(--muted); background: var(--paper-2);
  border: 1px solid var(--line-2); border-radius: 4px;
  padding: 4px 7px; pointer-events: none;
}
/* Once focused the hint has done its job and would only be noise. */
.tf-search input:focus ~ .tf-slash { opacity: 0; }

.qr .qr-g {
  margin: 0; padding: 9px 16px 5px;
  font-family: var(--mono); font-size: .64rem; letter-spacing: .13em;
  text-transform: uppercase; color: var(--muted);
  background: var(--paper-2); border-bottom: 1px solid var(--line);
}
.qr a mark {
  background: var(--accent-soft); color: inherit;
  border-radius: 2px; padding: 0 1px; font-weight: 700;
}
/* Keyboard selection must be a BACKGROUND change, not just colour: it is the
   only cue when the pointer never moves, and :hover cannot express it. */
.qr a.on { background: var(--paper-2); color: var(--accent); outline: none; }
.qr a.on::after {
  content: "\21B5"; font-family: var(--mono); font-size: .8rem;
  color: var(--accent); margin-left: 8px; flex: none;
}
/* The exact designation the reader typed, pinned to the top. */
.qr a.qr-hit { border-left: 3px solid var(--accent); }
.qr a.qr-hit span { font-weight: 700; }
.qr .qr-k {
  margin: 0; padding: 8px 16px; border-top: 1px solid var(--line);
  background: var(--paper-2);
  font-family: var(--mono); font-size: .66rem; letter-spacing: .06em;
  color: var(--muted); display: flex; gap: 14px;
}
.qr .qr-k b {
  color: var(--muted); font-weight: 600;
  border: 1px solid var(--line-2); border-radius: 3px; padding: 1px 5px; margin-right: 3px;
}
.qr-none b { color: var(--ink-2); font-family: var(--mono); }

/* ============================================================== 9. SUNDRY */
.tf-pill {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--mono); font-size: .7rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
  border: 1px solid var(--line-2); border-radius: 999px; padding: 4px 11px;
}
.tf-pill b { color: var(--ink-2); font-weight: 600; letter-spacing: .04em; }
.tf-two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }
@media (max-width: 720px) {
  .tf-two { grid-template-columns: 1fr; }
  .tf-verdict { padding: 18px 16px 20px; }
  .tf-v-delta { margin-left: 0; width: 100%; }
  .tf-plate-body { padding: 16px 12px 6px; }
}

/* ====================================================== 10. THE PLOTTER
   The header of this file used to say "nothing here animates". That was a
   promise about the OUTPUT, not a rejection of motion: the plate must be a
   finished drawing in the HTML, correct with JavaScript off and correct in
   print. It still is — every circle, dimension and label below is rendered
   server-side, and nothing here adds a script or changes a coordinate.

   What this adds is the ACT of drawing. The hand this site draws in is a
   plotter, so the hero plate draws itself the way a plotter would: centre
   lines first, then the tolerance band, then the original tyre, then the
   proposed one, then the dimensions it was all measured against. It is the
   site's argument performed rather than stated — you watch the second tyre
   land inside or outside the ring.

   Three rules held throughout:
     · It is ENHANCEMENT. Every element's final state is its natural state,
       so if the animation never runs the plate is simply there, complete.
     · It runs ONCE, in the hero only. A size page carrying four plates that
       all redraw on load would be a toy, not a reference.
     · It does not exist under prefers-reduced-motion — note the media query
       is `no-preference`, matching the ring's own `.reveal` convention, so
       motion is opt-in rather than something to be switched back off.
   ====================================================================== */
@media (prefers-reduced-motion: no-preference) {

  /* The dash lives ENTIRELY inside the keyframes, never as a static property.
     That distinction is the difference between a drawing and a blank plate:
     set statically, `stroke-dashoffset: 1400` hides the stroke completely, and
     anything that declines to run the animation — PRINT, most obviously, where
     CSS animations do not play — would render the tyre as nothing at all. With
     the offset scoped to the keyframes, the element's natural state stays a
     solid stroke, so a plate that is never animated is simply a finished
     drawing. That is the same guarantee the file header makes about JS.
     1400 comfortably exceeds the largest circumference here (the outer band
     circle is ~1257px at this viewBox), so one constant serves every circle
     and the dash never repeats mid-stroke. */
  /* Wrapped in `@media screen` for the same reason the tolerance chart is:
     every rule in here starts its element hidden and depends on the
     animation running to reach the natural state. Print does not run CSS
     animations but DOES apply the `both` backwards fill, so unguarded these
     rules print the plate as an empty frame — the exact failure the file
     header promises cannot happen. */
  @media screen {
    .hero .tf-plate:not(.tf-tol) .tf-draw .subject,
    .hero .tf-plate:not(.tf-tol) .tf-draw .accent {
      animation: tf-draw 1100ms var(--ease-out) both;
    }
    /* The original is drawn before what is proposed for it — the order carries
       the meaning, so the delays are not decoration. */
    .hero .tf-plate:not(.tf-tol) .tf-draw .subject { animation-delay: 240ms; }
    .hero .tf-plate:not(.tf-tol) .tf-draw .accent  { animation-delay: 620ms; }

    /* The rim circles already carry an inline stroke-dasharray to render as
       dashed. Animating dashoffset here would fight that pattern and make them
       crawl, so they fade instead. */
    .hero .tf-plate:not(.tf-tol) .tf-draw .rim { animation: tf-fade 700ms var(--ease-out) 900ms both; }

    .hero .tf-plate:not(.tf-tol) .tf-draw .band { animation: tf-band 900ms var(--ease-out) 120ms both; }
    .hero .tf-plate:not(.tf-tol) .tf-draw .cl   { animation: tf-fade 600ms var(--ease-out) both; }
    .hero .tf-plate:not(.tf-tol) .tf-draw .ext  { animation: tf-fade 600ms var(--ease-out) 380ms both; }
    /* Dimensions and labels arrive last, once there is something to measure. */
    .hero .tf-plate:not(.tf-tol) .tf-draw .dim,
    .hero .tf-plate:not(.tf-tol) .tf-draw text  { animation: tf-fade 700ms var(--ease-out) 1250ms both; }

  }

  @keyframes tf-draw {
    from { stroke-dasharray: 1400; stroke-dashoffset: 1400; }
    to   { stroke-dasharray: 1400; stroke-dashoffset: 0; }
  }
  @keyframes tf-fade { from { opacity: 0; } }
  @keyframes tf-band { from { opacity: 0; } to { opacity: .08; } }

  /* ---- the tolerance chart ---------------------------------------------
     The two rules fade up first, then the SOLID legal edge draws itself, and
     the gate arrives last — which is the order the argument is made in. The
     gate is NEVER transformed: it is positioned by an SVG transform that the
     calculator owns, and a CSS transform on the same element would fight it
     and land the mark away from the value it reports. It fades instead. */
  /* `@media screen` is not decoration here. Every rule below starts its
     element from a hidden state and relies on the animation running to reach
     the natural one. Print does not run CSS animations, but `fill: both` still
     applies the BACKWARDS fill — so without this guard the single most
     important mark on the site (the solid legal edge at 0.00%) would come out
     of a printer blank. Same guarantee the file header makes about JS, one
     medium further out. */
  @media screen {
    .tf-tol .band, .tf-tol .nogo { animation: tf-fade 620ms var(--ease-out) 160ms both; }
    .tf-tol .edge-soft { animation: tf-fade 520ms var(--ease-out) 340ms both; }
    .tf-tol .edge-hard { animation: tf-edge 560ms var(--ease-out) 460ms both; }
    .tf-tol .tf-gate-g { animation: tf-fade 480ms var(--ease-out) 820ms both; }
  }
  @keyframes tf-edge {
    from { stroke-dasharray: 70; stroke-dashoffset: 70; }
    to   { stroke-dasharray: 70; stroke-dashoffset: 0; }
  }

  /* ---- small hover life ------------------------------------------------ */
  .tf-index a { transition: color var(--t-fast) var(--ease-out), padding-left var(--t-fast) var(--ease-out); }
  .tf-index a:hover { padding-left: 6px; }
  .qr a { transition: background var(--t-fast) var(--ease-out); }
  .tf-search .tf-slash { transition: opacity var(--t-fast) var(--ease-out); }
}
