/* =============================================================================
   MotorcycleRidePlanner — HERITAGE
   The American motorcycle idiom riders actually expect: full-bleed photography,
   heavy uppercase gothic, square corners, black / white / one orange.
   Type is Libre Franklin — the open revival of Franklin Gothic, which is the
   face this whole category is set in.
   Not affiliated with, endorsed by, or imitating any motorcycle manufacturer.
   ========================================================================== */

:root{
  /* ---------------------------------------------------------------------
     DARK IS THE DEFAULT (Dean, 2026-09-14: "I would default to dark but let
     users toggle the color"). Light is one attribute away.

     Tokens are split by ROLE, not by colour name, because --white was doing
     two jobs: the page ground AND text sitting on dark chrome. In dark mode
     those move in opposite directions, so a straight swap broke the site.
       --surface / --panel / --chrome  are things you put behind content
       --ink / --steel / --smoke       are things you write with
       --white / --black               stay literal, for text on dark chrome
                                       and for the rare always-dark element
     --------------------------------------------------------------------- */
  /* 2026-10-08 design brief: canvas/sheet/text/secondary/separator/orange replace the
     values below in place (same roles, same call sites) so every page that links this
     file picks up the brief's palette without a markup change. --chrome/--chrome2/--white
     /--stone are not brief tokens (the utility bar is deliberately dark in both themes)
     and are left as they were. */
  --surface:#111515;        /* canvas: page and card ground */
  --panel:#202222;          /* sheet: the quieter panel that was --stone */
  --chrome:#000000;         /* utility bar, hero grounds, badges */
  --chrome2:#0A0A0A;        /* the darker chrome that was --ink */
  --rule:#434844;           /* separator */
  /* .util/.foot's own ground, split off from --chrome (WBH dr-c, 2026-11-08). plan.css
     redefines --chrome on :root to equal --surface, for its OWN map/card chrome, which on
     plan.html silently overwrote the "stays dark in both themes" contract .util/.foot were
     built on - in light theme --chrome there resolves to #F8F5EF (cream), so the header
     nav and footer links/logo, all light-on-dark colours, landed on cream at ~1.5:1. A
     name plan.css never sets stays correct regardless of what it does to --chrome. */
  --util-chrome:#000000;

  --ink:#F8F5EF;            /* text */
  --steel:#B8BDB8;          /* secondary */
  --smoke:#868C87;          /* faintest text, not a named brief token */

  --black:#181B1A;          /* brief's dark text, used ON the orange and other light fills */
  --white:#FFFFFF;
  --stone:#1B1B1B;
  --text-strong:#F8F5EF;    /* headings that were near-black on a light ground */

  --orange:#FF7A1A;         /* brief primary, same value in both themes */
  --orange-dk:#D9630E;

  --gothic:"Libre Franklin","Franklin Gothic Medium","Arial Narrow",
           system-ui,-apple-system,sans-serif;
  --page:1320px;
  --gut:26px;
  color-scheme:dark;
}

:root[data-theme="light"]{
  --surface:#F8F5EF;
  --panel:#FFFFFF;
  --chrome:#0A0A0A;
  --chrome2:#1A1A1A;
  --util-chrome:#0A0A0A;
  --rule:#D8D9D4;

  --ink:#181B1A;
  --steel:#606661;
  --smoke:#9DA39E;

  --black:#181B1A;
  --white:#FFFFFF;
  --stone:#F2F2F0;
  --text-strong:#181B1A;

  --orange:#FF7A1A;
  --orange-dk:#D9630E;
  color-scheme:light;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--surface);color:var(--ink);
  font-family:var(--gothic);font-weight:400;
  -webkit-font-smoothing:antialiased;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
:focus-visible{outline:3px solid var(--orange);outline-offset:2px}

.shell{max-width:var(--page);margin:0 auto;padding:0 var(--gut)}

/* ------------------------------ utility bar ------------------------------ */
.util{background:var(--util-chrome);color:#CFCFCF}
.util .shell{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:10px 26px;align-items:center;min-height:36px;padding:5px 0}
.util a{font-size:11.5px;font-weight:600;letter-spacing:.055em;text-transform:uppercase;
  /* 19px tall was not a tap target, it was a dare — and on the one bar of this site that
     every page shows, for the riders this whole text-size work is for. */
  display:inline-flex;align-items:center;min-height:40px}
.util .themeb{min-height:40px}
.util a:hover{color:var(--white)}

/* -------------------------------- masthead ------------------------------- */
.mast{background:var(--surface);border-bottom:1px solid var(--rule)}
.mast .shell{display:flex;align-items:center;gap:38px;height:70px}
.mark{display:flex;align-items:center;gap:11px;flex:none}
/* THE MARK (WBH-4269).
 *
 * This was the letters M R P set in the body font inside a dark square, which is a
 * placeholder, not an identity. The approved artwork is the machined monogram with the
 * road carved through the R and P and the route ending in a node - so use that artwork
 * rather than a redraw of it.
 *
 * It is a background-image on an empty span, not an <img>, for one reason: the theme
 * has to swap it and CSS cannot rewrite a src. The adjacent <b>Motorcycle Ride
 * Planner</b> carries the accessible name, so the span stays decorative.
 *
 * Silver on the dark ground the site defaults to; the one-colour black version on the
 * light one, where brushed silver goes weak. Masters and the full-resolution cuts live
 * in assets/brand/logo-set-imagegen-v3/. */
.mark-badge{
  width:129px;height:36px;flex:none;
  background:url('../assets/brand/mrp-mark-silver.png') left center/contain no-repeat;
}
:root[data-theme="light"] .mark-badge{
  background-image:url('../assets/brand/mrp-mark-black.png');
}
/* ...except in the footer, which keeps its dark chrome ground in BOTH themes. The black
   mark would vanish into it. */
:root[data-theme="light"] .foot .mark-badge{
  background-image:url('../assets/brand/mrp-mark-silver.png');
}
.mark b{
  font-weight:800;font-size:15.5px;letter-spacing:-.005em;text-transform:uppercase;
  line-height:1.05;color:var(--text-strong);
}
.mark b i{display:block;font-style:normal;font-weight:600;font-size:9.5px;
  letter-spacing:.16em;color:var(--steel)}
/* The masthead drops the spelled-out name, because the mark now says it.
 *
 * With both, "MOTORCYCLE RIDE PLANNER" in bold caps sat immediately right of a logo
 * whose whole job is to be that name, and the 230px it cost pushed the bar over its
 * budget: "Plan a ride" broke onto THREE lines inside a one-line nav and the search
 * field ran off the right edge. The footer still carries the full name, which is where
 * a reader who has scrolled that far actually wants it spelled out. */
.mast .mark{flex-direction:column;align-items:flex-start;gap:5px}
.mark-est{font-size:9.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  color:var(--steel);line-height:1}

/* A nav item that wraps mid-phrase reads as a broken layout, so they never wrap; the
   gap gives way instead. The item list has grown (ride handoff, club invitations,
   diagnostics...) past what 1280-1600px can hold in one row without this: a flex item
   with nowrap children refuses to shrink below its content width by default, so the
   overflow used to push the whole document sideways. min-width:0 + overflow-x:auto
   contains that scroll inside the nav itself, same pattern as .filters below. */
.mast nav{display:flex;gap:clamp(15px,1.9vw,28px);margin-left:6px;
  min-width:0;overflow-x:auto;scrollbar-width:none}
.mast nav::-webkit-scrollbar{display:none}
.mast .mark,.mast form{flex-shrink:0}
.mast nav a{white-space:nowrap}
.mast nav a{
  font-size:13px;font-weight:800;letter-spacing:.045em;text-transform:uppercase;
  color:var(--text-strong);padding:4px 0;border-bottom:3px solid transparent;
}
.mast nav a:hover{border-bottom-color:var(--orange)}
.mast nav a.on{border-bottom-color:var(--orange)}
.mast form{margin-left:auto;display:flex;align-items:center}
.mast input{
  font-family:var(--gothic);font-size:13px;border:1px solid var(--rule);
  padding:9px 13px;min-width:230px;background:var(--surface);color:var(--ink);
}
.mast input::placeholder{color:var(--smoke)}

/* ------------------------------ promo strip ------------------------------ */
.promo{background:var(--orange);color:var(--white)}
.promo .shell{display:flex;align-items:center;justify-content:center;gap:10px;height:42px;text-align:center}
.promo p{margin:0;font-size:13px;font-weight:700;letter-spacing:.02em}
.promo a{text-decoration:underline;font-weight:800}

/* --------------------------------- hero ---------------------------------- */
.hero{position:relative;background:var(--chrome);overflow:hidden}
.hero-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 58%}
.hero::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,rgba(0,0,0,.82) 0%,rgba(0,0,0,.55) 38%,rgba(0,0,0,.08) 72%,rgba(0,0,0,.25) 100%);
}
.hero-body{position:relative;z-index:2;padding:112px 0 118px;color:var(--white)}
.hero-eyebrow{
  font-size:13px;font-weight:800;letter-spacing:.13em;text-transform:uppercase;
  margin:0 0 16px;color:var(--white);
}
.hero h1{
  font-weight:900;font-size:clamp(44px,7.2vw,92px);line-height:.92;letter-spacing:-.022em;
  text-transform:uppercase;margin:0 0 20px;max-width:16ch;
}
.hero h1 em{font-style:normal;color:var(--orange)}
.hero p.sub{
  font-size:17px;line-height:1.5;max-width:46ch;margin:0 0 30px;color:#E6E6E6;font-weight:400;
}
/* A button never pushes the page wider than the phone it is on. The Clubhouse contact
   button is a whole email address in uppercase with 48px of padding - one unbreakable
   token, 58px past the edge of a 390px screen, and the sideways scroll it caused was on
   every section of that page, not just the button. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:13px;
  background:var(--surface);color:var(--text-strong);
  font-size:14px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  padding:16px 24px;border:0;max-width:100%;overflow-wrap:anywhere;text-align:center;
}
.btn:hover{background:var(--orange);color:var(--white)}
.btn.ghost{background:transparent;color:var(--white);box-shadow:inset 0 0 0 2px var(--white)}
.btn.ghost:hover{background:var(--surface);color:var(--text-strong)}
.btn-row{display:flex;gap:14px;flex-wrap:wrap}
.hero-credit{
  position:absolute;right:14px;bottom:10px;z-index:3;font-size:10.5px;color:rgba(255,255,255,.62);
}
.hero-credit a{text-decoration:underline}

/* ------------------------------- filter row ------------------------------ */
.filters{border-bottom:1px solid var(--rule);background:var(--surface)}
.filters .shell{display:flex;gap:10px;overflow-x:auto;padding-top:18px;padding-bottom:18px}
.chip{
  flex:none;font-size:12.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  padding:11px 18px;border:1px solid var(--rule);background:var(--surface);color:var(--text-strong);
  white-space:nowrap;cursor:pointer;font-family:var(--gothic);
}
.chip:hover{border-color:var(--black)}
.chip.on{background:var(--chrome);color:var(--white);border-color:var(--black)}

/* -------------------------------- section -------------------------------- */
.sec{padding:62px 0 0}
.sec-head{display:flex;align-items:flex-end;justify-content:space-between;gap:26px;margin-bottom:26px}
.sec-head h2{
  font-weight:900;font-size:clamp(26px,3.4vw,40px);line-height:1;letter-spacing:-.02em;
  text-transform:uppercase;margin:0;
}
.sec-head p{margin:0;font-size:15px;color:var(--steel);max-width:44ch;line-height:1.5}
.sec-head a{font-size:13px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  border-bottom:3px solid var(--orange);padding-bottom:3px;white-space:nowrap}

/* --------------------------------- cards --------------------------------- */
.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:26px}
.rcard{background:var(--surface);display:flex;flex-direction:column}
.rcard-media{position:relative;aspect-ratio:4/3;overflow:hidden;background:var(--panel)}
.rcard-media img{width:100%;height:100%;object-fit:cover;transition:transform .5s cubic-bezier(.2,.7,.3,1)}
.rcard:hover .rcard-media img{transform:scale(1.04)}
.rcard-tag{
  position:absolute;left:0;top:0;background:var(--orange);color:var(--white);
  font-size:11px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;padding:7px 12px;
}
.rcard-body{padding:18px 0 0;display:flex;flex-direction:column;flex:1}
.rcard h3{
  font-weight:900;font-size:21px;line-height:1.08;letter-spacing:-.012em;text-transform:uppercase;
  margin:0 0 7px;
}
.rcard .where{font-size:12.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--steel);margin:0 0 11px}
.rcard p{font-size:14.5px;line-height:1.55;color:var(--steel);margin:0 0 16px;flex:1}
.rspecs{display:flex;gap:0;border-top:2px solid var(--black)}
.rspecs div{flex:1;padding:12px 10px 12px 0}
.rspecs b{display:block;font-weight:900;font-size:19px;line-height:1;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.rspecs span{display:block;margin-top:5px;font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--steel)}

/* ------------------------------- stat band ------------------------------- */
.band{background:var(--chrome);color:var(--white);margin-top:66px;padding:54px 0 58px}
.band-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:0}
.band-cell{padding:0 26px;border-left:1px solid #2A2A2A}
.band-cell:first-child{border-left:none;padding-left:0}
.band-cell b{display:block;font-weight:900;font-size:clamp(34px,4.4vw,54px);line-height:.95;
  letter-spacing:-.03em;color:var(--orange);font-variant-numeric:tabular-nums}
.band-cell span{display:block;margin-top:12px;font-size:11.5px;font-weight:800;letter-spacing:.12em;
  text-transform:uppercase;color:#B5B5B5}

/* --------------------------------- table --------------------------------- */
.tbl-head{background:var(--chrome);color:var(--white);padding:44px 0 34px}
.tbl-head h1{font-weight:900;font-size:clamp(34px,5vw,58px);line-height:.95;letter-spacing:-.025em;
  text-transform:uppercase;margin:0 0 12px}
.tbl-head p{margin:0;font-size:16px;color:#C6C6C6;max-width:56ch;line-height:1.5}
.ctrls{border-bottom:1px solid var(--rule);background:var(--surface);position:sticky;top:0;z-index:40}
.ctrls .shell{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding-top:14px;padding-bottom:14px}
.ctrls select,.ctrls input{
  font-family:var(--gothic);font-size:13px;font-weight:600;border:1px solid var(--rule);
  padding:10px 12px;background:var(--surface);color:var(--ink);
}
.ctrls input{min-width:230px}
.ctrls .tally{margin-left:auto;font-size:12px;font-weight:800;letter-spacing:.08em;
  text-transform:uppercase;color:var(--steel);font-variant-numeric:tabular-nums}
table.roads{width:100%;border-collapse:collapse}
table.roads th{
  text-align:left;font-size:10.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  color:var(--steel);padding:16px 16px 12px 0;border-bottom:2px solid var(--black);white-space:nowrap;
}
table.roads th.num,table.roads td.num{text-align:right;font-variant-numeric:tabular-nums}
table.roads td{padding:16px 16px 16px 0;border-bottom:1px solid var(--rule);vertical-align:middle}
table.roads tbody tr:hover{background:var(--panel)}
.road-nm{font-weight:900;font-size:16px;text-transform:uppercase;letter-spacing:-.01em;line-height:1.12}
.road-where{display:block;font-size:11.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--steel);margin-top:4px}
.tag{
  display:inline-block;font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  background:var(--chrome);color:var(--white);padding:5px 9px;white-space:nowrap;
}
td.num b{font-weight:900;font-size:16px}
.bar{display:inline-flex;align-items:center;gap:9px;font-weight:800;font-variant-numeric:tabular-nums}
.bar i{display:block;width:46px;height:6px;background:var(--rule);position:relative}
.bar i u{position:absolute;inset:0 auto 0 0;background:var(--orange);display:block;text-decoration:none}
.none{padding:52px 0;text-align:center;color:var(--steel);font-weight:700;text-transform:uppercase;letter-spacing:.08em}

/* -------------------------------- credits -------------------------------- */
.creds{list-style:none;margin:0;padding:0}
/* min-width:0 on the text column, because a grid 1fr refuses to shrink below its
   content's minimum and some of these are raw Wikimedia filenames with no space in
   them - "File:Digging for Iron Mountain RR right of way at..." ran 141px off a 360px
   phone and took the whole page sideways with it. anywhere lets the filename break. */
.creds li{display:grid;grid-template-columns:130px minmax(0,1fr);gap:20px;align-items:center;
  padding:18px 0;border-bottom:1px solid var(--rule)}
.creds li > div{min-width:0;overflow-wrap:anywhere}
.creds img{width:130px;height:84px;object-fit:cover}
.creds b{display:block;font-weight:800;font-size:15px;text-transform:uppercase;letter-spacing:-.005em}
.creds span{display:block;font-size:13px;color:var(--steel);margin-top:4px;line-height:1.5}
.creds a{text-decoration:underline}

/* --------------------------------- footer -------------------------------- */
.foot{background:var(--util-chrome);color:#9A9A9A;padding:46px 0 54px;margin-top:0}
.foot .shell{display:flex;justify-content:space-between;gap:28px;flex-wrap:wrap;align-items:flex-start}
.foot .mark b{color:var(--white)}
/* .mark b i ("Measured, not crowdsourced") inherits var(--steel), which is #606661 in
   light theme - fine on the --surface/--panel grounds --steel is tuned for, but the
   footer keeps its dark chrome ground in BOTH themes (see the mark-badge override
   above), so that resolved to 3.37:1 on #0A0A0A. Pin it to the footer's own base grey
   instead of the theme token: 7:1+ on chrome in both themes (WBH dr-c). */
.foot .mark b i{color:#9A9A9A}
.foot nav{display:flex;gap:24px;flex-wrap:wrap}
.foot a{font-size:12px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;color:#C9C9C9}
.foot a:hover{color:var(--orange)}
/* Was #6E6E6E: 3.88:1 on light-theme chrome (#0A0A0A) and 4.12:1 on dark-theme chrome
   (#000), both under the 4.5:1 floor for this 11px text. #9A9A9A matches .foot's own
   base colour above and clears 7:1+ against both (WBH dr-c). */
.foot small{display:block;width:100%;font-size:11px;line-height:1.6;color:#9A9A9A;margin-top:8px}

/* ------------------------------- responsive ------------------------------ */
/* The footer mark is badge + full name on one row, and the badge is now 129px rather
   than a 40px square. On a 390px phone that row ran 9px past the viewport and gave the
   whole page a sideways scroll. Stack it instead of shrinking the mark. */
@media (max-width:560px){
  .foot .mark{flex-direction:column;align-items:flex-start;gap:9px}
}
@media (max-width:1040px){
  .grid{grid-template-columns:repeat(2,1fr)}
  .band-grid{grid-template-columns:repeat(2,1fr);gap:30px 0}
  .band-cell:nth-child(3){border-left:none;padding-left:0}
  .mast nav{display:none}
}
@media (max-width:680px){
  .grid{grid-template-columns:1fr}
  .band-grid{grid-template-columns:1fr}
  .band-cell{border-left:none;padding-left:0}
  .hero-body{padding:74px 0 78px}
  .util .shell{gap:8px 16px;justify-content:center}
  .mast form{display:none}
  .sec-head{flex-direction:column;align-items:flex-start;gap:12px}
  .ctrls .tally{margin-left:0;width:100%}
  .creds li{grid-template-columns:92px 1fr}
  .creds img{width:92px;height:62px}
}
/* The Index turns from a table into a card list well before a phone.
 *
 * These rules used to sit in the 680px block, which left a band from 681px to about
 * 880px - a tablet held upright, a large phone on its side - where the roads table was
 * still a table and 113px wider than the screen. The whole page scrolled sideways to
 * show one truncated column. The table's natural width is around 830px, so the cards
 * take over before that is in doubt. */
@media (max-width:920px){
  table.roads thead{display:none}
  table.roads,table.roads tbody,table.roads tr,table.roads td{display:block;width:100%}
  table.roads tr{padding:16px 0;border-bottom:1px solid var(--rule)}
  table.roads td{border:none;padding:3px 0;text-align:left!important}
  table.roads td[data-l]::before{content:attr(data-l) " ";font-size:10px;font-weight:800;
    letter-spacing:.1em;text-transform:uppercase;color:var(--steel)}
}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}

/* ------------------------------ road map -------------------------------- */
.mapsec{padding:62px 0 0}
.mapwrap{position:relative;margin-top:26px;background:var(--chrome)}
#roadmap{width:100%;height:clamp(380px,54vh,620px)}
.maplegend{
  position:absolute;left:0;bottom:0;z-index:2;display:flex;align-items:center;gap:10px;
  background:var(--chrome);color:var(--white);padding:12px 18px;
  font-size:11.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
}
.maplegend .dot{width:11px;height:11px;background:var(--orange);display:block;border-radius:50%}
.mapfallback{
  padding:60px 24px;text-align:center;color:#B5B5B5;font-weight:700;
  letter-spacing:.05em;text-transform:uppercase;font-size:13px;margin:0;
}
.mapfallback a{color:var(--orange);text-decoration:underline}

/* popup, restyled out of maplibre's default rounded white bubble */
.maplibregl-popup-content{
  background:var(--chrome);color:var(--white);border-radius:0;padding:16px 18px 18px;
  box-shadow:0 10px 30px rgba(0,0,0,.5);
}
.maplibregl-popup-tip{display:none}
.maplibregl-popup-close-button{color:#9A9A9A;font-size:19px;padding:2px 8px}
.maplibregl-popup-close-button:hover{background:transparent;color:var(--orange)}
.mappop h4{
  font-family:var(--gothic);font-weight:900;font-size:16px;line-height:1.12;margin:0 0 5px;
  text-transform:uppercase;letter-spacing:-.01em;color:var(--white);
}
.mappop-where{
  font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:#9A9A9A;margin:0 0 13px;
}
.mappop-figs{display:flex;gap:18px;border-top:2px solid var(--orange);padding-top:11px;margin-bottom:13px}
.mappop-figs b{display:block;font-weight:900;font-size:16px;line-height:1;font-variant-numeric:tabular-nums}
.mappop-figs span{display:block;margin-top:4px;font-size:9px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;color:#9A9A9A}
.mappop-go{
  font-size:11.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  color:var(--orange);border-bottom:2px solid var(--orange);padding-bottom:2px;
}

/* =============================================================================
   DISCOVER — the signed-off split-screen concept, in Heritage.
   Feed left, live map right, both alive at once. Real SVG icons, no emoji.
   The map container is EXPLICITLY bounded: the old build let it inherit auto
   height and it grew to 43,898px, past the WebGL canvas cap, rendering blank.
   ========================================================================== */
.dsc{display:grid;grid-template-columns:minmax(360px,440px) 1fr;
     height:calc(100vh - 148px);min-height:520px;border-top:1px solid var(--rule)}
.dsc-feed{display:flex;flex-direction:column;border-right:1px solid var(--rule);background:var(--surface);
     min-width:0;min-height:0}   /* min-height:0 — grid items default to min-height:auto, which
                                    lets 252 cards push the row (and the map) to 32,853px. This
                                    single declaration is the whole fix, and it is the same class
                                    of bug that made the old cockpit map 43,898px tall. */
/* Discover's heading. The tools are the interface on this page, so it sits above them
   at body weight rather than as a banner - present for a screen reader and a crawler,
   quiet for everyone else. */
.dsc-h1{font-size:calc(17px * var(--ts));font-weight:800;letter-spacing:.01em;
  margin:0;padding:16px 18px 0}
.dsc-tools{padding:14px 18px;border-bottom:1px solid var(--rule);display:flex;flex-direction:column;gap:10px;flex:none}
.dsc-tools input,.dsc-tools select{
  font-family:var(--gothic);font-size:13px;font-weight:600;border:1px solid var(--rule);
  padding:10px 12px;background:var(--surface);color:var(--ink);width:100%}
/* The filter row holds 924px of chips. On a 354px phone that meant four of the six
   were off the right-hand edge, reachable only by a sideways swipe on a screen whose
   every other gesture pans the map underneath. A rider cannot filter by a control he
   cannot see, and the brief asks this row to fit the screen. It wraps now: every
   category visible at once, which is the point of browsing by chips. No change on a
   desktop, where they already fit on one line and nothing wraps. */
.dsc-chips{display:flex;flex-wrap:wrap;gap:8px;padding-bottom:2px}
.dsc-chip{
  flex:none;display:inline-flex;align-items:center;gap:7px;font-family:var(--gothic);
  font-size:11.5px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  padding:9px 13px;border:1px solid var(--rule);background:var(--surface);color:var(--text-strong);
  white-space:nowrap;cursor:pointer}
.dsc-chip svg{width:15px;height:15px;flex:none}
.dsc-chip:hover{border-color:var(--black)}
.dsc-chip[aria-pressed="true"]{background:var(--chrome);color:var(--white);border-color:var(--black)}
.dsc-count{font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--steel);
  padding:0 18px 12px;flex:none;font-variant-numeric:tabular-nums}
/* the feed scrolls INSIDE itself — it must never grow the page */
.dsc-list{flex:1;overflow-y:auto;overscroll-behavior:contain}
.dsc-card{display:block;width:100%;text-align:left;background:var(--surface);border:0;
  border-bottom:1px solid var(--rule);padding:16px 18px;cursor:pointer;font-family:var(--gothic)}
.dsc-card:hover{background:var(--panel)}
.dsc-card[aria-current="true"]{background:var(--panel);box-shadow:inset 4px 0 0 var(--orange)}
.dsc-card h3{font-weight:900;font-size:15.5px;line-height:1.14;letter-spacing:-.012em;
  text-transform:uppercase;margin:0 0 4px;display:flex;align-items:center;gap:8px}
/* THE ROAD'S MARK. Dean: "ToTD and miner have logos." Sized to be recognised, not read -
   it sits left of the name the way a route shield does on a sign. Our own silhouette is
   the default and the fallback; a hosted third-party logo takes the same slot, which is
   what makes removing one a no-op for the layout. */
.dsc-mark{flex:0 0 auto;width:26px;height:26px;display:grid;place-items:center}
.dsc-mark svg{width:100%;height:100%;overflow:visible}
.dsc-mark svg path{fill:none;stroke:var(--orange);stroke-width:7;
  stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke}
/* A published logo is usually a banner, not a square. The Tail of the Dragon mark is
   341x150; forced into the 26px square slot it is an unreadable smudge. So the logo
   variant sizes to its own aspect and is shown WHOLE - which is also the more defensible
   position, since cropping somebody's mark makes a derivative of it. */
.dsc-mark--logo{width:auto;max-width:74px;height:24px}
.dsc-mark--logo img{width:auto;max-width:74px;height:100%;object-fit:contain;display:block}
.dsc-card[aria-current="true"] .dsc-mark svg path{stroke:var(--black)}
.dsc-where{font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--steel);margin:0 0 11px}
.dsc-figs{display:flex;gap:18px;border-top:2px solid var(--black);padding-top:9px}
.dsc-figs b{display:block;font-weight:900;font-size:15px;line-height:1;font-variant-numeric:tabular-nums}
.dsc-figs span{display:block;margin-top:4px;font-size:9px;font-weight:800;letter-spacing:.12em;
  text-transform:uppercase;color:var(--steel)}
/* Ad slot: BETWEEN cards, never above the first. Mirrors the signed-off board. */
.dsc-ad{border-bottom:1px solid var(--rule);padding:14px 18px;background:var(--panel)}
.dsc-ad span{display:block;font-size:9px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--smoke);margin-bottom:6px}
.dsc-ad p{margin:0;font-size:12.5px;color:var(--steel);line-height:1.45}
/* House ad. Our own mark on a true black plate so it reads as ours rather than as
   a card that failed to load. Contained height: a logo that dwarfs the road cards
   around it is an advert for us at the expense of the thing people came for. */
.dsc-ad--house img{display:block;width:100%;max-width:230px;height:auto;
  max-height:64px;object-fit:contain;background:#000;border-radius:7px;
  padding:9px 12px;margin:0 0 9px}
.dsc-map{position:relative;min-width:0;min-height:0;background:var(--chrome)}
.dsc-map #dscmap{position:absolute;inset:0}   /* bounded by the grid row, never auto */
.dsc-empty{padding:44px 18px;text-align:center;color:var(--steel);font-weight:700;
  text-transform:uppercase;letter-spacing:.08em;font-size:12px}

@media (max-width:900px){
  .dsc{grid-template-columns:1fr;height:auto}
  .dsc-map{height:44vh;min-height:280px;order:-1}      /* map on top, always visible */
  .dsc-feed{border-right:0}
  .dsc-list{max-height:none;overflow:visible}
}

/* 3D terrain toggle — sits on the map, Heritage square, one accent */
.dsc-3d{
  position:absolute;left:14px;top:14px;z-index:3;font-family:var(--gothic);
  font-size:11.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  padding:10px 14px;border:0;background:var(--surface);color:var(--text-strong);cursor:pointer}
.dsc-3d:hover{background:var(--orange);color:var(--white)}
.dsc-3d[aria-pressed="true"]{background:var(--orange);color:var(--white)}

/* ------------------------ discover map click popup ------------------------
   Route information plus an overview of the road's own shape, per Dean
   2026-09-14. The shape is the real OSM track, normalised; roads without
   geometry omit it rather than showing a placeholder. */
.dpop-wrap .maplibregl-popup-content{
  padding:0;border-radius:0;border:1px solid var(--black);
  box-shadow:0 10px 30px rgba(0,0,0,.34);background:var(--surface);overflow:hidden}
.dpop-wrap .maplibregl-popup-tip{border-top-color:var(--black)}
.dpop-wrap .maplibregl-popup-close-button{
  font-size:20px;color:var(--white);background:var(--chrome);width:26px;height:26px;
  line-height:1;border-radius:0;right:0;top:0}
.dpop-wrap .maplibregl-popup-close-button:hover{background:var(--orange)}
.dpop{display:grid;grid-template-columns:96px 1fr;gap:0;align-items:stretch}
.dpop-shape{width:96px;height:auto;min-height:96px;align-self:stretch;
  background:var(--chrome);padding:8px;display:block}
.dpop-shape path{fill:none;stroke:var(--orange);stroke-width:2.6;
  stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke}
.dpop-b{padding:12px 13px;min-width:0}
.dpop-where{margin:0 0 4px;font-size:9.5px;font-weight:700;letter-spacing:.15em;
  text-transform:uppercase;color:var(--steel)}
.dpop-b h3{margin:0 0 7px;font-size:15px;font-weight:800;letter-spacing:-.012em;
  line-height:1.2;color:var(--text-strong)}
.dpop-stats{margin:0 0 10px;font-size:11.5px;color:var(--steel);
  font-variant-numeric:tabular-nums}
.dpop-stats b{color:var(--ink);font-weight:800}
.dpop-stats i{font-style:normal;color:var(--rule);margin:0 6px}
.dpop-go{display:inline-block;background:var(--orange);color:#fff;padding:7px 12px;
  font-size:10.5px;font-weight:800;letter-spacing:.11em;text-transform:uppercase}
.dpop-go:hover{background:var(--orange-dk)}
/* no geometry: let the text use the full width instead of leaving a black hole */
.dpop:not(:has(.dpop-shape)){grid-template-columns:1fr}
.dpop-badge{display:inline-block;margin-left:7px;background:var(--orange);color:#fff;
  padding:2px 6px;font-size:8.5px;font-weight:800;letter-spacing:.11em;
  text-transform:uppercase;vertical-align:1px}

/* ------------------------- discover card thumbnail ------------------------
   A vista on the card where we have one (Dean, 2026-09-14). Where we do not,
   the road's own shape stands in, so a card never shows an empty grey box and
   never shows a picture of somewhere else. */
.dsc-thumb{display:block;width:100%;aspect-ratio:16/9;overflow:hidden;
  background:var(--chrome);margin:0 0 11px;position:relative}
.dsc-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.dsc-thumb--shape{display:grid;place-items:center;padding:8px}
.dsc-thumb--shape svg{width:auto;height:100%;max-width:100%}
.dsc-thumb--shape path{fill:none;stroke:var(--orange);stroke-width:2.4;
  stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke}
@supports not (aspect-ratio:16/9){.dsc-thumb{height:150px}}

/* ------------------------------ detail sheet ------------------------------
   Dean, 2026-09-14: "pops up as screen on the map, not the side. Keep the side
   too." So the feed is untouched and the detail rises over the map instead. It
   is inset rather than full-bleed so the map stays legible behind it and you
   keep your bearings. */
.dsc-sheet{position:absolute;left:0;right:0;bottom:0;z-index:5;
  background:var(--surface);border-top:3px solid var(--orange);
  box-shadow:0 -16px 44px rgba(0,0,0,.4);
  display:grid;grid-template-columns:230px 1fr;max-height:78%;
  animation:sheet-in .22s cubic-bezier(.2,.7,.3,1)}
.dsc-sheet[hidden]{display:none}
@keyframes sheet-in{from{transform:translateY(14px);opacity:0}to{transform:none;opacity:1}}
@media (prefers-reduced-motion:reduce){.dsc-sheet{animation:none}}

.dsh-detent{display:none}
.dsh-content{display:contents}

.dsh-media{background:var(--chrome);position:relative;overflow:hidden;min-height:170px}
/* The terrain view is the lead image, so it gets real height and a true black
   ground: Dean asked for the 3D layer on the slide and to keep it black. */
.dsh-media--3d{background:#000;min-height:230px}
.dsh-media--3d #dsh3d{position:absolute;inset:0}
.dsh-media--3d .maplibregl-canvas{outline:none}
.dsh-media img{width:100%;height:100%;object-fit:cover;display:block}
.dsh-media svg{width:100%;height:100%;padding:16px;display:block}
.dsh-media path{fill:none;stroke:var(--orange);stroke-width:2.6;
  stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke}

.dsh-b{padding:18px 20px 20px;min-width:0;overflow:auto}
.dsh-top{display:flex;justify-content:space-between;align-items:flex-start;gap:14px}
.dsh-where{margin:0 0 5px;font-size:10px;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--steel)}
.dsh-badge{display:inline-block;margin-left:8px;background:var(--orange);color:#fff;
  padding:2px 7px;font-size:8.5px;font-weight:800;letter-spacing:.12em;
  text-transform:uppercase;vertical-align:1px}
.dsh-b h3{margin:0 0 12px;font-size:clamp(18px,2.3vw,25px);font-weight:900;
  letter-spacing:-.018em;line-height:1.08;text-transform:uppercase;color:var(--text-strong)}
.dsh-close{flex:none;width:32px;height:32px;border:1px solid var(--rule);background:var(--surface);
  font-size:19px;line-height:1;cursor:pointer;color:var(--ink)}
.dsh-close:hover{background:var(--chrome);color:var(--white);border-color:var(--black)}

.dsh-figs{display:flex;gap:0;border:1px solid var(--rule);margin:0 0 14px;flex-wrap:wrap}
.dsh-figs div{padding:10px 14px;border-right:1px solid var(--rule);min-width:82px}
.dsh-figs div:last-child{border-right:0}
.dsh-figs b{display:block;font-size:19px;font-weight:900;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;line-height:1.1}
.dsh-figs span{display:block;font-size:9.5px;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--steel);margin-top:3px}
.dsh-acts{display:flex;gap:9px;flex-wrap:wrap}
.dsh-acts a{display:inline-block;padding:11px 16px;font-size:10.5px;font-weight:800;
  letter-spacing:.12em;text-transform:uppercase;background:var(--orange);color:#fff}
.dsh-acts a:hover{background:var(--orange-dk)}
.dsh-acts a.ghost{background:var(--surface);color:var(--ink);border:1px solid var(--ink)}
.dsh-acts a.ghost:hover{background:var(--chrome2);color:var(--white)}

@media(max-width:760px){
  /* Both detents need a definite block size. Previously the sheet only had a
     max-height, so the percentage max-height on .dsh-content could not resolve;
     the content kept its full 519px height and painted through the 359px sheet.
     Keep the compact sheet in the map, but let the reading detent use the phone
     viewport so it is meaningfully larger than compact on short map panels. */
  .dsc-sheet{display:flex;flex-direction:column;overflow:hidden;max-height:none;
    transition:height .2s ease}
  .dsc-sheet[data-detent="compact"]{height:min(32dvh,18rem)}
  .dsc-sheet[data-detent="expanded"]{position:fixed;height:min(76dvh,calc(100dvh - 4rem));
    padding-bottom:env(safe-area-inset-bottom)}
  .dsh-detent{display:flex;width:100%;min-height:44px;border:0;border-bottom:1px solid var(--rule);
    background:var(--surface);color:var(--ink);align-items:center;justify-content:center;gap:9px;
    font:inherit;font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;cursor:pointer}
  .dsh-detent:focus-visible{outline:3px solid var(--orange);outline-offset:-3px}
  .dsh-grip{width:36px;height:4px;border-radius:4px;background:var(--steel)}
  .dsh-content{display:block;flex:1 1 auto;min-height:0;max-height:none;overflow-y:auto;
    overflow-x:hidden;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
  .dsc-sheet[data-detent="compact"] .dsh-media{display:none}
  .dsh-media{min-height:120px;max-height:150px}
  /* On a phone the sheet is most of the screen; the map still needs to read as
     terrain rather than a stripe, so it keeps more height than a flat trace. */
  .dsh-media--3d{min-height:185px;max-height:185px}
  html[data-text="xl"] .dsc-sheet[data-detent="compact"]{height:min(38dvh,22rem)}
  html[data-text="xl"] .dsh-detent{min-height:52px;font-size:14px}
}
@media (prefers-reduced-motion:reduce){.dsc-sheet{transition:none}}
.dsc-ad p b{color:var(--ink);font-weight:800}
.dsc-ad p a{color:var(--orange);font-weight:700}
/* Measured twistiness. Four bands from our own corners-per-mile figure, not a
   published claim: relentless 30+, twisty 18+, flowing 9+, open below that. */
.dsc-band{display:inline-block;margin:0 0 9px;font-size:9.5px;font-weight:800;
  letter-spacing:.13em;text-transform:uppercase;padding:3px 7px;border:1px solid var(--rule)}
.dsc-band--relentless{background:var(--orange);color:#fff;border-color:var(--orange)}
.dsc-band--twisty{background:var(--chrome2);color:#fff;border-color:var(--ink)}
.dsc-band--flowing{color:var(--steel)}
.dsc-band--open{color:var(--smoke)}

/* ------------------------------ theme toggle ------------------------------ */
.util .themeb{background:none;border:0;color:inherit;font:inherit;font-size:11.5px;
  font-weight:600;letter-spacing:.055em;text-transform:uppercase;cursor:pointer;padding:0}
.util .themeb:hover{color:var(--white)}

/* ---------------------------------------------------------------------------
   OFFLINE / INSTALL (2026-09-15)

   Every colour here comes from the role tokens, so this works in both themes
   without a second definition. The status bar is deliberately loud: a rider
   looking at cached data has to KNOW it is cached. A fallback that hides the
   fact it fired is worse than no fallback — that lesson cost us a week of
   silent car-routing on the Valhalla proxy.
   --------------------------------------------------------------------------- */
.mrp-save-offline{
  font:600 13px/1 "Libre Franklin",system-ui,-apple-system,sans-serif;
  letter-spacing:.02em;
  color:var(--ink);
  background:var(--panel);
  border:1px solid var(--rule);
  border-radius:2px;
  padding:10px 14px;
  cursor:pointer;
  transition:border-color .15s ease,color .15s ease;
}
.mrp-save-offline:hover:not(:disabled){ border-color:var(--orange); color:var(--orange); }
.mrp-save-offline:focus-visible{ outline:2px solid var(--orange); outline-offset:2px; }
.mrp-save-offline:disabled{ opacity:.55; cursor:progress; }
/* No floating variant. It overlapped the primary input on a phone — a control that
   covers the thing it sits above is worse than no control. Inline only. */
.mrp-offline-row{ margin-top:12px; }

.mrp-offline-bar{
  position:fixed; left:0; right:0; bottom:0; z-index:950;
  font:600 13px/1.45 "Libre Franklin",system-ui,-apple-system,sans-serif;
  padding:12px 16px calc(12px + env(safe-area-inset-bottom));
  text-align:center;
  background:var(--chrome); color:var(--white);
  border-top:2px solid var(--orange);
}
.mrp-offline-bar[data-kind="good"]{ border-top-color:#3FA34D; }
.mrp-offline-bar[data-kind="bad"] { border-top-color:#C4342B; }
.mrp-offline-bar[data-kind="warn"]{ border-top-color:var(--orange); }
.mrp-offline-bar[data-kind="work"]{ border-top-color:var(--steel); }

@media (prefers-reduced-motion:reduce){
  .mrp-save-offline{ transition:none; }
}

/* ---------------------------------------------------------------------------
   TEXT SIZE (2026-09-16)

   Dean: "You A++ should be the base, I have great vision and a lot of these guys
   don't."  Then, after the first attempt only raised the floor:
   "for mobile the A++ font size should be default (everything is hard to see) and then
   get bigger"

   Two things, and the first pass only did one of them. The base is big AND there is
   room ABOVE it. Making the old maximum the new default while the scale still only ran
   downwards left the person who needs the most help with nowhere to go — which is the
   one person the feature exists for.

   The scale runs s - m - (default) - l - xl. Default sits fourth from the bottom on a
   phone, not in the middle, because a phone at a petrol station in daylight through a
   visor is the hard case, not the average one.

   One multiplier drives everything, so nothing drifts out of step. Touch targets scale
   with the text, because a bigger label in the same small box helps nobody.
   --------------------------------------------------------------------------- */
:root{ --ts: 1.32; }                    /* the base */
:root[data-text="m"]{  --ts: 1.15; }    /* a notch down */
:root[data-text="s"]{  --ts: 1; }       /* for good eyes, like Dean's */
:root[data-text="l"]{  --ts: 1.6; }     /* above the default */
:root[data-text="xl"]{ --ts: 1.9; }     /* as big as the layout holds */

/* ON A PHONE THE DEFAULT IS BIGGER STILL. This is the screen Dean was looking at when
   he said everything is hard to see, and it is the screen the site is actually used on.
   The small end stays genuinely small so good eyes can still get more on screen. */
@media (max-width: 760px){
  :root{ --ts: 1.5; }
  :root[data-text="m"]{  --ts: 1.2; }
  :root[data-text="s"]{  --ts: 1; }
  :root[data-text="l"]{  --ts: 1.8; }
  :root[data-text="xl"]{ --ts: 2.1; }
}

body{ font-size: calc(15px * var(--ts)); }

.pauto h2{ font-size: calc(17px * var(--ts)); }
.pauto-lead{ font-size: calc(12.5px * var(--ts)); }
.pauto-grid label{ font-size: calc(11px * var(--ts)); }
.pauto input{ font-size: calc(16px * var(--ts)); min-height: calc(48px * var(--ts)); }
.pauto-mode .tbtn{ font-size: calc(14px * var(--ts)); min-height: calc(48px * var(--ts)); }
#pa-go{ font-size: calc(16px * var(--ts)); min-height: calc(54px * var(--ts)); }
.pauto-note{ font-size: calc(13px * var(--ts)); }
.pauto-sug button{ font-size: calc(14px * var(--ts)); min-height: calc(52px * var(--ts)); }
.pstop{ font-size: calc(14px * var(--ts)); }
.psum b{ font-size: calc(22px * var(--ts)); }
.pdays li{ font-size: calc(13px * var(--ts)); }
.proutes .tbtn{ font-size: calc(13px * var(--ts)); min-height: calc(46px * var(--ts)); }
.pexp button{ font-size: calc(14px * var(--ts)); min-height: calc(48px * var(--ts)); }
.mast nav a{ font-size: calc(12px * var(--ts)); }
.util a{ font-size: min(calc(11px * var(--ts)), 16px); }
.pauto-hint, #pa-budget, .pauto-append, .phint{ font-size: calc(12.5px * var(--ts)); }
.pleg select{ font-size: calc(12.5px * var(--ts)); min-height: calc(40px * var(--ts)); }
.pauto-append input{ width: calc(18px * var(--ts)); height: calc(18px * var(--ts)); }
.pauto-here{ font-size: calc(12px * var(--ts)); min-height: calc(48px * var(--ts)); }

/* Two explicit buttons, not one that cycles. A cycling control makes you press it and
   watch what happens; A- and A+ tell you what you get before you touch them, and at 65
   with gloves on that difference is the whole feature. */
.tsize{ display: inline-flex; gap: 2px; }
.tsize .themeb{ min-width: 40px; padding-left: 8px; padding-right: 8px; }
.tsize .themeb sup{ font-size: .72em; }
.tsize .themeb[aria-disabled="true"]{ opacity: .35; pointer-events: none; }
@media (max-width: 760px){
  /* Big enough to hit while the bike is running. These deliberately do NOT scale with
     --ts: the control that fixes the text size must be reachable at every text size. */
  .tsize .themeb{ min-width: 48px; min-height: 40px; }
}

/* Buy us a beer. Uses the existing orange accent rather than introducing a second
   warm hue, so the donation ask reads as part of the site and not as an ad slot.
   .foot a is (0,1,1) and would otherwise win the colour, hence the paired selector.
   DEAN-AUDIT-1 item 8 / dr-fix-1 item 5: white text on this orange measured 2.61:1,
   below both the 4.5:1 normal-text and 3:1 large-text WCAG thresholds, and contrary to
   the token rule the rest of the site's orange CTAs already follow ("Find routes" etc,
   #181B1A text on var(--orange) - see css/plan.css) - var(--black) is that same dark
   text, >=4.5:1 on var(--orange) in both themes since --orange does not change between
   them. Only this one rule. */
.beer,.foot .beer{display:inline-flex;align-items:center;gap:9px;padding:11px 18px;
  border-radius:999px;background:var(--orange);color:var(--black);border:0;white-space:nowrap;
  font-size:12px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
  font-family:var(--gothic);transition:background .15s ease}
.beer:hover,.foot .beer:hover{background:var(--orange-dk);color:var(--black)}
.beer:focus-visible,.foot .beer:focus-visible{outline:3px solid var(--orange);
  outline-offset:3px}
.beer svg{width:16px;height:16px;flex:0 0 auto}

.support{background:var(--panel);border-top:1px solid var(--rule);margin-top:54px;
  padding:42px 0 46px}
.support h2{font-size:calc(21px * var(--ts));margin:0 0 10px;color:var(--text-strong);
  text-wrap:balance}
.support p{font-size:calc(14px * var(--ts));line-height:1.65;color:var(--steel);
  max-width:62ch;margin:0 0 20px}
@media (prefers-reduced-motion:reduce){.beer{transition:none}}

/* "Recentre on me" - shown only when the map has stopped following, which happens the
   moment anybody pans. Sized for a gloved thumb and placed where a thumb already is,
   because the rider who needs it is the one who has just knocked the map sideways. */
.precentre{display:block;width:100%;margin:8px 0 0;min-height:52px;border:0;border-radius:8px;
  background:var(--orange);color:var(--black);font:inherit;font-size:16px;font-weight:800;
  letter-spacing:.02em;cursor:pointer}
.precentre:hover{filter:brightness(1.08)}

/* ---------------------------------------------------------------------------
   APP MODE. Set by js/app-shell.js before first paint, only when the page is
   running as an installed app. A browser tab never sees any of this.

   Dean, 2026-09-23: "get away from the website on boarding... set it up to be
   like the app and then build the app to it." Step 1 of docs/APP-SHAPE.md.

   The rule is subtraction, not a second design: the same pages lose the website
   furniture and gain one bar. Nothing here restyles content, so a page keeps
   whatever it already got right.
   --------------------------------------------------------------------------- */
html[data-app] .util,
html[data-app] .mast,
html[data-app] .promo,
html[data-app] .foot { display: none !important; }

/* Room for the bar, plus the home indicator on a notched phone. */
html[data-app] body { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }

.appbar { display: none; }
/* P0-SHL-02: the four-tab bar is Home/Roads/Plan/Garage navigation, not a guidance
   control. During active turn-by-turn it has nothing live to say and would sit over
   the bottom of the maneuver view on a short phone, so it goes away the moment
   js/ride.js adds body.riding and returns the instant it is removed (End ride). */
html[data-app] body.riding .appbar { display: none !important; }
html[data-app] body.riding { padding-bottom: env(safe-area-inset-bottom, 0px); }
html[data-app] .appbar {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 900;
  height: calc(56px + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: var(--chrome); border-top: 1px solid var(--rule);
}
.appbar__t {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px;
  font: 700 10.5px/1 var(--gothic); letter-spacing: .09em; text-transform: uppercase;
  color: var(--steel); text-decoration: none;
  /* The whole 56px is the target. A rider taps this in gloves, at a petrol station,
     without looking properly. */
  -webkit-tap-highlight-color: transparent;
}
.appbar__t.is-on { color: var(--white); box-shadow: inset 0 2px 0 var(--orange); }
.appbar__t:focus-visible { outline: 2px solid var(--orange); outline-offset: -4px; }

/* ---------------------------------------------------------------------------
   Moved here from css/styles.css on 2026-09-23. ride.html loads ONLY heritage.css
   plus the MapLibre sheet, so every one of these rules was dead: the first-run
   screen rendered unstyled and the weather card's buttons sat under the map canvas
   because .rv-wx never got its position or z-index. The behaviour tests all passed,
   because they read text and hidden flags and never once asked what the thing
   looked like. Check the computed style, not the textContent.
   --------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   FIRST RUN. docs/APP-SHAPE.md section 1. One question, two buttons, and
   nothing else competing for the thumb. Everything else on this page is
   deferred until the rider has seen a ride.
   --------------------------------------------------------------------------- */
.ride-first { padding: 24px 18px 8px; }
.ride-first__q {
  font-size: clamp(30px, 8.5vw, 44px); line-height: 1.04; margin: 0 0 22px;
  text-wrap: balance;
}
.ride-first__btns { display: flex; flex-direction: column; gap: 10px; margin: 0 0 6px; }
/* Full width and tall, because this is tapped in gloves. */
.ride-first__btns > button { width: 100%; min-height: 54px; font-size: 17px; }
.ride-first__note { margin: 12px 0 0; color: var(--steel); font-size: 14px; min-height: 1.2em; }
.ride-first__hours { margin: 22px 0 0; }
.ride-first__hours .tbtns { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.ride-first__hours .tbtn { min-height: 48px; }
.ride-first__out { margin: 20px 0 0; }
.ride-first__sum { margin: 0 0 10px; font-size: 16px; }
.ride-first__roads { list-style: none; margin: 0 0 18px; padding: 0;
  display: flex; flex-direction: column; gap: 6px; }
/* The roads are named because measured roads are the whole product; a bent line
   on a map is what everyone else gives you. */
.ride-first__roads li { font-size: 14.5px; color: var(--steel);
  padding-left: 12px; border-left: 2px solid var(--orange); }
.ride-first__roads li b { color: var(--ink); font-weight: 600; }


/* The account ask, at the first save. A line and a link, never a wall: a rider who ignores
   it keeps everything, locally, exactly as before. */
.ride-first__acct{margin:14px 0 0;padding:12px 14px;border-radius:4px;
  background:rgba(255,91,18,.10);border-left:3px solid var(--orange);
  font-size:14.5px;line-height:1.5;color:var(--ink)}
.ride-first__acct a{color:var(--orange);font-weight:600}
.ride-first__acct[hidden]{display:none}
/* Three buttons now, so they share the row on anything but the narrowest phone. */
@media(min-width:380px){
  .ride-first__out .ride-first__btns{flex-direction:row}
  .ride-first__out .ride-first__btns > button{width:auto;flex:1}
}


/* WEATHER AHEAD, on the riding screen. Sits under the instruction band like the known-road
   card, because the next turn always outranks the sky. Not a modal: a rider who ignores it
   keeps riding and nothing is taken away from him. */
.rv-wx{position:absolute;left:12px;right:12px;top:calc(96px + env(safe-area-inset-top,0));
  z-index:5;padding:13px 14px;border-radius:12px;border:1px solid var(--orange);
  background:rgba(10,10,10,.94);text-align:left}
.rv-wx[hidden]{display:none !important}
.rv-wx b{display:block;font-size:clamp(17px,4.6vw,23px);font-weight:800;color:#fff;
  line-height:1.2;text-wrap:balance}
.rv-wx span{display:block;margin-top:4px;font-size:clamp(13px,3.4vw,16px);color:#C9C9C9}
.rv-wx-btns{display:flex;gap:8px;margin-top:11px}
/* Full height targets: this is answered in gloves, at a standstill or not at all. */
.rv-wx-btns .rv-btn{flex:1;min-height:50px;font-size:14px;padding:0 6px}
.ride-live.rv-day .rv-wx{background:rgba(255,255,255,.96);border-color:#D8541B}
.ride-live.rv-day .rv-wx b{color:#0A0A0A}
.ride-live.rv-day .rv-wx span{color:#4A4A4A}

/* Saved rides in the garage. A row is: what it is, how far, and the two things you can do
   with it. Nothing else, because a saved ride is not a document to browse. */
.g-trips{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.g-trips li{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:12px 13px;border:1px solid var(--rule);border-radius:4px;background:var(--panel)}
.g-trip-w{flex:1;min-width:11rem}
.g-trips b{display:block;font-size:calc(15px * var(--ts,1));line-height:1.25}
.g-trips span{display:block;margin-top:3px;font-size:calc(12px * var(--ts,1));color:var(--steel)}
.g-trips .tbtn{min-height:calc(42px * var(--ts,1));padding:0 14px;font-size:calc(13px * var(--ts,1))}
.g-trip-x{opacity:.75}

/* The radar toggle sits with the zoom column. Same on-state as the map switch beside it, so
   the two read as the same kind of control: a thing that is costing you something. */
.rv-zbtn--rain{font-size:12px;font-weight:800;letter-spacing:.06em}
.rv-zbtn--rain.rv-on{background:var(--orange);color:var(--black);border-color:var(--orange)}

/* Tab icons. 22px is the size at which the motorcycle still reads as a motorcycle on a
   phone; below about 20 the wheels and the engine block merge into a smudge. They take
   currentColor, so the on-state needs no second set. */
.appbar__i{width:22px;height:22px;flex:none}
.appbar__t.is-on .appbar__i{color:var(--orange)}
/* A rider who has turned text size up is telling us he cannot read small things. Give the
   label room rather than letting it collide with the icon. */
@media (max-width:340px){ .appbar__t span{display:none} .appbar__i{width:24px;height:24px} }
