/* Vamoto public pages: the marketing landing (#/ root view), features.html
   and the two legal pages share this sheet. Everything is namespaced under
   .lp (the landing view, the features <main> and the legal <main> all carry
   the class) with lp- classes so nothing collides with the app views in
   style.css. Brand colours come from the :root knobs in style.css; the
   public-page knobs live below.

   The one layout rule (owner, round 27): text never sits on a photo. Every
   photo is either framed in its own column with the caption directly
   beneath it, or it bleeds to the viewport edge in a split (hero, bands)
   with the copy on solid asphalt beside it. Each photo names its subject in
   `--focal` (an object-position, from deploy/make-site-photos.py's SLOTS)
   so whatever object-fit: cover trims at a given width, it is never the
   rider or the road. */

.lp {
  --lp-display: "Bricolage Grotesque", system-ui, -apple-system, sans-serif;
  --lp-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --lp-col: 1160px;
  --lp-gutter: clamp(20px, 4.5vw, 48px);
  --lp-indent: clamp(20px, 4.5vw, 56px);
  --lp-radius: 14px;
  --lp-line: rgba(255, 138, 42, 0.32);
  /* Body copy on the public pages sits between --text and --text-2. Mixed
     rather than fixed so the pages read in the light chrome too (round 27
     B11): in dark these land on the old #cfd8e3 / #c6d0db / #b7c2ce, in
     light they land on the same steps down from the near-black ink. */
  --lp-body-text: color-mix(in srgb, var(--text) 78%, var(--text-2));
  --lp-body-soft: color-mix(in srgb, var(--text) 65%, var(--text-2));
  --lp-body-dim: color-mix(in srgb, var(--text) 55%, var(--text-2));
  /* The containing block for the JS-drawn route spine, which is positioned
     with offsets accumulated up to this element. */
  position: relative;
  overflow-x: clip;
}

#view-landing {
  /* Full-bleed marketing page: undo style.css's centered app column and
     pull the hero up under the translucent fixed topnav. */
  max-width: none;
  padding: 0;
  margin: calc(-1 * var(--topbar-h)) 0 0;
}

/* ---------- shared type ---------- */

.lp .lp-display {
  font-family: var(--lp-display);
  font-weight: 800;
  font-size: clamp(44px, 6vw, 84px);
  line-height: 0.98;
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 10px 0 22px;
}

.lp .lp-h2 {
  font-family: var(--lp-display);
  font-weight: 700;
  font-size: clamp(30px, 4.6vw, 54px);
  line-height: 1.04;
  letter-spacing: -0.015em;
  text-wrap: balance;
  margin: 10px 0 18px;
}

/* Roadbook eyebrow: rally pace-note voice; the dot is a waypoint on the
   dashed route spine that stitches the sections together. */
.lp .lp-roadbook {
  position: relative;
  font-family: var(--lp-mono);
  font-size: 12.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin: 0;
}

.lp .lp-lead {
  font-size: clamp(16px, 2vw, 19px);
  line-height: 1.55;
  color: var(--lp-body-text);
  margin: 0 0 14px;
}

.lp .lp-measure { max-width: 62ch; }

.lp .lp-sec > p,
.lp .lp-split-text > p,
.lp .lp-band-copy > p {
  color: var(--text-2);
  max-width: 62ch;
}

/* ---------- photo captions ----------
   One caption style for every photo on the site: mono, wide tracking,
   muted, the place name (.lp-geo, with data-lat/lon) and the accent
   "Plan a ride here" link. Always BELOW the photo, never on it. */

.lp .lp-cap,
.lp figcaption.lp-tile-cap {
  font-family: var(--lp-mono);
  font-size: 11.5px;
  letter-spacing: 0.1em;
  line-height: 1.6;
  color: var(--text-2);
  margin: 10px 0 0;
}

.lp .lp-geo {
  font-family: var(--lp-mono);
  font-style: normal;
  font-size: 11.5px;
  letter-spacing: 0.1em;
  color: var(--text-2);
}

/* ---------- bleed photo box (hero + bands) ----------
   The figure is a column: the photo box fills whatever height the split
   gives it, the caption sits under it on solid background. */

.lp .lp-photo {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  /* The width is stated, never left to the flex stretch. The photo box is a
     flex item in a column flex figure, and on phones it also carries an
     aspect-ratio plus a max-height (below). WebKit then resolves the cross
     size THROUGH the ratio from the clamped height instead of stretching it
     to the figure: on an iPhone 15 Pro the hero photo came out 326.86 px in
     a 393 px viewport, a 66 px gap down the right edge that Chromium (which
     stretches) never showed. An explicit width makes the cross size definite
     so the ratio can only ever drive the height. */
  width: 100%;
  overflow: hidden;
  background: var(--surface);
}

.lp .lp-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
  display: block;
}

/* ---------- hero: copy left on asphalt, photo bleeding right ----------
   Four tracks: gutter | copy | photo | gutter. Track 1 reproduces
   .lp-body's own arithmetic (max-width 1160px, centred, plus its gutter
   padding), so the hero copy starts exactly where the body column's content
   starts below it and the km 0 ring lands on the sections' spine x. Below
   1160px the computed max drops under the gutter minimum and minmax()
   floors it at the gutter, which is where .lp-body's content starts there
   too. The 100% is the grid container's width, never 100vw: 100vw includes
   the classic scrollbar and the body column does not. The photo track runs
   on through the right gutter to the viewport edge. */

.lp .lp-hero {
  display: grid;
  grid-template-columns:
    minmax(var(--lp-gutter), calc((100% - var(--lp-col)) / 2 + var(--lp-gutter)))
    minmax(0, 540px)
    minmax(0, 620px)
    minmax(var(--lp-gutter), 1fr);
  min-height: 100vh;
  min-height: 100svh;
}

.lp .lp-hero-copy {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--topbar-h) + 48px) clamp(28px, 4vw, 64px) 56px 0;
}

.lp .lp-hero-media {
  grid-column: 3 / 5;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  margin: 0;
  min-height: 0;
}

.lp .lp-hero-media .lp-photo { min-height: 360px; }

.lp .lp-hero-media .lp-cap {
  padding: 0 var(--lp-gutter) 14px 0;
  margin-top: 12px;
}

.lp .lp-hero-sub {
  font-size: clamp(16px, 2.1vw, 19px);
  line-height: 1.55;
  color: var(--lp-body-text);
  max-width: 46ch;
  margin: 0 0 24px;
}

.lp .lp-cta-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
}

/* The CTA's precondition (round 27 N1-B1): routing needs the phone app. */
.lp .lp-cta-note {
  max-width: 46ch;
  margin: 14px 0 0;
  font-size: 13.5px;
  line-height: 1.55;
}

.lp .lp-hero-note {
  font-family: var(--lp-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  line-height: 1.6;
  color: var(--text-2);
  margin: 18px 0 0;
}

/* Hero entrance: one orchestrated rise, then the page stays quiet. */
@keyframes lp-rise {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: none; }
}

.lp .lp-hero-copy > * {
  animation: lp-rise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.lp .lp-hero-copy > :nth-child(2) { animation-delay: 0.08s; }
.lp .lp-hero-copy > :nth-child(3) { animation-delay: 0.16s; }
.lp .lp-hero-copy > :nth-child(4) { animation-delay: 0.24s; }
.lp .lp-hero-copy > :nth-child(5),
.lp .lp-hero-copy > :nth-child(6),
.lp .lp-hero-copy > :nth-child(7) { animation-delay: 0.32s; }
/* km 0 rises last, by class rather than position: it is the one child whose
   index would move again if the hero copy ever gains a line. */
.lp .lp-hero-copy > .lp-roadbook { animation-delay: 0.4s; }

/* ---------- app store badges (mocked until release) ---------- */

.lp .lp-badges {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 18px;
}

.lp .lp-badge {
  display: flex;
  align-items: center;
  gap: 11px;
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 9px 18px 9px 14px;
  text-decoration: none;
  color: var(--text);
  background: var(--surface);
  cursor: default;
  transition: border-color 0.25s ease;
}

.lp .lp-badge:hover,
.lp .lp-badge:focus-visible { border-color: var(--accent); }

.lp .lp-badge svg {
  width: 24px;
  height: 24px;
  flex: none;
}

.lp .lp-badge small {
  display: block;
  font-family: var(--lp-mono);
  font-size: 10px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-2);
}

.lp .lp-badge strong {
  display: block;
  font-family: var(--lp-display);
  font-weight: 700;
  font-size: 17px;
  line-height: 1.15;
}

/* ---------- body column + route spine ---------- */

.lp .lp-body {
  max-width: var(--lp-col);
  margin: 0 auto;
  padding: 0 var(--lp-gutter);
}

/* The route spine: ONE dashed line per page, drawn by js/landing_fx.js from
   the first km dot to the last one, so it never breaks in the white space
   between two .lp-body blocks or across a full-bleed .lp-band. Width 0 with
   a 2px border, so the painted line is [left, left+2] and its centre is
   left+1 - the JS sets left = dot centre - 1. z-index 1 sits BELOW the
   bands (z-index 2, see .lp-band below) so the opaque band background and
   the flipped band's full-bleed photo paint over this x - the line enters
   at the band's top border and resumes at its bottom border, never
   crossing the band copy or photo. The rings (z-index 2) still paint over
   the line everywhere else. Without JS the element is never created and
   the dots stand alone. */
.lp .lp-spine {
  position: absolute;
  width: 0;
  border-left: 2px dashed var(--lp-line);
  z-index: 1;
  pointer-events: none;
}

.lp .lp-sec,
.lp .lp-final {
  position: relative;
  padding: clamp(64px, 10vw, 128px) 0 0 var(--lp-indent);
}

/* km 0 is the last line of the hero copy and the spine starts on its ring.
   The hero copy column starts on the body column's own content edge, so
   this one line carries the indent itself and its ring then hangs in the
   indent exactly like every section ring below. margin (not padding) so the
   shared ::before rule, which is measured from the element's own left edge,
   needs no hero-specific variant. */
.lp .lp-hero-copy > .lp-roadbook { margin-left: var(--lp-indent); }

/* One waypoint ring per roadbook line. The ring is 18px across (12px box +
   2x3px border), so left = -(indent) - 10px puts its centre 1px left of the
   section's content edge, which is where js/landing_fx.js draws the spine.
   z-index 2 keeps the ring over the line (z-index 1) so the spine visibly
   enters and leaves it. */
.lp .lp-sec > .lp-roadbook::before,
.lp .lp-final > .lp-roadbook::before,
.lp .lp-page-head > .lp-roadbook::before,
.lp .lp-hero-copy > .lp-roadbook::before {
  content: "";
  position: absolute;
  top: 50%;
  left: calc(-1 * var(--lp-indent) - 10px);
  z-index: 2;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--bg);
  border: 3px solid var(--accent);
  transform: translateY(-50%);
}

/* ---------- split sections (text + framed photo) ---------- */

.lp .lp-split {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 6fr);
  gap: clamp(24px, 4.5vw, 60px);
  align-items: center;
}

.lp .lp-split-flip .lp-split-media { order: -1; }

.lp .lp-split-media { margin: 0; min-width: 0; }

.lp .lp-split-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
  border-radius: var(--lp-radius);
  border: 1px solid var(--line);
}

/* ---------- stat lines (roadbook data) ---------- */

.lp .lp-statline {
  list-style: none;
  margin: 22px 0 0;
  padding: 0;
  font-family: var(--lp-mono);
  font-size: 13px;
  color: var(--lp-body-dim);
}

.lp .lp-statline li {
  padding: 9px 0;
  border-top: 1px solid var(--line);
}

.lp .lp-statline li:last-child { border-bottom: 1px solid var(--line); }

/* Roadbook bullet. A single right-pointing angle, escaped so the stylesheet
   stays ASCII. */
.lp .lp-statline li::before {
  content: "\203A";
  color: var(--accent-ink);
  margin-right: 10px;
}

/* ---------- profile cards: photo on top, caption in a solid body ---------- */

.lp .lp-cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 2vw, 24px);
  margin-top: 30px;
}

.lp .lp-card {
  display: flex;
  flex-direction: column;
  margin: 0;
  min-width: 0;
  border-radius: var(--lp-radius);
  border: 1px solid var(--line);
  background: var(--surface);
  overflow: hidden;
}

.lp .lp-card img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
}

.lp .lp-card figcaption {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 16px 18px 18px;
}

.lp .lp-card strong {
  font-family: var(--lp-display);
  font-weight: 700;
  font-size: 21px;
  line-height: 1.15;
}

.lp .lp-card span {
  color: var(--lp-body-soft);
  font-size: 14px;
  line-height: 1.4;
}

.lp .lp-card .lp-geo { margin-top: 8px; }

/* ---------- ride photo gallery: 16:9 tiles, caption bar beneath ---------- */

/* align-items: start so a tile never stretches to its row's height, and
   min-width: 0 so a long place name cannot push a column wider. */
.lp .lp-gallery {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: start;
  gap: 14px;
  margin-top: 30px;
}

.lp .lp-tile {
  margin: 0;
  min-width: 0;
  overflow: hidden;
  border-radius: var(--lp-radius);
  border: 1px solid var(--line);
  background: var(--surface);
}

/* height: auto is load-bearing. The markup carries width/height attributes,
   which the UA maps to presentational width/height; author CSS overrides the
   width but, without this, NOT the height, so the tile kept the attribute's
   pixel height and rendered as a tall column with a cropped photo in it. */
.lp .lp-tile img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
}

.lp figcaption.lp-tile-cap {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 14px 12px;
  margin-top: 0;
}

.lp .lp-chiprow {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin: 18px 0 0;
}

.lp .lp-chip {
  font-family: var(--lp-mono);
  font-size: 12px;
  color: var(--text-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 13px;
  white-space: nowrap;
}

/* ---------- planner feature grid ---------- */

.lp .lp-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin-top: 26px;
}

.lp .lp-cell {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  padding: 18px;
}

.lp .lp-cell h3 {
  margin: 0 0 8px;
  font-size: 16px;
  color: var(--accent-ink);
}

.lp .lp-cell p {
  margin: 0;
  color: var(--text-2);
  font-size: 14px;
}

/* ---------- full-width photo bands: copy on one side, photo on the other ----------
   Same four tracks as the hero, track 1 included, so the band copy starts
   on the body column's content edge like everything else. The band is a
   direct child of the landing view (not of the body column), so it spans
   the viewport without any 100vw arithmetic. .lp-band-flip puts the photo
   on the left. */

.lp .lp-band {
  display: grid;
  grid-template-columns:
    minmax(var(--lp-gutter), calc((100% - var(--lp-col)) / 2 + var(--lp-gutter)))
    minmax(0, 540px)
    minmax(0, 620px)
    minmax(var(--lp-gutter), 1fr);
  min-height: min(72vh, 680px);
  margin-top: clamp(72px, 10vw, 140px);
  background: var(--surface);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  /* The band is an opaque full-bleed block sitting on the same x as the
     route spine (.lp-spine, z-index 1). Without its own stacking context
     the spine's absolute positioning would still let it paint through on
     some engines; position+z-index 2 pins the band above it so the dashed
     line visibly disappears behind the band at its top border and
     reappears below its bottom border, instead of running through the
     band copy or the km 81 photo. */
  position: relative;
  z-index: 2;
}

.lp .lp-band-copy {
  grid-column: 2;
  grid-row: 1;
  align-self: center;
  padding: clamp(44px, 6vw, 80px) clamp(28px, 4vw, 64px) clamp(44px, 6vw, 80px) 0;
}

.lp .lp-band-media {
  grid-column: 3 / 5;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  margin: 0;
  min-height: 0;
}

.lp .lp-band-media .lp-photo { min-height: 360px; }

.lp .lp-band-media .lp-cap {
  padding: 0 var(--lp-gutter) 14px 0;
  margin-top: 12px;
}

.lp .lp-band-flip .lp-band-copy {
  grid-column: 3;
  padding-left: clamp(28px, 4vw, 64px);
  padding-right: 0;
}

.lp .lp-band-flip .lp-band-media { grid-column: 1 / 3; }

.lp .lp-band-flip .lp-band-media .lp-cap { padding: 0 0 14px var(--lp-gutter); }

.lp .lp-band-copy .lp-lead { max-width: 46ch; margin-bottom: 24px; }
.lp .lp-band-copy .lp-h2 { max-width: 16ch; }
.lp .lp-band-copy .lp-statline { max-width: 440px; }

/* ---------- pricing ---------- */

.lp .lp-price-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(28px, 5vw, 72px);
  align-items: center;
  margin-top: 14px;
}

.lp .lp-price {
  display: flex;
  align-items: baseline;
  gap: 16px;
  margin: 0;
}

.lp .lp-price-num {
  font-family: var(--lp-display);
  font-weight: 800;
  font-size: clamp(88px, 13vw, 184px);
  line-height: 0.9;
  letter-spacing: -0.03em;
  color: var(--accent-ink);
}

.lp .lp-price-per {
  font-family: var(--lp-mono);
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-2);
}

.lp .lp-price-text .lp-lead { max-width: 44ch; }
.lp .lp-price-text p:last-child { margin-bottom: 0; }

/* ---------- FAQ ---------- */

.lp .lp-faq {
  margin-top: 26px;
  max-width: 760px;
}

.lp .lp-faq details {
  border-top: 1px solid var(--line);
}

.lp .lp-faq details:last-child { border-bottom: 1px solid var(--line); }

.lp .lp-faq summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 16px 2px;
  font-weight: 600;
  font-size: 16.5px;
}

.lp .lp-faq summary::-webkit-details-marker { display: none; }

.lp .lp-faq summary::after {
  content: "+";
  font-family: var(--lp-mono);
  font-size: 20px;
  color: var(--accent-ink);
  flex: none;
}

.lp .lp-faq details[open] summary::after { content: "\2212"; } /* U+2212 minus */

.lp .lp-faq details p {
  margin: 0 0 18px;
  color: var(--text-2);
  max-width: 62ch;
}

/* ---------- final CTA + footer ---------- */

.lp .lp-final {
  padding-bottom: clamp(72px, 10vw, 128px);
}

.lp .lp-final-line {
  font-size: clamp(34px, 5.8vw, 76px);
  max-width: 16ch;
  margin: 12px 0 30px;
}

.lp .lp-footer {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  border-top: 1px solid var(--line);
  padding: 26px 0 34px;
}

.lp .lp-footer-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  color: var(--text);
  text-decoration: none;
}

.lp .lp-footer-brand img { width: 20px; height: 20px; }

.lp .lp-footer-nav {
  display: flex;
  gap: 4px 18px;
  flex-wrap: wrap;
  flex: 1;
}

.lp .lp-footer-nav a {
  color: var(--text-2);
  text-decoration: none;
  font-size: 14px;
}

.lp .lp-footer-nav a:hover,
.lp .lp-footer-nav a:focus-visible { color: var(--text); }

.lp .lp-footer-note {
  font-family: var(--lp-mono);
  font-size: 12px;
  color: var(--text-2);
  margin: 0;
}

/* The OpenStreetMap/ODbL credit is a licence obligation, so its link has to
   read on the dark footer instead of falling back to the browser's default
   blue. It is inline text inside a sentence, hence .allow-small in the
   markup (the audit's 44 px tap-target rule has the same WCAG exception). */
.lp .lp-footer-note a {
  color: var(--text-2);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.lp .lp-footer-note a:hover,
.lp .lp-footer-note a:focus-visible { color: var(--text); }

.lp a:focus-visible,
.lp summary:focus-visible,
.lp button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- standalone public pages (features.html, legal) ---------- */

/* Page head: the roadbook eyebrow, a display headline and a lead, in the
   body column. Standalone pages sit below the fixed nav like the app views
   (main's padding-top) and add their own breathing room. */
.lp .lp-page-head {
  padding: clamp(40px, 7vh, 88px) 0 clamp(8px, 2vw, 24px) var(--lp-indent);
  position: relative;
}

.lp .lp-page-head .lp-display {
  font-size: clamp(38px, 5.4vw, 72px);
  max-width: 16ch;
}

/* Phone-frame rows: the bezel is baked into the image, so no border and no
   radius here. Three across on the wide sets, five on the "everything else"
   row. Where a row would wrap (3-2 for the five on a tablet, 2-1 and 2-2-1
   orphans on a phone) the group is a snap strip instead: see .lp-frames-5
   under 1024px and .lp-frames under 601px in the responsive block. */
.lp .lp-frames {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 2.5vw, 32px);
  margin-top: 30px;
  align-items: start;
}

.lp .lp-frames-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: clamp(12px, 1.6vw, 22px); }

.lp .lp-frame { margin: 0; min-width: 0; }

.lp .lp-frame img {
  display: block;
  width: 100%;
  height: auto;
}

.lp .lp-frame .lp-cap { margin-top: 12px; }

.lp .lp-frame .lp-cap strong {
  display: block;
  font-family: var(--lp-display);
  font-size: 15px;
  letter-spacing: 0;
  color: var(--text);
  margin-bottom: 2px;
}

/* The liveries composite is 3200px wide by design and used to scroll
   sideways inside this box. It no longer does (owner, round 28): the image
   is scaled to the column, and <ol class="lp-names"> under it carries the
   names at the widths where the baked caption strip gets too small to read.
   overflow: hidden rather than visible only so the corners still follow the
   box's radius; with width:100% there is nothing left to scroll either way. */
.lp .lp-wide {
  margin: 30px 0 0;
  overflow: hidden;
  border-radius: var(--lp-radius);
  border: 1px solid var(--line);
  background: var(--surface);
}

.lp .lp-wide img {
  display: block;
  width: 100%;
  height: auto;
}

/* CSS-only Night/Day switch over the liveries composite (round 28 C).
   Two native radios: the inputs are visually hidden with the site's
   standard clip technique (same as .scheme-tile / .mode-segment in
   css/settings.css) and the label is the 44px tap target and the focus
   ring's carrier. Night is checked because the baked composite has always
   been the night map. Both segments and the figure are siblings of the
   inputs, so the swap is a plain sibling selector: no :has(), no JS. */
.lp .lp-mode-switch {
  border: 0;
  margin: 26px 0 0;
  padding: 0;
  min-width: 0; /* a fieldset defaults to min-width: min-content */
}

.lp .lp-mode-legend {
  padding: 0;
  margin: 0 0 10px;
  font-family: var(--lp-mono);
  font-size: 12.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-2);
}

.lp .lp-mode-input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.lp .lp-mode-seg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 92px;
  min-height: 44px;
  margin: 0 8px 0 0;
  padding: 0 18px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--lp-mono);
  font-size: 12.5px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

.lp .lp-mode-seg:hover { color: var(--text); }

.lp .lp-mode-input:checked + .lp-mode-seg {
  border-color: var(--accent);
  color: var(--text);
}

.lp .lp-mode-input:focus-visible + .lp-mode-seg {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* The swap. Night is the default, so the day shot starts hidden. */
/* Default-hidden day shot: .lp .lp-wide img (display:block) outranks a bare
   .lp .lp-livery-day, so the hiding rule carries the .lp-wide class too. */
.lp .lp-wide .lp-livery-day { display: none; }
.lp .lp-mode-input[value="day"]:checked ~ .lp-wide-fig .lp-livery-night { display: none; }
.lp .lp-mode-input[value="day"]:checked ~ .lp-wide-fig .lp-livery-day { display: block; }

.lp .lp-names {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  counter-reset: livery;
}

.lp .lp-names li {
  counter-increment: livery;
  font-family: var(--lp-mono);
  font-size: 12px;
  color: var(--text-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 12px;
  white-space: nowrap;
}

.lp .lp-names li::before {
  content: counter(livery, decimal-leading-zero) " ";
  color: var(--accent-ink);
}

/* Legal pages: one reading column, the same type and footer as the rest. */
.lp .lp-article {
  max-width: 760px;
  margin: 0 auto;
  padding: clamp(40px, 7vh, 88px) var(--lp-gutter) 0;
}

.lp .lp-article h1 {
  font-family: var(--lp-display);
  font-weight: 700;
  font-size: clamp(34px, 5vw, 56px);
  line-height: 1.04;
  letter-spacing: -0.015em;
  margin: 10px 0 12px;
}

.lp .lp-article .lp-sub {
  color: var(--text-2);
  margin: 0 0 8px;
}

.lp .lp-article .lp-sub + .lp-sub { margin-bottom: 0; }

.lp .lp-article h2 {
  font-family: var(--lp-display);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: -0.01em;
  margin: 36px 0 10px;
}

.lp .lp-article h2:first-of-type { margin-top: 40px; }

.lp .lp-article p,
.lp .lp-article li {
  color: var(--lp-body-text);
  line-height: 1.65;
}

.lp .lp-article p { margin: 0 0 12px; }
.lp .lp-article ul { margin: 0 0 12px; padding-left: 20px; }
.lp .lp-article li { margin: 0 0 4px; }
.lp .lp-article dl { margin: 0; }
.lp .lp-article dt { color: var(--text-2); font-size: 13px; margin-top: 14px; }
.lp .lp-article dd { margin: 2px 0 0; }
.lp .lp-article a { color: var(--accent-ink); }

/* Contact reveal (js/contact.js): a small secondary button in the article's
   mono type. It replaces itself with the plain mailto link once the visitor
   has interacted with the page, and that link inherits .lp-article a. */
.lp .lp-article .contact-reveal-btn {
  font-family: var(--lp-mono);
  font-size: 13px;
  line-height: 1.4;
  color: var(--text);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 14px;
  cursor: pointer;
}

.lp .lp-article .contact-reveal-btn:hover {
  border-color: var(--accent);
  color: var(--accent-ink);
}

.lp .lp-article .contact-reveal-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.lp .lp-article .contact-reveal-btn[disabled] {
  opacity: 0.65;
  cursor: default;
}

.lp .lp-article .lp-footer { margin-top: 56px; }

/* ---------- scroll reveal (progressive enhancement) ----------
   Initial hidden state only applies once landing_fx.js has tagged the view
   with .lp-js. Without JS everything simply renders visible. */

.lp.lp-js .lp-reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.lp.lp-js .lp-reveal.lp-in {
  opacity: 1;
  transform: none;
}

/* ---------- responsive ---------- */

/* Below 1024px the splits stack: photo first, caption under it, copy
   beneath on solid asphalt. The photo box gets an aspect ratio instead of
   the split's height. */
@media (max-width: 1023px) {
  .lp .lp-hero,
  .lp .lp-band {
    grid-template-columns: 1fr;
    min-height: 0;
  }
  .lp .lp-hero-media,
  .lp .lp-band-media,
  .lp .lp-band-flip .lp-band-media {
    grid-column: 1;
    grid-row: 1;
  }
  .lp .lp-hero-copy,
  .lp .lp-band-copy,
  .lp .lp-band-flip .lp-band-copy {
    grid-column: 1;
    grid-row: 2;
    padding: 36px var(--lp-gutter) 48px;
  }
  .lp .lp-hero-media .lp-photo,
  .lp .lp-band-media .lp-photo {
    flex: none;
    min-height: 0;
    aspect-ratio: 3 / 2;
  }
  .lp .lp-hero-media .lp-cap,
  .lp .lp-band-media .lp-cap,
  .lp .lp-band-flip .lp-band-media .lp-cap {
    padding: 0 var(--lp-gutter);
  }
  .lp .lp-band-copy { align-self: start; }
  /* The frame strip: one row that scrolls sideways with a snap per shot,
     bleeding into the body gutter so the first card starts on the text edge
     and the next card peeks in at the right (that peek is the scroll
     affordance; the scrollbar is hidden). Each figure states an explicit
     width AND flex: 0 0 auto: WebKit derives a flex item's width from its
     height when only a ratio is given (the hero photo bug), and the figures
     must never shrink to fit the row. The strip scrolls inside its own box
     and .lp clips x, so the page itself never scrolls sideways.
     Five phone shots would wrap 3-2 at this width, so the five-wide row is
     a strip from here down (the three-wide sets still fit as one row of
     three); 28vw shows three cards and a clear peek of the fourth. */
  .lp .lp-frames-5 {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: 12px;
    margin-left: calc(-1 * var(--lp-gutter));
    margin-right: calc(-1 * var(--lp-gutter));
    padding: 0 var(--lp-gutter) 6px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--lp-gutter);
    scrollbar-width: none;
  }
  .lp .lp-frames-5::-webkit-scrollbar { display: none; }
  .lp .lp-frames-5 .lp-frame {
    flex: 0 0 auto;
    width: 28vw;
    scroll-snap-align: start;
  }
}

@media (max-width: 900px) {
  .lp .lp-split,
  .lp .lp-split-flip {
    grid-template-columns: 1fr;
  }
  .lp .lp-split-flip .lp-split-media { order: 0; }
  .lp .lp-cards { grid-template-columns: 1fr; }
  .lp .lp-card img { aspect-ratio: 3 / 2; }
  .lp .lp-gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lp .lp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lp .lp-price-row { grid-template-columns: 1fr; gap: 20px; }
  /* Footer links read fine as small text on desktop, but at this width
     they are real thumb targets: give each one a 44px tap box without
     changing its font size (site UI audit, round 26 section 6). */
  .lp .lp-footer-nav a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 4px 8px;
    margin: -4px -8px;
  }
  /* The brand mark is a link home on the standalone pages: same 44px box. */
  .lp a.lp-footer-brand { min-height: 44px; }
}

@media (max-width: 600px) {
  .lp .lp-chip { white-space: normal; }
  .lp .lp-footer {
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
  }
  .lp .lp-footer-nav { gap: 4px 12px; }
  .lp .lp-hero-media .lp-photo {
    aspect-ratio: 4 / 5;
    max-height: 62svh;
  }
  .lp .lp-band-media .lp-photo { aspect-ratio: 4 / 3; }
  .lp .lp-gallery { grid-template-columns: 1fr; }
  .lp .lp-grid { grid-template-columns: 1fr; }
  /* Every phone-frame group is a strip on a phone: two across gave 2-1 and
     2-2-1 orphan rows. 72vw is a phone screen at near phone size with the
     next one peeking in; the same block as the five-wide tablet strip above,
     repeated because the two groups switch at different widths. */
  .lp .lp-frames {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: 12px;
    margin-left: calc(-1 * var(--lp-gutter));
    margin-right: calc(-1 * var(--lp-gutter));
    padding: 0 var(--lp-gutter) 6px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--lp-gutter);
    scrollbar-width: none;
  }
  .lp .lp-frames::-webkit-scrollbar { display: none; }
  .lp .lp-frames .lp-frame {
    flex: 0 0 auto;
    width: 72vw;
    scroll-snap-align: start;
  }
  .lp .lp-card img { aspect-ratio: 4 / 3; }
}

@media (prefers-reduced-motion: reduce) {
  .lp .lp-hero-copy > * { animation: none; }
  .lp.lp-js .lp-reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
