
@font-face{font-family:Oswald;src:url(fonts/oswald-400.woff2)format("woff2");font-weight:400;font-display:swap}
@font-face{font-family:Oswald;src:url(fonts/oswald-500.woff2)format("woff2");font-weight:500;font-display:swap}
@font-face{font-family:Oswald;src:url(fonts/oswald-600.woff2)format("woff2");font-weight:600;font-display:swap}
@font-face{font-family:Assistant;src:url(fonts/assistant-400.woff2)format("woff2");font-weight:400;font-display:swap}
@font-face{font-family:Assistant;src:url(fonts/assistant-600.woff2)format("woff2");font-weight:600;font-display:swap}
@font-face{font-family:Assistant;src:url(fonts/assistant-700.woff2)format("woff2");font-weight:700;font-display:swap}
/* METRIC-MATCHED FALLBACKS. The shell nav reflowed 62px -> 41px when Oswald and Assistant swapped in
   over Arial (a 21px shift on every element below it, CLS 0.19-0.40 on 870 diagram pages). Measured
   2026-09-06 on the real faces: Oswald is 79.8% of Arial's width, Assistant 84.5%. The fallback
   faces below are Arial scaled to those widths, with Oswald's and Assistant's own ascent/descent
   so the line box is the same height before and after the swap. */
@font-face{font-family:"Oswald Fallback";src:local("Arial"),local("Helvetica Neue"),local("Roboto");
  size-adjust:80%;ascent-override:149%;descent-override:36%;line-gap-override:0%}
@font-face{font-family:"Assistant Fallback";src:local("Arial"),local("Helvetica Neue"),local("Roboto");
  size-adjust:84.5%;ascent-override:124%;descent-override:31%;line-gap-override:0%}

:root{
  --ink:#121212; --page:#ffffff; --muted:#f3f3f3; --dark:#242833; --accent:#334fb4;
  --accent-soft:rgba(51,79,180,.09); --accent-line:rgba(51,79,180,.35);
  --edge:#e2e2e0; --edge-soft:#eeeeec;
  --text:#121212; --text-dim:#5f6166; --text-faint:#8b8d93;
  --sheet:#ffffff; --sheet-edge:#dcdcda;
  /* Two greens, on purpose. --stock is the deeper one and is the ONLY chip that may imply the
     part is physically in the building; --order is a lighter green for "Triumph supplies it".
     Luke asked for Available to read green rather than grey — it is not a lesser outcome — but
     collapsing them to one colour would erase the distinction the wording carries. */
  --stock:#1f7a4d; --stock-bg:rgba(31,122,77,.10);
  --order:#2f9e68; --order-bg:rgba(47,158,104,.10);
  --warn:#8a5d00;
  /* An ERROR, not a caution. --warn is amber and belongs to "Low stock at Triumph" -- a fact
     about supply the customer can still act on. A VIN we cannot read is a failed input and
     reads red, which is why this is a separate token rather than a reuse of --warn. */
  --err:#b3261e;
  --dead:#9a9ca2; --dead-bg:rgba(154,156,162,.12);
  --hover:rgba(18,18,18,.04);
  --shadow:0 1px 2px rgba(18,18,18,.05),0 10px 28px rgba(18,18,18,.07);
  --hero:#f7f7f6;
  /* One height for every control in the header bar. The search field and the cart used to size
     themselves from their own padding and landed ~9px apart, which is the kind of misalignment
     you feel before you can name it. Not a colour, so the dark blocks below do not restate it. */
  --ctl-h:44px;
}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
  --ink:#f4f4f2; --page:#121212; --muted:#1a1a1c; --dark:#242833; --accent:#7d95e8;
  --accent-soft:rgba(125,149,232,.13); --accent-line:rgba(125,149,232,.4);
  --edge:#2e2f33; --edge-soft:#242528;
  --text:#f4f4f2; --text-dim:#a1a4ab; --text-faint:#74777e;
  --sheet-edge:#3a3b40;
  --stock:#5bc08b; --stock-bg:rgba(91,192,139,.14);
  --order:#7fd3a6; --order-bg:rgba(127,211,166,.13);
  --warn:#d6a83f;
  --err:#f2857c;
  --dead:#7a7d84; --dead-bg:rgba(122,125,132,.15);
  --hover:rgba(255,255,255,.05);
  --shadow:0 1px 2px rgba(0,0,0,.4),0 12px 32px rgba(0,0,0,.4);
  --hero:#17171a;
}}
:root[data-theme="dark"]{
  --ink:#f4f4f2; --page:#121212; --muted:#1a1a1c; --dark:#242833; --accent:#7d95e8;
  --accent-soft:rgba(125,149,232,.13); --accent-line:rgba(125,149,232,.4);
  --edge:#2e2f33; --edge-soft:#242528;
  --text:#f4f4f2; --text-dim:#a1a4ab; --text-faint:#74777e;
  --sheet-edge:#3a3b40;
  --stock:#5bc08b; --stock-bg:rgba(91,192,139,.14);
  --order:#7fd3a6; --order-bg:rgba(127,211,166,.13);
  --warn:#d6a83f;
  --err:#f2857c;
  --dead:#7a7d84; --dead-bg:rgba(122,125,132,.15);
  --hover:rgba(255,255,255,.05);
  --shadow:0 1px 2px rgba(0,0,0,.4),0 12px 32px rgba(0,0,0,.4);
  --hero:#17171a;
}

*{box-sizing:border-box}
body{margin:0;background:var(--page);color:var(--text);
  font:16px/1.55 Assistant,ui-sans-serif,system-ui,-apple-system,sans-serif;
  -webkit-font-smoothing:antialiased}
h1,h2,h3,.osw{font-family:Oswald,"Oswald Fallback",ui-sans-serif,system-ui,sans-serif;font-weight:500;
  letter-spacing:.01em;text-wrap:balance}
.mono{font-family:ui-monospace,"SF Mono",Menlo,Consolas,monospace;font-variant-numeric:tabular-nums}
.eyebrow{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:12px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--text-faint)}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}
[hidden]{display:none!important}
img{max-width:100%}

/* ── header ─────────────────────────────────────────────────────────────────
 * Matches the Shopify theme's own header: logo hard left, cart hard right, search filling
 * the middle. Consistency with the store matters more than cleverness — moving between gear
 * and parts should not feel like changing sites.
 */
.hdr{position:sticky;top:0;z-index:20;background:var(--page);border-bottom:1px solid var(--edge)}
.hdr-in{max-width:1240px;margin:0 auto;padding:16px 24px;display:flex;align-items:center;gap:20px}
.logo{display:flex;align-items:center;text-decoration:none;padding:0;border:0;background:none;flex:0 0 auto}
.logo img{height:40px;width:auto;display:block}
.lbl{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:13px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--text-faint);white-space:nowrap;border:0;background:none;
  cursor:pointer;padding:0 0 0 20px;position:relative;flex:0 0 auto;text-decoration:none}
.lbl::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:1px;height:24px;background:var(--edge)}
.lbl:hover{color:var(--text)}
.search-wrap{position:relative;display:flex;align-items:center;flex:1 1 auto;max-width:460px;margin-left:auto}
.search-ico{position:absolute;left:14px;color:var(--text-faint);font-size:18px;pointer-events:none;line-height:1}
#find{font:15px/1 Assistant,"Assistant Fallback",sans-serif;height:var(--ctl-h);padding:0 14px 0 38px;width:100%;border-radius:3px;
  border:1px solid var(--edge);background:var(--muted);color:var(--text)}
#find:focus{border-color:var(--accent);background:var(--page);outline:none;box-shadow:0 0 0 3px var(--accent-soft)}
#find::placeholder{color:var(--text-faint)}
@media (max-width:720px){
  /* The label goes; the SEARCH STAYS. Hiding it was backwards — the phone is exactly where
     someone types a part number, standing over the bike with the broken one in their hand. */
  .lbl{display:none}
  .hdr-in{flex-wrap:wrap;gap:12px;padding:12px 16px;--ctl-h:40px}
  .search-wrap{order:3;flex:1 1 100%;max-width:none;margin:0}
  .cart{margin-left:auto}
}

/* ── the bike band ──────────────────────────────────────────────────────────
 * Which machine you are shopping for, stated properly instead of as a footnote. The VIN is
 * a field you type straight into — it used to be a button that opened a browser prompt,
 * which is friction on the one input that resolves every otherwise-ambiguous part.
 */
.bikebar{background:var(--muted);border-bottom:1px solid var(--edge)}
.bikebar-in{max-width:1240px;margin:0 auto;padding:20px 24px;display:flex;align-items:center;gap:22px;flex-wrap:wrap}
.bb-bike{display:flex;align-items:baseline;gap:12px}
.bb-name{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:28px;line-height:1}
.bb-year{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:28px;line-height:1;
  color:var(--text-faint);font-variant-numeric:tabular-nums}
.bb-change{border:0;background:none;color:var(--accent);cursor:pointer;
  font:600 14px/1 Assistant,"Assistant Fallback",sans-serif;text-decoration:underline;padding:0}
.bb-vin{margin-left:auto;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.bb-vin label{font-size:14px;color:var(--text-dim);white-space:nowrap}
.bb-vin input{font:15px/1 ui-monospace,Menlo,monospace;padding:11px 13px;width:170px;
  border:1px solid var(--edge);border-radius:3px;background:var(--page);color:var(--text);text-transform:uppercase}
.bb-vin input:focus{border-color:var(--accent);outline:none;box-shadow:0 0 0 3px var(--accent-soft)}
.btn-sm{font:600 14px/1 Assistant,"Assistant Fallback",sans-serif;padding:11px 18px;border-radius:3px;
  border:1px solid var(--ink);background:var(--ink);color:var(--page);cursor:pointer}
.btn-sm:hover{opacity:.88}
.bb-set{display:inline-flex;align-items:center;gap:10px;font-size:14px;color:var(--text-dim)}
.bb-set .mono{color:var(--text)}
/* WIDTH 100% MAKES THIS ITS OWN FLEX LINE, and that is deliberate -- the message can run to a
   full sentence and must not squeeze the VIN input. But a full-width line starts at the LEFT
   edge of the bar, which put a validation error under the bike name, a third of a screen away
   from the field that produced it. text-align:right lands it under the input and Save button,
   which .bb-vin has already pushed flush right with margin-left:auto. */
.bb-msg{font-size:13.5px;width:100%;text-align:right}
.bb-msg.ok{color:var(--stock)} .bb-msg.no{color:var(--err);font-weight:600}
/* Base FIRST, override in the media query second. Written the other way round, the base
   display:none sat after the query at equal specificity and won everywhere — which left a
   phone with the VIN band collapsed and no control to open it. Order is the whole rule. */
.bb-vintoggle{display:none;align-items:center;gap:6px;background:none;border:0;padding:0;
  cursor:pointer;font:inherit;font-size:13.5px;color:var(--accent);
  text-decoration:underline;text-underline-offset:2px}
@media (max-width:720px){
  .bb-vin{margin-left:0;width:100%}
  /* The field is no longer flush right here, so neither is its message. */
  .bb-msg{text-align:left}
  /* Collapsed by default on a phone. It was consuming a fifth of the viewport on every
     screen for an optional field; it opens from the summary line when actually wanted. */
  .bikebar-in{padding:12px 16px;gap:10px}
  .bikebar.collapsed .bb-vin{display:none}
  .bb-vintoggle{display:inline-flex}
}

/* Fitment verdict, per part. "Unknown" is shown as unknown — never dressed up as a fit. */
.fit{margin-top:5px;font-size:12px;font-weight:600}
.fit.yes{color:var(--stock)}
.fit.no{color:var(--warn)}
.fit.unk{color:var(--text-dim);font-weight:400}
.fit-link{border:0;background:none;color:var(--accent);cursor:pointer;font:inherit;
  text-decoration:underline;padding:0}
.row.nofit{opacity:.55}

/* Product photo sits under the callout badge, so the row keeps its shape whether a part
   has photography or not. Accessories have it; a needle bearing never will. */
.pshot{display:block;width:100%;margin-top:7px;border:1px solid var(--edge);border-radius:2px;
  background:var(--page);aspect-ratio:1;object-fit:contain}
.row.haspic{grid-template-columns:56px 1fr auto}

/* Recommendations — collapsed by default so they never crowd the part itself. */
.rel{margin-top:7px;font-size:12.5px}
.rel summary{cursor:pointer;color:var(--accent);font-weight:600;list-style:none}
.rel summary::-webkit-details-marker{display:none}
.rel summary::before{content:"+ ";font-weight:700}
.rel[open] summary::before{content:"\2212 "}
.rel-i{display:flex;align-items:center;gap:8px;padding:6px 0 6px 12px;
  border-left:2px solid var(--edge);margin-top:5px}
.rel-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rel-n{color:var(--text-faint);font-size:11px}
.rel-p{font-variant-numeric:tabular-nums;font-size:12px}
.rel-add{border:1px solid var(--edge);background:var(--page);color:var(--text);
  border-radius:2px;padding:4px 9px;cursor:pointer;font:600 11.5px/1 Assistant,"Assistant Fallback",sans-serif}
.rel-add:hover{border-color:var(--accent);background:var(--accent-soft)}

.hdr-search{margin-left:auto;position:relative}
/* Running total lives in the header at every level of the site — a parts order is built
   up over several diagrams, so the customer must always see what they have so far.
 *
 * NOT a black pill (owner, 2026-08-17). A solid ink block was the heaviest thing in an
 * otherwise quiet white header and read as pasted on rather than part of it. The cart now
 * wears the SAME shell as the search field in both states — same height, radius, border and
 * fill tokens — so the header is one row of matching controls. It earns its weight from the
 * COUNT BADGE, which goes solid ink the moment there is something in it, not from the button.
 *
 * Still two states, because an empty cart has nothing to report: empty shows the word Cart
 * and hides the 0 badge and $0.00, which is noise dressed as information.
 *
 * Height comes from --ctl-h, shared with #find, so the two align exactly. */
.cart{display:inline-flex;align-items:center;gap:10px;height:var(--ctl-h);
  border:1px solid var(--edge);cursor:pointer;text-decoration:none;
  color:var(--text);background:var(--muted);border-radius:3px;padding:0 14px;
  font:600 14px/1 Assistant,"Assistant Fallback",sans-serif;white-space:nowrap;
  transition:background .15s,border-color .15s,color .15s}
.cart:hover{border-color:var(--accent);background:var(--accent-soft)}
/* Named cart-empty, NOT empty: .empty is the empty-STATE block class further down this
   sheet, and on equal specificity its later source order won — an empty header cart picked up
   padding:26px 0 and max-width:64ch and ballooned into a slab. It reproduced only on the live
   store, since the class is applied from a /cart.js response that 404s anywhere else. */
.cart-empty{color:var(--text-dim)}
.cart-empty .cart-n,.cart-empty .cart-t{display:none}
.cart:not(.cart-empty) .cart-lbl{display:none}
/* An inline SVG rather than the 🛒 emoji: it inherits currentColor across both states and
   renders identically everywhere, which a colour emoji does not. */
.cart-ico{width:17px;height:17px;flex:0 0 auto;display:block}
.cart-lbl{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:13px;letter-spacing:.1em;
  text-transform:uppercase}
/* The badge is where the cart gets its weight now that the button itself is quiet. */
.cart-n{background:var(--ink);color:var(--page);border-radius:999px;min-width:21px;
  padding:3px 7px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px;font-weight:700}
.cart-t{font-variant-numeric:tabular-nums;font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;
  font-size:15px;color:var(--text)}

.drawer-scrim{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:40}
.drawer{position:fixed;top:0;right:0;bottom:0;width:min(420px,100vw);z-index:41;
  background:var(--page);border-left:1px solid var(--edge);display:flex;flex-direction:column;
  box-shadow:-8px 0 40px rgba(0,0,0,.18)}
.drawer-hd{display:flex;align-items:center;padding:16px 20px;border-bottom:1px solid var(--edge)}
.drawer-hd h2{margin:0;font-size:20px}
.drawer-x{margin-left:auto;background:none;border:0;font-size:26px;line-height:1;cursor:pointer;
  color:var(--text-dim);padding:0 4px}
.drawer-x:hover{color:var(--text)}
.drawer-body{flex:1;overflow-y:auto}
.drawer-ft{border-top:1px solid var(--edge);padding:16px 20px;background:var(--muted)}
.cl{display:grid;grid-template-columns:1fr auto;gap:10px;padding:14px 20px;
  border-bottom:1px solid var(--edge-soft)}
.cl-t{font-size:14.5px;line-height:1.3}
.cl-n{font-family:ui-monospace,Menlo,monospace;font-size:11.5px;color:var(--text-faint);margin-top:2px}
.cl-q{display:flex;align-items:center;gap:8px;margin-top:7px}
.cl-q button{width:26px;height:26px;border:1px solid var(--edge);background:var(--page);
  color:var(--text);border-radius:2px;cursor:pointer;font-size:14px;line-height:1}
.cl-q button:hover{border-color:var(--accent)}
.cl-q span{font-variant-numeric:tabular-nums;min-width:18px;text-align:center;font-size:14px}
.cl-rm{background:none;border:0;color:var(--text-faint);font-size:12px;cursor:pointer;
  text-decoration:underline;padding:0;margin-left:4px}
.cl-rm:hover{color:var(--warn)}
.cl-p{text-align:right;font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:15px;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.sub{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:4px}
.sub .lbl2{font-size:14px;color:var(--text-dim)}
.sub .amt{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:22px;
  font-variant-numeric:tabular-nums}
.ship-note{font-size:12.5px;color:var(--text-dim);margin:6px 0 14px;line-height:1.5}
.ship-note b{color:var(--stock)}
.co{display:block;width:100%;text-align:center;text-decoration:none;background:var(--ink);
  color:var(--page);border:0;border-radius:2px;padding:14px;cursor:pointer;
  font:600 15px/1 Assistant,"Assistant Fallback",sans-serif}
.co:hover{opacity:.88}
.drawer-empty{padding:40px 20px;text-align:center;color:var(--text-dim)}

/* ── two doors ──────────────────────────────────────────────────────────────
 * Two boxes, side by side, that look like buttons because they are. Equal weight, equal
 * size, and the WHOLE box is the target — no hunting for the clickable part.
 */
.doors{display:grid;gap:20px;grid-template-columns:1fr 1fr;margin-top:8px}
@media (max-width:760px){.doors{grid-template-columns:1fr}}
.door{display:flex;flex-direction:column;border:2px solid var(--edge);border-radius:4px;
  padding:34px 30px 28px;cursor:pointer;background:var(--page);text-align:left;font:inherit;
  color:var(--text);min-height:210px;
  transition:border-color .14s,box-shadow .14s,transform .14s,background .14s}
.door:hover,.door:focus-visible{border-color:var(--accent);background:var(--accent-soft);
  box-shadow:var(--shadow);transform:translateY(-3px);outline:none}
.door h2{margin:0 0 12px;font-size:30px;line-height:1.15}
.door p{margin:0 0 22px;color:var(--text-dim);font-size:15.5px;line-height:1.5}
.door-cta{margin-top:auto;display:inline-block;color:var(--accent);font-weight:700;font-size:16px}
.door:hover .door-cta{text-decoration:underline}

/* ── category filters ───────────────────────────────────────────────────────
 * Words only, no thumbnails. These are a filter, not a destination — a picture on each
 * would compete with the product grid right below and slow the scan down.
 * Styled as the site's standard control so they read as siblings of every other button.
 */
.cats{display:flex;flex-wrap:wrap;gap:9px;margin:0 0 26px;padding-bottom:22px;
  border-bottom:1px solid var(--edge)}
.cat{font:600 14px/1 Assistant,"Assistant Fallback",sans-serif;padding:11px 18px;border-radius:3px;cursor:pointer;
  border:1px solid var(--edge);background:var(--page);color:var(--text);
  transition:border-color .12s,background .12s,color .12s}
.cat:hover{border-color:var(--accent);background:var(--accent-soft)}
.cat.on{background:var(--ink);border-color:var(--ink);color:var(--page)}
.cat.on:hover{background:var(--ink);color:var(--page)}

/* ── accessory grid ─────────────────────────────────────────────────────── */
.grid.acc{grid-template-columns:repeat(auto-fill,minmax(232px,1fr))}
.acard{border:1px solid var(--edge);border-radius:2px;overflow:hidden;cursor:pointer;
  background:var(--page);display:flex;flex-direction:column;
  transition:border-color .14s,box-shadow .14s,transform .14s}
.acard:hover{border-color:var(--accent);box-shadow:var(--shadow);transform:translateY(-2px)}
.acard-img{background:var(--hero);aspect-ratio:1;display:grid;place-items:center;padding:14px}
.acard-img img{width:100%;height:100%;object-fit:contain}
.acard-b{padding:13px 15px 15px;display:flex;flex-direction:column;gap:3px;flex:1}
.acard-t{font-size:14.5px;line-height:1.3}
.acard-n{font-size:11px;color:var(--text-faint)}
.acard-f{margin-top:auto;padding-top:10px;display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.acard-p{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:17px;
  font-variant-numeric:tabular-nums}
.acard-f .chip{margin-top:0}

/* ── accessory detail popup ─────────────────────────────────────────────── */
.accmodal{position:fixed;z-index:41;top:50%;left:50%;transform:translate(-50%,-50%);
  width:min(880px,94vw);max-height:90vh;overflow:auto;background:var(--page);
  border:1px solid var(--edge);border-radius:2px;box-shadow:0 20px 60px rgba(0,0,0,.3)}
.accx{position:absolute;top:10px;right:14px;z-index:2}
.accbody{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
@media (max-width:720px){.accbody{grid-template-columns:1fr}}
.am{background:var(--hero);display:grid;place-items:center;padding:26px;aspect-ratio:1}
.am img{width:100%;height:100%;object-fit:contain}
.ad{padding:28px 30px}
.ad h2{margin:6px 0 4px;font-size:26px}
.ad-n{font-size:12.5px;color:var(--text-faint);margin-bottom:14px}
.ad-desc{font-size:14.5px;color:var(--text-dim);line-height:1.6}
.ad-desc ul{padding-left:18px;margin:0 0 14px}
.ad-desc li{margin-bottom:5px}
.ad-buy{display:flex;align-items:center;gap:11px;margin:16px 0 14px;flex-wrap:wrap}
.ad-p{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:28px;
  font-variant-numeric:tabular-nums}
.ad-buy .chip{margin-top:0}
.ad .btn{width:100%}
.ad-link{margin-top:14px}
.ad-link button{background:none;border:0;color:var(--accent);cursor:pointer;font:600 14px/1 Assistant,"Assistant Fallback",sans-serif;
  text-decoration:underline;padding:0}

/* ── breadcrumb ─────────────────────────────────────────────────────────── */
.crumbs{background:var(--page);border-bottom:1px solid var(--edge-soft)}
.crumbs-in{max-width:1240px;margin:0 auto;padding:12px 24px;display:flex;flex-wrap:wrap;
  align-items:center;gap:8px;font-size:14px}
.crumbs button{background:none;border:0;padding:0;cursor:pointer;color:var(--accent);font:inherit}
.crumbs button:hover{text-decoration:underline}
.crumbs .sep{color:var(--text-faint)}
.crumbs .here{color:var(--text-dim)}

/* Segmented control: two peer views of the same bike, both always visible. The filled
   segment is where you are; the other is one tap away. */
.seg{margin-left:auto;display:inline-flex;border:1px solid var(--edge);border-radius:3px;
  overflow:hidden;background:var(--page)}
.seg button{border:0;background:none;color:var(--text-dim);cursor:pointer;
  font:600 13.5px/1 Assistant,"Assistant Fallback",sans-serif;padding:10px 18px;white-space:nowrap}
.seg button + button{border-left:1px solid var(--edge)}
.seg button:hover{background:var(--accent-soft);color:var(--text)}
.seg button.on{background:var(--ink);color:var(--page);cursor:default}
.seg button.on:hover{background:var(--ink);color:var(--page)}
@media (max-width:640px){.seg{margin-left:0;margin-top:8px;width:100%}
  .seg button{flex:1;text-align:center}}

/* ── shared page frame ──────────────────────────────────────────────────── */
.wrap{max-width:1240px;margin:0 auto;padding:34px 22px 80px}
/* A screen that asks ONE question is narrower on purpose — nothing to scan past. */
.wrap.narrow{max-width:760px}
.page-head{margin-bottom:26px}
.page-head h1{margin:6px 0 8px;font-size:clamp(28px,3.4vw,40px)}
.page-head p{margin:0;color:var(--text-dim);max-width:64ch}

/* ── card grids (bikes · sections · assemblies) ─────────────────────────── */
.grid{display:grid;gap:18px}
.grid.bikes{grid-template-columns:repeat(auto-fill,minmax(272px,1fr))}
.grid.tiles{grid-template-columns:repeat(auto-fill,minmax(226px,1fr))}
.tile{display:flex;flex-direction:column;text-align:left;cursor:pointer;background:var(--page);
  border:1px solid var(--edge);border-radius:2px;padding:0;color:var(--text);font:inherit;
  overflow:hidden;transition:border-color .14s,box-shadow .14s,transform .14s}
.tile:hover{border-color:var(--accent);box-shadow:var(--shadow);transform:translateY(-2px)}
.tile .shot{background:var(--hero);display:grid;place-items:center;padding:14px;
  aspect-ratio:4/3;overflow:hidden}
/* Triumph's studio shots are transparent PNGs, so they sit on the tile ground in either
   theme with no blend trickery — which is why the earlier multiply hack is gone. */
.tile .shot img{width:100%;height:100%;object-fit:contain}
.tile .body{padding:13px 15px 15px;display:flex;flex-direction:column;gap:3px;flex:1}
.tile .nm{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:19px;line-height:1.2}
.tile .fam{font-size:13px;color:var(--text-faint)}
.tile .meta{margin-top:auto;padding-top:9px;font-size:13px;color:var(--text-dim);
  font-variant-numeric:tabular-nums}
.tile .meta .u{color:var(--stock);font-weight:700}

/* The year screen. Big targets, the bike pictured so you can see what you chose. */
.yearshot{background:var(--hero);border:1px solid var(--edge);border-radius:2px;
  display:grid;place-items:center;padding:22px;margin-bottom:22px}
.yearshot img{max-height:210px;width:auto;object-fit:contain}
.years-big{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
.ybtn{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:30px;padding:24px 16px;
  border:1px solid var(--edge);background:var(--page);color:var(--text);border-radius:2px;
  cursor:pointer;font-variant-numeric:tabular-nums;transition:border-color .14s,transform .14s}
.ybtn:hover{border-color:var(--accent);background:var(--accent-soft);transform:translateY(-2px)}
.hint{margin-top:18px;color:var(--text-faint);font-size:14px}

/* ── VIN helper ─────────────────────────────────────────────────────────── */
.vinbox{margin-top:30px;border:1px solid var(--edge);border-radius:2px;padding:18px 20px;
  background:var(--muted)}
.vinbox h3{margin:0 0 5px;font-size:17px}
.vinbox p{margin:0 0 12px;color:var(--text-dim);font-size:14.5px;max-width:70ch}
.vinrow{display:flex;gap:9px;flex-wrap:wrap}
#vin{font:15px/1 ui-monospace,Menlo,monospace;padding:10px 13px;width:230px;border-radius:2px;
  border:1px solid var(--edge);background:var(--page);color:var(--text);text-transform:uppercase}
.btn{font:600 15px/1 Assistant,"Assistant Fallback",sans-serif;padding:11px 20px;border-radius:2px;cursor:pointer;
  border:1px solid var(--ink);background:var(--ink);color:var(--page)}
.btn:hover{opacity:.86}
.btn.ghost{background:none;color:var(--text);border-color:var(--edge)}
.btn.ghost:hover{border-color:var(--accent);opacity:1}
#vinout{margin-top:11px;font-size:14.5px}
#vinout .good{color:var(--stock);font-weight:700}
#vinout .bad{color:var(--warn);font-weight:700}

/* ── fiche workbench ────────────────────────────────────────────────────── */
/*
 * THE WORKBENCH, and why its height is measured rather than assumed.
 *
 * 'height:calc(100vh - 178px)' encoded ONE store's chrome. The off-road catalogue wears its own
 * compact header and 178px was right for it; the main shop's header is an announcement bar, a
 * nav, a utility row and a breadcrumb, and the bench then ran ~120px past the fold.
 *
 * That alone would only have pushed the footer down. What actually put the footer THROUGH the
 * drawing is the second bug: '.stage' and '.list' are grid items, whose default 'min-height:auto'
 * refuses to shrink below their content. So a 1,300px-tall drawing and a 1,354px-tall parts list
 * both painted at full height out of a 722px box, straight over everything that followed them.
 * Measured on the live Bobber route at 1440x900: bench bottom 267px, sheet bottom 876px.
 *
 * Both are fixed here. '--bench-top' is set from the bench's own position by 'sizeBench()', so
 * any chrome on any store is correct by measurement; 'min-height:0' lets the grid items shrink
 * so their own 'overflow' actually clips them.
 */
/*
 * THE PARTS LIST TAKES THE WIDTH THE DRAWING CANNOT USE.
 *
 * Every drawing is 884px wide and that is Triumph's ceiling, so past ~930px of stage the extra
 * width does the drawing no good at all — measured at 1920, the stage was 1490px wide holding a
 * 549px drawing with 941px of empty grey beside it. Meanwhile the list was pinned at 430px with
 * 2,887px of rows scrolling through an 878px column: one pane could not use its space and the
 * one next to it was starving.
 *
 * So the list grows on wide screens and the drawing keeps its natural size. Clamped rather than
 * proportional, because a 900px-wide list of 25 part rows is as wrong in the other direction.
 */
.bench{display:grid;grid-template-columns:minmax(0,1fr) clamp(430px,26vw,520px);gap:0;
  height:calc(100dvh - var(--bench-top,178px));min-height:420px;
  border-top:1px solid var(--edge);overflow:hidden;
  /*
   * THE WORKBENCH IS SIZED BY ITS CONTENT, NOT BY THE WINDOW.
   *
   * A drawing is 884px wide and Triumph publishes nothing larger, so a stage wider than about
   * 930px cannot make it any bigger -- it just puts more grey beside it. Stretched to a 1920
   * window that meant 537px of empty pane next to a drawing already at full resolution.
   *
   * 884 + 48px of breathing room + a 520px list = 1452. Past that the bench stops growing and
   * centres, so the leftover reads as page margin rather than as a pane that failed to fill.
   * Below it nothing changes: at 1440 the bench is already narrower than the cap.
   */
  max-width:1452px;margin-inline:auto}
@media (max-width:1080px){.bench{grid-template-columns:1fr;height:auto;overflow:visible}
  .sheet-wrap{height:64vh}}
/* Above the stacking breakpoint the bench IS the screen, so the shop footer would only ever be
   reachable by scrolling a pane that does not scroll the page. Below it the page scrolls
   normally and the footer belongs exactly where it is. */
@media (min-width:1081px){body.bench-open .scmfoot{display:none}}
/*
 * THE BIKE BAR COMPACTS WHILE THE WORKBENCH IS OPEN.
 *
 * On the main shop the announcement bar, nav, bike bar, tab row and breadcrumb take ~290px before
 * the bench starts, and the bench gets whatever is left — so every pixel of chrome comes straight
 * out of the drawing. The bike bar is the one piece that is pure restatement on this screen: the
 * breadcrumb directly beneath it already names the motorcycle and the year.
 *
 * It is compacted rather than hidden. "Change bike" and the VIN field are how a customer corrects
 * a wrong machine or resolves a frame-number split, and removing them here would mean going back
 * a screen to do either.
 */
@media (min-width:1081px){
  /*
   * MEASURED at 1920x1080 on the live page: announcement 38 + header 70 + department tabs 46 +
   * breadcrumb 47 = 201px, plus a 69px bike bar once a customer has chosen a machine. 270px of
   * chrome above a workbench that then gets whatever is left -- so every band here is taken
   * directly out of the drawing.
   *
   * Two of them say nothing this screen has not already said:
   *
   *   .scmann   a GEAR shipping promotion. Free shipping on $99 of apparel is not an answer to
   *             "which camshaft bolt fits my Speedmaster", and it is the first thing on the page.
   *   .scmsub   "Choose Your Motorcycle / Genuine Accessories / OEM Parts Diagrams" -- restated,
   *             in order and with more precision, by the breadcrumb directly beneath it.
   *
   * Both come back the moment the customer leaves the diagram, because 'bench-open' is set only
   * while a drawing is on screen. The breadcrumb stays: it is the only band that says where the
   * customer actually is, and it is how they get back.
   */
  body.bench-open .scmann{display:none}
  body.bench-open .scmsub{display:none}
  /*
   * THE BIKE BAR SHRINKS TO A UTILITY STRIP.
   *
   * Compacting it to 19px was not enough: measured on the reported page it still took ~80px, and
   * every one of those pixels comes out of the drawing, because the workbench gets whatever the
   * chrome leaves. The 28px "BONNEVILLE BOBBER 2026" headline is the largest thing on the screen
   * and the breadcrumb DIRECTLY BENEATH IT already reads "Bobber / Bobber 2026" — the same fact,
   * twice, one of them shouting.
   *
   * On the workbench the bar keeps only what the breadcrumb cannot do: change the bike, save it,
   * and take a VIN. The name drops to the size of the text around it, so it reads as a label on
   * a toolbar rather than a page title, and the whole strip lands near 34px instead of 80.
   */
  body.bench-open .bikebar-in{padding:5px 24px;gap:14px;max-width:1452px}
  body.bench-open .bb-name,body.bench-open .bb-year{font-size:15px;letter-spacing:.02em}
  body.bench-open .bb-vin input{padding:5px 10px;width:150px}
  body.bench-open .bb-vin label,body.bench-open .bb-set{font-size:13px}
  body.bench-open .bb-vin button,body.bench-open .bb-change{padding-top:0;padding-bottom:0}
  /* Padding lives on .crumbs-in, not .crumbs — targeting the wrapper would have been inert.
     The bar, the breadcrumb and the bench are one object seen three times; three different
     max-widths read as a misprint, so they align here. */
  body.bench-open .crumbs-in{padding:7px 24px;max-width:1452px}
}
.stage{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden;
  background:var(--muted);position:relative}
.stage-bar{display:flex;align-items:center;gap:13px;padding:11px 20px;background:var(--page);
  border-bottom:1px solid var(--edge)}
.stage-bar h2{margin:0;font-size:19px}
.stage-bar .cnt{font-size:13px;color:var(--text-faint)}
.zoom{margin-left:auto;display:flex;gap:6px}
.zoom button{width:31px;height:31px;border:1px solid var(--edge);border-radius:2px;
  background:var(--page);color:var(--text-dim);cursor:pointer;font-size:15px;line-height:1}
.zoom button:hover{border-color:var(--accent);color:var(--text)}
/*
 * CENTRING AN OVERFLOWING CHILD HIDES ITS TOP EDGE, PERMANENTLY.
 *
 * 'place-items:center' on a scroll container is a well-known trap: once the child is taller than
 * the box, centring pushes its top ABOVE the container's scrollable origin, and no amount of
 * scrolling brings it back — scrollTop cannot go negative. The opening view now fills the pane
 * width, so portrait drawings routinely overflow and callout 1, which Triumph draws at the top,
 * would be permanently unreachable.
 *
 * 'safe center' centres only while the child fits and falls back to start alignment the moment it
 * would overflow. The plain 'start' underneath is the fallback for engines that do not know the
 * keyword: they lose the vertical centring of short drawings and keep every pixel reachable,
 * which is the right way round to fail.
 */
.sheet-wrap{flex:1;overflow:auto;display:grid;justify-items:center;padding:24px;min-height:0}
.sheet-wrap{align-items:start}
.sheet-wrap{align-items:safe center}
/* A zoomed drawing is a transform, and a transform paints outside its box unless something
   clips it. '.sheet-wrap' scrolls, which clips; this makes that explicit so a future layout
   change cannot quietly remove it. */
.sheet-wrap{contain:paint}
.sheet{position:relative;background:var(--sheet);box-shadow:var(--shadow);
  border:1px solid var(--sheet-edge);transform-origin:top center}
.sheet img{display:block;width:100%;height:auto}
.sheet svg{position:absolute;inset:0;width:100%;height:100%}
.spot{fill:transparent;stroke:transparent;stroke-width:2;cursor:pointer;transition:.12s}
.spot:hover,.spot.on,.spot:focus-visible{fill:var(--accent-soft);stroke:var(--accent)}
.spot:focus-visible{outline:none;stroke-width:3}
.spot.on{stroke-width:2.5}
@keyframes ping{0%{opacity:0;transform:scale(.6)}45%{opacity:1}100%{opacity:0;transform:scale(1.9)}}
.ping{fill:none;stroke:var(--accent);stroke-width:3;transform-box:fill-box;
  transform-origin:center;animation:ping .75s ease-out}
@media (prefers-reduced-motion:reduce){.ping{animation:none;opacity:.9}
  .tile:hover{transform:none}}

.list{background:var(--page);border-left:1px solid var(--edge);overflow-y:auto;min-width:0}
.grp{padding:11px 18px 6px;border-bottom:1px solid var(--edge-soft)}
.row{display:grid;grid-template-columns:36px 1fr auto;gap:12px;align-items:start;
  padding:11px 18px;border-bottom:1px solid var(--edge-soft);cursor:pointer}
.row:hover{background:var(--hover)}
.row.on{background:var(--accent-soft);box-shadow:inset 3px 0 0 var(--accent)}
.cal{font:700 12px/1 ui-monospace,Menlo,monospace;font-variant-numeric:tabular-nums;
  color:var(--page);background:var(--ink);border-radius:2px;text-align:center;padding:5px 0}
.row.un .cal{background:var(--dead-bg);color:var(--text-faint)}
.pn{font-family:ui-monospace,Menlo,monospace;font-size:12.5px}
.nm{font-size:14.5px;margin-top:1px}
.qty{color:var(--text-faint);font-size:12px}
/*
 * THE CONDITION IS THE DECIDING INFORMATION, SO IT STOPS LOOKING LIKE A FOOTNOTE.
 *
 * On a callout split by frame or engine number, four rows carry the same part name and the same
 * price, and this line is the ONLY thing that tells them apart. It was set as a 12px grey italic
 * aside -- the styling of a remark you may skip -- under a part number in monospace and a name at
 * 14.5px, so the eye went everywhere except the one line that decides the order.
 *
 * Now it reads as a condition: upright, full size, and marked with a rule down the left so a
 * stack of them scans as a set of alternatives rather than four near-identical rows.
 */
.cm{font-size:13px;line-height:1.4;color:var(--text);margin-top:5px;
  padding:3px 0 3px 9px;border-left:2px solid var(--accent)}
.right{text-align:right;white-space:nowrap}
.price{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:16px;
  font-variant-numeric:tabular-nums}
.chip{display:inline-block;margin-top:5px;font:600 10.5px/1 Oswald,"Oswald Fallback",sans-serif;letter-spacing:.07em;
  text-transform:uppercase;padding:4px 8px;border-radius:2px}
.chip.s{color:var(--stock);background:var(--stock-bg)}
.chip.o{color:var(--order);background:var(--order-bg)}
.chip.x{color:var(--dead);background:var(--dead-bg)}
/* ON BACKORDER: neither our shelf nor Triumph's — amber, not the red of "not supplied". */
.chip.b{color:var(--warn);background:var(--order-bg)}
/* A block-level <button> shrink-wraps its label and then sits at the START of its line, so
   text-align:right on .right never reached it: the button hung off the left of a column whose
   width was set by whichever chip happened to be above it. "IN STOCK IN BREA" is far wider
   than "AVAILABLE", so the same button moved between rows according to stock status. An auto
   left margin pushes it flush right in every branch, without forcing one width on labels that
   legitimately differ ("Add to cart" vs "Shipping quote or pickup"). */
/* The quantity control. Sits on its own line above the button, right-aligned with it. */
.qtyctl{display:inline-flex;align-items:stretch;margin-top:7px;margin-left:auto;border:1px solid var(--edge);
  border-radius:2px;overflow:hidden;background:var(--page)}
.qtyctl .qtyb{width:30px;border:0;background:none;color:var(--text);cursor:pointer;font:600 15px/1 Assistant,"Assistant Fallback",sans-serif}
.qtyctl .qtyb:hover{background:var(--hover)}
.qtyctl .qtyin{width:40px;border:0;border-left:1px solid var(--edge-soft);border-right:1px solid var(--edge-soft);
  text-align:center;font:600 13px/1 Assistant,"Assistant Fallback",sans-serif;color:var(--text);background:none;
  -moz-appearance:textfield;appearance:textfield}
.qtyctl .qtyin::-webkit-outer-spin-button,.qtyctl .qtyin::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.right .qtyctl{display:inline-flex}
.right .add{margin-left:auto}
.add{display:block;margin-top:7px;border:1px solid var(--ink);background:var(--ink);
  color:var(--page);border-radius:2px;padding:7px 13px;cursor:pointer;
  font:600 13px/1 Assistant,"Assistant Fallback",sans-serif}
.add:hover{opacity:.86}
.add[disabled]{opacity:.35;cursor:not-allowed;background:none;color:var(--text-dim);
  border-color:var(--edge)}

/* Triumph's supply — the second axis, quieter than our shelf on purpose. */
.supply{margin-top:6px;font-size:12px;line-height:1.45}
.sup.ok{color:var(--text-dim)} .sup.low{color:var(--warn)} .sup.eta{color:var(--warn)}
.sup.back{color:var(--text-dim)} .sup.no{color:var(--dead)}
.sup.unk{color:var(--text-faint);font-style:italic}
.sup::before{content:"";display:inline-block;width:5px;height:5px;border-radius:50%;
  margin-right:6px;vertical-align:1.5px;background:currentColor}
.sup.ok::before{background:var(--stock)}

.foot{padding:16px 18px;font-size:12.5px;color:var(--text-faint);line-height:1.6;
  border-top:1px solid var(--edge-soft)}
.wrap .foot{border:0;padding:34px 0 0;max-width:78ch}

/* ── search results ─────────────────────────────────────────────────────── */
/* A list, not a card grid: parts are scanned by name and number, and a row lets the
   name, the number, the fitment, the price and the stock state all sit on one line. */
.results{display:flex;flex-direction:column;border-top:1px solid var(--edge-soft)}
.res{display:grid;grid-template-columns:34px 1fr auto;gap:14px;align-items:center;
  padding:14px 6px;border-bottom:1px solid var(--edge-soft);cursor:pointer;text-align:left;
  background:none;border-left:0;border-right:0;border-top:0;color:var(--text);font:inherit;
  width:100%}
.res:hover{background:var(--hover)}
.res-ico{display:grid;place-items:center;width:34px;height:34px;border-radius:2px;
  background:var(--muted);color:var(--text-faint);font-size:15px}
.res.diagram .res-ico{background:var(--accent-soft);color:var(--accent)}
.res-main{min-width:0}
.res-t{font-size:15.5px;line-height:1.3}
.res-for{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;color:var(--accent);font-size:14px;
  margin-left:5px}
.res-sub{font-size:13px;color:var(--text-dim);margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.res-right{text-align:right;white-space:nowrap}
.res-right .price{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:16px;
  font-variant-numeric:tabular-nums}
.res-right .chip{margin-top:3px}
.empty{padding:26px 0;max-width:64ch}
.empty h2{margin:0 0 8px;font-size:22px}
.empty p{margin:0;color:var(--text-dim)}
.empty a{color:var(--accent)}
@media (max-width:620px){
  .res{grid-template-columns:28px 1fr;gap:11px}
  .res-right{grid-column:2;text-align:left;margin-top:4px}
  .res-sub{white-space:normal}
}


/* ── the parts-desk enquiry sheet ───────────────────────────────────────────
   Opened from the 57.4% of diagram rows that are not buyable online. Everything the desk
   needs is already on screen, so the customer never has to recite it. */
.askpane{display:flex;flex-direction:column;gap:14px}
.askpane h2{margin:0}
.askfacts{display:grid;gap:1px;background:var(--edge);border:1px solid var(--edge);border-radius:2px}
.askfacts div{display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  background:var(--page);padding:10px 13px}
.askfacts span{color:var(--text-dim);font-size:13px}
.askfacts b{font-weight:600;font-size:14.5px;text-align:right}
.askacts{display:flex;flex-wrap:wrap;gap:10px}
.askacts .btn{text-decoration:none;display:inline-flex;align-items:center;justify-content:center}
@media (max-width:620px){
  .askacts{flex-direction:column;align-items:stretch}
  .askacts .btn{width:100%}
}
/* The workbench on a phone: the drawing is the draw, but the buyable rows are the sale, and
   a full-height fiche pushed every one of them off the bottom of the screen. */
@media (max-width:1080px){
  .sheet-wrap{max-height:52vh}
  .sheet img{max-height:52vh;width:auto;object-fit:contain;margin:0 auto}
}

/* The ask sheet reuses the accessory dialog, which is a photo+detail two-column grid. With
   no photo the second column was simply empty, so this mode collapses to one column and
   stops the sheet sprawling across the screen. */
.accmodal.asking{max-width:540px}
.accmodal.asking .accbody{grid-template-columns:1fr}

/* ── the enquiry form inside the ask sheet ─────────────────────────────────── */
.askform{display:flex;flex-direction:column;gap:7px;margin-top:2px}
.askform label{font-size:13px;color:var(--text-dim);font-weight:600}
.askform label .opt{font-weight:400;color:var(--text-faint)}
.askform input,.askform textarea{font:inherit;font-size:15px;padding:11px 13px;
  border:1px solid var(--edge);border-radius:2px;background:var(--page);color:var(--ink);
  width:100%}
.askform input:focus,.askform textarea:focus{outline:2px solid var(--accent);outline-offset:-1px;
  border-color:var(--accent)}
.askform textarea{resize:vertical;min-height:56px}
.askform .btn{margin-top:4px}
.askmsg{font-size:13.5px;line-height:1.5;min-height:0}
.askmsg.ok{color:var(--stock);font-weight:600}
/* A failure has to be as loud as a success, and has to carry the way out. This is the branch
   that stops a form silently swallowing an enquiry — the dead button in a nicer coat. */
.askmsg.bad{color:#a3341f}
.askmsg a{color:inherit;text-decoration:underline;text-underline-offset:2px}

/* Buy straight from the accessory card. */
.acard{display:flex;flex-direction:column}
.acard-b{display:flex;flex-direction:column;flex:1}
.acard-buy{margin-top:10px}
.acard-buy .btn{width:100%;justify-content:center}

/* ── saved bikes ────────────────────────────────────────────────────────────── */
.mygarage{padding:0 0 30px;margin:0 0 8px;border-bottom:1px solid var(--edge)}
.tile.mine{border-color:var(--accent)}
.tile.mine .fam{color:var(--accent);font-weight:600}
.bb-save{color:var(--accent);font-weight:600}
.bb-saved{display:inline-flex;align-items:center;gap:10px;font-size:13.5px;color:var(--stock);
  font-weight:600}
/* ── the motorcycle hub ──────────────────────────────────────────────────────
   The selected machine, shown before the two journeys, so a customer can see at a glance that
   the site knows which bike they are shopping for — and change it in one click. */
.bikehub{display:grid;gap:20px;align-items:center;margin:0 0 26px;grid-template-columns:1fr}
.bikehub-pic{background:var(--hero);border:1px solid var(--edge);border-radius:2px;
  display:grid;place-items:center;padding:12px}
/* BOTH dimensions must be constraints, not one computed from the other. A width of 100% with
   height:auto computed a 205px height from the 274px column, then max-height:190px clamped the
   height WITHOUT touching the width — rendering a 1000x750 studio shot at 274x190 and visibly
   stretching the motorcycle. Letting the browser satisfy two max-* constraints keeps the aspect
   ratio intact. (No backticks in this file: it is a JS template literal.) */
.bikehub-pic img{width:auto;height:auto;max-width:100%;max-height:190px}
.bikehub-id h1{margin:4px 0 6px;line-height:1.05}
.bikehub-yr{opacity:.45;font-weight:400}
.bikehub-change{font-size:13.5px;color:var(--accent);text-decoration:underline;text-underline-offset:3px}
@media (min-width:750px){.bikehub{grid-template-columns:300px 1fr;gap:28px}}

/* Both doors carry equal weight. A count only appears where it is a real number. */
.door-n{display:block;margin-top:10px;font-size:13px;font-weight:700;opacity:.75;
  font-variant-numeric:tabular-nums}
/* The honest state for a bike-year with no published fiche. Deliberately NOT disabled-looking:
   there IS a way forward, it is just a person rather than a diagram. */
.door.door-soon{border-style:dashed;cursor:default}
.door.door-soon:hover{transform:none;border-color:var(--edge);box-shadow:none}
.door-sub{display:block;margin-top:8px;font-size:13px;opacity:.7}
/* The hub doors are anchors so they are real links (keyboard, middle-click, copy-link). The
   theme underlines anchors, which turned the whole card into underlined text. */
a.door,a.door *{text-decoration:none}
a.door h2{text-decoration:none}
a.door .door-cta{font-weight:700}



/* ── the motorcycle selector ────────────────────────────────────────────────
   Progressive disclosure: 30 family tiles, then a handful of variations, then year chips.
   A customer never faces all 81 variations at once. */

.finder{margin:0 0 34px;max-width:620px}
.finder-lbl{display:block;font-size:12px;letter-spacing:.12em;text-transform:uppercase;
  opacity:.55;font-weight:700;margin-bottom:8px}
.finder-wrap{position:relative}
#mfind{width:100%;font:inherit;font-size:17px;padding:15px 16px;border:1px solid var(--edge);
  border-radius:2px;background:var(--page);color:var(--text)}
#mfind:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.finder-list{position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:40;margin:0;padding:6px 0;
  list-style:none;background:var(--page);border:1px solid var(--edge);border-radius:2px;
  box-shadow:0 14px 30px rgba(0,0,0,.12);max-height:340px;overflow:auto}
.finder-list li{padding:10px 16px;cursor:pointer;display:flex;flex-direction:column;gap:2px}
.finder-list li:hover,.finder-list li.is-on{background:var(--hero)}
.fo-name{font-size:15px}
.fo-path{font-size:12.5px;opacity:.6}

.yourbike{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;margin:0 0 22px;padding:12px 16px;
  background:var(--hero);border:1px solid var(--edge);border-radius:2px;font-size:14px}
.yourbike-lbl{font-size:11px;letter-spacing:.12em;text-transform:uppercase;opacity:.55;font-weight:700}
.yourbike-go{font-weight:700;color:var(--text)}
.yourbike-sep{opacity:.35}
.yourbike-change{color:var(--accent);text-decoration:underline;text-underline-offset:3px}

.secttl{margin:38px 0 4px;font-size:13px;letter-spacing:.14em;text-transform:uppercase;
  opacity:.6;font-weight:700}
.secttl.sm{margin:26px 0 10px}
.secsub{margin:0 0 16px;font-size:14px;opacity:.65}

.grid.ftiles{grid-template-columns:repeat(auto-fill,minmax(240px,1fr));margin-top:14px}
.ftile{display:flex;flex-direction:column;text-decoration:none;color:var(--text);
  border:1px solid var(--edge);border-radius:2px;overflow:hidden;background:var(--page);
  transition:border-color .14s,transform .14s,box-shadow .14s}
.ftile:hover{border-color:var(--accent);box-shadow:var(--shadow);transform:translateY(-2px)}
.ftile:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* The box is reserved before the image lands so the grid never jumps. */
.ftile-pic{display:grid;place-items:center;aspect-ratio:4/3;background:var(--hero);padding:12px;overflow:hidden}
.ftile-pic img{width:auto;height:auto;max-width:100%;max-height:100%}
/* A family with no official asset gets a DESIGNED typographic tile, never a broken box. */
.ftile-pic--type{background:linear-gradient(160deg,var(--hero),rgba(0,0,0,.05))}
.ftile-pic--type span{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:24px;letter-spacing:.02em;
  opacity:.34;text-align:center;padding:0 14px;line-height:1.15}
.ftile-body{padding:13px 15px 15px;display:flex;flex-direction:column;gap:3px}
.ftile-name{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:19px;line-height:1.2}
.ftile-scope{font-size:13px;color:var(--text-faint);line-height:1.35}

.vgrid{display:grid;gap:10px;grid-template-columns:1fr}
@media (min-width:620px){.vgrid{grid-template-columns:repeat(2,1fr)}}
.vcard{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  padding:16px 18px;border:1px solid var(--edge);border-radius:2px;text-decoration:none;
  color:var(--text);background:var(--page)}
.vcard:hover{border-color:var(--accent)}
/* The VIN choice list renders its cards as BUTTONS, not links: choosing there is an action on
   state we already hold, not a navigation to a URL that could be shared. A button carries the
   user agent's own font and centring, which is what turned the first render of that list into
   centred 13px system text beside identical-looking anchors elsewhere on the site. */
button.vcard{font:inherit;text-align:left;width:100%;cursor:pointer}
.vcard:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.vcard-name{font-size:16px;font-weight:600}
.vcard-meta{font-size:13px;opacity:.6;font-variant-numeric:tabular-nums;white-space:nowrap}
/*
 * A GENERATION CARD carries a whole sentence — "Covers frames from VIN AV5527 onward." — where a
 * variation card carries "2017-2026". "white-space:nowrap" is right for a year span and wrong
 * for a sentence: it is what would push the grid past the viewport once a generation name grows.
 * So the generation variant stacks instead, and wraps.
 */
.vgrid--gen .vcard{flex-direction:column;align-items:flex-start;gap:6px;min-height:44px}
.vgrid--gen .vcard-meta{white-space:normal;line-height:1.45}
.vgrid--gen .vcard-name{line-height:1.3}

.ychips{display:flex;flex-wrap:wrap;gap:10px;margin:6px 0 26px}
.ychip{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:20px;padding:13px 20px;
  border:1px solid var(--edge);border-radius:2px;text-decoration:none;color:var(--text);
  min-width:88px;text-align:center;font-variant-numeric:tabular-nums}
.ychip:hover{border-color:var(--accent);background:var(--hero)}
.ychip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ynone{font-size:15px;opacity:.75;margin:0 0 22px;max-width:52ch;line-height:1.55}
.yalt{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:16px}
.ybtn-alt{font:inherit;font-size:14px;padding:11px 16px;background:none;border:1px dashed var(--edge);
  border-radius:2px;cursor:pointer;color:var(--text);text-decoration:none}
.ybtn-alt:hover{border-color:var(--accent)}
.ybtn-alt:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ymanual{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:10px}
.ymanual label{width:100%;font-size:13px;opacity:.7}
.ymanual input{font:inherit;font-size:16px;padding:11px 14px;border:1px solid var(--edge);
  border-radius:2px;width:130px;background:var(--page);color:var(--text)}
.ymanual button{font:inherit;font-size:14px;padding:12px 18px;border:0;border-radius:2px;
  background:var(--text);color:var(--page);cursor:pointer}

.vgrid--gen .vcard-name{line-height:1.3}

.ychips{display:flex;flex-wrap:wrap;gap:10px;margin:6px 0 26px}
.ychip{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:20px;padding:13px 20px;
  border:1px solid var(--edge);border-radius:2px;text-decoration:none;color:var(--text);
  min-width:88px;text-align:center;font-variant-numeric:tabular-nums}
.ychip:hover{border-color:var(--accent);background:var(--hero)}
.ychip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ynone{font-size:15px;opacity:.75;margin:0 0 22px;max-width:52ch;line-height:1.55}
.yalt{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:16px}
.ybtn-alt{font:inherit;font-size:14px;padding:11px 16px;background:none;border:1px dashed var(--edge);
  border-radius:2px;cursor:pointer;color:var(--text);text-decoration:none}
.ybtn-alt:hover{border-color:var(--accent)}
.ybtn-alt:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ymanual{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:10px}
.ymanual label{width:100%;font-size:13px;opacity:.7}
.ymanual input{font:inherit;font-size:16px;padding:11px 14px;border:1px solid var(--edge);
  border-radius:2px;width:130px;background:var(--page);color:var(--text)}
.ymanual button{font:inherit;font-size:14px;padding:12px 18px;border:0;border-radius:2px;
  background:var(--text);color:var(--page);cursor:pointer}

/*
 * THE OPTIONAL VIN CONTROL — its own region, not whatever space is left over.
 *
 * Measured at 1440px: the generation cards ended at y=513 and this block began at y=513. Zero
 * gap, so the input's top border sat exactly on the card's bottom border and the control read as
 * though it had fallen through the card above it. "margin:0" was the whole defect — the label is
 * 328px wide, which put the input directly under the seam between the two cards, and a
 * coincidence of geometry made a correct DOM look broken.
 *
 * So it is now a bounded panel with its own space above and below, the label is tied to the
 * input by "for"/"id", and the input keeps a 44px target at every width. "flex-wrap" plus a
 * flexible label basis is what lets it reflow to two lines on a phone instead of overflowing.
 */
.vinask{margin:28px 0 24px;display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;
  padding:14px 16px;border:1px solid var(--edge);border-radius:2px;background:var(--accent-soft)}
/* ── the frame-number question ─────────────────────────────────────────────
 * Triumph splits some sections by frame number. The tile that asks must read as a QUESTION,
 * not as one more diagram, or a customer clicks it expecting a drawing and gets a form. */
.vbnote{font-size:12.5px;line-height:1.35;color:#5c6470;margin:2px 0 4px}
.vbtag{display:inline-block;margin-left:10px;padding:3px 9px;border-radius:12px;
  background:#eef3f9;color:#1f5fa9;font-size:12.5px;font-weight:600;white-space:nowrap}
.tile--ask{border-color:#c8ced8;background:#fbfcfd}
.tile--ask .vbnote{color:#1f5fa9}
.tile--ask .meta{font-weight:600;color:#1f5fa9}
.vinask--inline{margin:0 0 22px}
.vinlbl{display:block;font-size:13.5px;font-weight:600;margin:0 0 6px}
.years-big--wide{grid-template-columns:1fr;gap:10px}
.ybtn--wide{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  text-align:left;padding:14px 18px;font-size:16px}
.ybtn-sub{font-size:13px;font-weight:400;color:#5c6470;white-space:nowrap}
.deskline{margin-top:18px;padding-top:14px;border-top:1px solid #e6e9ee}
.rawnames{margin:0 0 16px;padding:0 0 0 20px;font-size:14px;line-height:1.6;color:#3c434e}
.rawnames li{margin:0 0 4px}
@media(min-width:700px){.years-big--wide{grid-template-columns:1fr 1fr}}

.vinask label{font-size:13.5px;opacity:.85;flex:1 1 22ch;min-width:0}
.vinask input{font:inherit;font-size:16px;padding:11px 13px;border:1px solid var(--edge);
  border-radius:2px;width:150px;min-height:44px;flex:0 0 auto;
  letter-spacing:.06em;text-transform:uppercase;
  background:var(--page);color:var(--text)}
.vinask input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.fitnote{margin:20px 0 0;font-size:13px;opacity:.65;max-width:60ch;line-height:1.55}

/* ══════════════════════════════════════════════════════════════════════════
 * FULL VIN — the second door, and the card that refuses to assume
 * ══════════════════════════════════════════════════════════════════════════
 * Deliberately quiet furniture around one field. This screen asks exactly one question and the
 * answer is seventeen characters a customer is reading off a headstock, so the field is the
 * biggest thing on it and everything else gets out of the way.
 * (No backticks in this file: it is a JS template literal.) */
.vinbox{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin:0 0 12px}
.vinbox label{width:100%;font-size:13.5px;font-weight:600;opacity:.85}
.vinbox input{font:inherit;font-size:19px;font-family:Assistant,ui-monospace,monospace;
  padding:14px 16px;border:1px solid var(--edge);border-radius:2px;min-height:52px;
  flex:1 1 22ch;min-width:0;letter-spacing:.14em;text-transform:uppercase;
  background:var(--page);color:var(--text)}
.vinbox input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.vinbox .btn{min-height:52px;flex:0 0 auto}
.vinmsg{width:100%;font-size:13.5px;line-height:1.5;color:var(--text-dim);min-height:1.2em}
.vinmsg:empty{min-height:0}
.vinmsg.bad{color:var(--err);font-weight:600}
.vinwhere{margin:0 0 26px;font-size:13px;opacity:.65;max-width:56ch;line-height:1.55}
.vinalt{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin:22px 0 0;
  padding-top:18px;border-top:1px solid var(--edge-soft);font-size:14px;color:var(--text-dim)}

/* The confirmation card. The motorcycle is the content; the words are a caption on it. A rider
   recognises their own bike from the photograph faster than from any name we could print. */
.vincard{display:grid;gap:18px;align-items:center;grid-template-columns:1fr;
  padding:18px;border:2px solid var(--accent-line);border-radius:4px;background:var(--accent-soft)}
.vincard-pic{background:var(--hero);border:1px solid var(--edge);border-radius:2px;
  display:grid;place-items:center;padding:12px}
/* Two max-* constraints, never one dimension computed from the other — see .bikehub-pic for
   the stretched studio shot that rule was written after. */
.vincard-pic img{width:auto;height:auto;max-width:100%;max-height:210px}
.vincard-yr{font-family:Oswald,"Oswald Fallback",sans-serif;font-size:15px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--accent);font-variant-numeric:tabular-nums}
.vincard-name{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:30px;line-height:1.1;
  margin:4px 0 6px}
.vincard-fam{font-size:14px;color:var(--text-dim)}
@media (min-width:750px){.vincard{grid-template-columns:320px 1fr;gap:26px}}

/* Yes first and larger. "No" is a real answer and must be easy to reach, but the card exists
   because we believe the decode — asking with two identical buttons pretends we do not. */
.vinacts{display:flex;flex-wrap:wrap;gap:12px;margin:22px 0 0}
.vinacts .btn{min-height:50px}
.vinnote{margin:20px 0 0;font-size:13px;opacity:.65;max-width:64ch;line-height:1.55}

/* The door on the picker. */
.vindoor{display:block;margin:0 0 26px;padding:16px 18px;border:1px dashed var(--edge);
  border-radius:3px;text-decoration:none;color:var(--text);background:var(--page)}
.vindoor:hover{border-color:var(--accent);border-style:solid}
.vindoor:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.vindoor-t{display:block;font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:19px}
.vindoor-s{display:block;margin:5px 0 8px;font-size:13.5px;color:var(--text-dim);
  max-width:62ch;line-height:1.5}

/* What a decode that reached the picker bought the customer. */
.vinnote-bar{display:flex;flex-wrap:wrap;gap:6px 12px;align-items:baseline;margin:0 0 22px;
  padding:13px 16px;border-left:3px solid var(--accent);border-radius:2px;
  background:var(--accent-soft);font-size:14px;line-height:1.55;max-width:78ch}
.vinnote-lbl{font-family:Oswald,"Oswald Fallback",sans-serif;font-size:12.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--accent);white-space:nowrap}

/* The year the factory already told us. Marked, never auto-chosen — one chip cannot know
   whether the rider is standing in front of the right motorcycle. */
.ychip--vin{border-color:var(--accent);background:var(--accent-soft);position:relative}
.ychip-tag{display:block;font-family:Assistant,"Assistant Fallback",sans-serif;font-size:10.5px;font-weight:600;
  letter-spacing:.05em;text-transform:uppercase;color:var(--accent);margin-top:3px}

/* Provenance on the bike bar: chosen from a menu, or read off the machine. */
.bb-basis{font-size:12px;color:var(--text-faint);white-space:nowrap}
.bb-basis--vin{color:var(--stock);font-weight:600}
.bb-vinfull{color:var(--accent);font-weight:600}

/* The one-line fitment answer, for a list where the full band would not fit. Same five states
   and the same colours as .fitbox, which seo-css.cjs defines for both bundles. */
.fitchip{display:inline-block;margin-top:6px;padding:3px 9px;border-radius:12px;
  font-size:12.5px;font-weight:600;line-height:1.5;
  border:1px solid var(--edge);color:var(--text-dim);background:var(--page)}
.fitchip.fit-confirmed{border-color:var(--stock);color:var(--stock);background:var(--stock-bg)}
.fitchip.fit-listed{border-color:var(--accent-line);color:var(--accent);background:var(--accent-soft)}
.fitchip.fit-vin-needed{border-color:var(--warn);color:var(--warn)}
.fitchip.fit-not-listed{border-color:var(--warn);color:var(--warn)}
/* EXCLUDED: the frame-number rule evaluated false against the customer's own serial. The one
   state that is a real "no", so the one that may be red. */
.fitchip.fit-excluded{border-color:var(--dead);color:var(--dead);background:var(--dead-bg)}
.row.fit-excluded .pn,.row.fit-excluded .nm{opacity:.6}
.row .fitchip{margin-top:6px}
.row .addvin{border:0;background:none;color:var(--accent);cursor:pointer;font:inherit;font-size:12.5px;
  text-decoration:underline;padding:0;margin-left:6px}
.ad-caution{margin:12px 0 0;font-size:13px;line-height:1.55;color:var(--text-dim);max-width:52ch}
/* The vin-needed caution is the ANSWERABLE one — the customer can resolve it in ten seconds —
   so it reads as an offer rather than a caveat. not-listed keeps the quieter treatment because
   there is nothing for them to fix; it is information, not a task. */
.ad-caution--vin{color:var(--text);border-left:3px solid var(--warn);padding-left:12px}

/* ══════════════════════════════════════════════════════════════════════════
 * THE LANDING — search first, then the three doors
 * ══════════════════════════════════════════════════════════════════════════
 * The hero is deliberately quiet furniture around one field. Everything above the tiles exists
 * to get a customer who can name what they want straight to it, and everything below is for the
 * ones who cannot. (No backticks in this file: it is a JS template literal.) */
.lhero{max-width:52rem;margin:0 0 40px}
.lhero h1{margin:6px 0 10px;line-height:1.05}
.lhero-sub{font-size:16px;line-height:1.6;color:var(--text-dim);max-width:60ch;margin:0 0 26px}
.lsearch{margin:0 0 10px}
.lsearch-lbl{display:block;font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:15px;
  letter-spacing:.02em;margin:0 0 8px}
.lsearch-row{display:flex;flex-wrap:wrap;gap:10px}
/* The field is the biggest control on the page. That is the hierarchy, not decoration. */
.lsearch-row input{font:inherit;font-size:18px;padding:15px 18px;border:1px solid var(--edge);
  border-radius:2px;min-height:56px;flex:1 1 26ch;min-width:0;background:var(--page);color:var(--text)}
.lsearch-row input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.lsearch-row .btn{min-height:56px;flex:0 0 auto}
.lsearch-eg{margin:0;font-size:13.5px;color:var(--text-dim)}
/* Real buttons, not styled spans: these run a search, so they must be reachable by keyboard
   and announced as controls. */
.egq{font:inherit;font-size:13.5px;background:none;border:0;padding:0;cursor:pointer;
  color:var(--accent);text-decoration:underline;text-underline-offset:3px}
.egq:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:2px}

.ltiles{display:grid;gap:14px;grid-template-columns:1fr;margin:0 0 30px}
@media (min-width:760px){.ltiles{grid-template-columns:repeat(3,1fr)}}
.ltile{display:flex;flex-direction:column;padding:22px 22px 20px;border:2px solid var(--edge);
  border-radius:4px;text-decoration:none;color:var(--text);background:var(--page)}
.ltile:hover{border-color:var(--accent)}
.ltile:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ltile-h{font-family:Oswald,"Oswald Fallback",sans-serif;font-weight:500;font-size:21px;line-height:1.15;
  margin:0 0 8px}
.ltile-p{font-size:14px;line-height:1.55;color:var(--text-dim);flex:1 1 auto}
.ltile-n{display:block;margin-top:10px;font-size:13px;font-weight:700;opacity:.75;
  font-variant-numeric:tabular-nums}
.ltile .door-cta{margin-top:14px}
/* A door with nowhere to go is not styled as a link, because it is not one. */
.ltile--none{border-style:dashed;cursor:default}
.ltile--none .door-cta{color:var(--text-faint)}

/* The context bar with no motorcycle yet. Same bar, same place, an offer instead of a claim. */
.bikebar--none{background:var(--accent-soft)}
.bb-ask{font-size:14px;font-weight:600}

/* ── check part fitment ──────────────────────────────────────────────────── */
.fitcard{padding:20px 22px;border:1px solid var(--edge);border-radius:3px;background:var(--page);
  margin:26px 0 30px}
.fitcard h2{margin:4px 0 6px;line-height:1.1}
.fitacts{display:flex;flex-wrap:wrap;gap:12px;margin:18px 0 0}
.fitacts .btn{min-height:46px}
.corrlist{margin:0 0 18px;padding:0;list-style:none;display:grid;gap:6px;
  grid-template-columns:1fr}
@media (min-width:620px){.corrlist{grid-template-columns:repeat(2,1fr)}}
.corrlist li{padding:9px 13px;border:1px solid var(--edge-soft);border-radius:2px;
  font-size:14px;background:var(--hero)}
.fitmiss{margin:22px 0 0;font-size:15px;line-height:1.6;color:var(--text-dim);max-width:60ch}

/* ── all-Triumph vs your-motorcycle accessory discovery ──────────────────── */
.acctoggle{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:0 0 24px}
.acctog{font:inherit;font-size:14px;padding:10px 16px;border:1px solid var(--edge);
  border-radius:2px;text-decoration:none;color:var(--text);background:var(--page)}
.acctog:hover{border-color:var(--accent)}
.acctog:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* The active scope is stated, not merely highlighted — a customer must be able to tell which
   list they are reading without comparing two shades of grey. */
.acctog.is-on{border-color:var(--accent);background:var(--accent-soft);color:var(--accent);
  font-weight:600}
.acctog-note{font-size:14px;color:var(--text-dim);line-height:1.55}
.accrow-pic{flex:0 0 auto;width:72px;height:72px;object-fit:contain;background:#fff;
  border:1px solid var(--edge-soft);border-radius:2px}
/* An empty box, not a broken one. The row keeps its shape whether Triumph photographs the
   part or not, which is what stops a list looking half-loaded. */
.accrow-pic--none{display:block;background:var(--hero)}
.accrow-main{flex:1 1 auto;min-width:0}
.accrow-right{display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex:0 0 auto}
a.accrow{text-decoration:none;color:var(--text)}
a.accrow:hover{border-color:var(--accent)}
a.accrow:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* Triumph's catalogue accessories. A row, not a tile: the name and the part number are what a
   customer scans, and a grid of squares buries both. */
.acclist{display:grid;gap:10px;margin:0 0 30px}
.accrow{display:flex;gap:16px;align-items:center;padding:14px 16px;
  border:1px solid var(--edge);border-radius:2px;background:var(--page)}
.accrow--old{opacity:.72}
/* WHITE, not a tint. A Triumph line drawing is black ink on white paper, and a lot of them are
   sparse; on the pale panel this box used to have, a faint drawing read as an empty tile rather
   than as artwork. Paper behind ink, and a hairline so the box still has an edge. */
.accrow-pic{flex:0 0 92px;display:block;background:#fff;border:1px solid var(--edge);border-radius:2px}
.accrow-pic img{display:block;width:100%;height:auto;max-height:72px;object-fit:contain}
.accrow-main{flex:1 1 auto;min-width:0}
.accrow-name{font-size:16px;font-weight:600;line-height:1.3}
.accrow-sub{font-size:13px;opacity:.65;margin-top:3px}
.accrow-note{font-size:12.5px;opacity:.7;margin-top:5px;line-height:1.45}
.accrow-right{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;gap:8px;
  min-width:150px;text-align:right}
.accrow-right .btn{min-height:44px}
@media (max-width:640px){
  .accrow{flex-wrap:wrap}
  .accrow-right{min-width:0;width:100%;flex-direction:row;justify-content:space-between;align-items:center}
}

@media (max-width:520px){
  .grid.ftiles{grid-template-columns:repeat(2,1fr);gap:12px}
  .ftile-name{font-size:16px}
  .ftile-scope{display:none}
  .ychip{min-width:76px;font-size:18px;padding:12px 14px}
}



/* ---- the parts list pane ---------------------------------------------------
   Same story as '.stage': a grid item that will not shrink cannot scroll, and a list that
   cannot scroll paints over whatever follows the bench. */
.list{min-height:0;min-width:0}

/* ---- a stage with no drawing ----------------------------------------------
   Three of 26,960 Triumph road drawings are blank paper and several hundred accessory
   assemblies were never drawn. '<img src="img/null">' used to 404 into an empty canvas here. */
.sheet-wrap.nodwg{display:grid;place-items:center;padding:34px}
.nodwg-shot{margin:0;max-width:520px;text-align:center}
.nodwg-shot img{display:block;width:100%;height:auto;background:#fff;border:1px solid var(--edge);
  border-radius:2px}
.nodwg-shot figcaption{margin-top:14px;font-size:13.5px;line-height:1.55;color:var(--text-dim)}
.nodwg-none{max-width:460px;text-align:center;color:var(--text-dim)}
.nodwg-none h3{margin:0 0 10px;font-size:20px;color:var(--text)}
.nodwg-none p{margin:0;font-size:14.5px;line-height:1.6}

/* ---- accessory cards, the parts the road lane adds ------------------------ */
.acard-img.is-dwg{background:#fff}
.acard-img.is-dwg img{mix-blend-mode:multiply}
.acard-img.is-none{background:var(--muted)}
.acard-nopic{font-size:12.5px;color:var(--text-faint);text-align:center;padding:0 10px}
.acard-note{font-size:12px;color:var(--text-dim);margin-top:6px}
.acard--old{opacity:.78}
.acard--old .acard-img{filter:grayscale(1)}
.cat-n{font-weight:400;opacity:.55;margin-left:4px}
.accold{margin:6px 0 30px;border-top:1px solid var(--edge);padding-top:18px}
.accold summary{cursor:pointer;font:600 15px/1.4 Assistant,"Assistant Fallback",sans-serif;padding:6px 0;
  color:var(--text-dim)}
.accold summary:hover{color:var(--accent)}
.accold .grid{margin-top:18px}

/* ---- accessory detail popup, the same three picture states ---------------- */
.am.is-dwg{background:#fff}
.am.is-none{background:var(--muted)}
.ad-note{font-size:13px;line-height:1.55;color:var(--text-dim);margin:10px 0 0}

/* ---- the product photo panel ----------------------------------------------
   Selecting a photographed row brings Triumph's photograph up OVER the drawing rather than
   replacing it, so the diagram is one button away and no DOM is thrown out and rebuilt. */
.stage-shot{position:absolute;inset:0;z-index:3;background:var(--page);display:flex;
  flex-direction:column}
.stage-shot[hidden]{display:none}
.stage-shot-bar{display:flex;align-items:center;gap:14px;padding:11px 20px;
  border-bottom:1px solid var(--edge);background:var(--page);flex:0 0 auto}
.stage-shot-t{font-size:13.5px;color:var(--text-dim);min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.stage-shot-back{margin-left:auto;flex:0 0 auto;background:none;border:1px solid var(--edge);
  border-radius:2px;padding:8px 14px;min-height:38px;cursor:pointer;color:var(--text);
  font:600 13px/1 Assistant,"Assistant Fallback",sans-serif}
.stage-shot-back:hover{border-color:var(--accent);color:var(--accent)}
/* FLEX, not grid. A grid item's percentage max-height resolves against an auto-sized grid
   area, so 'max-height:100%' is circular there and the browser falls back to the intrinsic
   height — which is how a 1,600px product shot painted straight out of a 640px panel. A flex
   container's content box has a definite height, so the constraint actually binds. */
.stage-shot-fig{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;
  padding:26px;background:#fff;overflow:hidden}
.stage-shot-fig img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain}
@media (max-width:1080px){.stage-shot{position:static;border-bottom:1px solid var(--edge)}
  .stage-shot-fig{height:52vh}}

.acard-sup{color:var(--accent);text-decoration:none;border-bottom:1px solid transparent}
.acard-sup:hover{border-bottom-color:var(--accent)}

/* ---- tap targets ---------------------------------------------------------------------------
 * 72 interactive elements under 32px tall on a 393px accessories page (audit 2026-09-06). On a
 * coarse pointer every chip and small button clears 44px; a mouse keeps the compact metrics. */
/* A narrow phone: the row's right rail may wrap instead of pushing the list sideways, and the
   bike bar's controls wrap rather than push the page 22px wide at 320px (render gate, road). */
@media (max-width:480px){
  .bb-bike{flex-wrap:wrap;white-space:normal;row-gap:6px}
  .right{white-space:normal}
  .right .qtyctl{margin-left:0}
  .qtyctl .qtyb{width:34px}
}
@media (pointer:coarse){
  .cat,.btn-sm,.acctog,.ybtn-alt,.add,.acard-buy .btn,.bb-change,.btn.ghost,.egq,.fit-act{min-height:44px}
  .cat,.btn-sm,.acctog,.ybtn-alt,.bb-change,.egq{display:inline-flex;align-items:center}
  .add{display:inline-flex;align-items:center;justify-content:center}
  .qtyctl .qtyb{width:44px}
  .qtyctl{min-height:44px}
}


/* ── pre-rendered pages ─────────────────────────────────────────────────────── */

/* Real anchors, styled like the viewer's buttons. Underline only what reads as a text link.
 *
 * The :not(...) list is load-bearing, not tidiness. .cart sets its own colours in both states —
 * white on ink when it holds items, dimmed on muted when empty; in the viewer it is a <button>
 * so nothing fought it. Here it is an <a>, and a blanket a{color:inherit} repainted the total
 * to body ink — dark on dark. It rendered "visible" to every automated check and was invisible
 * to a person.
 *
 * NOTE FOR ANYONE EDITING THIS FILE: it is a template literal. No backticks in comments —
 * one here silently terminated the string and the whole stylesheet stopped compiling. */
body.seo a:not(.cart):not(.add){color:inherit}
/* Belt and braces. The :not() list above is the THIRD time this blanket rule has repainted a
   dark-backgrounded element into invisibility — first the cart total, now the "Ask the parts
   desk" action, which is an <a> on these pages and a <button> in the viewer. Every future dark
   element would have to remember to add itself to that list, which is not a pattern that holds.
   So anything wearing .add also states its own colour at a specificity the blanket cannot beat. */
body.seo a.add{color:var(--page)}
body.seo a{text-decoration:none}
body.seo .crumbs-in a,body.seo a.fit-link{text-decoration:underline;text-underline-offset:2px;
  text-decoration-thickness:1px;text-decoration-color:var(--edge)}
body.seo .crumbs-in a:hover,body.seo a.fit-link:hover{text-decoration-color:var(--accent);color:var(--accent)}
body.seo .foot a{text-decoration:underline;text-underline-offset:2px}

/* The search box is a real <form> here — it has no index of its own and hands off to the
   viewer — so it needs the flex sizing .search-wrap gets as a plain div. */
body.seo .search-wrap{margin:0 0 0 auto}
body.seo .cart{text-decoration:none}

/* Result rows: no icon column, and the subtitle is allowed to be a sentence. */
body.seo .res{grid-template-columns:1fr auto;gap:18px;padding:14px 2px;
  border-bottom:1px solid var(--edge-soft)}
body.seo .res:last-child{border-bottom:0}
body.seo .res-sub{white-space:normal;overflow:visible;text-overflow:clip}
body.seo .res-t{font-family:Oswald,sans-serif;font-weight:500;font-size:17px}
body.seo .list{border-left:0;overflow:visible;background:transparent}

/* Tiles are links now; keep the lift, drop the underline. */
body.seo .tile{padding:14px 16px;gap:3px}
body.seo .tile .pn{font-family:Oswald,sans-serif;font-weight:500;font-size:17px;line-height:1.25}
body.seo .tile .qty{font-size:13px;color:var(--text-dim)}
body.seo .tile .nm{font-size:14px;color:var(--text-dim);line-height:1.35}
body.seo .tile .price{font-family:Oswald,sans-serif;font-weight:500;font-size:16px;margin-top:6px}

/* ── the part page hero ─────────────────────────────────────────────────────── */
/* Deliberately NOT .row — .row is the callout table (36px callout | detail | right rail) and
   a part page has no callout. Its own three-column grid, collapsing to one on a phone. */
body.seo .phero{display:grid;grid-template-columns:minmax(0,1fr) minmax(180px,auto);
  gap:30px;align-items:start;padding:26px 0 30px;border-bottom:1px solid var(--edge)}
body.seo .phero.haspic{grid-template-columns:minmax(0,300px) minmax(0,1fr) minmax(180px,auto)}
body.seo .phero-media{border:1px solid var(--edge);border-radius:2px;background:var(--sheet);
  padding:14px;display:grid;place-items:center}
body.seo .phero-media img{width:100%;height:auto;display:block}
body.seo .phero-main{min-width:0;display:flex;flex-direction:column;gap:12px}
body.seo .phero-main .ad-desc{margin:0;color:var(--text-dim);line-height:1.55;max-width:62ch}
body.seo .phero-buy{display:flex;flex-direction:column;align-items:flex-end;gap:9px}
body.seo .phero-buy .price{font-family:Oswald,sans-serif;font-weight:500;font-size:30px;
  line-height:1;font-variant-numeric:tabular-nums}
body.seo .phero-buy .add{padding:11px 22px;font-size:15px}
body.seo .phero .supply{display:flex;flex-direction:column;gap:5px;align-items:flex-start}
@media (max-width:860px){
  body.seo .phero,body.seo .phero.haspic{grid-template-columns:1fr}
  body.seo .phero-buy{align-items:flex-start}
}

/* ── the diagram page ───────────────────────────────────────────────────────── */
/* The viewer's .sheet-wrap is a flex pane inside a fixed-height workbench; here the drawing
   is just a figure in the page flow, so the height constraint has to go or it collapses. */
body.seo .sheet-wrap{flex:none;height:auto;min-height:0;overflow:visible;padding:0;margin:6px auto 4px;
  display:block;background:var(--sheet);border:1px solid var(--edge);border-radius:2px}
/* Cap the drawing's height. At full width a tall fiche filled the viewport and pushed the
   whole buyable parts table below the fold — the drawing is the draw, but the table is the
   sale.
   THE BOX IS SIZED BEFORE THE IMAGE ARRIVES. The page carries the drawing's own width and
   height as --sw/--sh, so the wrapper holds its aspect ratio from the first paint instead of
   growing from an 86x54 placeholder when the JPEG lands — that growth collapsed the parts list
   beneath it for a CLS of 0.19 on a phone and 0.40 on a desktop, on 870 indexable pages. */
body.seo .sheet-wrap[style*="--sw"]{aspect-ratio:var(--sw)/var(--sh);
  max-width:min(100%,calc(66vh * var(--sw) / var(--sh)))}
body.seo .sheet-wrap img{display:block;width:auto;max-width:100%;height:auto;max-height:66vh;
  object-fit:contain;margin:0 auto}
body.seo .sheet-wrap[style*="--sw"] img{width:100%;height:100%;max-height:none}
body.seo .row{grid-template-columns:38px minmax(0,1fr) minmax(150px,auto);padding:14px 4px;
  border-bottom:1px solid var(--edge-soft)}
body.seo .row:last-child{border-bottom:0}
body.seo .row .right{display:flex;flex-direction:column;align-items:flex-end;gap:6px}
body.seo .row a.fit-link{display:block;text-decoration:none}
body.seo .row a.fit-link:hover .pn{color:var(--accent)}
body.seo .row a.fit-link .pn{text-decoration:underline;text-underline-offset:2px;
  text-decoration-color:var(--edge)}
@media (max-width:700px){
  body.seo .row{grid-template-columns:30px minmax(0,1fr);gap:10px}
  body.seo .row .right{grid-column:2;align-items:flex-start;margin-top:8px}
}

/* ── shared page furniture ──────────────────────────────────────────────────── */
body.seo .eyebrow{margin:34px 0 14px}
body.seo .page-head h1{margin:0 0 8px}
body.seo .hint{color:var(--text-dim);font-size:14px;line-height:1.6;max-width:76ch;margin:14px 0 0}
body.seo .foot{margin-top:52px;padding-top:26px;border-top:1px solid var(--edge);
  color:var(--text-faint);font-size:13.5px;line-height:1.6;max-width:80ch}
body.seo .foot p{margin:0 0 8px}
body.seo .doors{margin:26px 0 8px}
body.seo .door h2{margin:0 0 8px}
body.seo .door p{margin:0}

/* The non-buyable action is an <a href="tel:"> on these pages, not a <button>. Give it the
   same shape as the buttons beside it so the row does not look half-broken. */
body.seo a.add.ask{display:inline-flex;align-items:center;justify-content:center;
  text-decoration:none;white-space:nowrap}

/* ── the enquiry sheet on a pre-rendered page ───────────────────────────────── */
.seo-scrim{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:60;display:grid;
  place-items:center;padding:20px;overflow-y:auto}
.seo-sheet{position:relative;background:var(--page);color:var(--ink);border-radius:2px;
  box-shadow:var(--shadow);max-width:520px;width:100%;padding:28px 30px 24px;
  display:flex;flex-direction:column;gap:13px}
.seo-sheet h2{margin:0}
.seo-sheet .ad-desc{margin:0;color:var(--text-dim);line-height:1.55}
.seo-x{position:absolute;top:10px;right:12px;background:none;border:0;font-size:26px;
  line-height:1;cursor:pointer;color:var(--text-dim);padding:4px 8px}
.seo-x:hover{color:var(--ink)}
@media (max-width:620px){
  .seo-scrim{place-items:end center;padding:0}
  .seo-sheet{max-width:none;border-radius:0;padding:26px 20px 22px}
}

/* ---- the fitment answer ---------------------------------------------------------------
 * Five states, five readings, and the colour carries the same meaning as the words rather than
 * decorating them. Deliberately NOT a green tick / red cross: three of the five states are
 * neither yes nor no, and a two-colour system forces every one of them into the wrong bucket.
 * The not-listed state is amber, not red: Triumph not associating a part is not proof it will
 * not fit, and the colour must not overclaim any more than the wording does.
 *
 * Empty until seo.js has read the motorcycle context, so the box collapses rather than flashing
 * a claim we have not earned yet.
 */
.fitbox{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:18px 0 0;
  padding:13px 16px;border:1px solid var(--edge);border-left-width:3px;border-radius:2px;
  background:var(--page);font-size:15px}
.fitbox:empty{display:none;border:0;padding:0;margin:0}
.fit-msg{font-weight:600}
.fit-basis{font-size:13px;color:var(--text-dim)}
.fit-act{margin-left:auto;font-size:14px;font-weight:600;color:var(--accent);
  text-decoration:none;border-bottom:1px solid currentColor;padding-bottom:1px}
.fit-act:hover{opacity:.75}
.fitbox.fit-confirmed{border-left-color:var(--stock);background:var(--stock-bg)}
.fitbox.fit-confirmed .fit-msg{color:var(--stock)}
.fitbox.fit-listed{border-left-color:var(--accent)}
.fitbox.fit-vin-needed{border-left-color:var(--warn)}
.fitbox.fit-vin-needed .fit-msg{color:var(--warn)}
.fitbox.fit-not-listed{border-left-color:var(--warn)}
.fitbox.fit-excluded{border-left-color:var(--dead);background:var(--dead-bg)}
.fitbox.fit-excluded .fit-msg{color:var(--dead)}
.fitbox.fit-no-bike{border-left-color:var(--edge)}
/* The last-six field inside the bike bar on a static page: the vin-needed answer is settled
   right here, without leaving the part. */
.bb-vin{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:6px;font-size:13px;white-space:normal}
.bb-vin label{white-space:normal;flex:1 1 100%;line-height:1.4}
.bb-vin input{font:inherit;font-size:14px;padding:6px 9px;border:1px solid var(--edge);border-radius:2px;width:120px;
  text-transform:uppercase}
.bb-vin .btn-sm{padding:8px 12px}
.bb-msg.no{color:var(--warn);font-size:13px;margin-top:4px}
.fitbox.fit-no-bike .fit-msg{font-weight:500;color:var(--text-dim)}
@media (max-width:560px){.fit-act{margin-left:0;width:100%}}
