:root {
  /* light (day) is the DEFAULT theme — soft off-white canvas, single blue accent,
     warm-orange rider, blue/green/pink rider triangle. No webfonts, no serif:
     the schematic is the personality, the type stays neutral system sans. */
  --bg: #f5f7fa; --panel: #ffffff; --line: #dde2ea; --fg: #1b212c;
  --muted: #5b6675; --accent: #2f6fd6; --accent-active: #2a63bd;
  --ok: #1f9d52; --warn: #b9770d; --bad: #d23b3b;
  /* chrome surfaces */
  --viz-bg: #e9eef5;        /* schematic canvas — a full step below panel so the diagram reads as "the screen" */
  --input-bg: #ffffff;      /* form fields, cards */
  --input-bg-deep: #f1f4f9; /* nested pickers/selects, ghost buttons */
  --track-off: #dde2ea;     /* switch track, off */
  --knob: #ffffff;          /* switch knob */
  --ground: #97a3b5;        /* schematic ground line */
  --shadow: rgba(20,25,35,.10);
  /* schematic: rider triangle + orange human + muted blue-grey bodywork */
  --rider: #ef7d00;         /* the stick-figure human — the only warm tone */
  --dot-seat: var(--accent);/* seat contact = blue */
  --dot-bar: var(--ok);     /* bar contact = green */
  --dot-peg: #e5318f;       /* peg contact = pink */
  --shoe: #11a99b;          /* feet-down shoe */
  --bike-outline: #66758d;  /* silhouette stroke */
  --bike-frame: #8492a7;    /* frame / detail lines */
  --bike-tyre: #4f5e75;     /* tyres */
}
:root[data-theme="dark"] {
  /* dark (night) — first-class alternate, near-black floor, brighter blue.
     Every token mirrored, including the rider-orange swap for legibility. */
  --bg: #0f1115; --panel: #181b22; --line: #2a2f3a; --fg: #e8ebf0;
  --muted: #9aa3b2; --accent: #4f9dff; --accent-active: #3f8ae8;
  --ok: #36c46b; --warn: #f0a93b; --bad: #ef5a5a;
  --viz-bg: #0c0e12;
  --input-bg: #0e1117;
  --input-bg-deep: #0c0e12;
  --track-off: #2a2f3a;
  --knob: #ffffff;
  --ground: #657084;
  --shadow: rgba(0,0,0,.45);
  --rider: #ff9d24;
  --dot-peg: #ff4fa3;
  --shoe: #36d3c4;
  --bike-outline: #5d6878;
  --bike-frame: #4f5a6a;
  --bike-tyre: #768499;
}
* { box-sizing: border-box; }
/* leave room for the sticky topnav on every in-page scroll (bike-card
   scrollIntoView + #pick / #how-we-measure anchor jumps) so the target
   isn't hidden under the banner. ~54px nav + 1px border + breathing gap. */
html { scroll-padding-top: 64px; }
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font: 16px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", sans-serif;
  transition: background .2s ease, color .2s ease;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* External links (nsw.gov.au etc.) get a ↗ so "leaves this site, new tab" is
   visible before the click; the link's title= says whose site it goes to.
   \FE0E forces the text glyph (no emoji rendering). */
a.ext::after { content: "\2197\FE0E"; font-size: .78em; margin-left: 2px; vertical-align: 1px; }
/* headings ride the native system sans — no webfont, no serif. Weight + size
   carry all hierarchy since there's no typeface contrast to lean on. */
h1, h2, h3 { font-weight: 700; letter-spacing: -.01em; }
.wrap { max-width: 880px; margin: 0 auto; padding: 24px 18px 64px; }
header { margin-top: 22px; }
/* H1 scales with the viewport (≈25px phone → 33px desktop) so the page opens
   with a real headline, not body-sized text. */
header h1 { font-size: clamp(1.55rem, 1.15rem + 1.6vw, 2.05rem); line-height: 1.22; margin: 0 0 8px; }
header p.sub { color: var(--muted); margin: 0 0 20px; }

/* sticky site-wide top nav — Compare / LAMS / browse always reachable */
.topnav {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--panel) 92%, transparent);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.navinner { position: relative; max-width: 880px; margin: 0 auto; padding: 0 18px; min-height: 54px; display: flex; align-items: center; gap: 14px; }
.topnav .brand { display: inline-flex; align-items: center; gap: 8px; font-weight: 800; font-size: 1.05rem; color: var(--fg); letter-spacing: -.01em; }
.topnav .brand .brandmark { flex: none; display: block; }
.topnav .brand .be { color: var(--accent); }
.topnav .brand:hover { color: var(--accent); text-decoration: none; }
.topnav .brand:hover .be { color: currentColor; }
.topnav .navlinks { display: flex; align-items: center; gap: 2px; flex: 1; min-width: 0; }
.topnav .navlinks a { color: var(--muted); font-size: .9rem; padding: 6px 10px; border-radius: 8px; }
.topnav .navlinks a:hover { color: var(--fg); background: var(--input-bg); text-decoration: none; }
.topnav .navlinks a[aria-current="page"] { color: var(--fg); font-weight: 600; background: var(--input-bg); }
.topnav .navright { margin-left: auto; display: flex; align-items: center; }

/* day/night toggle — sits at the right of the nav */
.themetoggle {
  width: 38px; height: 38px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--input-bg); color: var(--fg);
  font-size: 1.05rem; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: border-color .15s, transform .15s;
}
.themetoggle:hover { border-color: var(--accent); transform: translateY(-1px); }
.themetoggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Instant tooltip (content from data-tip): the native title= is a dead end —
   ~2s delay, and Chrome didn't show it at all on the compare pickers
   (2026-07-04 UAT). Used by the theme toggle and the truncated compare
   bike-name buttons. Hover reveal is hover-capable pointers only; on touch
   JS can flash the bubble instead by toggling .tipflash (gated overlay btn). */
[data-tip] { position: relative; }
[data-tip]::after {
  content: attr(data-tip);
  position: absolute; top: calc(100% + 8px); left: 0; z-index: 30;
  background: var(--fg); color: var(--bg);
  font-size: .72rem; font-weight: 500; line-height: 1; white-space: nowrap;
  padding: 6px 9px; border-radius: 6px; box-shadow: 0 2px 8px var(--shadow);
  opacity: 0; pointer-events: none; transition: opacity .12s ease;
}
@media (hover: hover) {
  [data-tip]:hover::after, [data-tip]:focus-visible::after { opacity: 1; }
}
[data-tip].tipflash::after { opacity: 1; }
/* the nav toggle sits at the viewport's right edge — anchor its bubble right */
.themetoggle[data-tip]::after { left: auto; right: 0; }

/* hamburger — desktop keeps the full row, so the toggle + its checkbox are hidden.
   The checkbox lives off-screen (never `display:none`, or `:checked` stops working). */
.navtoggle-cb { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.navburger {
  display: none; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 8px; margin-right: 8px;
  border: 1px solid var(--line); background: var(--input-bg); color: var(--fg);
  cursor: pointer; transition: border-color .15s;
}
.navburger:hover { border-color: var(--accent); }
.navtoggle-cb:focus-visible + .navlinks + .navright .navburger { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 640px) {
  .navinner { gap: 8px; padding: 0 12px; }
  .topnav .brand { font-size: 1rem; }
  .navburger { display: inline-flex; }
  /* links drop into a full-width panel under the bar, revealed by the checkbox */
  .topnav .navlinks {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 2px; flex: none;
    background: var(--panel); border-bottom: 1px solid var(--line);
    padding: 8px 12px 12px; box-shadow: 0 8px 20px var(--shadow);
  }
  .navtoggle-cb:checked ~ .navlinks { display: flex; }
  .topnav .navlinks a { padding: 11px 12px; font-size: 1rem; border-radius: 8px; }
}

.tool {
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 16px;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start;
}
.tool .viz { min-width: 0; }
.tool .info { min-width: 0; }
.pose { width: 100%; height: auto; background: var(--viz-bg); border: 1px solid var(--line); border-radius: 10px; display: block; }
.pose .ground { stroke: var(--ground); stroke-width: 2; }
/* legacy filled bodywork (kept for older bikeGeom paths) — muted blue-grey, theme-aware */
.pose .bike { fill: var(--bike-frame); stroke: var(--bike-outline); stroke-width: 2.5; stroke-linejoin: round; }
.pose .engine { fill: var(--bike-tyre); stroke: var(--bike-outline); stroke-width: 2.5; stroke-linejoin: round; }
.pose .tank { fill: var(--bike-frame); stroke: var(--bike-outline); stroke-width: 3; stroke-linejoin: round; }
.pose .seat { fill: var(--bike-frame); stroke: var(--bike-outline); stroke-width: 2.5; stroke-linejoin: round; }
.pose .cowl { fill: var(--bike-frame); stroke: var(--bike-outline); stroke-width: 2.5; stroke-linejoin: round; }
.pose .saddle { fill: var(--bike-frame); stroke: var(--bike-outline); stroke-width: 2.5; stroke-linejoin: round; }
/* live self-drawn outline schematic — muted blue-greys so the orange rider leads */
.pose .outline { fill: none; stroke: var(--bike-outline); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.pose .frame { stroke: var(--bike-frame); stroke-width: 2.5; stroke-linecap: round; }
.pose .engine { fill: none; stroke: var(--bike-frame); stroke-width: 2; stroke-linejoin: round; }
.pose .tyre { fill: none; stroke: var(--bike-tyre); stroke-width: 3.5; }
.pose .rim { fill: none; stroke: var(--bike-frame); stroke-width: 2; }
.pose .spoke { stroke: var(--bike-frame); stroke-width: 1.5; }
.pose .hub { fill: var(--bike-tyre); }
.pose .board { stroke: var(--bike-outline); stroke-width: 5; stroke-linecap: round; }
.pose .fork { stroke: var(--bike-outline); stroke-width: 3; stroke-linecap: round; }
.pose .swingarm { stroke: var(--bike-outline); stroke-width: 3; stroke-linecap: round; }
.pose .shock { stroke: var(--bike-outline); stroke-width: 2.5; stroke-linecap: round; }
.pose .fender { fill: none; stroke: var(--bike-outline); stroke-width: 2.5; stroke-linecap: round; }
.pose .exhaust { fill: none; stroke: var(--bike-outline); stroke-width: 3; stroke-linecap: round; }
.pose .bar { stroke: var(--bike-outline); stroke-width: 3; stroke-linecap: round; }
.pose .triangle { fill: rgba(239,125,0,.10); stroke: rgba(239,125,0,.55); stroke-width: 1.5; stroke-dasharray: 5 5; }
/* knockout casing: bg-colored under-stroke keeps the rider crisp where limbs cross the triangle / frame / shoe */
.pose .limb-c, .pose .spine-c { stroke: var(--viz-bg); stroke-linecap: round; }
.pose .limb-c { stroke-width: 11; }
.pose .spine-c { stroke-width: 12; }
.pose .limb { stroke: var(--rider); stroke-width: 7; stroke-linecap: round; }
.pose .spine { stroke: var(--rider); stroke-width: 8; stroke-linecap: round; }
.pose .head { fill: none; stroke: var(--rider); stroke-width: 6.5; }
.pose .seat { fill: var(--dot-seat); } .pose .bar { fill: var(--dot-bar); } .pose .peg { fill: var(--dot-peg); }
/* feet-on-ground: shoe + reach gap */
.pose .shoe { fill: var(--shoe); stroke: var(--viz-bg); stroke-width: 1.5; stroke-linejoin: round; }
.pose .gap { stroke: var(--bad); stroke-width: 3; stroke-dasharray: 5 5; }
.pose .gaptext { fill: var(--bad); font-weight: 700; }

/* photo mode: rider overlaid on a real side-view photo */
.pose.photomode { background: var(--viz-bg); }
.pose.photomode .limb-c { stroke-width: 21; }
.pose.photomode .spine-c { stroke-width: 23; }
.pose.photomode .limb { stroke: #ff8a00; stroke-width: 15; }
.pose.photomode .spine { stroke: #ff8a00; stroke-width: 17; }
.pose.photomode .head { stroke: #ff8a00; stroke-width: 11; }
.pose.photomode .triangle { stroke: rgba(255,138,0,.5); }
.pose.photomode .shoe { stroke-width: 3; }
.pose.photomode .gap { stroke-width: 6; stroke-dasharray: 9 9; }
.pose.photomode .ground { stroke: rgba(255,255,255,.4); stroke-dasharray: 7 7; }

/* feet-on-ground: iOS-style switch */
.switch { display: inline-flex; align-items: center; gap: 9px; margin: 0 0 10px; cursor: pointer; user-select: none; font-size: .9rem; color: var(--fg); }
.switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.switch .track { position: relative; flex: none; width: 44px; height: 26px; background: var(--track-off); border-radius: 999px; transition: background .15s; }
.switch .knob { position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; background: var(--knob); border-radius: 50%; transition: transform .15s; box-shadow: 0 1px 3px var(--shadow); }
.switch input:checked + .track { background: var(--accent); }
.switch input:checked + .track .knob { transform: translateX(18px); }
.switch input:focus-visible + .track { outline: 2px solid var(--accent); outline-offset: 2px; }

.legend { display: flex; flex-wrap: wrap; gap: 14px; margin: 10px 2px 0; font-size: .78rem; color: var(--muted); }
.legend .lg { display: inline-flex; align-items: center; gap: 6px; }
.legend .lg::before { content: ""; width: 10px; height: 10px; border-radius: 50%; background: currentColor; }
.legend .seat { color: var(--dot-seat); } .legend .bar { color: var(--dot-bar); } .legend .peg { color: var(--dot-peg); }
.legend .foot { color: var(--shoe); }
.legend .tri { color: var(--rider); } .legend .tri::before { border-radius: 2px; }
/* legend follows the active mode (peg vs ground) */
[data-pose-mode="ground"] .lg.peg, [data-pose-mode="ground"] .lg.tri { display: none; }
[data-pose-mode="peg"] .lg.foot { display: none; }

.controls { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
.controls label { display: flex; flex-direction: column; font-size: .82rem; color: var(--muted); gap: 4px; min-width: 0; }
.controls input, .controls select {
  width: 100%; min-width: 0;
  background: var(--input-bg); color: var(--fg); border: 1px solid var(--line);
  border-radius: 8px; padding: 9px 10px; font-size: 1rem;
}
.controls .full { grid-column: 1 / -1; }

/* Units segmented toggle — same pill/accent language as the feet-down switch. */
/* No visible caption (cm/ft·in is self-explanatory) — the pill bottom-aligns in
   its cell so it sits level with the "Adjust the fit" pill beside it. */
.unitfield { display: flex; flex-direction: column; justify-content: flex-end; font-size: .82rem; color: var(--muted); gap: 4px; min-width: 0; }
.segtoggle { display: inline-flex; align-self: flex-start; background: var(--track-off); border-radius: 999px; padding: 3px; gap: 2px; }
.segtoggle .seg { border: 0; background: none; color: var(--muted); font: inherit; font-size: .84rem; font-weight: 600; line-height: 1; padding: 6px 11px; border-radius: 999px; cursor: pointer; transition: background .15s, color .15s; }
.segtoggle .seg.on { background: var(--accent); color: #fff; box-shadow: 0 1px 3px var(--shadow); }
.segtoggle .seg:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Height field: single cm input vs feet+inches pair, toggled by tool data-units. */
.hfield .h-one { display: block; }
.hfield .h-one input { width: 100%; }
.hfield .h-ftin { display: none; }
[data-units="imp"] .hfield .h-one { display: none; }
[data-units="imp"] .hfield .h-ftin { display: flex; align-items: center; gap: 6px; }
/* ft/in are tiny 1–2 digit fields — drop the number spinner and trim side padding so
   the centered digit isn't clipped (compare trims width to 2.7em, below the spinner
   threshold; the sim's 3.4em survived it but stays consistent here). */
.hfield .h-ftin input { flex: none; width: 3.4em; min-width: 0; text-align: center; padding-left: 4px; padding-right: 4px; }
.hfield .h-ftin input::-webkit-outer-spin-button,
.hfield .h-ftin input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.hfield .h-ftin input { -moz-appearance: textfield; appearance: textfield; }
.hfield .usuf { flex: none; color: var(--muted); font-size: .85rem; }

/* Ground-reach verdict — the emotional payload ("can I touch the ground?") gets
   a full-width status banner, not a tile among tiles. Status colour only. */
.verdict { display: flex; flex-direction: column; gap: 1px; margin-top: 12px; padding: 11px 14px; border: 1px solid; border-radius: 10px; }
.verdict .vk { font-size: .72rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; opacity: .85; }
.verdict .vv { font-size: 1.28rem; font-weight: 700; line-height: 1.25; }
.verdict.ok   { color: var(--ok);   background: color-mix(in srgb, var(--ok) 9%, var(--panel));   border-color: color-mix(in srgb, var(--ok) 38%, var(--line)); }
.verdict.warn { color: var(--warn); background: color-mix(in srgb, var(--warn) 9%, var(--panel)); border-color: color-mix(in srgb, var(--warn) 38%, var(--line)); }
.verdict.bad  { color: var(--bad);  background: color-mix(in srgb, var(--bad) 9%, var(--panel));  border-color: color-mix(in srgb, var(--bad) 38%, var(--line)); }
#ehOut .grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 14px; }
#ehOut .grid > div { background: var(--input-bg); border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; }
#ehOut .k { display: block; color: var(--muted); font-size: .75rem; }
#ehOut .v { font-size: 1.15rem; font-weight: 600; }
.reach { font-weight: 600; } .reach.ok { color: var(--ok); } .reach.warn { color: var(--warn); } .reach.bad { color: var(--bad); }
.conf { display: inline-flex; align-items: center; gap: 6px; font-size: .76rem; font-weight: 600; padding: 3px 9px; border-radius: 999px; border: 1px solid var(--line); cursor: help; }
.conf::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
/* Linked variant (→ methodology page): "what does this mean?" is one click away. */
a.conf { cursor: pointer; }
/* In the share row the badge parks at the right edge, opposite the button. */
.sharerow .conf { margin-left: auto; }
a.conf::after { content: "\2197\FE0E"; font-size: .82em; opacity: .7; }
a.conf:hover { text-decoration: none; border-color: currentColor; }
.conf-high { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, var(--line)); }
.conf-med { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, var(--line)); }
.conf-low { color: var(--muted); }
.note, .hint { color: var(--muted); font-size: .8rem; }
.note { margin: 12px 0 0; }

/* "what-if" fit-mod sliders (single simulator) */
.mods { margin-top: 14px; border: 1px solid var(--line); border-radius: 10px; background: var(--input-bg); }
/* In the controls grid (cell right of Units): compact pill while collapsed
   (subtitle hidden, bottom-aligned to the unit toggle); spans the full row
   when open so the sliders get full width and the results move down. */
.controls .mods { margin-top: 0; min-width: 0; align-self: end; }
.controls .mods > summary { padding: 9px 12px; }
.controls .mods:not([open]) .modsum-tx small { display: none; }
.controls .mods[open] { grid-column: 1 / -1; }
.mods > summary { display: flex; align-items: center; gap: 10px; padding: 11px 12px; cursor: pointer; color: var(--fg); list-style: none; border-radius: 10px; }
.mods > summary::-webkit-details-marker { display: none; }
.mods > summary:hover { color: var(--accent); background: var(--input-bg-deep); }
.slideico { flex: none; }
.slideico path { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
.slideico circle { fill: var(--input-bg); stroke: currentColor; stroke-width: 1.5; }   /* knob sits on the track */
.mods > summary:hover .slideico circle { fill: var(--input-bg-deep); }
.modsum-tx { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.modsum-tx b { font-size: .9rem; font-weight: 600; }
.modsum-tx small { font-size: .74rem; font-weight: 400; color: var(--muted); line-height: 1.3; }
.mods > summary:hover .modsum-tx small { color: var(--muted); }
.modsum-cv { flex: none; color: var(--muted); font-size: 1.2rem; line-height: 1; transition: transform .15s ease; }
.mods[open] .modsum-cv { transform: rotate(90deg); }
.modgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; padding: 2px 12px 10px; }
.modgrid label { display: flex; flex-direction: column; gap: 4px; font-size: .8rem; color: var(--muted); }
.modgrid output { color: var(--fg); font-weight: 600; }
.modgrid input[type=range] { width: 100%; accent-color: var(--accent); margin: 2px 0; }
.modhint { color: var(--muted); font-size: .72rem; }
.na-note { display: none; color: var(--accent); }
/* Footpeg mods do nothing in the feet-down view (foot is on the road) — grey
   them out and explain, without removing the value they hold for the riding view. */
[data-pose-mode="ground"] label[data-ridingonly] { opacity: .45; }
[data-pose-mode="ground"] label[data-ridingonly] input { pointer-events: none; }
[data-pose-mode="ground"] label[data-ridingonly] .modhint:not(.na-note) { display: none; }
[data-pose-mode="ground"] label[data-ridingonly] .na-note { display: block; opacity: 1; }
.modfoot { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; padding: 0 12px 12px; }
.modfoot .note { margin: 0; }
[data-modreset], [data-modclose] { background: var(--input-bg-deep); color: var(--fg); border: 1px solid var(--line); border-radius: 8px; padding: 6px 12px; font-size: .82rem; cursor: pointer; }
[data-modreset]:hover, [data-modclose]:hover { border-color: var(--accent); color: var(--accent); }
/* "Done" collapse sits at the far right of the panel foot — a visible way out
   once you've scrolled past the summary chevron at the top. */
[data-modclose] { margin-left: auto; }

/* "Copy my fit link" — shares the current body size (+ bike & fit-mods) as a URL.
   Same ghost-button language as the mod reset; goes accent when the copy lands. */
.sharerow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 14px; }
.sharehint { color: var(--muted); font-size: .78rem; }
.copylink { display: inline-flex; align-items: center; gap: 7px; background: var(--input-bg-deep); color: var(--fg); border: 1px solid var(--line); border-radius: 8px; padding: 6px 12px; font-size: .82rem; font-weight: 500; cursor: pointer; white-space: nowrap; }
.copylink:hover { border-color: var(--accent); color: var(--accent); }
.copylink.copied { border-color: var(--accent); color: var(--accent); }
.shareico { flex: none; }
.shareico circle, .shareico path { fill: none; stroke: currentColor; stroke-width: 1.6; }
.modtag { font-size: .7rem; font-weight: 500; color: var(--muted); margin-left: 6px; white-space: nowrap; }

.cmplink { white-space: nowrap; font-weight: 600; }

/* Contextual compare link under the ground-reach verdict — a quiet accent text
   link (not a filled button: it must not compete with the verdict banner). */
.cmpnext { display: inline-flex; align-items: center; gap: 6px; margin-top: 9px; font-size: .88rem; font-weight: 600; }
.cmpnext .hl-arr { transition: transform .15s; }
.cmpnext:hover .hl-arr { transform: translateX(2px); }

/* multi-bike compare */
.cmptool { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 16px; }
.cmpctl { display: flex; flex-wrap: wrap; gap: 12px 12px; align-items: flex-end; margin-bottom: 14px; }
/* Height + Inseam + Units + the view/share cluster all sit on one line — and stay
   there when you flip cm<->ft. The imperial ft+in pair is wider than one cm box, so
   the whole bar is trimmed tight (compact Inseam, snug ft/in inputs, small gaps) to
   fit the 880px column in BOTH units; without this the extra imperial width bumped
   the view/share cluster onto a second row only in ft. Height col is PINNED to the
   ft+in width (118px) so Inseam/Units/toggles don't jump left when you flip to cm
   (the cm box is narrower and just sits left-aligned in the fixed column). */
.cmpctl .controls { flex: 0 1 auto; grid-template-columns: 119px minmax(112px, 132px) auto; column-gap: 12px; margin: 0; }
/* One-line optical alignment: every control bottom-aligns via flex-end, but the
   controls are DIFFERENT heights (input 40px, pill 31px, switch track 26px), so
   flush bottoms still read as crooked — the eye tracks vertical CENTERS. Pin the
   input to exactly 40px as the row reference, then lift each shorter control by
   half the height difference so all centers sit on one line:
   pill (40−31.4)/2 ≈ 4px, switch (40−26)/2 = 7px. */
.cmpctl .controls input { height: 40px; }
/* The units pill (no caption) drops to the cell bottom, then the centering
   margin lifts it onto the shared line. */
.cmpctl .controls .unitfield { justify-self: start; }
.cmpctl .controls .segtoggle { margin-bottom: 4px; }
.cmpctl .hfield .h-one input { width: 4.5em; }
/* Imperial ft/in inputs hold only 1–2 digits — keep them snug so the bar fits one line. */
.cmpctl .hfield .h-ftin { gap: 4px; }
.cmpctl .hfield .h-ftin input { width: 2.7em; }
.cmpctl .hfield .usuf { font-size: .8rem; }
.cmpctl .modes { margin: 0; }
/* Small phones: the pinned 119px + 112px + pill row (~365px) overflows the
   viewport and forces the whole page to scroll sideways. Fall back to the base
   two-column grid — Height + Inseam share a row, the Units pill takes its own. */
@media (max-width: 480px) {
  .cmpctl .controls { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .cmpctl .controls .unitfield { grid-column: 1 / -1; }
}
.compare { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; align-items: stretch; }
.compare .col { background: var(--input-bg); border: 1px solid var(--line); border-radius: 12px; padding: 10px; min-width: 0; }
.compare .col.placeholder { border-style: dashed; }
.compare .col.placeholder .colviz { opacity: .32; }
.cmphint { margin: 8px 0 0; font-size: .82rem; color: var(--muted); }
.colhead { display: flex; gap: 6px; margin-bottom: 8px; }
.colhead select { flex: 1; min-width: 0; background: var(--input-bg-deep); color: var(--fg); border: 1px solid var(--line); border-radius: 8px; padding: 7px 8px; font-size: .9rem; }
.colhead .rm { flex: none; width: 34px; background: var(--input-bg-deep); color: var(--muted); border: 1px solid var(--line); border-radius: 8px; font-size: 1.1rem; line-height: 1; cursor: pointer; }
.colhead .rm:hover { color: var(--bad); border-color: var(--bad); }
.colviz .pose { width: 100%; height: auto; }
/* Fixed three-row layout — Seat / Reach / angles — so the rows line up across
   compare columns no matter how long the reach label is (free wrap put Reach on
   row 1 in one card and row 2 in the next). */
.cmpmetrics { display: flex; flex-wrap: wrap; gap: 5px 14px; margin-top: 8px; font-size: .82rem; }
.cmpmetrics .cm:nth-child(-n+2) { flex: 0 0 100%; }
.cmpmetrics .cm { color: var(--fg); }
.cmpmetrics .cm b { color: var(--muted); font-weight: 500; margin-right: 4px; }
.addcol { background: transparent; border: 1.5px dashed var(--line); border-radius: 12px; color: var(--muted); min-height: 140px; cursor: pointer; font-size: .95rem; }
.addcol:hover { border-color: var(--accent); color: var(--accent); }

/* compare view toggle + overlay (flip between bikes on a shared frame) */
/* These carry no top label; flex-end drops them to the row bottom, then the same
   center-line margins as the units pill (see .cmpctl .controls input above) lift
   them so their vertical centers match the 40px inputs. */
.cmpctlright { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 12px; }
.cmpctlright .viewtoggle { margin-bottom: 4px; }
/* The sim's feet-down .switch carries a 10px bottom margin for its stacked layout;
   here 7px centers its 26px track on the input row. */
.cmpctlright .switch { margin: 0 0 7px; }
/* Shares the segtoggle pill shell (same radius/padding/track) so units + view read
   as one control family; only the active fill differs — units .on is accent blue
   (the selected VALUE), view .on is a neutral raised chip so blue stays scarce. */
.viewtoggle { display: inline-flex; background: var(--track-off); border-radius: 999px; padding: 3px; gap: 2px; }
.vt { border: 0; background: none; color: var(--muted); font: inherit; font-size: .84rem; font-weight: 600; line-height: 1; padding: 6px 11px; border-radius: 999px; cursor: pointer; white-space: nowrap; transition: background .15s, color .15s; }
.vt.on { background: var(--input-bg); color: var(--fg); box-shadow: 0 1px 3px var(--shadow); }
.vt:hover:not(.on):not(:disabled):not([aria-disabled="true"]) { color: var(--fg); }
.vt:disabled, .vt[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
/* gated overlay btn sits at the toggle's right end — anchor its bubble right
   so the long hint doesn't run past the viewport on narrow screens */
.vt[data-tip]::after { left: auto; right: 0; }
[data-view="overlay"] .compare { display: block; }
/* Overlay = image on the left (~half width), all the readout (metrics + bike tabs
   + hint) stacked in a right-hand column. Stacks vertically on narrow screens. */
.overlay { min-width: 0; display: grid; grid-template-columns: minmax(0, 50%) 1fr; gap: 18px; align-items: start; }
.ovinfo { min-width: 0; }
.ovviz { background: var(--viz-bg); border-radius: 10px; touch-action: pan-y; }
.ovviz .pose { width: 100%; height: auto; }
@media (max-width: 560px) { .overlay { grid-template-columns: 1fr; gap: 12px; } }
@keyframes ovfade { from { opacity: .25; } to { opacity: 1; } }
.ovviz.flip .pose { animation: ovfade .2s ease; }
.ovtabs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
/* One tab per row, full width — bikes stack as equal-height rows (up to 3 + Add)
   instead of a lopsided 2-small+1-wide wrap; long model names ellipsize. */
.ovtab { position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 1px; flex: 1 1 100%; min-width: 0; background: var(--input-bg); border: 1px solid var(--line); border-radius: 10px; padding: 8px 30px 8px 12px; cursor: pointer; color: var(--muted); text-align: left; }
.ovtab .m { font-weight: 600; font-size: .85rem; color: var(--fg); max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ovtab .s { font-size: .72rem; }
.ovtab.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.ovtab:hover { border-color: var(--accent); }
.ovrm { position: absolute; top: 5px; right: 7px; color: var(--muted); font-size: 1rem; line-height: 1; padding: 2px; }
.ovrm:hover { color: var(--bad); }
.ovadd { background: transparent; border: 1.5px dashed var(--line); border-radius: 10px; color: var(--muted); padding: 8px 14px; cursor: pointer; font-size: .85rem; align-self: stretch; flex: 1 1 auto; }
.ovadd:hover { border-color: var(--accent); color: var(--accent); }
.ovhint { margin-top: 10px; }

@media (prefers-reduced-motion: reduce) { .ovviz.flip .pose { animation: none; } }

/* Grid, not flex: the chips/count row spans only the search-input column, so
   the right-aligned count lines up with the input's right edge (the "LAMS only"
   label sits in its own column beyond it). */
.bikefilter { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px; margin: 14px 0 0; }
.bikefilter input[type=search] { min-width: 0; background: var(--input-bg); color: var(--fg); border: 1px solid var(--line); border-radius: 8px; padding: 9px 11px; font-size: .9rem; }
.bikefilter .lamsonly { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: .85rem; cursor: pointer; user-select: none; white-space: nowrap; }
.bikefilter .lamsonly input { accent-color: var(--accent); }
/* Chips row: chips left, bike-count caption pushed to the right edge (under the
   end of the search bar) so the count doesn't take its own line. */
.bikefilter .egrow { grid-column: 1; display: flex; flex-wrap: wrap; align-items: center; gap: 7px 12px; }
.bikefilter .egchips { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }
.bikefilter .gridcap { margin: 0 0 0 auto; text-align: right; }
.egchips .eglabel { color: var(--muted); font-size: .82rem; }
.egchip { background: var(--input-bg); color: var(--fg); border: 1px solid var(--line); border-radius: 999px; padding: 4px 12px; font-size: .82rem; cursor: pointer; }
.egchip:hover { border-color: var(--accent); color: var(--accent); }
.browse { margin: 28px 0 6px; padding: 16px 18px; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; }
.browse h2 { margin: 0 0 8px; }
.browse p { margin: 8px 0; color: var(--muted); font-size: .9rem; line-height: 1.7; }
.browse b { color: var(--fg); }
.browse a { color: var(--accent); }
.browseall { margin-top: 28px; }
.browseall > summary { font-size: 1.1rem; font-weight: 700; cursor: pointer; padding: 6px 0; color: var(--fg); list-style: none; }
.browseall > summary::-webkit-details-marker { display: none; }
.browseall > summary::before { content: '▸'; color: var(--muted); margin-right: 8px; }
.browseall[open] > summary::before { content: '▾'; }
.browseall > summary:hover { color: var(--accent); }
.bikegrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; margin-top: 14px; }
.bikegrid a { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; color: var(--fg); }
.bikegrid a:hover { border-color: var(--accent); text-decoration: none; }
.bikegrid .m { font-weight: 600; } .bikegrid .s { color: var(--muted); font-size: .8rem; }
.bikegrid[data-selectgrid] a { cursor: pointer; }
.bikegrid a.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }

/* hub-page sort + filter bar (LAMS / brand / type / low-seat — build.js hubControls) */
.hubctl { margin: 16px 0 4px; display: flex; flex-direction: column; gap: 10px; }
.hubctl-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.hubctl label { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: .85rem; }
.hubctl select { font: inherit; font-size: .9rem; color: var(--fg); background: var(--input-bg); border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; cursor: pointer; }
.hubctl select:hover { border-color: var(--accent); }
.hubcount { margin: 0; margin-left: auto; color: var(--muted); font-size: .82rem; white-space: nowrap; }
.segchips { display: flex; flex-wrap: wrap; gap: 6px; }
.segchip { font: inherit; font-size: .82rem; color: var(--muted); background: var(--input-bg); border: 1px solid var(--line); border-radius: 999px; padding: 5px 12px; cursor: pointer; transition: border-color .12s, color .12s; }
.segchip:hover { border-color: var(--accent); color: var(--fg); }
.segchip[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Homepage nudge under the bike search: the guided path for people who don't
   yet know what bike names to type. */
.newrider { margin: 8px 0 0; font-size: .9rem; color: var(--muted); }

/* First-bike finder (first-lams-bike.html): size + use-case panel above the
   LAMS grid. Reuses .controls / .segchips / .hubcount; [data-units] sits on
   the box itself (no [data-tool] on this page) so the height field's cm vs
   ft·in swap keys off it the same way as in the simulator. */
.finderbox { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; margin-top: 16px; display: flex; flex-direction: column; gap: 12px; }
.finderbox .controls { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; align-items: end; }
.finderbox .hubcount { margin-left: 0; white-space: normal; }
[data-usechips] .uselabel { color: var(--muted); font-size: .82rem; align-self: center; margin-right: 2px; }
/* Fit tag app.js appends to each card once a body size is known (colour and
   weight come from .reach.ok/.warn/.bad). */
.bikegrid .fittag { display: block; font-size: .8rem; margin-top: 2px; }
@media (max-width: 640px) {
  .finderbox .controls { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .finderbox .controls .unitfield { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
  .hubcount { margin-left: 0; width: 100%; }
}
.simwrap { margin-top: 22px; }
.selbike { display: flex; align-items: baseline; gap: 8px; margin: 0 0 12px; padding-bottom: 12px; border-bottom: 1px solid var(--line); }
.selbike .k { color: var(--muted); font-size: .75rem; }
.selbike b { font-size: 1.05rem; }
/* newest-models freshness strip (homepage) */
.newest { margin: 28px 0 6px; }
.newest h2 { margin: 0; }
.newest .hint { margin: 6px 0 0; }
/* 150px min keeps phones at 2-up so the card (and its thumb crop) stays compact */
.newgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-top: 12px; }
.newgrid a { display: flex; flex-direction: column; gap: 3px; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 11px 13px; color: var(--fg); }
.newgrid a:hover { border-color: var(--accent); text-decoration: none; }
.newgrid .m { font-weight: 600; font-size: .92rem; }
.newgrid .s { color: var(--muted); font-size: .8rem; }
/* mini bike-only schematic on the similar-bikes cards — same engine render,
   no rider, so the cards carry the brand's diagram language, not just text.
   The render frame includes the (absent) rider's headroom, so the box crops
   from the top: bottom-aligned, fixed height, overflow hidden. */
.newgrid .thumb { display: flex; align-items: flex-end; height: 92px; overflow: hidden; margin: -3px 0 6px; border-radius: 8px; background: var(--viz-bg); border: 1px solid var(--line); }
.newgrid .thumb .pose { border: 0; border-radius: 0; background: none; }
/* compare: per-column bike picker button + shared search modal */
.cmpPick { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 6px; background: var(--input-bg-deep); color: var(--fg); border: 1px solid var(--line); border-radius: 8px; padding: 7px 10px; font-size: .9rem; cursor: pointer; text-align: left; }
.cmpPick:hover { border-color: var(--accent); }
/* keep the header one line tall so a long model name can't grow the column */
.cmpPick .nm { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmpPick .caret { flex: none; color: var(--muted); }
.cmppicker { position: fixed; inset: 0; z-index: 50; background: rgba(0, 0, 0, .55); display: flex; align-items: flex-start; justify-content: center; padding: 8vh 16px; }
.cmppicker[hidden] { display: none; }
.pkpanel { width: min(640px, 100%); max-height: 84vh; overflow: auto; background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 16px; }
.pkpanel .pkClose { background: none; border: none; color: var(--muted); font-size: 1.3rem; line-height: 1; cursor: pointer; padding: 0 4px; }
.pkGrid { margin-top: 12px; }

/* methodology — folded by default (a trust reference, not first-visit reading);
   the content stays in the DOM for crawlers either way */
.method { margin-top: 28px; }
.method > details { border: 1px solid var(--line); border-radius: 12px; background: var(--panel); padding: 0 16px; }
.method summary { display: flex; align-items: center; gap: 10px; padding: 13px 0; cursor: pointer; list-style: none; }
.method summary::-webkit-details-marker { display: none; }
.method summary h2 { margin: 0; font-size: 1.05rem; flex: 1 1 auto; }
.method summary .mcv { flex: none; color: var(--muted); font-size: 1.2rem; line-height: 1; transition: transform .15s ease; }
.method > details[open] summary .mcv { transform: rotate(90deg); }
.method summary:hover h2 { color: var(--accent); }
.method ul { margin: 2px 0 12px; padding-left: 20px; }
.method li { margin: 8px 0; }
.method .note { margin: 0 0 14px; }
/* "Read the full method →" under the folded methodology summary. */
.method-more { margin: 0 0 14px; }
.method-more a { color: var(--accent); font-size: .9rem; }
/* "How to measure →" helper link: its own full-width row after the size
   fields (above Units), pulled up toward the fields it explains. */
.fieldhint { display: inline-block; color: var(--accent); font-size: .78rem; }
.controls .fieldhint { margin-top: -4px; justify-self: start; }

footer { margin-top: 40px; padding-top: 16px; border-top: 1px solid var(--line); color: var(--muted); font-size: .8rem; text-align: center; }
footer p { margin: 3px 0; }
footer a { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
footer a:hover { color: var(--fg); }
.faq h3 { margin: 24px 0 6px; font-size: 1rem; }
.faq p { margin: 0 0 10px; color: var(--muted); }
.prose { margin: 18px 0; color: var(--fg); line-height: 1.6; max-width: 70ch; }
/* Editorial deep-dive lists (P3, build.js contentSection) share the prose
   measure; bullets just need breathing room between items. */
ul.prose { padding-left: 22px; }
ul.prose li { margin: 6px 0; }
/* Section headings inside a prose page (privacy / methodology / how-to-measure)
   get clear rhythm without needing per-page classes. */
.prose h2 { margin: 28px 0 8px; font-size: 1.1rem; }
.prose ul { padding-left: 22px; }
.prose li { margin: 6px 0; }
/* Explainer diagrams (methodology 5-point, inseam how-to): self-drawn schematic
   SVGs, centered, scale down on narrow screens. Caption reuses .note colour. */
.diagram { margin: 22px auto; max-width: 480px; }
.diagram svg { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); }
.diagram figcaption { text-align: center; margin: 8px 0 0; }
.faq { margin-top: 26px; }
.faq details { border: 1px solid var(--line); border-radius: 8px; padding: 8px 12px; margin: 8px 0; }
.faq summary { cursor: pointer; font-weight: 600; }
.faq details p { margin: 8px 0 2px; }
/* Contact page: hero email card. The address is big selectable TEXT with a
   single Copy button — no mailto anywhere (a dead mailto looks broken
   without a mail app, 2026-07-04 UAT). Topic hints sit under it as small
   cards, not dead-looking list rows. */
.contactcard { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 18px; margin: 16px 0 8px; }
.contactkicker { margin: 0; font-size: .76rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.contactmail { margin: 6px 0 14px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: clamp(1.15rem, .9rem + 1.8vw, 1.55rem); font-weight: 600; overflow-wrap: anywhere; user-select: all; -webkit-user-select: all; }
.contactacts { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.contactacts .copymain { display: inline-flex; align-items: center; gap: 7px; background: var(--accent); color: #fff; border: 0; border-radius: 8px; padding: 11px 14px; font-size: .9rem; font-weight: 700; cursor: pointer; }
.contactacts .copymain:hover { background: var(--accent-active); }
.contact h2 { margin: 26px 0 10px; font-size: 1.1rem; }
.contactopts { list-style: none; padding: 0; margin: 0 0 22px; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; }
.contactopts li { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; }
.contactopts b { font-size: .95rem; }
.contactopts span { display: block; color: var(--muted); font-size: .85rem; margin-top: 4px; line-height: 1.5; }

.cmplinks { margin-top: 22px; }
.cmplinks ul { list-style: none; padding: 0; margin: 8px 0; }
.cmplinks li { padding: 6px 0; border-bottom: 1px solid var(--line); }
.cmplinks a { color: var(--accent); text-decoration: none; }
.cmplinks a:hover { text-decoration: underline; }

@media (max-width: 640px) {
  .tool { grid-template-columns: 1fr; gap: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  body, .themetoggle, .switch .track, .switch .knob { transition: none; }
}
