/* Vetta Line: the signature layer (docs/design/SIGNATURE.md). Loaded last, over index.html's own rules and controls.css.
   The map is the page; chrome is paper laid on it, lifted by a soft shadow instead of boxed in ink. One ink key and at
   most one red thing per screen. Things arrive by being drawn. Colours are the look's tokens only, so every look keeps
   its own palette; what this file owns is form: weight, space, lift and motion. */
:root {
  --plan-bar: 76px;   /* the deck's bar (14 + 52 + 8 + 2) until cockpit.js measurePlanBar measures it: the first frame is where it stays */
  --lift-1: 0 1px 2px rgba(20, 16, 8, 0.10), 0 2px 8px rgba(20, 16, 8, 0.10);          /* a key or a plate on the map */
  --lift-2: 0 -1px 0 rgba(20, 16, 8, 0.06), 0 -10px 30px rgba(20, 16, 8, 0.16);        /* the deck and sheets, rising from below */
  --lift-0: 0 0 0 1px var(--hair), 0 1px 2px rgba(20, 16, 8, 0.08);                         /* a card on the deck: a hairline and a breath of shadow */
  --arrive: cubic-bezier(0.2, 0.8, 0.2, 1);
  --well: color-mix(in srgb, var(--panel-ink) 6%, var(--panel));                         /* a field or a card's ground: paper, one step down */
  --well-2: color-mix(in srgb, var(--panel-ink) 11%, var(--panel));
}

/* ---------------- the masthead: where you are, set in type on the map (was a boxed plate) ---------------- */
.place-plate { top: calc(10px + var(--safe-top)); left: 16px; right: 84px; padding: 0; background: none; border: 0; box-shadow: none;
  display: grid; gap: 1px; pointer-events: none; color: var(--ink, var(--panel-ink));
  text-shadow: 0 0 1px var(--stage), 0 0 3px var(--stage), 0 0 8px var(--stage); }
.place-plate { font: 800 30px/1 var(--font-num); letter-spacing: 0.005em; }
.place-plate b { font: inherit; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-bottom: 0.14em; margin-bottom: -0.14em; }   /* room for a g or y's tail under the tight line (Gatlinburg cut flat) */
.place-plate i { display: none; }
.place-plate span { font: 600 14px/1.3 var(--font-ui); letter-spacing: 0; color: var(--dim, var(--panel-dim)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.place-plate span::before { content: ""; display: inline-block; width: 7px; height: 7px; margin: 0 7px 1px 1px; border-radius: 50%; background: var(--accent); }
/* the paper under the masthead: a wash down from the top edge, so the type sits on paper and the map fades in under it */
#app.idle .stage::before { content: ""; position: absolute; z-index: 3; left: 0; right: 0; top: 0; height: calc(var(--safe-top) + 110px); pointer-events: none;
  background: linear-gradient(to bottom, var(--stage) 0, color-mix(in srgb, var(--stage) 78%, transparent) 42%, transparent 100%); }
#app.plan-open .stage::before { display: none; }

/* ---------------- map keys: paper on the map ---------------- */
.map-key { border: 0; box-shadow: var(--lift-1); }
.map-key:active { box-shadow: 0 0 0 rgba(0, 0, 0, 0); transform: translateY(1px); }

/* ---------------- the deck: one sheet of paper risen over the map ---------------- */
.plan { border-top: 0; box-shadow: var(--lift-2); }
[data-theme="roadbook"] .plan { border-top-width: 0; }
[data-theme="roadbook"] #app.idle .binnacle { border-top: 0; }
.plan-bar { padding: 14px 16px 8px; gap: 10px; }
.plan-bar::before { top: 6px; height: 4px; border-radius: 2px; opacity: 0.35; }
.plan-search { height: 52px; border: 0; background: var(--well); padding-left: 14px; gap: 10px; color: var(--panel-dim); }
.plan-search:focus-within { box-shadow: inset 0 0 0 2px var(--panel-ink); }
.plan-search input { font-size: 17px; font-weight: 500; }
.plan-search svg { width: 20px; height: 20px; }
/* Just drive: the one red key. The app's first verb is to drive. */
.btn-start { height: 52px; font-size: 16px; padding: 0 18px; box-shadow: none; }
.plan:not(.routed) #startDrive { background: var(--accent); color: var(--stage); border: 0; padding: 0 16px; font-size: 16px; font-weight: 700; gap: 8px; }
.plan:not(.routed) #startDrive i { width: 9px; height: 9px; background: currentColor; }
.plan:not(.routed) .start-more { background: var(--accent); color: var(--stage); border: 0; width: 34px; margin-left: -10px; box-shadow: inset 1px 0 0 color-mix(in srgb, var(--stage) 35%, transparent); }
.btn-start:active { filter: brightness(0.9); }

@media (orientation: portrait), (min-height: 541px) {
  /* the shelf: the deck's invitations side by side, turned with a thumb; each is a card with its road drawn on it */
  .deck-shelf { display: none; gap: 8px; margin: 0 -10px; padding: 6px 16px 14px; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; scroll-padding: 0 16px; scrollbar-width: none; }
  .deck-shelf::-webkit-scrollbar { display: none; }
  #app.idle:not(.plan-open):not(.routed):not(.deck-min) .deck-shelf { display: flex; }
  .deck-shelf .your-roads { display: contents; }
  .deck-shelf > .deck-chips { order: 9; padding: 0; flex: none; }
  .deck-shelf .loop-suggest { flex: none; width: auto; min-width: 216px; max-width: 78vw; margin: 0; padding: 8px 6px 8px 8px; border: 0; background: var(--face, var(--panel)); box-shadow: var(--lift-0); scroll-snap-align: start;
    min-height: 68px; column-gap: 4px; }
  .deck-shelf .loop-suggest .ls-show { grid-template-columns: 48px minmax(0, 1fr); gap: 10px; }
  .deck-shelf .loop-suggest .ls-glyph { width: 48px; height: 48px; background: var(--well); }
  .deck-shelf .loop-suggest svg { width: 48px; height: 48px; border: 0; padding: 6px; }
  .deck-shelf .loop-suggest b { font-size: 15px; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .deck-shelf .loop-suggest small { margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .deck-shelf .loop-suggest .ls-go { padding: 0 10px; align-self: stretch; }
  .deck-shelf .loop-suggest em { text-decoration: none; font-weight: 700; font-size: 14px; display: inline-flex; align-items: center; gap: 5px; }
  .deck-shelf .loop-suggest em::after { content: ""; width: 6px; height: 6px; border-top: 2px solid currentColor; border-right: 2px solid currentColor; transform: rotate(45deg); }
  .deck-shelf .loop-suggest.drive-today { display: grid; }
  /* Best roads nearby: the last card on the shelf, a key of the same height */
  .deck-shelf .deck-chips .chip { min-height: 68px; height: 68px; width: 124px; padding: 8px 12px; border: 0; background: var(--face, var(--panel)); box-shadow: var(--lift-0); font-size: 15px; font-weight: 600; line-height: 1.2; text-align: left;
    display: grid; align-content: space-between; justify-items: start; scroll-snap-align: start; }
  .deck-shelf .nearby-chip::before { width: 22px; height: 14px; margin: 2px 0 0; }
  html[data-type-size] .deck-shelf .loop-suggest { max-width: 86vw; }
  html[data-type-size] .deck-shelf .loop-suggest :is(b, small) { white-space: normal; }
  html[data-type-size] .deck-shelf .deck-chips .chip { height: auto; width: auto; max-width: 60vw; }
}
@media (orientation: landscape) and (max-height: 540px) { .deck-shelf { display: contents; } }

/* ---------------- the tab bar: the apex dot marks where you are ---------------- */
.tabbar { border-top: 1px solid var(--hair); }
.tab { height: 54px; font-size: 11px; letter-spacing: 0.01em; transition: color 0.12s; }
.tab.on { color: var(--panel-ink); }
.tab.on::before { top: 3px; left: 50%; right: auto; width: 6px; height: 6px; margin-left: -3px; border-radius: 50%; background: var(--accent); }
.tab svg { transition: transform 0.22s var(--arrive); }
.tab.on svg { transform: translateY(1px) scale(1.08); stroke-width: 2.1; }

/* ---------------- arrival: the deck rises, the shelf deals its cards, the masthead is set (once, after the cover lifts) ---------------- */
@keyframes vl-rise { from { transform: translateY(18px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes vl-ink { from { opacity: 0; transform: translateY(-6px); letter-spacing: 0.04em; } to { opacity: 1; transform: none; } }
#app.idle .plan-bar { animation: vl-rise 0.42s var(--arrive) 0.05s both; }
#app.idle .deck-shelf > * { animation: vl-rise 0.46s var(--arrive) both; }
#app.idle .deck-shelf > :nth-child(1) { animation-delay: 0.12s; }
#app.idle .deck-shelf > :nth-child(2) { animation-delay: 0.18s; }
#app.idle .deck-shelf > :nth-child(3) { animation-delay: 0.24s; }
#app.idle .deck-shelf > :nth-child(n+4) { animation-delay: 0.30s; }
.place-plate:not([hidden]) b { animation: vl-ink 0.6s var(--arrive) both; }
.place-plate:not([hidden]) span { animation: vl-rise 0.5s var(--arrive) 0.15s both; }
@media (prefers-reduced-motion: reduce) {
  #app.idle .plan-bar, #app.idle .deck-shelf > *, .place-plate b, .place-plate span { animation: none; }
}

/* ================= the Log (analysis.html, body.log-page): the same book as the map page =================
   Before this it kept the old furniture: a red bar over the open tab where the map page has the apex dot, a slide switch for
   two places, every row and panel boxed in ink. Here: the two places are the page's head, rows are hairline-divided, a box
   is paper with a breath of shadow, keys are flat ink, and the score is set once, as the masthead is. */
.log-page .vh { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* the tab bar: the apex dot marks where you are, as on the map page */
.log-page .tabbar { border-top-color: var(--hair); }
.log-page .tabbar a { height: 54px; transition: color 0.12s; }
.log-page .tabbar a.on { color: var(--panel-ink); }
.log-page .tabbar a.on::before { top: 3px; left: 50%; right: auto; bottom: auto; width: 6px; height: 6px; margin-left: -3px; border-radius: 50%; background: var(--accent); }
.log-page .tabbar a.on svg { transform: translateY(1px) scale(1.08); stroke-width: 2.1; }
@media (orientation: landscape) and (max-height: 540px) {
  .log-page .tabbar { border-left-color: var(--hair); }
  .log-page .tabbar a.on::before { top: 50%; left: 7px; margin: -3px 0 0; }
}

/* the head: Drives and Stages, two places, underlined like People's Friends and Crews */
.log-page .log-head { align-items: flex-end; min-height: 0; margin: 0 -16px; padding: 0 16px; border-bottom: 1px solid var(--hair); }
.log-page .log-tabs { display: flex; gap: 26px; }
.log-page .log-tabs > button { position: relative; min-height: 48px; padding: 0 2px 10px; border: 0; background: transparent; color: var(--panel-dim); cursor: pointer;
  font: 800 26px/1 var(--font-num); letter-spacing: 0.005em; display: flex; align-items: flex-end; }
.log-page .log-tabs > button[aria-selected="true"] { color: var(--panel-ink); }
.log-page .log-tabs > button::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 3px; background: var(--panel-ink); transform: scaleX(0); transform-origin: left; transition: transform 0.22s var(--arrive); }
.log-page .log-tabs > button[aria-selected="true"]::after { transform: none; }
.log-page .log-tabs > button:active { opacity: 0.7; }

/* quiet rows: hairlines, not ink rules */
.log-page :is(table:is(.road-index, .fp-index) td, details.quiet, td, th, .dv-tagrow, .dv-head, details.more, .log-hero, .fp-ghost, .fp-ghost .hero-score) { border-color: var(--hair); }
.log-page :is(.road-index, .fp-index) .ix-road b { font-size: 17px; }
/* a drive's date is set, not stamped: the day in the numeral face, the month small under it */
.log-page .stamp-d { border: 0; width: 42px; padding: 0; color: var(--panel-dim); font-size: 11px; letter-spacing: 0.08em; gap: 1px; }
.log-page .stamp-d b { color: var(--panel-ink); font-size: 26px; line-height: 0.95; }
.log-page .fp-ghost .stamp-d { border: 0; } .log-page .fp-ghost .stamp-d b { color: var(--panel-dim); }
.log-page tr.row-link:active td { background: var(--well); }

/* a box is paper on the page: a hairline and a breath of shadow, never an ink frame */
.log-page :is(.dp-card, .seg, .dv-corner, .dv-time button, .card, .empty, .dv-map, .dv-lanes, .seg-map, .vote-map) { border: 0; background: var(--face, var(--panel)); box-shadow: var(--lift-0); }
/* a corner overlay's clip key keeps its ink: the .dv-time button face above would paint it panel on panel (contrast floor) */
.log-page .dv-ovl button.btn.dv-clip.solid { background: var(--panel-ink); color: var(--panel); }
.log-page .dp-card { padding: 14px; } .log-page .dp-card b { font-size: 20px; }
.log-page :is(.seg, .dv-corner).on { box-shadow: inset 3px 0 0 var(--accent), var(--lift-0); }
.log-page .dv-read { background: var(--hair); border-color: var(--hair); }
.log-page .dv-z:not(.on) { border-color: var(--hair); }
/* a panel is a section of the page under a hairline, not a box */
.log-page .panel:not(.index-panel) { border: 0; border-top: 1px solid var(--hair); padding: 14px 0 0; }
.log-page .panel h2 { font-size: 20px; }
/* a disclosure's own hairline is the rule above the panel after it: one line, not two (Kudos for you, then Friends lately) */
.log-page details.quiet:not([hidden]) + .panel:not(.index-panel) { border-top: 0; }
/* the drive list straight into a panel (no quiet line between): the panel's rule closes the list, the last row draws none */
.log-page #historyPanel:not(:has(~ details.quiet:not([hidden]))) .road-index tr:last-child > td { border-bottom: 0; }
/* Share older drives holds only the road-data panel, which stays hidden until you are a member: closed or open, an empty fold is not shown */
#shareOlder:not(:has(> #contribPanel:not([hidden]))) { display: none; }

/* fields are wells, as Where to? is on the map page */
.log-page :is(select, input:not([type="range"]):not([type="checkbox"]), textarea) { border: 0; background-color: var(--well); }
.log-page :is(select, input, textarea):focus-visible { box-shadow: inset 0 0 0 2px var(--panel-ink); }
/* keys are flat ink; the old pressed-in bottom edge belonged to the boxed look */
.log-page :is(a.btn.fp-go, .dv-acts .dv-replay) { box-shadow: none; }
.log-page :is(button.btn, a.btn, label.btn):active { transform: translateY(1px); }

/* a drive's page and Your driving: the title is a masthead, like the place on the map */
.log-page #tab-drive .stages-h, .log-page #tab-driving .stages-h { font: 800 30px/1.05 var(--font-num); letter-spacing: 0.005em; }

/* arrival: the score is set once, as the masthead is; reduced motion, a cut */
.log-page .hero-score b { animation: vl-ink 0.6s var(--arrive) both; }
.log-page .dv-head .score.big { animation: vl-ink 0.6s var(--arrive) both; }
@media (prefers-reduced-motion: reduce) { .log-page .hero-score b, .log-page .dv-head .score.big { animation: none; } }

/* ================= the Garage (index.html, the sheet's garage view): you, your cars and the looks as paper =================
   It kept the boxed look: a 22 px title beside a gear in an ink box with a drop edge, each car in an ink frame with its keys
   stacked in outlines, each look framed in 1.5 px ink. Now the title is a masthead, the gear is a key laid on the page, a car
   is a card of paper with its name set large and its keys as wells, and the look in use is the one card ringed in ink. */
.sheet header { border-bottom-color: var(--hair); }
.sheet[data-view="garage"] #sheetTitle { font: 800 30px/1 var(--font-num); letter-spacing: 0.005em; }
.gear-key { border: 0; background: var(--face, var(--panel)); box-shadow: var(--lift-1); transition: transform 0.12s; }
.gear-key:active { box-shadow: 0 0 0 1px var(--hair); transform: translateY(1px); }

.garage-cards .car-card { border: 0; background: var(--face, var(--panel)); box-shadow: var(--lift-0); padding: 14px; gap: 6px; }
.garage-cards .car-card .car-cover { width: calc(100% + 28px); margin: -14px -14px 8px; }
.garage-cards .car-card .car-title b { font: 700 22px/1.1 var(--font-num); letter-spacing: 0.005em; }
.garage-cards .car-card .car-title .note { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 600; }
.garage-cards .car-card .car-title .note::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }   /* the daily car: the apex dot, the one you drive now */
.garage-cards .car-card :is(.ink-btn, label.ink-btn):not(.solid) { border-color: transparent; background: var(--well); }
.garage-cards .car-card .car-gallery img { border-color: var(--hair); }
.garage-cards { gap: 10px; }   /* .garage-cards before .car-card: garage_ui.js adds its own rules after this file */

.theme-card { border: 0; background: var(--face, var(--panel)); box-shadow: var(--lift-0); overflow: hidden; }
.theme-card.in-use { border-width: 0; box-shadow: 0 0 0 2px var(--panel-ink), var(--lift-1); }
.theme-cards, html:not([data-type-size]) .theme-cards { padding-top: 4px; padding-bottom: 8px; }   /* the in-use ring and the lift are not clipped by the shelf */

/* ================= People: the same head as the Log, cards as paper ================= */
.people-tabs > button { font: 800 26px var(--font-num); letter-spacing: 0.005em; }
.people-tabs > button::after { transform-origin: left; transition: transform 0.22s var(--arrive); }
.sheet .card:not(.sample-crew) { border: 0; background: var(--face, var(--panel)); box-shadow: var(--lift-0); }
/* a friend's request is the one thing to answer on the page: paper, marked with the apex dot */
.sheet .request-card { padding: 14px; }
.sheet .request-card p b::before { content: ""; display: inline-block; width: 7px; height: 7px; margin: 0 7px 2px 0; border-radius: 50%; background: var(--accent); }

/* ================= the sheets over a page (.side-pop: Settings and each setting, Options, Best roads nearby, People's,
   a crew's, roadbooks, duels): paper risen over the scrim, a masthead, the choices laid in wells =================
   They kept the boxed look: a 1 px rule on the top edge and a hard shadow, an 18 px title, every mode switch framed in
   2 px ink with a pressed-in thumb. Now a sheet rises like the deck (--lift-2), its title is set like the Garage's,
   and a mode switch is a well with the chosen key in ink: the choice still reads at a glance. */
.side-pop { border-top: 0; box-shadow: var(--lift-2); }
.side-pop::before { top: 6px; height: 4px; border-radius: 2px; opacity: 0.35; }   /* the grabber, as on the deck */
.side-pop > .side-pop-head { gap: 12px; }   /* no rule under it: the first row's hairline divides, so a switch or a list never doubles it */
.side-pop > .side-pop-head h3 { font: 800 26px/1.05 var(--font-num); letter-spacing: 0.005em; min-width: 0; overflow-wrap: anywhere; }
.side-pop > .side-pop-head h3 + * { flex: none; }
@media (min-width: 1100px) and (min-height: 600px) { .side-pop { border-left: 0; } }   /* a desk: the panel beside the Garage, on its lift */

/* a mode: a well, the chosen key in ink (was a 2 px ink frame and a drop edge on the thumb) */
.switch { border: 0; background: var(--well); }
.switch > .on, .switch > [aria-checked="true"], .switch > [aria-pressed="true"] { box-shadow: none; }
.switch > button:active { box-shadow: none; filter: brightness(0.92); }

/* ================= a crew's page and the route card's Share box =================
   The crew's name was set in the body face beside an ink-boxed Invite, and Edit livery sat on the cover in an ink box;
   the Share box offered friends and crews as a wall of ink-framed keys. Now the crew's name is a masthead (Barlow, as
   the Garage's), its keys are paper laid on the page, the chat field is a well, and the people you can send a route to
   are wells that turn ink when picked. crew_page.js appends its <style> after this file, so these rules start `body`. */
.crew-head > b { font: 800 30px/1.05 var(--font-num); letter-spacing: 0.005em; }
body .cp-title h2 { font: 800 32px/1.02 var(--font-num); letter-spacing: 0.005em; }
body :is(.cp-head .cp-edit, .cp-title .ink-btn:not(.solid)) { border: 0; background: var(--face, var(--panel)); box-shadow: var(--lift-1); }
body .cp-say textarea { border: 0; background: var(--well); }
body .cp-say textarea:focus { box-shadow: inset 0 0 0 2px var(--panel-ink); outline: 0; }
#routeSharePick .row .ink-btn:not(.solid):not(.on) { border-color: transparent; background: var(--well); }
#routeSharePick .row .ink-btn.on { border-color: var(--panel-ink); }

/* ================= the map under the deck: never cut off at the top =================
   On the idle map the top of the canvas came out blank paper with a hard edge, exactly as tall as the deck (157 px on an
   iPhone 13; Roamer B's first run, 2026-11-11). The map draws to the top (its pixels are all there); Chromium's compositor
   saw the opaque deck over the canvas and culled that much of it, at the wrong end of the y-flipped WebGL layer. A deck
   that is not quite opaque is not an occluder, so nothing is culled; 0.4 % of the map under it is invisible. */
.binnacle { background: color-mix(in srgb, var(--panel) 99.6%, transparent); }

/* ================= the first friend, the first crew (signed in, nobody yet) =================
   Signed out, People is a page: a drawing, its name set large, the key at the foot. Signed in with nobody yet it was one
   grey sentence and a small key. Now it is the same page: your road drawn, the friend's (or the crew's file) still pencil,
   what to do set large, and the one key full width under it. */
.people-first { display: flex; flex-direction: column; }
#accountSection .people-first .join-head { margin-top: 18px; }
.people-first .people-lead { margin-top: 6px; font-size: 15px; color: var(--panel-dim); }
.people-first + .row { margin-top: 4px; }
.people-first + .row > .ink-btn.solid { flex: 1 1 auto; min-height: 52px; font-size: 16px; }
.join-art .jr-seat { fill: var(--panel); stroke: var(--panel-dim); stroke-width: 2; stroke-dasharray: 2.5 3; }

/* The empty Garage: a bay waiting for a car (garage_ui.js), the People first pages' drawing set into the section as a well */
.garage-first .join-art { margin: 2px 0 0; border: 0; border-radius: 12px; overflow: hidden; background: var(--well); }
.garage-first .join-art .jr-bay { fill: none; stroke: var(--panel-dim); stroke-width: 2; stroke-dasharray: 5 5; }
.garage-first .join-head { margin: 18px 0 0; padding: 0; border: 0; font: 700 30px/1.02 var(--font-num); letter-spacing: 0.005em; text-transform: none; }

/* Theme cards with no essay (TestFlight 2026-11-12): the voice line keeps a breath under the Use key */
.theme-card .tc-voice { margin-top: 10px; }
