/* =============================================================================
   HERITAGE — the garage
   Saved roads and the bikes you ride. Device-local for now; the page says so.
   ========================================================================== */
.g-head{background:var(--chrome);color:var(--white);padding:40px 0 34px}
.g-head h1{margin:0 0 9px;font-size:clamp(28px,4.4vw,46px);font-weight:900;
  letter-spacing:-.022em;text-transform:uppercase;line-height:.98}
.g-head p{margin:0;font-size:14.5px;line-height:1.55;color:#C9C9C9;max-width:62ch}
.g-head b{color:var(--orange)}

.g-sec{padding:38px 0 0}
.g-sec:last-of-type{padding-bottom:56px}
.g-h{display:flex;align-items:center;gap:14px;margin:0 0 18px}
.g-h h2{margin:0;font-size:13px;font-weight:800;letter-spacing:.17em;
  text-transform:uppercase;white-space:nowrap}
.g-h::after{content:"";flex:1;height:1px;background:var(--rule)}
.g-h span{font-size:11px;font-weight:600;letter-spacing:.06em;color:var(--steel);
  text-transform:uppercase;white-space:nowrap}

.g-empty{margin:0;font-size:14px;line-height:1.6;color:var(--steel);max-width:62ch}
.g-empty a{color:var(--orange);font-weight:700}

/* REDESIGN S11 (round 3, REDESIGN-AUDIT-3 #1): the signed-out migration nudge above
   the ride list - trimmed to one short line, styled as a small caption (not a full
   body paragraph) so it reads as a helper hint under the segmented control rather
   than a whole extra content block the tile does not draw. */
.g-migration-hint{margin:0 0 12px;font-size:12px;line-height:1.4;color:var(--steel)}

.g-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(252px,1fr));gap:18px}
.g-card{border:1px solid var(--rule);background:var(--surface);display:flex;
  flex-direction:column}
.g-media{display:block;aspect-ratio:16/9;background:var(--chrome);overflow:hidden}
.g-media img{width:100%;height:100%;object-fit:cover;display:block}
.g-media--shape{display:grid;place-items:center;padding:9px}
.g-media--shape svg{width:auto;height:100%;max-width:100%}
.g-media--shape path{fill:none;stroke:var(--orange);stroke-width:2.6;
  stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke}
.g-cb{padding:14px 15px 15px;display:flex;flex-direction:column;gap:6px;flex:1}
.g-where{margin:0;font-size:9.5px;font-weight:700;letter-spacing:.15em;
  text-transform:uppercase;color:var(--steel)}
.g-cb h3{margin:0;font-size:15px;font-weight:800;letter-spacing:-.012em;line-height:1.24}
.g-cb h3 a:hover{color:var(--orange)}
.g-figs{margin:0;font-size:12px;color:var(--steel);font-variant-numeric:tabular-nums}
.g-figs b{color:var(--ink);font-weight:800}
.g-rm{margin-top:auto;align-self:flex-start;border:1px solid var(--rule);
  background:var(--surface);color:var(--steel);font:inherit;font-size:10px;font-weight:700;
  letter-spacing:.11em;text-transform:uppercase;padding:7px 11px;cursor:pointer}
.g-rm:hover{background:var(--chrome2);color:var(--white);border-color:var(--ink)}

.g-bikes{list-style:none;margin:0 0 20px;padding:0;border:1px solid var(--rule);
  max-width:620px}
.g-bikes li{display:flex;justify-content:space-between;align-items:center;gap:12px;
  padding:13px 15px;border-bottom:1px solid var(--rule)}
.g-bikes li:last-child{border-bottom:0}
.g-bikes b{font-size:15px;font-weight:800;letter-spacing:-.01em}
.g-bikes i{display:block;font-style:normal;font-size:11.5px;color:var(--steel);margin-top:2px}
.g-bikes button{width:28px;height:28px;border:1px solid var(--rule);background:var(--surface);
  cursor:pointer;font-size:15px;line-height:1;color:var(--ink);flex:none}
.g-bikes button:hover{background:var(--chrome);color:var(--white);border-color:var(--black)}

.g-form{display:flex;gap:9px;flex-wrap:wrap;align-items:flex-end;max-width:760px}
.g-form label{display:flex;flex-direction:column;gap:5px;font-size:10px;font-weight:700;
  letter-spacing:.13em;text-transform:uppercase;color:var(--steel)}
.g-form input{border:1px solid var(--ink);padding:9px 10px;font:inherit;font-size:14px;
  background:var(--surface);color:var(--ink);width:150px}
.g-form input[name=year]{width:86px}
.g-form button{border:1px solid var(--orange);background:var(--orange);color:#181B1A;
  font:inherit;font-size:10.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  padding:11px 16px;cursor:pointer}
.g-form button:hover{background:var(--orange-dk);border-color:var(--orange-dk)}

.g-foot{margin:30px 0 0;padding:16px 18px;background:var(--panel);
  border-left:3px solid var(--orange);max-width:72ch}
.g-foot p{margin:0 0 9px;font-size:12.5px;line-height:1.6;color:var(--steel)}
.g-foot p:last-child{margin:0}
.g-foot b{color:var(--ink)}
#g-clear{border:1px solid var(--rule);background:var(--surface);color:var(--steel);
  font:inherit;font-size:10px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  padding:8px 12px;cursor:pointer;margin-top:12px}
#g-clear:hover{background:var(--chrome2);color:var(--white);border-color:var(--ink)}

/* the save control, wherever it appears */
.savebtn{border:1px solid var(--ink);background:var(--surface);color:var(--ink);font:inherit;
  font-size:10.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  padding:11px 16px;cursor:pointer}
.savebtn:hover{background:var(--chrome2);color:var(--white)}
.savebtn[aria-pressed="true"]{background:var(--orange);border-color:var(--orange);color:#181B1A}

/* Sign-in block. Deliberately quiet: the garage works without it, and a loud
   sign-up prompt on a page that does not need one is the thing riders hate about
   every other route site. */
.g-auth{margin:18px 0 0;padding:16px 18px;background:var(--panel);
  border:1px solid var(--rule);border-radius:10px;max-width:56ch}
.g-auth p{margin:0 0 12px;font-size:calc(13.5px * var(--ts));line-height:1.6;color:var(--steel)}
.g-auth p b{color:var(--text-strong)}
.g-auth small{display:block;margin-top:12px;font-size:calc(11.5px * var(--ts));
  line-height:1.55;color:var(--smoke)}
.g-auth .btn,.g-auth .tbtn{min-height:calc(46px * var(--ts))}
.g-auth-note{margin-top:12px;font-size:calc(12.5px * var(--ts))}
.g-auth-note[data-ok="1"]{color:#57b36b}
.g-auth-note[data-ok="0"]{color:#e0704f}

/* SAVED RIDES, converged (P1-SAV-02/04/05-web; scope-board 05 "Ready when you are").
   One card shape for a local save, a server-only ride and a completed recording -
   thumbnail from the ride's own stored geometry, duration x distance, sync state, a
   styled primary ("Open ride"), and an overflow for the rest instead of crowded
   inline buttons (js/garage.js cardHtml/paintRideList). */
.g-lede{margin:0 0 16px;font-size:15px;font-weight:700;color:var(--ink)}
.g-segmented{display:inline-flex;gap:4px;padding:4px;margin:0 0 18px;background:var(--panel);
  border:1px solid var(--rule);border-radius:999px}
.g-seg-btn{border:0;background:none;color:var(--steel);font:inherit;font-size:13px;
  font-weight:700;padding:9px 18px;min-height:44px;border-radius:999px;cursor:pointer}
.g-seg-btn.is-active{background:var(--orange);color:#181B1A}
.g-seg-btn:not(.is-active):hover{color:var(--ink)}

ul.g-trips{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px;max-width:720px}
.g-ride-card{display:flex;align-items:center;gap:14px;padding:12px;border:1px solid var(--rule);
  background:var(--surface);border-radius:12px;flex-wrap:wrap}
/* X5 (c1106 repair): --chrome/--chrome2 are DELIBERATELY near-black in BOTH themes
   (heritage.css's own comment: "the utility bar is deliberately dark in both themes") -
   right for a persistent dark toolbar, wrong for a map-thumbnail placeholder. The
   MapLibre canvas mounted into .g-ride-map starts fully transparent (confirmed: a WebGL
   readback before `idle` fires returns alpha 0) and only reveals whatever this element's
   CSS background is until the style/tiles actually paint over it - against --chrome2 that
   read as a flat black square in EITHER theme during that window (the real 2026-11-06
   capture caught dark specifically because dark-matter's style/tiles happened to still be
   loading at the capture's fixed wait while positron had already settled, not because dark
   mode itself is broken - confirmed empirically: a WebGL pixel readback at the exact same
   wait the capture script uses returns alpha 0 in BOTH themes). --surface is the page-
   ground token, never near-black in light; used here (not --panel) because the app-mode
   card itself is --panel (below, html[data-app] .g-ride-card) and the thumbnail needs to
   read as a distinct, inset well against it on the screen this bug was actually caught on.
   A correctly theme-varying placeholder reads as "loading/no map" rather than "broken",
   and the fix holds even if a paint is slow or a browser blocks WebGL entirely, not just
   a faster average load. */
.g-ride-thumb{flex:0 0 auto;width:64px;height:64px;border-radius:9px;background:var(--surface);
  display:grid;place-items:center;overflow:hidden}
.g-ride-map{display:block;width:100%;height:100%;background:var(--surface)}
.g-ride-map .maplibregl-canvas{display:block}
/* X6 (c1106 repair, B1): js/route-preview-canvas.js's mountThumbnail() falls back to a
   plain drawn line (draw()) when the live CARTO map does not reach 'idle' within its own
   bounded wait; this is that fallback canvas, sized to fill the same thumbnail well the
   WebGL canvas would have. */
.g-ride-fallback-canvas{display:block;width:100%;height:100%}
.g-ride-thumb--none{background:var(--surface)}
.g-ride-body{flex:1 1 180px;min-width:0;display:flex;flex-direction:column;gap:2px}
.g-ride-badge{align-self:flex-start;font-size:10px;font-weight:800;letter-spacing:.1em;
  text-transform:uppercase;color:#181B1A;background:var(--orange);padding:2px 8px;
  border-radius:999px;margin-bottom:2px}
.g-ride-name{margin:0;font-size:15px;font-weight:800;letter-spacing:-.01em;line-height:1.25;
  overflow-wrap:anywhere}
.g-ride-meta{margin:0;font-size:12.5px;color:var(--ink);font-variant-numeric:tabular-nums}
.g-ride-state{margin:0;font-size:11.5px;color:var(--steel)}
/* Open + overflow stay one unbroken group (flex:0 0 auto on the GROUP, not each
   piece) so the menu's `right:0` always anchors to this group's own right edge -
   not to a bare 44px overflow button that can wrap onto its own line and leave
   the menu's right edge only 44px from the card's LEFT side. */
.g-ride-actions{display:flex;align-items:center;gap:8px;flex:0 0 auto}
.g-ride-open{flex:0 0 auto;border:1px solid var(--orange);background:var(--orange);color:#181B1A;
  font:inherit;font-size:12.5px;font-weight:800;letter-spacing:.04em;padding:10px 16px;
  min-height:44px;display:inline-flex;align-items:center;border-radius:9px;text-decoration:none}
.g-ride-open:hover{background:var(--orange-dk);border-color:var(--orange-dk)}
.g-ride-overflow{position:relative;flex:0 0 auto}
.g-ride-more{width:44px;height:44px;border:1px solid var(--rule);background:var(--surface);
  color:var(--ink);font-size:20px;line-height:1;border-radius:9px;cursor:pointer}
.g-ride-more:hover{background:var(--chrome2)}
.g-ride-menu{position:absolute;right:0;top:calc(100% + 4px);z-index:5;min-width:170px;
  background:var(--panel);border:1px solid var(--rule);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.28);
  display:flex;flex-direction:column;padding:6px;gap:2px}
/* A class selector's display:flex above outranks the UA stylesheet's bare-attribute
   [hidden]{display:none} - without this, the menu painted open on every page load,
   the exact "state stored in a label" class of bug: a control that LOOKS live
   (closed) when the element backing it is actually visible the whole time. */
.g-ride-menu[hidden]{display:none}
.g-ride-menu a,.g-ride-menu button{display:block;width:100%;text-align:left;border:0;background:none;
  color:var(--ink);font:inherit;font-size:13px;padding:10px 10px;min-height:40px;border-radius:7px;
  cursor:pointer;text-decoration:none}
.g-ride-menu a:hover,.g-ride-menu button:hover{background:var(--chrome2)}
.g-ride-menu [data-act="remove"],.g-ride-menu [data-act="delete"]{color:#e0704f}
.g-ride-card--collection .g-ride-open{background:var(--surface);color:var(--ink);border-color:var(--rule)}
/* Chevron after "Open ride"/"Open in Library": only drawn in the app-mode card
   restyle below (a plain text link, mockup-style); the website's filled-button
   treatment keeps its own look, unchanged. */
.g-ride-open-chev{display:none}

@media (max-width:480px){
  .g-ride-card{padding:10px}
  .g-ride-actions{width:100%}
  .g-ride-open{flex:1 1 auto;justify-content:center}
}

/* =============================================================================
   S11 "Saved rides" APP SCREEN (scope-board tile 05, mock-022-018). html[data-app]
   only - css/heritage.css already strips the website chrome (.util/.mast/.promo/
   .foot) and the four-tab .appbar in app mode; this makes the ONE section the
   mockup draws ("Saved rides" header, "Ready when you are", My rides/Collections,
   ride cards) the whole screen, with "My garage" (the auth block), Saved roads and
   My bikes/export moved into this bar's own overflow (#g-appbar-sheet) rather than
   left in the main layout or made unreachable (BUILDER-RULES: no feature removed
   to match a mockup). Plain website visits never set html[data-app], so none of
   this runs there and today's "My garage" page is untouched. */
/* The V1 four-tab bar (js/app-shell.js, css/heritage.css's own
   html[data-app] .appbar rule) has no place in ANY scope-board mockup, same as
   every full-fidelity screen already fixed it (rows/rd-home-status.md pass 4:
   "the app's bottom tab bar... has no place in the brief"). heritage.css hides
   the website chrome for every page but still shows this bar in app mode
   site-wide, since garage.html carries none of plan.html's own fix (that one
   lives in css/plan.css, scoped to plan.html). Hidden here, scoped to THIS
   file/page only - every destination it held is one tap away in #g-appbar-sheet
   above (Garage itself, the page this bar would have pointed back to, is
   literally the screen already on screen). */
html[data-app] #garage-page ~ .appbar{display:none}

.g-appbar{display:none}
html[data-app] .g-appbar{display:flex;align-items:center;gap:10px;padding:14px 16px;
  background:var(--surface);border-bottom:1px solid var(--rule);position:sticky;top:0;z-index:50}
.g-appbar-back{flex:0 0 auto;color:var(--ink);text-decoration:none;font-size:20px;line-height:1;
  padding:4px 6px;margin:-4px 0}
.g-appbar-back:hover{color:var(--orange)}
.g-appbar-title{flex:1 1 auto;text-align:center;font-size:15px;font-weight:800;color:var(--ink)}
.g-appbar-overflow{position:relative;flex:0 0 auto}
.g-appbar-more{background:none;border:0;color:var(--ink);font-size:20px;line-height:1;
  padding:4px 6px;margin:-4px 0;cursor:pointer}
.g-appbar-more:hover{color:var(--orange)}
.g-appbar-sheet{position:absolute;right:0;top:calc(100% + 6px);z-index:55;width:min(340px,calc(100vw - 32px));
  max-height:calc(100vh - 76px);overflow:auto;
  background:var(--panel);border:1px solid var(--rule);border-radius:10px;
  box-shadow:0 8px 24px rgba(0,0,0,.28);display:flex;flex-direction:column;padding:6px;gap:2px}
.g-appbar-sheet[hidden]{display:none}
.g-appbar-row{display:block;padding:10px 12px;border-radius:7px;color:var(--ink);
  text-decoration:none;font-size:14px;font-weight:600}
.g-appbar-row:hover{background:var(--chrome2)}

/* Local-to-Library migration is intentionally secondary. On the website this is a
   closed disclosure beside the Saved content; in app mode js/garage.js reparents the
   same node into the existing More sheet. Until that move completes it stays out of
   the title/tabs/cards flow, preventing the old fieldset flash from pushing cards
   below the fold. */
.g-migration-disclosure{margin:14px 0 0;border:1px solid var(--rule);border-radius:10px;
  background:var(--panel);color:var(--ink)}
.g-migration-disclosure[hidden]{display:none}
.g-migration-disclosure>summary{display:flex;align-items:center;gap:10px;min-height:44px;
  box-sizing:border-box;padding:9px 12px;cursor:pointer;list-style:none;font-size:14px;font-weight:700}
.g-migration-disclosure>summary::-webkit-details-marker{display:none}
.g-migration-disclosure>summary::after{content:'+';margin-left:auto;color:var(--orange);font-size:18px}
.g-migration-disclosure[open]>summary::after{content:'\2212'}
.g-migration-disclosure>summary:hover{background:var(--chrome2)}
.g-migration-disclosure>summary:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
#g-library-migration{padding:0 12px 12px}
#g-library-migration fieldset{margin:0;padding:12px;border:1px solid var(--rule);border-radius:8px;
  background:var(--surface)}
#g-library-migration legend{padding:0 5px;font-size:13px;font-weight:800;color:var(--ink)}
#g-library-migration p{margin:7px 0;font-size:12px;line-height:1.45;color:var(--steel)}
#g-library-migration label{display:flex;align-items:center;gap:8px;min-height:40px;
  border-top:1px solid var(--rule);font-size:13px;line-height:1.3;cursor:pointer}
#g-library-migration label input{width:18px;height:18px;flex:0 0 auto;accent-color:var(--orange)}
#g-library-migration .tbtn{min-height:44px;width:100%;white-space:normal}
html[data-app] #g-rides-section .g-migration-disclosure{display:none}
html[data-app] .g-appbar-sheet .g-migration-disclosure{display:block;margin:2px 0 0;background:var(--surface)}
html[data-app] .g-appbar-sheet .g-migration-disclosure[hidden]{display:none}

/* js/offline.js (every page, unrelated to this redesign) mounts "Save ride for
   offline" unconditionally on DOMContentLoaded, falling back to appending it to
   the nearest .pln-side/main when no trip-actions row exists - garage.html has
   neither, so it lands in <main id="garage-page"> itself. There is no "this
   ride" on a LIST of saved rides for that button to act on (confirmed pre-
   existing on the website version of this page too, same fallback selector,
   nothing this round touched); hidden here, app-mode-only, rather than editing
   the shared offline.js every page loads. */
html[data-app] #garage-page > .mrp-offline-row,
html[data-app] #garage-page > .mrp-save-offline{display:none}

html[data-app] #garage-page{display:flex;flex-direction:column;min-height:100vh}
html[data-app] #garage-page > .g-appbar{order:0}
html[data-app] #garage-page > #g-rides-section{order:1;padding-top:14px}
html[data-app] #garage-page > .g-head{order:2}
html[data-app] #garage-page > #g-roads-section{order:3}
html[data-app] #garage-page > #g-bikes-section{order:4}

/* "My garage" (auth) / Saved roads / My bikes are real features with no row in
   this tile - hidden from the main app screen, but never made unreachable: the
   overflow's own rows link to their anchors, and :target (via :has for the
   auth block, nested two levels inside .g-head) brings the exact same section
   Home's own overflow already links to (garage.html#g-auth) back on screen. */
html[data-app] .g-head,
html[data-app] #g-roads-section,
html[data-app] #g-bikes-section{display:none}
html[data-app] .g-head:has(#g-auth:target),
html[data-app] #g-roads-section:target,
html[data-app] #g-bikes-section:target{display:block}

/* "Saved rides" section becomes the screen: its own redundant "SAVED RIDES" label
   (the app header above already carries the screen name) hides, "Ready when you
   are" becomes the big sheet heading (brief: 22-28pt sheet titles) instead of a
   15px lede, and the segmented control spans full width like the mockup's two
   equal halves instead of sizing to its own content. */
html[data-app] #g-rides-section .g-h{display:none}
html[data-app] #g-rides-section .g-lede{font-size:26px;font-weight:800;color:var(--ink);
  margin:4px 0 16px;line-height:1.15}
html[data-app] #g-rides-section .g-segmented{display:flex;width:100%;box-sizing:border-box;
  border-radius:12px}
html[data-app] #g-rides-section .g-seg-btn{flex:1 1 0;text-align:center;border-radius:8px}

/* Ride cards: thumb top-left, name/meta/Open-ride stacked in one column next to
   it (mockup: "[thumb] name / meta / Open ride >", not a filled button pinned to
   the far right) - the per-card overflow (rename/edit/share/GPX, a real P1-SAV-04
   feature the tile does not draw at all) tucks into the card's own top-right
   corner instead of competing with Open ride's row. */
html[data-app] .g-ride-card{position:relative;display:grid;
  grid-template-columns:104px minmax(0,1fr);grid-template-rows:auto 1fr;
  align-items:start;column-gap:14px;row-gap:8px;min-height:126px;padding:10px 40px 10px 10px;
  border:0;border-radius:16px;background:var(--panel);flex-wrap:nowrap}
html[data-app] .g-ride-thumb{grid-column:1;grid-row:1 / span 2;width:104px;height:106px;
  border-radius:11px;align-self:stretch}
html[data-app] .g-ride-body{grid-column:2;grid-row:1;align-self:end;padding-top:3px}
html[data-app] .g-ride-actions{grid-column:2;grid-row:2;width:auto;margin:0;
  align-self:start;justify-content:flex-start}
html[data-app] .g-ride-open{background:none;border:0;color:var(--orange);padding:0;
  min-height:auto;flex:0 0 auto;justify-content:flex-start;font-weight:600;font-size:13px;
  justify-self:start;text-align:left}
html[data-app] .g-ride-open:hover{background:none;text-decoration:underline}
html[data-app] .g-ride-open-chev{display:inline-block;margin-left:2px}
html[data-app] .g-ride-overflow{position:absolute;top:10px;right:10px}
html[data-app] .g-ride-more{width:28px;height:28px;border:0;background:none;
  color:var(--steel);font-size:16px}
