/* ============================================================
   Detroit Metro SUV Rental, on the network's original palette

   The colour here is the network's, not this site's. A forest ink
   ground with a moss accent shipped for a while and has been taken
   back out: the five satellites are one estate and they are set in
   one palette, restored from the first commit in this repository
   and byte-identical to the other four.

   Black page, two near-black surfaces above it, white and grey
   type, one gold accent, and white hairlines for the rules. The
   only value that is not literally the original number is
   --line-strong, and the reason is written beside it.

   Three grounds, each one step lighter and each one measured:
     --void     the page
     --surface  cards, panels, the footer
     --raised   media wells and the panel inside a panel

   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 half carries .mute,
   the emphatic half is plain. That single pattern does the work
   that eyebrow lockups would otherwise do.

   Every colour below is measured by scripts/contrast.mjs, which
   reads this block rather than a list kept beside it. Nothing here
   is eyeballed. Run `npm run check:contrast` after any change.
   ============================================================ */

/* ── 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. The originals,
     read back out of the first commit in this repository. */
  --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;

  /* Two rules with two different jobs, both white hairlines as
     they always were. --line separates panels of the same colour
     family and is decoration, so it is reported and not gated, and
     it is the original 0.10 exactly.

     --line-strong is the only number on this page that is not the
     original. It is the edge of something you can operate: a field,
     a submit button, the quiet button, the menu control, the hero
     slab. None of those existed when 0.20 was chosen, and 0.20 is
     1.66:1 on the ground and 1.85:1 on a surface, which is not a
     border a gate at 3:1 can accept. 0.42 is the same white
     hairline at the alpha the measurement demands: 3.95:1 on the
     ground, 4.10:1 on a surface, 4.06:1 on a raised panel. The
     construction is the original one; only the alpha moved, and it
     moved because scripts/contrast.mjs said so rather than because
     anyone looked at it. */
  --line:        rgba(255, 255, 255, 0.10);
  --line-strong: rgba(255, 255, 255, 0.42);

  /* --hero-floor is a BOUND, not the surface. It is --hero-panel
     composited over a pure white frame, and it was the only way the
     old gate could say anything at all about type over a photograph.
     It is not what the page paints: the hero copy sits on two washes
     over hero-suv.jpg, and this comment used to claim a solid slab
     that no rule in this file has ever drawn. That gap is the whole
     of defect S3. The real number now comes from measuring the
     photograph, cell by cell, in data/photo-luminance.json, and
     compositing the wash over the brightest pixel under the type.
     Both are reported; the second is the one that governs.

     These three are not palette names this site invented for its
     own colour scheme: they name the slab the contrast work added
     and the lede colour the original wrote inline as
     rgba(255, 255, 255, 0.86). Their VALUES are back on black. */
  --hero-panel: rgba(0, 0, 0, 0.92);
  --hero-floor: #141414;
  --hero-lede:  rgba(255, 255, 255, 0.86);

  --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;

  /* ── The wiring kit's 48 properties ──────────────────────────
     assets/rr-network.css carries no colour value at all. It is
     driven entirely from here, which is how one shared file styles
     seven sites without being forked. The kit's contract is in
     assets/rr-network-README.md; the colours below are the ones it
     names, mapped onto the palette above and measured with the rest
     of it by scripts/contrast.mjs.

     Every colour is an alias, never a new value. A second accent
     defined down here is a second brand nobody measured, and a
     bridge left pointing at a name the palette no longer has is
     worse again: var() with no fallback and no definition paints
     nothing at all, so the form would lose its border on one page
     and keep it on another. Every one of the nineteen below now
     resolves into the restored palette, and scripts/contrast.mjs
     throws on an undefined custom property rather than skipping
     the pair.                                                     */

  /* colours (19) */
  --rr-text:            var(--fg);
  --rr-text-muted:      var(--fg-mute);
  --rr-surface:         var(--surface);
  --rr-surface-2:       var(--raised);
  --rr-border:          var(--line-strong);
  --rr-accent:          var(--gold);
  --rr-price:           var(--fg);
  --rr-ok:              var(--gold);
  --rr-warn:            #E0B24E;
  --rr-danger:          #F08A7A;
  --rr-focus:           var(--gold);
  /* The field sits one step DOWN from the panel it is set into, which
     on this palette is the ground itself rather than a fourth near
     black nobody named. */
  --rr-input-bg:        var(--void);
  --rr-input-text:      var(--fg);
  --rr-input-border:    var(--line-strong);
  --rr-placeholder:     var(--fg-mute);
  --rr-button-bg:       var(--gold);
  --rr-button-bg-hover: var(--gold-lit);
  --rr-button-text:     var(--on-gold);
  --rr-button-border:   var(--gold);

  /* layout, type and motion (25). Wide cards and a heavy gap: this
     site is about vehicles you cannot photograph in a narrow crop. */
  --rr-card-min:         20rem;
  --rr-gap:              clamp(1rem, 2vw, 1.5rem);
  --rr-gap-tight:        0.5rem;
  --rr-card-pad:         clamp(1.15rem, 2vw, 1.4rem);
  --rr-card-aspect:      16 / 10;
  --rr-radius:           var(--r);
  --rr-radius-inner:     var(--r-sm);
  --rr-border-width:     1px;
  --rr-title-size:       clamp(1.25rem, 2vw, 1.5rem);
  --rr-price-size:       clamp(1.5rem, 2.6vw, 1.875rem);
  --rr-small-size:       0.9375rem;
  --rr-font-display:     var(--sans);
  --rr-status-transform: uppercase;
  --rr-status-tracking:  0.12em;
  /* The retired dim property is not set here, and setting it would do
     nothing: the rule that read it is gone from the kit. A dimmed grid
     was the state the built page ARRIVED in, and at 0.72 it took the
     muted spec label from 6.30:1 to 3.88:1 and the card border from
     3.54:1 to 2.43:1 against this ground. A refresh now ADDS a row of
     text, the string at the foot of this block, and paints it only
     while html carries .rr-js.
     0.8, not 0.6, on the disabled control: at 0.6 the submit label measured
     3.63:1 against the form while it was sending, at 0.8 it is 5.43:1.
     scripts/contrast.mjs measures this number rather than trusting it. */
  --rr-disabled-opacity: 0.8;
  --rr-motion:           180ms;
  --rr-form-width:       36rem;
  --rr-form-pad:         clamp(1.5rem, 2.6vw, 2rem);
  --rr-control-height:   52px;
  --rr-control-pad:      0.8rem 1.05rem;
  --rr-button-pad:       0.85rem 2rem;
  --rr-textarea-height:  8rem;
  --rr-focus-width:      2px;
  --rr-focus-offset:     3px;
  /* Reveal, owned by the kit's stylesheet. A heavier travel than the
     kit default: the blocks on this site are wide and solid, so a
     short shift reads as a flicker rather than as an arrival. */
  --rr-reveal-shift:     14px;
  --rr-reveal-motion:    600ms;
  --rr-reveal-delay:     0ms;

  /* strings (5). Written for this site only: seven identical
     sentences would breach the network's distinctness rule.
     The loading line is painted on --rr-surface-2 in --rr-text-muted,
     the pair scripts/contrast.mjs already gates, and the kit shows it
     only while html carries .rr-js. It adds a row of text; it takes
     contrast away from nothing. */
  --rr-msg-loading: "Reading the seat counts and the day rates back from the operator's dashboard.";
  --rr-msg-stale: "Seat counts and rates below were saved earlier and could not be checked just now.";
  --rr-msg-empty: "Nothing is listed on this page at the moment. Every vehicle is at rochester.rentals.";
  --rr-mark-success: "\2713";
  --rr-mark-error: "\0021";

  /* Site level, not part of the kit's 48: what a blank spec cell
     says. The dashboard leaves a seat count null when the listing
     never published one, and this page will not guess. */
  --rr-unknown: "not published";

  /* And what an empty media box says. A listing with no photograph
     gets no photograph: the stand-in that used to sit here was an
     aerial of ten sedans, presented as the vehicle named under it.
     Painted --fg-mute on --raised, a pair the contrast gate already
     measures. */
  --rr-msg-nophoto: "No photograph published for this vehicle yet. The listing on the main site carries the current images.";
}

/* ── 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: var(--void);
}
.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; }

/* Two scrims, not one: a vertical wash so the booking bar has ground
   under it, and a left wash so the headline holds over bright bodywork. */
.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%, rgba(0,0,0,0.30) 100%),
    linear-gradient(to right, rgba(0,0,0,0.70) 0%, rgba(0,0,0,0.22) 42%, rgba(0,0,0,0) 68%);
}

/* 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; }
.hero .lede { margin-top: 1.5rem; color: var(--hero-lede); }

/* ── 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); }
}


/* The landing sites lead with vehicle photography shot by the host in
   daylight, not with the night apron plate the main hero was graded for.
   Grass and sky sit right behind the lede on some of them, so the left wash
   runs deeper and further here. Applied to all five rather than flagged per
   site: a flag on the one bright photo is a flag someone forgets on the
   next one. */
/* These stops are unchanged, and that is now a measured statement rather than
   an assumption. scripts/contrast.mjs composites this wash, at the alpha its
   own stops give at each point, over the brightest pixel of hero-suv.jpg under
   that point, read from data/photo-luminance.json: the photograph carries near
   white cells at 31 to 44 percent across and 11 to 33 percent down, which is
   behind the headline. Nothing on this site is painted directly on this wash.
   The copy sits on .page-satellite .hero-copy, a slab at 0.92, and the booking
   bar on its own panels, and both are measured through this wash to the
   photograph. Type straight onto this gradient would measure 1.92:1 there;
   that is why there is a slab. */
.page-satellite .hero::before {
  background:
    linear-gradient(to top, rgba(0,0,0,0.90) 0%, rgba(0,0,0,0.48) 26%, rgba(0,0,0,0.10) 58%, rgba(0,0,0,0.34) 100%),
    linear-gradient(to right, rgba(0,0,0,0.88) 0%, rgba(0,0,0,0.66) 30%, rgba(0,0,0,0.22) 58%, rgba(0,0,0,0) 78%);
}

/* ══ 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;
}
/* Same measurement, same conclusion. The tile copy is a flex child at
   flex-start, so the heading and its paragraph sit in the top two fifths of a
   340px tile, and plate-aerial.jpg is a daylight aerial: its brightest cells
   run to 0.93 relative luminance right under that copy. At the old 0.45 mid
   stop the paragraph measured 2.40:1. The wash now holds until the copy has
   finished and thins afterwards, where nothing is written. */
.tile-photo::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(to bottom, rgba(0,0,0,0.88) 0%, rgba(0,0,0,0.78) 45%, rgba(0,0,0,0.52) 70%, rgba(0,0,0,0.74) 100%);
}
.tile-photo p { color: var(--hero-lede); }

@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); }

/* ══ 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; } }

/* ══ 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 ═════════════════════════════════════════════════
   There is deliberately NO reveal rule here any more.

   This block used to read `.rise { opacity: 0 }` with a matching
   `.rise.in { opacity: 1 }` that only assets/site.js ever added.
   That is the trap: content hidden by a stylesheet, which always
   loads, and revealed by a script, which sometimes does not. One
   404 and the entire page below the hero was blank.

   Reveal now lives in assets/rr-network.css, where the base state
   is VISIBLE and the hidden state is scoped to html.rr-js, a class
   assets/rr-gate.js adds and takes back off again unless the kit
   claims it. Tune it with the --rr-reveal-* properties in :root.
   Do not reintroduce an opacity rule in this file.              */

@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;
  }
  .rr-card:hover { transform: none; }
  .rr-card:hover .rr-card-img { transform: none; }
}

/* ══ Hero slab ═══════════════════════════════════════════════
   The network's hero puts white type straight onto a scrimmed
   photograph. That works right up until you have to prove the
   ratio, because the ratio depends on the frame. Here the copy
   gets its own slab, so the ground under every word is a colour
   with a name and a measured number. The slab is a contrast fix
   and it stays; only its colour went back to black, because a
   headline measured at 1.92:1 over the photograph is the reason
   it exists and no palette change repairs that.                 */
.page-satellite .hero-copy {
  max-width: 40rem;
  padding: clamp(1.5rem, 3vw, 2.5rem);
  background: var(--hero-panel);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
}
.page-satellite .hero .lede { color: var(--hero-lede); }

/* ══ Seat ladder ═════════════════════════════════════════════
   The one table on the page. It answers the only question this
   site exists for, and it says out loud when it was last read
   from the dashboard rather than pretending to be live.        */
.ladder {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  overflow: hidden;
  font-variant-numeric: tabular-nums;
}
.ladder caption {
  caption-side: bottom;
  margin-top: 1rem;
  color: var(--fg-mute);
  font-size: 0.9375rem;
  text-align: left;
}
.ladder th,
.ladder td {
  padding: clamp(0.9rem, 1.8vw, 1.25rem) clamp(1rem, 2vw, 1.5rem);
  text-align: left;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}
.ladder thead th {
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--fg-mute);
  background: var(--raised);
}
.ladder tbody tr:last-child th,
.ladder tbody tr:last-child td { border-bottom: 0; }
.ladder tbody th { font-weight: 700; font-size: 1.0625rem; }
.ladder td:last-child { color: var(--fg-mute); }
.ladder .is-unknown th,
.ladder .is-unknown td { color: var(--fg-mute); font-weight: 400; }

/* ══ Fleet grid, site layer ══════════════════════════════════
   rr-network.css already lays the grid out and paints the card
   from the --rr-* properties. Everything below is character the
   kit deliberately has no opinion about: the photograph filling
   the top of the card, the category tag over it, and the way a
   blank spec cell admits it is blank instead of showing nothing.
   No kit logic is forked to get any of it.                     */
.rr-card { overflow: hidden; padding: 0; }
.rr-card:hover { transform: translateY(-3px); }

/* A collision inside the kit, neutralised here rather than forked.
   rr-network.css styles the lead form's live region with the bare attribute
   selector [data-rr-status], and rr-network.js also writes data-rr-status onto
   every card. So the moment the inventory fetch fails and the grid gains
   rr-is-error, the kit's ".rr-is-error [data-rr-status]::before" rule paints an
   exclamation mark as the first flex child of all sixteen cards, pushing every
   photograph 31px down the card, and the base [data-rr-status] rule shrinks the
   card's type and mutes its colour. Measured, not guessed: card top 126, media
   top 159, with a 23.25px pseudo element and an 8px gap between them.
   The kit's logic is untouched; only its selector reach is trimmed, and the
   collision is reported upstream so the fix can land in the kit for all seven
   sites. */
.rr-card[data-rr-status] { min-height: 0; font-size: 1rem; color: var(--rr-text); }
.rr-card[data-rr-status]::before { content: none; margin-right: 0; }

.rr-card-media {
  position: relative;
  border-radius: 0;
  margin: 0;
}
.rr-card-img { transition: transform 0.5s var(--ease); }
.rr-card:hover .rr-card-img { transform: scale(1.03); }

/* A listing with no published photograph. The box is empty on purpose: the
   card used to fall back to /assets/plate-aerial.jpg, an aerial of ten sedans,
   and a stock photograph inside a card that names a year, a make and a rate
   reads as a picture of that vehicle. The gap is labelled in words instead,
   in the muted-on-raised pair scripts/contrast.mjs already gates, so nothing
   here is a colour the measurement cannot see. Both the build and
   assets/rr-network.js mark the box, so a card inserted after load behaves the
   same way as one the build painted. */
[data-rr-nophoto] .rr-card-img,
[data-rr-nophoto] img[hidden] { display: none; }

[data-rr-nophoto] {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--rr-card-pad);
  background: var(--raised);
}
[data-rr-nophoto]::after {
  content: var(--rr-msg-nophoto, "No photograph published for this vehicle yet.");
  color: var(--fg-mute);
  font-size: var(--rr-small-size);
  line-height: 1.4;
  text-align: center;
  text-wrap: balance;
}

.car-tag {
  position: absolute;
  top: 0.875rem;
  left: 0.875rem;
  z-index: 1;
  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);
}

.rr-card-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--rr-gap-tight);
  padding: var(--rr-card-pad);
}
.rr-card-title { font-weight: 700; }
.rr-card-title a { text-decoration: none; }
.rr-card-title a:hover { color: var(--gold); }

.rr-card-specs {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.35rem 1rem;
  margin-top: 0.35rem;
}
.rr-card-specs > div { display: flex; flex-direction: column; gap: 0.15rem; }
.rr-card-specs dt {
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.rr-card-specs dd { font-weight: 700; }

/* A dashboard row with no published seat count leaves this cell
   empty after the client script repaints it. Saying so is the
   honest thing; printing a guessed number is not. */
.rr-card-specs dd:empty::after {
  content: var(--rr-unknown);
  color: var(--fg-mute);
  font-weight: 400;
  font-size: 0.9375rem;
  letter-spacing: 0;
  text-transform: none;
}

.rr-card-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-top: auto;
  padding-top: 1.25rem;
}
.rr-card-price { display: flex; align-items: baseline; gap: 0.35rem; font-weight: 700; }
.rr-card-status { margin-left: auto; }

/* ══ Lead form band ══════════════════════════════════════════ */
.ask {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}
.ask-copy { display: flex; flex-direction: column; gap: 1rem; }
.ask-copy .body-copy { max-width: 44ch; }
.ask-note { color: var(--fg-mute); font-size: 0.9375rem; max-width: 44ch; }
[data-rr-lead-form] { width: 100%; max-width: none; }
.rr-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--rr-gap); }
.rr-button { border-radius: var(--r-pill); font-weight: 700; }

@media (max-width: 900px) {
  .ask { grid-template-columns: 1fr; }
  .rr-field-row { grid-template-columns: 1fr; }
}
