/* ============================================================
   Rochester Car Rental design system

   A dark system, built to the shape of realcar.nyc: black page,
   two raised near-black surfaces, generously rounded cards, pill
   buttons, and a wide geometric sans set large. Where RealCar
   uses teal, this uses Rochester's gold. The accent is the only
   place the two systems diverge, and it carries the brand.

   The face is TeX Gyre Adventor, an open metric clone of ITC
   Avant Garde Gothic (GUST Font License / LPPL 1.3c). It ships
   Regular and Bold only; there is no 500, so display type is set
   Bold and body Regular rather than faked with a synthetic weight.

   Section headings are two-tone: the muted grey half is marked up
   with <i>, the emphatic half is plain. That single pattern does
   the work that eyebrow lockups would otherwise do.

   Deliberately absent, because they read as machine-generated:
   icon-in-a-circle badges, gradient headlines, drop shadows under
   everything, and a uniform card grid where a bento would say
   more.

   Reference: realcar.nyc (layout, rhythm, card and button shapes).
   ============================================================ */

/* ── Typeface ── */
@font-face {
  font-family: 'Adventor';
  src: url('adventor-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Adventor';
  src: url('adventor-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ── Tokens ── */
:root {
  /* Ground and the two surfaces that sit on it. */
  --void:     #000000;
  --surface:  #121212;
  --raised:   #1B1B1B;

  --fg:       #FFFFFF;
  --fg-mute:  #888888;   /* 5.9:1 on void, 5.3:1 on surface */

  /* One gold, used for every accent. 8.1:1 on void, 7.2:1 on
     surface, and 7.6:1 the other way round for text on a fill. */
  --gold:     #C49A55;
  --gold-lit: #D9B679;
  --on-gold:  #0B0B0B;

  --line:        rgba(255, 255, 255, 0.10);
  /* Every border this token draws is a control edge: the quiet button, the
     hamburger, the fleet filter pills. At 0.20 it composited to #333333 on the
     page ground, 1.66:1, so the only thing marking those controls as controls
     failed the 3:1 boundary floor. 0.38 clears 3:1 on all three grounds this
     site paints, and tests/contrast.mjs composites the alpha and prints the
     numbers rather than leaving them as a claim in this comment: 3.39:1 on
     --void, 3.57:1 on --surface, 3.58:1 on --raised. */
  --line-strong: rgba(255, 255, 255, 0.38);

  --sans: 'Adventor', 'Century Gothic', 'URW Gothic', -apple-system,
          BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;

  /* Radii, taken from the reference: 0.8rem is the workhorse. */
  --r-sm:   0.8rem;
  --r:      1.25rem;
  --r-lg:   1.5rem;
  --r-pill: 50rem;

  --maxw:   1180px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --nav-h:  72px;

  --band:   clamp(4.5rem, 9vw, 8.5rem);   /* vertical rhythm between sections */

  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  --z-nav: 80;
}

/* ── Reset ── */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* The sticky header must not park on top of whatever an anchor lands on.
   scroll-padding on the scroller covers in-page jumps; scroll-margin on the
   targets themselves covers the cases the padding misses (focus moves,
   scrollIntoView from script). Both, because either alone leaves a gap. */
html { scroll-padding-top: calc(var(--nav-h) + 1.5rem); }
:target,
[id]:not(body):not(html) { scroll-margin-top: calc(var(--nav-h) + 1.5rem); }

body {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--void);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.55;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

main { flex: 1 0 auto; }

img, video, svg { display: block; max-width: 100%; }
img { height: auto; }

ul, ol { list-style: none; }

a { color: inherit; text-decoration: none; }

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: var(--gold); color: var(--on-gold); }

/* ── Focus ── */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: 1rem;
  top: -100%;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--gold);
  color: var(--on-gold);
  border-radius: var(--r-pill);
  font-weight: 700;
  transition: top 0.2s var(--ease);
}
.skip-link:focus-visible { top: 1rem; }

/* ── Layout ── */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.band { padding-block: var(--band); }
.band-tight { padding-block: calc(var(--band) * 0.62); }

/* ── Type ── */
h1, h2, h3, h4 {
  font-weight: 700;
  line-height: 1.14;
  letter-spacing: -0.005em;
  text-wrap: balance;
}

.h-page {
  font-size: clamp(2.5rem, 6.6vw, 4.5rem);
  line-height: 1.1;
}

.h-sec {
  font-size: clamp(2rem, 4.6vw, 3.5rem);
  line-height: 1.16;
}

/* The two-tone heading. .mute is the greyed half. A <span> with a class
   rather than <i>, which would claim an alternate voice this never means. */
.h-sec .mute, .h-page .mute, .footer-mark .mute, .wordmark .mute {
  font-style: normal;
  color: var(--fg-mute);
}

.h-card { font-size: clamp(1.25rem, 2vw, 1.5rem); line-height: 1.2; }

.lede {
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
  line-height: 1.5;
  color: var(--fg-mute);
  max-width: 42ch;
}

.body-copy {
  color: var(--fg-mute);
  max-width: 68ch;
}
.body-copy + .body-copy { margin-top: 1rem; }
.body-copy strong { color: var(--fg); font-weight: 400; }

/* The definition paragraph. Set a step up from body copy because it is the
   sentence a search engine or an assistant is most likely to lift whole. */
.answer-block > p:first-child {
  font-size: clamp(1rem, 1.2vw, 1.0625rem);
  line-height: 1.6;
  max-width: 62ch;
}

/* Letterspaced micro-label. 0.75rem = 12px, the floor the tests hold. */
.micro {
  font-size: 0.75rem;
  line-height: 1.4;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-mute);
}

.sec-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-bottom: clamp(2rem, 4vw, 3.25rem);
}
.sec-head .lede { max-width: 46ch; }

/* ── Links ── */
.inline-link {
  color: var(--gold);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
  transition: color 0.18s var(--ease);
}
.inline-link:hover { color: var(--gold-lit); }

/* Gold link with a trailing arrow that steps forward on hover. */
.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--gold);
  font-weight: 700;
  transition: color 0.18s var(--ease);
}
.arrow-link::after {
  content: '\2192';
  font-weight: 400;
  transition: transform 0.24s var(--ease);
}
.arrow-link:hover { color: var(--gold-lit); }
.arrow-link:hover::after { transform: translateX(0.28em); }

/* ── Buttons ── */
.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 52px;
  padding: 0.85rem 2rem;
  border-radius: var(--r-pill);
  font-weight: 700;
  text-align: center;
  border: 1px solid transparent;
  transition: background-color 0.18s var(--ease), color 0.18s var(--ease),
              border-color 0.18s var(--ease), transform 0.18s var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn-primary { background: var(--gold); color: var(--on-gold); }
.btn-primary:hover { background: var(--gold-lit); }

.btn-ghost { border-color: var(--gold); color: var(--gold); }
.btn-ghost:hover { background: rgba(196, 154, 85, 0.12); color: var(--gold-lit); border-color: var(--gold-lit); }

.btn-quiet { border-color: var(--line-strong); color: var(--fg); }
.btn-quiet:hover { border-color: var(--fg); background: rgba(255, 255, 255, 0.06); }

.btn-sm { min-height: 44px; padding: 0.6rem 1.4rem; }

/* ══ Header ══════════════════════════════════════════════════ */
.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}
.site-header.pinned {
  background: rgba(0, 0, 0, 0.9);
  border-bottom-color: var(--line);
}

.site-nav {
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
  height: var(--nav-h);
  display: flex;
  align-items: center;
  gap: clamp(1rem, 3vw, 2.75rem);
}

/* The wordmark splits weight the way the reference does: the place
   name light, the trade bold, both letterspaced. */
.wordmark {
  font-size: 0.9375rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
  margin-right: auto;
}
.wordmark b { font-weight: 700; }
.wordmark span { font-weight: 400; color: var(--fg-mute); }

.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.4vw, 2.25rem);
}
.nav-links a {
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--fg-mute);
  transition: color 0.18s var(--ease);
}
.nav-links a:hover { color: var(--fg); }
.nav-links a[aria-current='page'] { color: var(--fg); }

.nav-book {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 0.45rem 1.35rem;
  border-radius: var(--r-pill);
  background: var(--gold);
  color: var(--on-gold);
  font-weight: 700;
  font-size: 0.9375rem;
  transition: background-color 0.18s var(--ease);
}
.nav-book:hover { background: var(--gold-lit); }

.hamburger {
  display: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 4px;
}
.hamburger i {
  display: block;
  width: 16px;
  height: 1.5px;
  background: var(--fg);
  transition: transform 0.22s var(--ease), opacity 0.22s var(--ease);
}
.hamburger[aria-expanded='true'] i:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.hamburger[aria-expanded='true'] i:nth-child(2) { opacity: 0; }
.hamburger[aria-expanded='true'] i:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

.mobile-menu {
  display: none;
  overflow: hidden;
  max-height: 0;
  /* max-height:0 clips the pixels but leaves every link focusable and in the
     accessibility tree, so a keyboard user tabs into a menu they cannot see.
     visibility:hidden is what actually makes it inert; it is not transitioned,
     so closing snaps rather than sliding, which is the right trade. */
  visibility: hidden;
  background: var(--surface);
  border-top: 1px solid var(--line);
  transition: max-height 0.32s var(--ease);
}
.mobile-menu.open { max-height: 24rem; visibility: visible; }
.mobile-menu a {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 1rem var(--gutter);
  font-size: 1.125rem;
  font-weight: 700;
  border-bottom: 1px solid var(--line);
}
.mobile-menu a:last-child { border-bottom: 0; color: var(--gold); }
.mobile-menu a span {
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  color: var(--fg-mute);
  font-weight: 400;
}

@media (max-width: 860px) {
  .nav-links { display: none; }
  .nav-book { display: none; }
  .hamburger { display: flex; }
  .mobile-menu { display: block; }
}

/* ══ Hero ════════════════════════════════════════════════════ */
.hero {
  position: relative;
  min-height: min(92vh, 820px);
  display: flex;
  align-items: stretch;
  padding-block: clamp(3rem, 7vw, 5.5rem) clamp(1.5rem, 3vw, 2.5rem);
  isolation: isolate;
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
  background: #050505;
}
.hero-media img,
.hero-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(1.18) contrast(1.04);
}
.hero-media video { position: absolute; inset: 0; opacity: 0; transition: opacity 0.6s var(--ease); }
.hero-media video.ready { opacity: 1; }

/* Three washes, because the copy and the booking bar sit at opposite ends of
   the frame and the bright parts of the photograph sit between them.
 *
 * 1. up from the bottom, so the booking bar has ground under it,
 * 2. down from the top, over the band the headline and lede occupy, released
 *    by 72% so the car line at the bottom of the frame keeps its own light,
 * 3. in from the left, for the column the copy is set in.
 *
 * The second one is the repair. Before it, the vertical wash reached zero at
 * 56% from the bottom, which is the middle of the frame, which is exactly
 * where the lede is: the copy was painted straight onto the landing light of
 * the aircraft at 390 and onto the light-pole bloom at 1440, and rated 1.25:1
 * and 1.90:1 against them. */
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to top, rgba(0,0,0,0.88) 0%, rgba(0,0,0,0.42) 26%, rgba(0,0,0,0) 56%),
    linear-gradient(to bottom, rgba(0,0,0,0.62) 0%, rgba(0,0,0,0.58) 46%, rgba(0,0,0,0.16) 62%, rgba(0,0,0,0) 72%),
    linear-gradient(to right, rgba(0,0,0,0.62) 0%, rgba(0,0,0,0.40) 45%, rgba(0,0,0,0) 72%);
}

/* Headline at the top, booking bar pinned to the bottom of the frame,
   photograph between them, which is the reference's arrangement. */
.hero-inner {
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: clamp(2.5rem, 6vw, 5rem);
}

/* Sized off the headline, not a character count: at the 4.5rem cap the
   h1 wants roughly nine words over three lines, which is 640px. */
.hero-copy { max-width: 640px; position: relative; }

/* Fourth wash, and the only one that knows where the words are.
 *
 * The three above are keyed to the frame, so they can only ever be tuned by
 * guessing which part of a photograph a line of text lands on at a width
 * nobody rendered. This one is keyed to the text block itself, so it follows
 * the copy when the type reflows and when the art is replaced.
 *
 * So the copy carries its own ground: a flat wash across the whole text block
 * plus its bleed, feathered outward by a shadow of the same colour so it reads
 * as the night vignette the photograph already has rather than as a panel. The
 * flat core is the part that matters, because it is the part that bounds the
 * backdrop under every glyph no matter what the picture does there.
 *
 * tests/photo-contrast.mjs rates the actual painted pixels and holds this. */
.hero-copy::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: -1.25rem -2rem -1.5rem;
  border-radius: 4rem;
  background: rgba(0, 0, 0, 0.30);
  /* Painted outside the border box only, never under it, so the core stays a
     single flat wash and the falloff is the shadow alone. Spread first, then
     blur: the shadow leaves the edge at full strength and only then fades, so
     the boundary is a gradient rather than a step. */
  box-shadow: 0 0 6rem 3rem rgba(0, 0, 0, 0.30);
}

/* Full strength ink. The 0.86 alpha this line used to carry bought a little
   hierarchy against the h1 and paid for it in contrast, and over a photograph
   an alpha can only ever lower the ratio. The hierarchy is in the size and the
   weight, where it costs nothing. */
.hero .lede { margin-top: 1.5rem; color: var(--fg); }

/* ── Booking bar ── */
.booking {
  display: grid;
  grid-template-columns: 1.5fr 1fr auto;
  gap: 0.75rem;
  align-items: stretch;
}

.booking-field {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.15rem;
  min-height: 72px;
  padding: 0.85rem 1.5rem;
  border-radius: var(--r-sm);
  background: rgba(18, 18, 18, 0.86);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--line);
}
.booking-field .micro { letter-spacing: 0.1em; }
.booking-field b { font-weight: 700; font-size: 1.0625rem; }

.booking .btn {
  min-height: 72px;
  padding-inline: clamp(2rem, 4vw, 3.25rem);
  border-radius: var(--r-sm);
  font-size: 1.0625rem;
}

@media (max-width: 900px) {
  .booking { grid-template-columns: 1fr; }
  .booking .btn, .booking-field { min-height: 64px; }
}

/* ── Fact rail under the hero ── */
.rail {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border-radius: var(--r);
  overflow: hidden;
  border: 1px solid var(--line);
}
.rail > div {
  background: var(--surface);
  padding: clamp(1.25rem, 2.4vw, 1.75rem);
}
.rail dt { margin-bottom: 0.35rem; }
.rail dd { font-size: clamp(1.0625rem, 1.6vw, 1.375rem); font-weight: 700; }

@media (max-width: 760px) {
  .rail { grid-template-columns: repeat(2, 1fr); }
}

/* ══ Fleet ═══════════════════════════════════════════════════ */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: clamp(1.75rem, 3vw, 2.5rem);
}
.filter {
  min-height: 40px;
  padding: 0.45rem 1.25rem;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-strong);
  color: var(--fg-mute);
  font-size: 0.9375rem;
  font-weight: 700;
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease),
              background-color 0.18s var(--ease);
}
.filter:hover { color: var(--fg); border-color: var(--fg); }
.filter[aria-pressed='true'] {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--on-gold);
}

.fleet-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}
.fleet-grid.is-two { grid-template-columns: repeat(auto-fill, minmax(440px, 1fr)); }

@media (max-width: 560px) {
  .fleet-grid, .fleet-grid.is-two { grid-template-columns: 1fr; }
}

.car {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  transition: border-color 0.22s var(--ease), transform 0.22s var(--ease);
}
.car:hover { border-color: var(--line-strong); transform: translateY(-3px); }

.car-media {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--raised);
  overflow: hidden;
}
.car-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.5s var(--ease);
}
.car:hover .car-media img { transform: scale(1.03); }

.car-tag {
  position: absolute;
  top: 0.875rem;
  left: 0.875rem;
  padding: 0.3rem 0.75rem;
  border-radius: var(--r-pill);
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--fg);
}

.car-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 0.4rem;
  padding: clamp(1.25rem, 2.2vw, 1.5rem);
}
.car-body h3 { display: flex; align-items: center; gap: 0.5rem; }
.car-body h3 .arrow-link { color: var(--fg); }
.car-body h3 .arrow-link::after { color: var(--fg-mute); transition: color 0.18s var(--ease), transform 0.24s var(--ease); }
.car:hover .car-body h3 .arrow-link, .car-body h3 .arrow-link:hover { color: var(--gold); }
.car:hover .car-body h3 .arrow-link::after { color: var(--gold); }
.car-spec { color: var(--fg-mute); font-size: 0.9375rem; }

.car-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: auto;
  padding-top: 1.25rem;
}
.car-price { display: flex; align-items: baseline; gap: 0.35rem; }
.car-price b {
  font-size: clamp(1.5rem, 2.6vw, 1.875rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.car-price span { color: var(--fg-mute); font-size: 0.9375rem; }

/* A car filtered out is removed from the flow, not just faded. */
.car[hidden] { display: none; }

.fleet-empty { color: var(--fg-mute); padding: 2rem 0; }

/* ══ Vehicle page ════════════════════════════════════════════ */
.vehicle {
  display: grid;
  grid-template-columns: 1.45fr 1fr;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  align-items: start;
  margin-top: clamp(1.25rem, 2.5vw, 2rem);
}
.vehicle-media {
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--raised);
  aspect-ratio: 16 / 10;
}
.vehicle-media img { width: 100%; height: 100%; object-fit: cover; }

.vehicle-side {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: clamp(1.5rem, 2.6vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  /* Sticks alongside a tall photograph on desktop, then releases once the
     two columns stack and there is nothing left to sit beside. */
  position: sticky;
  top: calc(var(--nav-h) + 1.5rem);
}
/* The section scale is too big for a side column: "2021 Mercedes-Benz G63"
   broke over three lines and pushed the price below the fold. */
.vehicle-side h1 { font-size: clamp(1.625rem, 2.4vw, 2.125rem); line-height: 1.15; }
.vehicle-price b { font-size: clamp(2rem, 3.6vw, 2.75rem); }
.vehicle-side .actions { margin-top: 0.25rem; }
.vehicle-side .btn { width: 100%; }
.vehicle-note { line-height: 1.5; }

@media (max-width: 860px) {
  .vehicle { grid-template-columns: 1fr; }
  .vehicle-side { position: static; }
}

/* ══ Bento ═══════════════════════════════════════════════════ */
.bento {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr 1.15fr;
  gap: clamp(1rem, 2vw, 1.5rem);
  align-items: start;
}
.bento-lede { padding-top: 0.25rem; }
.bento-stack {
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  grid-column: span 2;
  grid-template-columns: 1fr 1fr;
}

.tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  padding: clamp(1.5rem, 2.6vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  min-height: 200px;
}
.tile p { color: var(--fg-mute); }
.tile .arrow-link { margin-top: auto; padding-top: 0.75rem; }

/* The one photo tile spans the stack's full height on the left. */
.tile-photo {
  grid-row: span 2;
  justify-content: flex-start;
  padding: 0;
  min-height: 340px;
}
.tile-photo .tile-copy {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  flex: 1;
  padding: clamp(1.5rem, 2.6vw, 2rem);
}
.tile-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}
.tile-photo::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(to bottom, rgba(0,0,0,0.86) 0%, rgba(0,0,0,0.45) 46%, rgba(0,0,0,0.72) 100%);
}
/* Full strength ink, for the same reason .hero .lede carries it. This copy is
   painted on a photograph under a gradient scrim, and over a picture an alpha
   can only ever lower the ratio: it cannot be bounded by any colour pair, so
   no static gate can rate it and the pixel gate has to rate whatever it finds.
   The 0.82 this line used to carry bought a half step of hierarchy under the
   h3 and paid for it in contrast. The hierarchy is in the size, where it is
   free. tests/contrast.mjs now fails the build on an alpha under .tile-photo. */
.tile-photo p { color: var(--fg); }

@media (max-width: 1040px) {
  .bento { grid-template-columns: 1fr 1fr; }
  .bento-lede { grid-column: span 2; }
  .bento-stack { grid-column: span 2; }
}
@media (max-width: 720px) {
  .bento, .bento-stack { grid-template-columns: 1fr; }
  .bento-lede, .bento-stack { grid-column: auto; }
  .tile-photo { grid-row: auto; }
}

/* ══ Steps ═══════════════════════════════════════════════════ */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}
.step {
  padding: clamp(1.5rem, 2.6vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.step-n {
  display: block;
  margin-bottom: 1.25rem;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  color: var(--gold);
  font-weight: 700;
}
.step h3 { margin-bottom: 0.6rem; }
.step p { color: var(--fg-mute); }

/* ══ Ledger, the comparison kept as two plain columns ═══════ */
.ledger {
  display: grid;
  align-items: start;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1rem, 2vw, 1.5rem);
  margin-top: clamp(2rem, 4vw, 3rem);
}
.ledger-col {
  padding: clamp(1.5rem, 2.6vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.ledger-col.is-us { border-color: rgba(196, 154, 85, 0.42); }
.ledger-col h3 { margin-bottom: 1.25rem; font-size: 1.125rem; }
.ledger-col ol { counter-reset: step; display: grid; gap: 0.6rem; }
.ledger-col li {
  counter-increment: step;
  display: flex;
  gap: 0.85rem;
  color: var(--fg-mute);
}
.ledger-col li::before {
  content: counter(step, decimal-leading-zero);
  /* The step number is the only place the order of these steps is written
     down, so it is text, not a rule. It was painted in --line-strong, a border
     token, at 1.66:1. */
  color: var(--fg-mute);
  font-variant-numeric: tabular-nums;
  flex: none;
}
.ledger-col.is-us li::before { color: var(--gold); }
.ledger-sum {
  display: block;
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  font-weight: 700;
}
.ledger-col.is-us .ledger-sum { color: var(--gold); }
.ledger-note { margin-top: 1.25rem; color: var(--fg-mute); font-size: 0.9375rem; }

@media (max-width: 720px) { .ledger { grid-template-columns: 1fr; } }

/* ══ Record ══════════════════════════════════════════════════ */
.record {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}
.record > div { background: var(--surface); padding: clamp(1.5rem, 2.6vw, 2rem); }
.record dt { margin-bottom: 0.5rem; }
.record dd {
  font-size: clamp(1.75rem, 3.4vw, 2.5rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

/* ══ Spec list ═══════════════════════════════════════════════ */
.spec { display: grid; gap: 1px; background: var(--line); border-radius: var(--r); overflow: hidden; border: 1px solid var(--line); }
.spec > div {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 1.5rem;
  padding: clamp(1.15rem, 2.2vw, 1.6rem) clamp(1.25rem, 2.4vw, 2rem);
  background: var(--surface);
}
.spec dt { color: var(--fg-mute); }
.spec dd { color: var(--fg); }

@media (max-width: 720px) {
  .spec > div { grid-template-columns: 1fr; gap: 0.35rem; }
}

/* ══ FAQ ═════════════════════════════════════════════════════
   The reference collapses these behind a plus. Ours stay open:
   an answer a crawler or an assistant cannot read is an answer
   that does not exist, and a test holds that line. The card
   shape is the reference's; the disclosure is not.            */
.qa {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1rem, 2vw, 1.5rem);
  align-items: start;
}
.qa > div {
  padding: clamp(1.35rem, 2.4vw, 1.85rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.qa dt {
  font-weight: 700;
  font-size: 1.0625rem;
  line-height: 1.3;
  margin-bottom: 0.75rem;
  padding-right: 1.5rem;
  position: relative;
}
.qa dt::after {
  content: '+';
  position: absolute;
  right: 0;
  top: -0.1em;
  color: var(--gold);
  font-weight: 400;
}
.qa dd { color: var(--fg-mute); }

@media (max-width: 860px) { .qa { grid-template-columns: 1fr; } }

/* ══ Rate table ══════════════════════════════════════════════
   A real table, because sixteen rates compared at once is a job
   a grid of cards does badly and a <table> does well. It is also
   the shape an answer engine lifts most reliably.

   EXACTLY ONE bounded scroller: the wrapper scrolls, the table
   does not. Two scrollers, or none, both break the sticky head. */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  -webkit-overflow-scrolling: touch;
}

.rate-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
  /* Below this the columns crush; the wrapper scrolls instead of wrapping
     "Mercedes-Benz" down four lines. */
  min-width: 680px;
}

.rate-table caption {
  caption-side: top;
  padding: clamp(1rem, 2vw, 1.35rem) clamp(1rem, 2.4vw, 1.5rem);
  text-align: left;
  color: var(--fg-mute);
  border-bottom: 1px solid var(--line);
}

.rate-table th,
.rate-table td {
  padding: 0.9rem clamp(0.75rem, 1.6vw, 1.25rem);
  text-align: left;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.rate-table tbody tr:last-child th,
.rate-table tbody tr:last-child td { border-bottom: 0; }

.rate-table thead th {
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-mute);
  font-weight: 400;
}

.rate-table tbody th {
  font-weight: 700;
  color: var(--fg);
}
.rate-table tbody th a { transition: color 0.18s var(--ease); }
.rate-table tbody th a:hover { color: var(--gold); }
.rate-table td { color: var(--fg-mute); }
.rate-table .num { font-variant-numeric: tabular-nums; text-align: right; }
.rate-table tbody td:last-child { color: var(--fg); font-weight: 700; }
.rate-table tbody tr:hover th,
.rate-table tbody tr:hover td { background: var(--raised); }

/* ══ Plate, a full-bleed photograph ════════════════════════ */
.plate { position: relative; }
.plate-media {
  position: relative;
  aspect-ratio: 16 / 7;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--raised);
}
.plate-media img { width: 100%; height: 100%; object-fit: cover; }
.plate figcaption {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
  margin-top: 1rem;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-mute);
}
.plate figcaption b { color: var(--gold); font-weight: 700; }

@media (max-width: 720px) { .plate-media { aspect-ratio: 4 / 3; } }

/* ══ CTA band ════════════════════════════════════════════════ */
.cta {
  position: relative;
  padding-block: clamp(3.5rem, 7vw, 6rem);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  text-align: center;
}
.cta .actions { justify-content: center; margin-top: 2rem; }
.cta .lede { margin-inline: auto; margin-top: 1rem; }
.cta-inner { padding-inline: clamp(1.5rem, 4vw, 3rem); }

/* ══ Footer ══════════════════════════════════════════════════ */
.site-footer {
  flex: none;
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding-block: clamp(3rem, 6vw, 4.5rem) 2rem;
}
.footer-inner { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }

.footer-mark {
  font-size: 0.9375rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}
.footer-mark b { font-weight: 700; }
.footer-mark span { color: var(--fg-mute); }

.footer-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 2.5rem 2rem;
}
.footer-cols h2 {
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-mute);
  font-weight: 400;
  margin-bottom: 1.1rem;
}
.footer-cols ul { display: grid; gap: 0.7rem; }
.footer-cols a, .footer-cols li {
  font-size: 0.9375rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-mute);
  /* admin@rochester.rentals is a single unbreakable token wider than this
     column between roughly 700 and 1100px, where auto-fit is still handing
     out 200px tracks. Without this it escapes the column instead of wrapping. */
  overflow-wrap: anywhere;
}
.footer-cols a { transition: color 0.18s var(--ease); }
.footer-cols a:hover { color: var(--gold); }

.footer-base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem 2rem;
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-mute);
}

/* ══ Reveals ═════════════════════════════════════════════════
   Deliberately NOT defined here any more.

   This file used to open the reveal with `.rise { opacity: 0 }`
   and rely on site.js to put it back. That hides the whole page
   behind a stylesheet that always loads, keyed to a script that
   sometimes does not: one 404, one parse error, one CSP block
   and every card, every paragraph and every price stays at zero
   opacity on a page that reports itself perfectly healthy.

   assets/rr-network.css now owns the reveal. Its base state is
   visible, the hidden state is scoped to .rr-js on <html>, and
   that class is armed by assets/rr-reveal.js and disarmed again
   by its own watchdog unless the kit claims it. Motion is tuned
   through --rr-reveal-shift, --rr-reveal-motion and
   --rr-reveal-delay in the token block below.

   Do not reintroduce a bare `.rise { opacity: 0 }` here.       */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .car:hover { transform: none; }
  .car:hover .car-media img { transform: none; }
}

/* ══ rr-network kit theme ════════════════════════════════════
   The shared wiring kit (assets/rr-network.css) paints no colour
   of its own: every one is a --rr-* custom property, defined
   here so the kit inherits this site's palette instead of
   carrying one. Nothing above this block changed; these tokens
   only reach the lead form, the checkout controls and the live
   inventory states.

   Ratios below are computed by tests/contrast.mjs against the
   surface actually painted behind the text, and the suite fails
   if any of them drops under its floor.                        */
:root {
  /* colours, no fallback on purpose: a missing one paints nothing */
  --rr-text:            #FFFFFF;   /* 18.73:1 on --rr-surface */
  --rr-text-muted:      #888888;   /*  5.28:1 on --rr-surface */
  --rr-surface:         #121212;
  --rr-surface-2:       #1B1B1B;
  --rr-border:          #6B6B6B;   /*  3.52:1 on --rr-surface, a real boundary */
  --rr-accent:          #C49A55;   /*  7.23:1 on --rr-surface */
  --rr-price:           #C49A55;
  --rr-ok:              #5FD08A;   /*  9.70:1 on --rr-surface */
  --rr-warn:            #E5B567;   /*  9.94:1 on --rr-surface */
  --rr-danger:          #FF7A7A;   /*  7.42:1 on --rr-surface */
  --rr-focus:           #D9B679;   /*  9.74:1 on --rr-surface */
  --rr-input-bg:        #000000;
  --rr-input-text:      #FFFFFF;   /* 21.00:1 on --rr-input-bg */
  --rr-input-border:    #6B6B6B;   /*  3.94:1 on --rr-input-bg */
  --rr-placeholder:     #9A9A9A;   /*  7.46:1 on --rr-input-bg */
  --rr-button-bg:       #C49A55;
  --rr-button-bg-hover: #D9B679;
  --rr-button-text:     #0B0B0B;   /*  7.59:1 on the fill, 10.23:1 on the hover fill */
  --rr-button-border:   #C49A55;

  /* layout and type, matched to the realcar bones already here */
  --rr-card-min:      17rem;
  --rr-gap:           1.25rem;
  --rr-gap-tight:     0.5rem;
  --rr-card-pad:      1rem;
  --rr-card-aspect:   16 / 10;
  --rr-radius:        1.25rem;
  --rr-radius-inner:  0.8rem;
  --rr-border-width:  1px;
  --rr-title-size:    1.0625rem;
  --rr-price-size:    1.25rem;
  --rr-small-size:    0.9375rem;
  --rr-font-display:  var(--sans);
  --rr-status-transform: none;
  --rr-status-tracking:  0.02em;
  /* --rr-loading-opacity is deliberately absent. It used to be 0.7, and the
     rule that read it dimmed every card inside a grid carrying
     class="rr-is-loading" - a class this site printed into its committed
     markup and only rr-network.js ever removed. Server rendered inventory is
     real content: it paints at full contrast in the state the page ships in,
     and it keeps that contrast for ever if a script is blocked or switched
     off. The refresh cue is a row of text now, not a dim. Do not add this
     token back; nothing reads it. */
  --rr-disabled-opacity: 0.6;
  --rr-motion:        180ms;

  /* Reveal, kept at the travel and duration this site already had
     when the rule lived in this file. Only the failure mode moved. */
  --rr-reveal-shift:  14px;
  --rr-reveal-motion: 600ms;
  --rr-reveal-delay:  0ms;

  --rr-form-width:    38rem;
  --rr-form-pad:      clamp(1.25rem, 3vw, 2rem);
  --rr-control-height: 3rem;
  --rr-control-pad:   0.75rem 1rem;
  --rr-button-pad:    0.9rem 1.6rem;
  --rr-textarea-height: 8rem;
  --rr-focus-width:   2px;
  --rr-focus-offset:  3px;

  /* strings. Written for this site alone: seven identical sentences
     across the network would breach the distinctness rule. */
  --rr-msg-loading: "Reading today's rates off the booking store.";
  --rr-msg-stale: "Rates below were saved a moment ago and could not be refreshed just now.";
  --rr-msg-empty: "Nothing is showing as bookable online at the moment. Call and we will check the yard.";
  --rr-mark-success: "\2713";
  --rr-mark-error: "\0021";
}

/* The kit's grid rules must never take over a grid this site already
   owns, so rr-network.css is linked BEFORE site.css and .fleet-grid
   wins the tie. This restates the site's own geometry for the one
   grid that now carries data-rr-inventory. */
.fleet-grid[data-rr-inventory] {
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}

/* The home page shows the six cheapest. The kit has one repaint and no
   notion of a subset, so the subset is expressed here: it paints the whole
   fleet in the declared price-asc order and the seventh card onward is not
   displayed. A lazy image inside a display:none card is never fetched, so
   the home page still carries six photographs, not sixteen. */
.fleet-grid.is-two[data-rr-inventory] > .car:nth-of-type(n+7) { display: none; }
@media (max-width: 720px) {
  .fleet-grid[data-rr-inventory] { grid-template-columns: 1fr; }
}
/* The card title anchor is an inline-flex box. Its label has to be one flex
   item, or the name splits into gapped items that cannot wrap and a long one
   escapes the card. */
.car-body h3 .arrow-link { min-width: 0; }
.car-name { min-width: 0; overflow-wrap: break-word; }

.car-noimg {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  background: var(--raised);
}

/* ══ Lead form and checkout ══════════════════════════════════ */
.lead-form { margin-top: clamp(1.5rem, 3vw, 2.25rem); }
.lead-form .rr-label { font-weight: 700; letter-spacing: 0.01em; }
.lead-form legend { font-size: 0.75rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-mute); }

.co-steps {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin: clamp(2rem, 4vw, 3rem) 0 clamp(1.5rem, 3vw, 2.25rem);
  padding: 0;
  list-style: none;
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-mute);
}
.co-steps li { display: flex; align-items: center; gap: 0.5rem; }
.co-steps li[aria-current='step'] { color: var(--gold); }
.co-steps li b { font-weight: 700; }

.co-panel { display: grid; gap: var(--rr-gap, 1.25rem); }
.co-panel[hidden] { display: none; }

.co-card {
  padding: var(--rr-form-pad);
  background: var(--rr-surface);
  border: 1px solid var(--rr-border);
  border-radius: var(--rr-radius);
}
.co-grid { display: grid; gap: var(--rr-gap); grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.co-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: var(--rr-gap); }
.co-note { font-size: var(--rr-small-size); color: var(--rr-text-muted); }
.co-consent { display: flex; gap: 0.75rem; align-items: flex-start; }
.co-consent input { width: 1.25rem; height: 1.25rem; margin-top: 0.2rem; accent-color: var(--gold); }
.co-summary { display: grid; gap: 0.5rem; margin: 0; }
.co-summary div { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; justify-content: space-between; }
.co-summary dt { color: var(--rr-text-muted); }
.co-summary dd { margin: 0; color: var(--rr-text); }
.co-file { font-size: var(--rr-small-size); color: var(--rr-text-muted); }
.co-file[data-state='ready'] { color: var(--rr-ok); }
.co-file[data-state='error'] { color: var(--rr-danger); }
.co-ref {
  font-family: var(--sans);
  font-size: clamp(1.75rem, 6vw, 2.75rem);
  letter-spacing: 0.08em;
  color: var(--gold);
}
