/* =========================================================================
   Soko — design system
   Modelled on Airbnb's visual language: Cereal-style type scale, rausch
   accent (#FF385C), 12px card radius, elevated pill search, soft shadows.
   No framework, no build step. Plain CSS custom properties.
   ========================================================================= */

@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400&display=swap');

/* --morph: how far the header has morphed from the expanded search bar to the
   compact pill. 0 = fully expanded, 1 = fully compact, and every value in
   between is a real, restable state — it is set from the scroll offset on each
   frame, so stopping halfway leaves the morph halfway.

   Registered with @property rather than left as a plain custom property for two
   reasons: an unregistered var is a *token stream*, so `calc(1 - var(--morph))`
   inside `opacity` only resolves by luck and cannot be interpolated; and the
   registration gives it a typed initial value, so a page that never sets it
   (every page without a search bar) still computes rather than falling back to
   `unset` and blanking the header. */
@property --morph {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

/* The two fade windows derived from --morph. Registered for the same reason,
   plus one more: a registered property reports a RESOLVED NUMBER through
   getComputedStyle, so the QA harness can read the choreography's actual state
   at a given scroll offset instead of asserting against the raw token text. */
@property --tabs-out { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --mini-in  { syntax: '<number>'; inherits: true; initial-value: 0; }

/* ---------------------------------------------------------------- tokens */
:root {
  /* brand */
  --rausch: #ff385c;
  --rausch-dark: #e00b41;
  --rausch-grad: linear-gradient(90deg, #e61e4d 0%, #e31c5f 50%, #d70466 100%);

  /* text */
  --fg: #222222;
  --fg-secondary: #6c6c6c;
  --fg-tertiary: #b0b0b0;
  --fg-inverse: #ffffff;

  /* surfaces */
  --bg: #ffffff;
  --bg-subtle: #f7f7f7;
  --bg-raised: #ffffff;
  --bg-scrim: rgba(0, 0, 0, 0.6);

  /* lines */
  --border: #dddddd;
  --border-subtle: #ebebeb;

  /* shape */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 24px;
  --r-pill: 999px;

  /* elevation — read off airbnb.co.uk. Every tier carries the same 1px
     hairline (0 0 0 1px rgba(0,0,0,.02)); that hairline is the signature. */
  --sh-sm: 0 0 0 1px rgba(0, 0, 0, 0.02), 0 2px 4px rgba(0, 0, 0, 0.16);
  --sh-md: 0 0 0 1px rgba(0, 0, 0, 0.02), 0 2px 6px rgba(0, 0, 0, 0.04),
           0 4px 8px rgba(0, 0, 0, 0.10);
  --sh-lg: 0 0 0 1px rgba(0, 0, 0, 0.02), 0 2px 6px rgba(0, 0, 0, 0.04),
           0 4px 8px rgba(0, 0, 0, 0.10);
  --sh-xl: 0 0 0 1px rgba(0, 0, 0, 0.02), 0 8px 24px rgba(0, 0, 0, 0.10);
  --sh-pill: 0 0 0 1px rgba(0, 0, 0, 0.02), 0 2px 6px rgba(0, 0, 0, 0.04),
             0 4px 8px rgba(0, 0, 0, 0.10);

  /* motion — airbnb uses one easing curve for everything */
  --ease: cubic-bezier(0.2, 0, 0, 1);
  --t-press: 0.1s var(--ease);
  --t-move: 0.25s var(--ease);
  --t-shadow: 0.2s var(--ease);
  --t-colour: 0.3s var(--ease);

  /* the hero backdrop fade */
  --hero-fade: linear-gradient(#ffffff 39.9%, #f8f8f8 100%);

  /* search bar geometry, measured at a 1536 viewport */
  --pill-w: 850px;
  --pill-h: 66px;
  --pill-divider-h: 32px;                     /* 1px x 32px, vertically centred */

  /* end-of-rail "See all" photo stack */
  --seeall-tile: 63.59px;

  /* category tab icon — reference is 72px; five tabs need room, so this steps
     down at narrower viewports rather than letting the header overflow */
  --tab-icon: 72px;

  /* the detail page's section bar, which replaces the header once the gallery
     has scrolled past — measured at 80px on the reference */
  --subnav-h: 80px;

  /* search page: the filter row is the second half of the sticky chrome */
  --filterbar-h: 55px;

  /* compact header pill, measured on the reference search page */
  --mini-w: 440px;
  --mini-h: 46px;
  --mini-shadow: 0 1px 2px rgba(0, 0, 0, .08), 0 4px 12px rgba(0, 0, 0, .05);

  /* focused-search state (measured on the reference) */
  --pill-track: #ebebeb;                      /* pill goes grey while searching */
  --sh-cushion: 0 0 0 1px #dddddd,            /* the 1px ring around the field */
                0 3px 12px rgba(0, 0, 0, 0.10),
                0 1px 3px rgba(0, 0, 0, 0.08);
  --grey-btn: #f2f2f2;
  --search-pink: #da1249;

  /* Logo lockup. Sampled off the supplied artwork rather than guessed: the red
     is the MEDIAN of the headlight's interior pixels after eroding the mask by
     4px, because the JPEG's edge ringing drags a naive average several shades
     light. Deliberately NOT --rausch (#ff385c) — this is a darker, bluer red
     and the two are not interchangeable, so the brand pink stays the brand pink
     for buttons and the logo carries its own pair. */
  --logo-ink: #000000;
  --logo-red: #c00618;

  /* Category icon palette, sampled off the supplied artwork the same way: the
     glass is a genuinely BLUE grey, which is what separates it from the neutral
     anti-alias halo around every black stroke, and the lamp is the eroded
     interior median rather than a naive average. Note the lamp is NOT
     --logo-red — the artwork uses a darker, browner red on the cars. */
  /* The header menu's own shadow and hover. The shadow is a MEASURED value that
     belongs to no tier — see the note at .pop--menu. */
  --sh-menu: 0 2px 16px rgba(0, 0, 0, .12);
  --menu-hover: #f7f7f7;

  --icon-ink: #000000;
  /* A THIRD red enters the palette here — the steering wheel's accents measure
     #dc1a1a, brighter than both --logo-red (#c00618) and --icon-lamp (#82152b).
     Kept faithful to the supplied artwork rather than quietly snapped to one of
     the others, but three reds is a brand question worth settling. */
  --wheel-red: #dc1a1a;
  --icon-glass: #dee2e7;
  --icon-lamp: #82152b;

  /* layout */
  --header-h: 96px;        /* header row at rest AND once compressed — measured
                              on the reference, whose header is 96px at every
                              scroll depth. It does not shrink. */
  --searchbar-h: 104px;    /* height of the search band. CONSTANT: the band
                              scrolls away under the header rather than
                              collapsing, so this never animates. See the morph
                              section for why that matters. */
  --page-max: 1760px;
  --page-pad: 80px;

  --font: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
    Roboto, Helvetica, Arial, sans-serif;
}

/* ------------------------------------------------------------------ base */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.45;
  color: var(--fg);
  background: var(--bg);
}

img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
ul { margin: 0; padding: 0; list-style: none; }

h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -0.02em; }
h1 { font-size: 32px; line-height: 1.2; }
h2 { font-size: 22px; line-height: 1.3; }
h3 { font-size: 16px; }

.muted { color: var(--fg-secondary); }
.tiny { font-size: 12px; }
.strike { text-decoration: line-through; color: var(--fg-tertiary); }
.center { text-align: center; }
.nowrap { white-space: nowrap; }

/* screen-reader only */
.sr {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --------------------------------------------------------------- layout */
.page {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--page-pad);
}
/* The detail page runs a centred 1120px column of CONTENT — measured on the
   reference, where the title starts at x=200 and the gallery ends at x=1320 in
   a 1521px viewport. Ours capped the whole box at 1120 and then ate 80px of
   padding either side, leaving only 960 of content: 160px narrower than the
   reference at every width. The padding is kept so narrow screens still
   breathe; it is added to the cap rather than taken out of it. */
.page--narrow { max-width: calc(1120px + 2 * var(--page-pad)); }
.page--form { max-width: 640px; }

.section { padding: 26px 0; }
.section__head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 18px; gap: 16px;
}
.section__title {
  display: flex; align-items: center; gap: 10px;
  font-size: 20px; font-weight: 600; letter-spacing: -0.18px;
}
.divider { height: 1px; background: var(--border-subtle); border: 0; margin: 32px 0; }

/* --------------------------------------------------------------- header */
.header {
  position: sticky; top: 0; z-index: 60;
  background: var(--bg);
}
/* The hairline under the header fades in with the morph rather than switching
   on at a threshold — a border that appears in one frame is exactly the kind of
   pop this whole section exists to remove.

   Drawn as a pseudo-element rather than `border-bottom`, and the reason is a
   measurement, not taste: the search band now sits after the header instead of
   inside it, so a 1px border lands BETWEEN the two and pushes the band's bottom
   edge to 201px. The hero gradient's whole job is to complete its ramp exactly
   at the 200px mark — that boundary is the line the eye reads as the divider —
   so one borrowed pixel is a visible defect, and QA catches it. A border with a
   transparent colour still occupies that pixel; only taking it out of the box
   model fixes it. (The same trap is recorded for the search page's header.) */
.header::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: rgba(235, 235, 235, var(--morph));
  pointer-events: none;
}

.header__inner {
  max-width: var(--page-max); margin: 0 auto;
  padding: 0 var(--page-pad);
  height: var(--header-h);
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: 24px;
}
/* The header height is deliberately NOT animated and NOT reduced when
   compressed. It used to drop 96 -> 80, which is 16px of document height
   vanishing mid-scroll; combined with the band collapse below that is what made
   the morph lurch. The reference holds 96px throughout. */

/* The search page never morphs — it is BORN compact — so its header keeps the
   full 96px the reference uses. Shrinking to the 80px scrolled height left the
   sticky filter row (pinned at --header-h) floating 15px below the header, with
   page content showing through the gap. */
body[data-search="compact"] .header__inner { height: var(--header-h); }
/* ...and the filter row below draws the hairline, so the header must not draw a
   second one 1px above it. Width 0, not just a transparent colour: the border
   still occupies a pixel, which made the header 97px and pushed the whole
   sticky stack one out from the reference. */
body[data-search="compact"] .header::after { display: none; }

/* ------------------------------------------- search bar <-> header morph */
/* The tabs and the compressed pill share one grid cell and cross-fade. */
.header__centre { display: grid; justify-self: center; align-items: center; }
/* justify-self: center matters as much as the grid-area. The tabs and the pill
   share one cell, so the cell is as wide as the WIDER of them — the tabs. A
   440px pill left to its default alignment then sits at that cell's left edge,
   which put it 117px left of the viewport centre. The reference centres it. */
.header__centre > * { grid-area: 1 / 1; align-self: center; justify-self: center; }

/* On the search page the tabs never appear at all, so they shouldn't size the
   cell either — dropping them entirely keeps the centre honest at every width
   rather than relying on the two 1fr side columns staying balanced. */
body[data-search="compact"] .tabs { display: none; }

/* The product page is the one page whose header does NOT stick. On the
   reference it scrolls away with the content and the section bar takes over
   once the photos are past. Everywhere else the header stays pinned.

   `relative`, NOT `static` — and the difference is not cosmetic. The header
   carries a `view-transition-name`, which makes it a stacking context, and
   `z-index` is ignored on a static element. Setting `static` therefore dropped
   that whole context to auto, so it painted in DOM order BELOW the gallery's
   positioned wrapper — and the menu popover, z-index 70 but trapped inside,
   could not escape. The dropdown disappeared behind the photos.
   `relative` scrolls away exactly the same way but keeps z-index working. */
body[data-page="car"] .header { position: relative; }

/* ................................................. the morph, and why it scrubs

   This used to be a state flip: a class went on past scrollY 80, off below 40,
   and CSS transitions tweened between the two. It glitched, and the cause was
   not the easing — it was that compressing CHANGED THE DOCUMENT'S HEIGHT.
   `.searchbar` animated 104px to 0 and the header shrank 16px, so 120px of flow
   disappeared over 250ms while the user was scrolling through it. Content below
   jumped up under the pointer, and near the threshold the scroll corrections
   that followed bounced back and forth across it. The collapse was moving the
   scroll position that triggered the collapse.

   So the band no longer collapses. It keeps its 104px and simply scrolls away
   under the opaque sticky header, which is what the reference does. Document
   height is now constant, and with nothing to feed back there is no need for
   hysteresis either — it only ever existed to damp that flicker.

   Progress is `--morph`, set from scrollY every frame. Because the value IS the
   scroll offset, stopping mid-scroll leaves the morph genuinely parked at that
   point rather than completing to the nearest end state.

   No `transition` on any of the scrubbed properties. A transition here would
   chase --morph one frame behind the scroll and reintroduce the lag this is
   meant to remove. Motion still reads as smooth because the input is smooth —
   including the expand button, whose smooth scroll-to-top drives --morph back
   down to 0 frame by frame for free. */

/* Fade windows, kept as tokens so the choreography is legible in one place and
   tunable without hunting through calc() chains. The two overlap: the tabs are
   most of the way out before the compact pill starts arriving.

   Declared on `body`, not on `.header__centre`, because the expanded pill needs
   `--tabs-out` too and it lives in `.searchbar`, outside that cell. Scoping
   them to the header cell silently gave the pill the registered initial value
   of 0 — it inherits from body or not at all. */
body {
  --tabs-out: clamp(0, (var(--morph) - 0.15) / 0.35, 1);   /* gone by  p=0.50 */
  --mini-in:  clamp(0, (var(--morph) - 0.35) / 0.35, 1);   /* full  at p=0.70 */
}

/* Why those two windows overlap between 0.35 and 0.50: they are a cross-fade,
   and a gap between them leaves the middle of the header visibly empty at the
   exact scroll offset a user is most likely to rest on. An earlier pass had the
   tabs finishing at 0.65 and the pill starting at 0.55, and a screenshot ladder
   at p=0.5 showed the dead spot immediately — computed values alone would not
   have caught it, since each curve is correct in isolation.

   And why the compact pill is fully in by 0.70 rather than 1.0: that is where
   the expanded pill has finished passing behind the header. The band runs from
   document y=96 to y=200 with the pill inset 10px, so the pill's bottom edge
   clears the 96px header at scrollY 76 — p=0.73 of a 104px band. Landing the
   arrival just before the departure completes is what makes it read as one
   movement rather than two. */

/* compressed pill — hidden until the page scrolls */
/* Compact header pill. Every number here was read off the reference search
   page at a 1536 viewport: 440 x 46 at a 40px radius, a .8px #ddd hairline and
   a two-layer shadow. The three fields are FIXED tracks (197 / 97 / 109) with a
   37px tail for the button — not flex — because flex re-divides the row as soon
   as the label text changes length, and the divider positions are part of the
   look. A 48px icon overhangs the pill's top edge by 1px, as it does there. */
.pill-mini {
  position: relative;
  display: grid; grid-template-columns: 197px 97px 109px minmax(0, 1fr);
  align-items: center;
  width: var(--mini-w); height: var(--mini-h); padding: 0;
  border: .8px solid var(--border); border-radius: 40px;
  background: var(--bg); box-shadow: var(--mini-shadow);
  font-size: 14px; font-weight: 500; color: var(--fg); white-space: nowrap;
  /* Scrubbed off --mini-in. `visibility` is deliberately absent: it is a
     discrete property, so it would snap at some arbitrary frame and undo the
     point of the exercise. Hit-testing is handled by pointer-events below,
     which is switched once from JS rather than tweened. */
  opacity: var(--mini-in);
  transform: scale(calc(0.88 + 0.12 * var(--mini-in)));
  pointer-events: none;
  transition: box-shadow var(--t-shadow);   /* hover only — never the morph */
}
.pill-mini:hover { box-shadow: 0 1px 2px rgba(0, 0, 0, .10), 0 6px 16px rgba(0, 0, 0, .08); }
.pill-mini__icon {
  position: absolute; left: 8px; top: -1px;
  width: 48px; height: 48px; pointer-events: none;
}
.pill-mini__seg {
  position: relative; padding: 0 8px; text-align: center;
  overflow: hidden; text-overflow: ellipsis;
}
.pill-mini__seg:first-of-type { padding-left: 64px; text-align: left; }  /* clears the icon */
.pill-mini__seg + .pill-mini__seg::before {
  content: ''; position: absolute; left: 0; top: 50%; translate: 0 -50%;
  width: 1px; height: 24px; background: var(--border);
}
.pill-mini__seg--muted { color: var(--fg-secondary); }
.pill-mini__go {
  justify-self: end; margin-right: 6px;
  display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--search-pink); color: #fff;
}

/* `is-compressed` survives, but its job has shrunk. It no longer drives any of
   the visible morph — it is now only the HANDOVER FLAG, flipped once at the
   halfway point, and all it decides is which of the two controls is clickable.
   Keeping the discrete concern discrete is what lets everything else be
   continuous. Other code (and the QA harness) still reads it to answer "is this
   header showing the compact pill?", which is why it kept its name. */
.pill-mini { pointer-events: none; }
body.is-compressed .pill-mini { pointer-events: auto; }
body.is-compressed .tabs { pointer-events: none; }

/* ...................................... signed-out / signed-in header state

   One attribute on <body> drives both the menu and the header row. There is no
   auth behind it — `data-auth` is set in memory when the login modal's Continue
   is pressed and lost on reload, because the project uses no browser storage.
   That is the honest prototype behaviour: it exercises the real flow without
   pretending to a session it does not have. */
/* The language globe gives way to the avatar, as on the reference — languages
   moves into the menu when signed in, so keeping both would leave two routes to
   one thing sitting side by side. */
.avatar { display: none; }
body[data-auth="in"] .header__actions .icon-btn { display: none; }
body[data-auth="in"] .avatar {
  display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 50%;
  background: #ffe1e8; color: var(--logo-red);
  font-size: 13px; font-weight: 600; letter-spacing: 0;
  user-select: none;
}

/* pages with no search bar at all keep the tabs and never compress */
body:not([data-search]) .pill-mini,
body:not([data-search]) .pop,
body:not([data-search]) .searchbar { display: none; }

/* Search and car are born compact and have no expanded state to scroll away
   from, so the band is removed outright rather than merely scrolled past.
   It used to be collapsed to `height: 0` by `is-compressed`, which these pages
   got for free — now that the band keeps its height on the homepage (see the
   morph notes above) they need to say so themselves, or the 104px band stacks
   under the header and puts their chrome at 200px instead of the measured 96. */
body[data-search="compact"] .searchbar { display: none; }

.logo {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: 800; font-size: 22px;
  letter-spacing: -0.04em;
}
/* The wordmark is two-tone with the mark: "so" red, "ko" black. The halves are
   separate spans rather than one coloured string because there is no way to
   colour part of a text node, and they sit in a wrapper so the 8px gap on
   `.logo` still applies once — between the mark and the WORD, not between the
   two syllables. The comment between the svg and the span in the markup kills
   the whitespace text node that would otherwise open a gap there. */
.logo__so { color: var(--logo-red); }
.logo__ko { color: var(--logo-ink); }
/* The mark is 1.1524:1, not square, so it is sized by HEIGHT and left to work
   its own width out from the viewBox. Pinning both axes to the old 30x30 would
   letterbox it inside a square box and cost ~4px of drawn height, making it
   read smaller than the mark it replaced. Matching on height keeps the optical
   weight beside the 22px wordmark exactly where it was. */
.logo svg { height: 30px; width: auto; flex: none; }

/* category tabs — the reference pairs a 72px illustrated icon with a 14px/500
   label on one row, both optically centred in the 96px header. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.tabs {
  display: flex; align-items: center; gap: 20px; justify-self: center;
  opacity: calc(1 - var(--tabs-out));
  transform: scale(calc(1 - 0.06 * var(--tabs-out)));
}
.tab {
  display: flex; align-items: center; gap: 2px;
  padding: 0 4px;
  background: none; border: 0; border-bottom: 2px solid transparent;
  color: var(--fg-secondary); font-size: 14px; font-weight: 500;
  opacity: .8; white-space: nowrap;
  transition: opacity var(--t-colour), color var(--t-colour), border-color var(--t-colour);
}
.tab__icon {
  width: var(--tab-icon); height: var(--tab-icon);
  flex: none;
  transition: transform var(--t-move);
}
.tab:hover .tab__icon { transform: scale(1.06); }

/* ....................................... the "All" wheel turns lock to lock

   Right lock -> hold -> sweep left -> hold -> back. The animation sits on the
   <use>, NOT on the <svg>, because the svg already carries the hover scale and
   one element cannot hold two independent transforms — driving both from here
   would mean re-declaring the scale inside every keyframe, which is the same
   trap the search button fell into.

   `transform-box: fill-box` makes the origin the wheel's own bounding box, so
   `center` is the hub. Without it the origin resolves against the SVG viewport
   and the wheel orbits instead of turning.

   About the ANGLE: a real car is about 1.5 turns — 540 degrees — to full lock.
   At 72px that does not read as steering, it reads as a spin, because the eye
   loses count of the spokes. 150 degrees is the largest angle that still reads
   as a deliberate steering input. Change --wheel-lock to 450deg for a literal
   full lock and lengthen --wheel-dur to match if you want the real thing. */
.tab__icon--wheel {
  --wheel-lock: 150deg;
  --wheel-dur: 10s;
}
.tab__icon--wheel use {
  transform-box: fill-box;
  transform-origin: center;
  /* ease-in-out, and this is a DELIBERATE departure from the site's single
     --ease curve. That curve is cubic-bezier(0.2, 0, 0, 1) — heavily
     front-loaded, which is right for a UI element answering a click but wrong
     here: measured, it threw the wheel 163 degrees in the first 0.7s of the
     sweep and then crawled the remaining 137 over 2.5s. Hands winding a wheel
     accelerate and decelerate symmetrically. The site rule governs UI
     transitions; a looping illustration is a different job. */
  animation: wheel-lock var(--wheel-dur) ease-in-out infinite;
}
@keyframes wheel-lock {
  0%   { transform: rotate(var(--wheel-lock)); }                 /* at right lock */
  18%  { transform: rotate(var(--wheel-lock)); }                 /* hold */
  50%  { transform: rotate(calc(-1 * var(--wheel-lock))); }      /* sweep to left lock */
  68%  { transform: rotate(calc(-1 * var(--wheel-lock))); }      /* hold */
  100% { transform: rotate(var(--wheel-lock)); }                 /* sweep back */
}
.tab.is-active .tab__icon { transform: none; }
.tab:hover { opacity: 1; border-bottom-color: var(--border); }
.tab.is-active { color: var(--fg); opacity: 1; border-bottom-color: var(--fg); }

.header__actions {
  display: flex; align-items: center; justify-content: flex-end; gap: 8px;
}
/* Header actions, measured on the reference: a 40px-tall text link at 14px/500,
   then TWO 40x40 circles filled #f2f2f2 carrying 16x16 icons. The circles are
   filled at rest — an icon floating on bare white was the old look and reads as
   unfinished next to the reference. */
.link-btn {
  display: inline-flex; align-items: center;
  height: 40px; padding: 0 14px; border-radius: 20px;
  background: none; border: 0; font-size: 14px; font-weight: 500;
  transition: background var(--t-colour);
}
.link-btn:hover { background: var(--bg-subtle); }

.icon-btn,
.usermenu {
  display: grid; place-items: center;
  width: 40px; height: 40px; border: 0; border-radius: 50%;
  background: var(--grey-btn); color: var(--fg);
  transition: background var(--t-colour), transform var(--t-press);
}
.icon-btn:hover, .usermenu:hover { background: #e6e6e6; }
.icon-btn:active, .usermenu:active { transform: scale(.94); }

/* ----------------------------------------------------------- search pill */
/* The hero band is 200px tall measured from the TOP OF THE PAGE — it sits
   behind the header as well as the search row. Our header is opaque white and
   occupies the first 96px of it, so this element renders the remaining 104px
   by pulling the gradient up by exactly one header height. That matters: the
   ramp only reaches #f8f8f8 at the 200px mark, and it is that colour meeting
   the white content below which draws the line the eye reads as a divider —
   with the gradient above it doing the work of a soft shadow. Rendering the
   gradient from 0 here (what it used to do) stopped at ~#fcfcfc and produced
   no edge at all. */
.searchbar {
  display: flex; justify-content: center; align-items: flex-start;
  height: var(--searchbar-h); overflow: hidden;
  background: var(--hero-fade);
  background-size: 100% 200px; background-repeat: no-repeat;
  background-position: 0 calc(-1 * var(--header-h));
  transform-origin: top center;
}
/* The band holds a CONSTANT height and scrolls away under the header — no
   collapse, no height transition, so the document never changes size and the
   scroll offset stays a trustworthy input. This is the load-bearing line of the
   whole fix; restoring `height: 0` on a compressed state brings the glitch back.

   The expanded pill is given NO fade and NO transform. It is opaque right up to
   the moment the opaque header covers it, which is what the reference does —
   its pill sits half-cut by the header edge at full strength. A first attempt
   faded it alongside the tabs and the screenshot ladder showed the cost at once:
   at p=0.5 the pill was a ghost while still sitting in plain view, well short of
   the header. Occlusion is the effect; anything else here fights it. */
.searchbar > .pill { margin-top: 10px; }

.pill {
  display: grid; grid-template-columns: repeat(3, 1fr); align-items: stretch;
  width: var(--pill-w); max-width: calc(100vw - 2 * var(--page-pad));
  height: var(--pill-h);
  background: var(--bg);
  border: 1px solid var(--border); border-radius: 100px;
  /* measured at rest on the reference: 0 0 0 1px rgba(0,0,0,.02),
     0 8px 24px rgba(0,0,0,.10) — the raised tier. This is the lift that makes
     the search bar sit above the page rather than on it. */
  box-shadow: var(--sh-xl);
  transition: box-shadow var(--t-shadow);
}
.pill { position: relative; }
.pill:hover { box-shadow: 0 0 0 1px rgba(0,0,0,.02), 0 10px 30px rgba(0,0,0,.13); }

/* ------------------------------------------------ focused search (H2)
   While a field is active the whole pill drops to grey and the active field
   lifts out of it on a white cushion. Measured on the reference: track
   #ebebeb, cushion white + 1px #ddd ring + a soft 3px/12px drop.          */
.pill.is-focused {
  background: var(--pill-track);
  border-color: transparent;
  box-shadow: var(--sh-md);
}
/* Dividers survive between two unfocused neighbours — only the pair touching
   the cushion loses theirs. Checked against the reference: with "Where" active
   the When|Who divider is still drawn. */
.pill.is-focused .pill__field.is-active::before,
.pill.is-focused .pill__field.is-active + .pill__field::before { opacity: 0; }
.pill.is-focused .pill__field:hover { background: rgba(0, 0, 0, .045); }

.pill__field {
  transition: background-color var(--t-colour), box-shadow var(--t-shadow);
}
.pill.is-focused .pill__field.is-active,
.pill.is-focused .pill__field.is-active:hover {
  background: var(--bg);
  box-shadow: var(--sh-cushion);
}
.pill.is-focused .pill__field.is-active .pill__label { color: var(--fg); }

.pill__field {
  position: relative;
  display: flex; flex-direction: column; justify-content: center; gap: 2px;
  /* measured: 15px 32px on the first field, 15px 24px on the rest */
  padding: 15px 24px; min-width: 0;
  border: 0; background: none; text-align: left;
  border-radius: var(--r-pill);
  transition: background .15s;
}
/* The divider is a SHORT centred rule, not a full-height seam. Measured on the
   reference: 1px x 32px in #dddddd, vertically centred in the 66px pill — so
   roughly the middle half. A full-height hairline (what this used to be) reads
   as a join between two panels rather than as a deliberate separator. */
.pill__field + .pill__field::before {
  content: ''; position: absolute; left: 0; top: 50%;
  translate: 0 -50%;
  width: 1px; height: var(--pill-divider-h);
  background: var(--border);
  transition: opacity var(--t-colour);
}
.pill__field:first-child { padding-left: 32px; }
/* the last field's right padding clears the search button */
.pill__field:last-of-type { padding-right: 122px; }
.pill.is-focused .pill__field:last-of-type { padding-right: 122px; }
.pill__field:hover { background: var(--bg-subtle); }
.pill__label { font-size: 12px; font-weight: 600; }
.pill__value {
  font-size: 14px; font-weight: 500; color: var(--fg-secondary);
  min-width: 0; overflow: hidden;
}
.pill__value input {
  border: 0; padding: 0; font: inherit; color: var(--fg);
  background: none; outline: none;
  width: 100%; min-width: 0;   /* inputs default to ~20ch; without this the
                                  last field steals width from the others */
  text-overflow: ellipsis;
}
.pill__value input::placeholder { color: var(--fg-secondary); }

/* The circle is 48x48, inset 10px from the pill's right edge and centred in the
   66px height. Two bugs lived here:

   1. `gap: 8px` applied between the icon and the collapsed "Search" label. A
      zero-WIDTH flex item still takes its gap, so the flex line measured
      17 + 8 + 0 = 25px and centring that put the magnifier 4px LEFT of the
      circle's centre. The gap now belongs to the label's padding, so it only
      exists once the label does.
   2. Two later `:hover`/`:active` rules re-declared `transform` without the
      `translateY(-50%)` that does the vertical centring, so the button dropped
      24px the moment you pointed at it. Consolidated into one rule each. */
.pill__search {
  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  margin: 0;
  display: flex; align-items: center; justify-content: center; gap: 0;
  width: 48px; height: 48px; padding: 0; border: 0; border-radius: var(--r-pill);
  background: var(--search-pink); color: #fff;
  overflow: hidden; white-space: nowrap;
  transition: width var(--t-move), transform var(--t-move),
              background-color var(--t-colour);
}
/* label is measured at 16px/500 white; hidden until the pill is focused */
.pill__search span {
  font-size: 16px; font-weight: 500;
  max-width: 0; opacity: 0; padding-left: 0;
  transition: max-width var(--t-move), opacity var(--t-move),
              padding-left var(--t-move);
}
.pill.is-focused .pill__search { width: 100px; }
.pill.is-focused .pill__search span { max-width: 60px; opacity: 1; padding-left: 8px; }

.pill__search:hover { background: #c00f3f; transform: translateY(-50%) scale(1.04); }
.pill__search:active {
  transform: translateY(-50%) scale(.96);
  transition: transform var(--t-press);
}
.pill.is-focused .pill__search:hover { transform: translateY(-50%) scale(1.02); }

/* ---------------------------------------------------------------- chips */
.chips { display: flex; gap: 10px; flex-wrap: wrap; }
/* Measured on the reference filter row: 34px tall, 24px radius, a .8px #ddd
   hairline, and 12px/400 text — noticeably lighter than a general-purpose chip. */
.chip {
  display: inline-flex; align-items: center; gap: 8px; flex: none;
  height: 34px; padding: 0 12px; border-radius: 24px;
  border: .8px solid var(--border); background: var(--bg);
  font-size: 12px; font-weight: 400; color: var(--fg);
  transition: border-color var(--t-colour), background-color var(--t-colour), box-shadow var(--t-shadow);
}
.chip:hover { border-color: var(--fg); background: var(--bg-subtle); }

/* ------------------------------------------------------------- pagination */
/* Reference: centred row of 32px circles on a 48px pitch (16px gap), the
   current page filled #222 with white text, chevrons set 24px out from the
   numbers and greyed to #ddd when they can't go anywhere. */
.pager {
  display: flex; align-items: center; justify-content: center; gap: 16px;
  margin: 40px 0 8px;
}
.pager__num {
  display: grid; place-items: center;
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: none; color: var(--fg);
  font-size: 14px; font-weight: 500;
  transition: background-color var(--t-colour), color var(--t-colour), transform var(--t-press);
}
.pager__num:hover { background: var(--bg-subtle); }
.pager__num:active { transform: scale(.92); }
.pager__num.is-current { background: var(--fg); color: var(--fg-inverse); }
.pager__num.is-current:hover { background: var(--fg); }
.pager__arrow {
  display: grid; place-items: center;
  width: 12px; height: 32px; margin: 0 8px;
  border: 0; background: none; color: var(--fg);
  transition: color var(--t-colour), transform var(--t-press);
}
.pager__arrow:active { transform: scale(.9); }
.pager__arrow[disabled] { color: var(--border); cursor: default; }
.pager__gap {
  display: grid; place-items: center;
  width: 32px; height: 32px; color: var(--fg); font-size: 14px;
}
.chip.is-active {
  border-color: var(--fg); background: var(--fg); color: var(--fg-inverse);
}

/* --------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 14px 24px; border-radius: var(--r-sm);
  border: 1px solid transparent; background: none;
  font-size: 15px; font-weight: 600; color: var(--fg);
  transition: transform var(--t-press), filter var(--t-colour),
              background-color var(--t-colour), border-color var(--t-colour);
}
.btn:active { transform: scale(.97); }
.btn--primary { background: var(--rausch-grad); color: #fff; }
.btn--primary:hover { filter: brightness(1.06); }
.btn--dark { background: var(--fg); color: #fff; }
.btn--dark:hover { filter: brightness(1.25); }
.btn--outline { border-color: var(--fg); background: var(--bg); }
.btn--outline:hover { background: var(--bg-subtle); }
.btn--ghost { text-decoration: underline; padding: 10px 6px; }
.btn--block { width: 100%; }
.btn--lg { padding: 16px 28px; font-size: 16px; }

/* ------------------------------------------------------------- car cards */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
  gap: 24px 20px;
}

/* horizontal scrolling strip (home page rows) */
.rail {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(178px, 1fr);
  gap: 20px; overflow-x: auto; scroll-behavior: smooth;
  scrollbar-width: none; -ms-overflow-style: none;
  padding-bottom: 4px;
}
.rail::-webkit-scrollbar { display: none; }
.rail__nav { display: flex; gap: 8px; }
.rail__btn {
  display: grid; place-items: center;
  width: 28px; height: 28px; border-radius: 50%;
  border: 0; background: var(--grey-btn); color: var(--fg);
  transition: transform var(--t-move), background-color var(--t-colour);
}
.rail__btn:hover { background: #e8e8e8; transform: scale(1.08); }
.rail__btn:active { transform: scale(.94); transition: transform var(--t-press); }

.card { position: relative; display: block; }
/* 20px, measured — NOT the 12px card radius token. On the reference the round
   corner is six ancestors above the <img>, on the wrapper that clips it, which
   is why an earlier pass reading the image's own border-radius found 0 and left
   this at --r-md. It is the same 20px the "See all" card already uses, so the
   rail now agrees with itself end to end. */
.card__media {
  position: relative; aspect-ratio: 20 / 19;   /* measured 182x173 = 1.05 */
  border-radius: 20px; overflow: hidden; background: var(--bg-subtle);
}
.card__img { width: 100%; height: 100%; object-fit: cover; }

/* Overlay badges are GLASS, not solid white. Measured on the reference:
   80% white over a 32px backdrop blur, a half-opaque white hairline border and
   the standard shadow tier. Solid white reads as a sticker; the blur lets the
   photo underneath tint the chip, which is what makes it sit ON the image. */
.card__badge {
  position: absolute; top: 10px; left: 10px;
  padding: 5.5px 9.5px; border-radius: 14px;
  background: rgba(255, 255, 255, .8);
  -webkit-backdrop-filter: blur(32px);
          backdrop-filter: blur(32px);
  border: .8px solid rgba(255, 255, 255, .5);
  box-shadow: var(--sh-md);
  /* 12px, not the 14px an earlier pass recorded. The pill measures 25.6px tall
     against 11px of vertical padding, which leaves a 14.6px line box — that is
     12px text at a normal line-height, and 14px cannot fit it. Ours rendered
     33.3px. The width corroborates it: "Guest favourite" is 103px on the
     reference, and at 14px our own glyph widths put it near 127px. */
  font-size: 12px; font-weight: 600; color: var(--fg);
  /* The line box is pinned, not left to inherit. Dropping to 12px alone still
     left the pill 30.4px tall because the badge inherits the body's roomier
     line-height. Working back from the measured 25.6px pill: minus the 1.6px of
     hairline border, minus 11px of padding, leaves a 13px line box. Font size
     alone does not size a pill — the line box does, and the border counts. */
  line-height: 13px;
}
.card__badge--muted { color: var(--fg-secondary); }

/* Fallback: without backdrop-filter the 80% white would let the photo show
   through as noise, so go opaque instead. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card__badge { background: rgba(255, 255, 255, .96); }
}

.card__fav {
  position: absolute; top: 10px; right: 10px;
  display: grid; place-items: center;
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: transparent; color: rgba(255,255,255,.92);
}
.card__fav svg { filter: drop-shadow(0 1px 2px rgba(0,0,0,.45)); }
.card__fav { transition: transform var(--t-move); }
.card__fav:hover { transform: scale(1.12); }
.card__fav:active { transform: scale(.92); transition: transform var(--t-press); }
.card__fav.is-on { color: var(--rausch); }
.card__fav.is-on svg { fill: var(--rausch); }

.card__body { padding: 10px 2px 0; display: grid; gap: 2px; }
.card__row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.card__title { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }
.card__meta { font-size: 13px; font-weight: 400; color: var(--fg-secondary); }
.card__price { font-size: 13px; color: var(--fg-secondary); display: flex; align-items: center; gap: 5px; }
.card__price b { font-weight: 600; color: var(--fg); }
.rating { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; white-space: nowrap; }

/* ------------------------------------------------------------ search page */
.split { display: grid; grid-template-columns: minmax(0, 776px) minmax(0, 1fr); }
.split__list { padding: 24px 48px 60px; overflow: auto; }

/* The map is a rounded CARD inset from the page edge, not a full-bleed panel.
   Measured on the reference at a 1536 viewport: 20px radius, pinned 192px from
   the top — that is the 151px sticky chrome (96 header + 55 filter row) plus a
   41px gap — 48px clear of the right edge, and 24px short of the bottom, so
   `100vh - 216px` tall. */
.split__map {
  position: sticky;
  top: calc(var(--header-h) + var(--filterbar-h) + 41px);
  height: calc(100vh - var(--header-h) - var(--filterbar-h) - 65px);
  margin-right: 48px;
  border-radius: 20px;
  overflow: hidden;
  background: linear-gradient(160deg, #e8ece8 0%, #dfe6dd 45%, #d7e2dd 100%);
}
/* The filter row is part of the sticky chrome — if it scrolled away the map
   would hang 55px below where it belongs for the rest of the page. */
.filterbar {
  position: sticky; top: var(--header-h); z-index: 50;
  background: var(--bg);
  display: flex; align-items: center; gap: 12px;
  height: var(--filterbar-h); padding: 0 48px;
  border-bottom: .8px solid rgba(0, 0, 0, .1);
  overflow-x: auto; scrollbar-width: none;
}
.filterbar::-webkit-scrollbar { display: none; }
.filterbar__rule { width: 1px; height: 24px; background: var(--border); flex: none; }
.chip--filters { font-weight: 500; }

.map__pin {
  position: absolute; transform: translate(-50%, -50%);
  padding: 7px 12px; border-radius: var(--r-pill);
  background: var(--bg); border: 0;
  box-shadow: var(--sh-sm);
  font-size: 13px; font-weight: 700; white-space: nowrap;
  transition: transform var(--t-move), background-color var(--t-colour), color var(--t-colour);
}
.map__pin:hover, .map__pin.is-active {
  background: var(--fg); color: #fff; transform: translate(-50%, -50%) scale(1.09);
}

.floating-toggle {
  position: fixed; left: 50%; bottom: 32px; transform: translateX(-50%);
  z-index: 50;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 14px 20px; border: 0; border-radius: var(--r-pill);
  background: var(--fg); color: #fff; font-size: 14px; font-weight: 600;
  box-shadow: var(--sh-xl);
  transition: transform var(--t-move);
}
.floating-toggle:hover { transform: translateX(-50%) scale(1.04); }

/* ------------------------------------------------------------ detail page */
/* Gallery mosaic, measured on a reference listing at a 1536 viewport: the row
   is 1120 wide and lays out 560 | 8 | 272 | 8 | 272. That is NOT 2:1:1 — the
   hero is 560 against a 552 right-hand block, eight wider. 70/34/34 reproduces
   it exactly at any width: 138 parts over (100% - 16px of gaps).
   The block is 402 tall, so it is far wider than the 2:1 we were drawing. */
.gallery {
  display: grid; grid-template-columns: 70fr 34fr 34fr;
  grid-template-rows: 1fr 1fr; gap: 8px;
  border-radius: var(--r-lg); overflow: hidden;
  aspect-ratio: 1120 / 402;
}
.gallery > *:first-child { grid-row: span 2; }
.gallery img { width: 100%; height: 100%; object-fit: cover; background: var(--bg-subtle); }
.gallery__all {
  position: absolute; right: 24px; bottom: 24px;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 15px; border-radius: var(--r-sm);
  background: var(--bg); border: 1px solid var(--fg);
  font-size: 13px; font-weight: 600;
}

.detail { display: grid; grid-template-columns: minmax(0, 1fr) 372px; gap: 80px; }
.detail__aside { position: relative; }

/* Sticks under the SECTION BAR, not under the header — the header has scrolled
   away by the time this card is pinned. Clearing --header-h here left a 40px
   gap where nothing was. */
.bookbox {
  position: sticky; top: calc(var(--subnav-h) + 24px);
  padding: 24px; border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--sh-lg);
  background: var(--bg);
}
.bookbox__head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 20px;
}
.bookbox__price { font-size: 22px; font-weight: 700; }

.fieldset-grid {
  display: grid; grid-template-columns: 1fr 1fr;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  overflow: hidden; margin-bottom: 16px;
}
.fieldset-grid > * { padding: 10px 12px; }
.fieldset-grid > *:first-child { border-right: 1px solid var(--border); }
.fieldset-grid .full { grid-column: 1 / -1; border-top: 1px solid var(--border); border-right: 0; }
.field__label {
  /* measured on the reference booking box: 10px / 700 / uppercase */
  display: block; font-size: 10px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
.field__input, .field__select {
  width: 100%; border: 0; padding: 2px 0; font: inherit; font-size: 14px;
  background: none; outline: none; color: var(--fg);
}

.feature-list { display: grid; gap: 18px; }
.feature { display: flex; gap: 16px; align-items: flex-start; }
.feature__icon { flex: none; width: 24px; color: var(--fg); }
.feature__title { font-weight: 600; }
.feature__text { color: var(--fg-secondary); font-size: 14px; }

.pillbox__icon { width: 16px; height: 16px; flex: none; }
.auth__social svg { width: 26px; height: 26px; }
.pillbox {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 14px; border: 1px solid var(--border-subtle);
  border-radius: var(--r-pill); font-size: 13px; background: var(--bg-subtle);
}

.host { display: flex; align-items: center; gap: 16px; }
.avatar { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; background: var(--bg-subtle); flex: none; }
.avatar--sm { width: 40px; height: 40px; }
.avatar--lg { width: 96px; height: 96px; }

.reviews { display: grid; grid-template-columns: 1fr 1fr; gap: 32px 48px; }
.review__head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }

/* ------------------------------------------------------------ forms/auth */
.card-panel {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg); box-shadow: var(--sh-sm);
  overflow: hidden;
}
.card-panel__head {
  padding: 18px 24px; border-bottom: 1px solid var(--border);
  font-weight: 700; text-align: center;
}
.card-panel__body { padding: 24px; }

.stack { display: grid; gap: 16px; }
.stack--tight { gap: 10px; }

.input-group {
  border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden;
}
.input-group > * { padding: 10px 12px; }
.input-group > * + * { border-top: 1px solid var(--border); }

.rule { display: flex; align-items: center; gap: 14px; color: var(--fg-secondary); font-size: 12px; }
.rule::before, .rule::after { content: ''; flex: 1; height: 1px; background: var(--border); }

.social-btn {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 13px 18px;
  border: 1px solid var(--fg); border-radius: var(--r-sm);
  background: var(--bg); font-size: 14px; font-weight: 600;
}
.social-btn:hover { background: var(--bg-subtle); }

/* ------------------------------------------------------------- checkout */
.checkout { display: grid; grid-template-columns: minmax(0, 1fr) 372px; gap: 100px; }
.option {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 18px; border: 1px solid var(--border); border-radius: var(--r-md);
  cursor: pointer; transition: border-color .15s, box-shadow .15s;
}
.option + .option { margin-top: -1px; }
.option:hover { border-color: var(--fg); }
.option.is-selected { border-color: var(--fg); box-shadow: 0 0 0 1px var(--fg) inset; }
.option input { margin-top: 3px; accent-color: var(--fg); }

.summary {
  position: sticky; top: calc(var(--header-h) + 24px);
  padding: 24px; border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--sh-sm);
}
.summary__row { display: flex; justify-content: space-between; gap: 16px; padding: 7px 0; font-size: 14px; }
.summary__total {
  display: flex; justify-content: space-between;
  padding-top: 16px; margin-top: 8px;
  border-top: 1px solid var(--border); font-weight: 700; font-size: 15px;
}

/* --------------------------------------------------------------- profile */
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; }
.tile {
  display: block; padding: 22px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  transition: box-shadow var(--t-shadow), transform var(--t-move);
}
.tile:hover { box-shadow: var(--sh-md); transform: translateY(-2px); }
/* Icon sizing for the sprite glyphs that replaced the emoji. Emoji sized
   themselves off font-size; SVGs need explicit boxes. */
.tile__icon { margin-bottom: 12px; color: var(--fg); }
.tile__icon svg { width: 26px; height: 26px; display: block; }

.badge-verified {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--fg-secondary);
}

/* --------------------------------------------------------------- success */
.hero-confirm { max-width: 620px; margin: 0 auto; padding: 80px 0; text-align: center; }
.hero-confirm__mark {
  width: 84px; height: 84px; margin: 0 auto 28px;
  display: grid; place-items: center; border-radius: 50%;
  background: var(--rausch-grad); color: #fff;
}

/* ---------------------------------------------------------------- footer */
.footer {
  margin-top: 48px; padding: 48px 0 32px;
  background: var(--bg-subtle); border-top: 1px solid var(--border-subtle);
}
.footer__cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 32px; padding-bottom: 32px;
}
.footer__title { font-size: 14px; font-weight: 700; margin-bottom: 14px; }
.footer__links { display: grid; gap: 12px; font-size: 14px; color: var(--fg-secondary); }
.footer__links a:hover { text-decoration: underline; color: var(--fg); }
.footer__bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 16px; padding-top: 24px; border-top: 1px solid var(--border);
  font-size: 14px; color: var(--fg-secondary);
}
.footer__bar nav { display: flex; flex-wrap: wrap; gap: 18px; }

/* ------------------------------------------------------------ responsive */
@media (max-width: 1280px) {
  :root { --page-pad: 40px; }
  .detail, .checkout { grid-template-columns: 1fr; gap: 40px; }
  .bookbox, .summary { position: static; }
  .reviews { grid-template-columns: 1fr; }
}

@media (max-width: 1024px) {
  .tabs { display: none; }
  .pill-mini { font-size: 13px; }
  .pill-mini__seg { padding: 4px 10px; }
  .split { grid-template-columns: 1fr; }
  .split__map { display: none; }
}

@media (max-width: 760px) {
  :root {
    --page-pad: 20px; --header-h: 68px;
    --searchbar-h: 190px;
  }
  .pill-mini__seg[data-mini="when"] { display: none; }
  /* Only the destination segment survives here, so the fixed reference tracks
     are dropped for fluid ones — a 440px pill cannot fit a 375px screen. */
  .pill-mini { grid-template-columns: minmax(0, 1fr) 37px; height: 42px; }
  .pill-mini__icon { width: 40px; height: 40px; left: 5px; top: 0; }
  .pill-mini__seg:first-of-type { padding-left: 50px; }
  .logo { font-size: 19px; }
  .logo svg { width: 24px; height: 24px; }
  h1 { font-size: 26px; }
  /* three columns still, so the actions never wrap onto a second row */
  .header__inner { grid-template-columns: auto minmax(0, 1fr) auto; gap: 10px; }
  .header__centre { min-width: 0; width: 100%; }
  /* only the destination segment survives at this width */
  .pill-mini { width: 100%; justify-content: space-between; padding: 5px 5px 5px 6px; }
  .pill-mini__seg[data-mini="who"] { display: none; }
  .pill-mini__seg {
    padding: 4px 8px; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .pill-mini__seg + .pill-mini__seg { box-shadow: none; }
  .pill-mini__go { width: 30px; height: 30px; margin-left: 2px; flex: none; }
  .pill { flex-direction: column; width: 100%; border-radius: var(--r-xl); }
  .pill__field + .pill__field { box-shadow: 0 -1px 0 var(--border-subtle); }
  .pill__search { margin: 0 0 12px auto; margin-right: 12px; }
  .gallery { grid-template-columns: 1fr; grid-template-rows: 1fr; aspect-ratio: 4 / 3; }
  .gallery > *:not(:first-child) { display: none; }
  .gallery > *:first-child { grid-row: span 1; }
  .fieldset-grid { grid-template-columns: 1fr; }
  .fieldset-grid > *:first-child { border-right: 0; border-bottom: 1px solid var(--border); }
  .link-btn { display: none; }
}

/* --------------------------------------------------------------- motion */
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
.fade-up { animation: fadeUp .28s ease both; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  /* The morph still happens — the band still scrolls away, because that is just
     the page scrolling — but the scrub is quantised to the halfway flag and the
     scale tweens are dropped. A continuously moving cross-fade tied to scroll
     is precisely the kind of motion this preference is asking us not to make,
     so here the two controls swap once and stay swapped. */
  .searchbar, .tabs, .pill-mini { transform: none !important; }
  /* A wheel that never stops turning is precisely the kind of unrequested,
     perpetual motion this preference exists to switch off. It rests centred. */
  .tab__icon--wheel use { animation: none !important; transform: none !important; }
  .tabs { opacity: 1; }
  .pill-mini { opacity: 0; }
  body.is-compressed .tabs { opacity: 0; }
  body.is-compressed .pill-mini { opacity: 1; }
  .pill__search, .pill__search span { transition: none !important; }
}

/* =========================================================================
   H3 — search popovers
   Measured on the reference: panel white with a large radius and the raised
   shadow tier; destination icon tiles 56px/#ebebeb/8px radius; segmented
   toggle track #ebebeb with a white 100px-radius thumb; steppers 32px
   #f2f2f2 circles that grey to #c1c1c1 when disabled.
   ========================================================================= */

.pop {
  position: fixed; z-index: 70;
  min-width: 400px; max-width: calc(100vw - 32px);
  padding: 16px 8px;
  background: var(--bg); border-radius: var(--r-xl);
  box-shadow: var(--sh-xl);
  opacity: 0; transform: translateY(-8px);
  transition: opacity var(--t-move), transform var(--t-move);
}
.pop.is-open { opacity: 1; transform: none; }
.pop--wide { padding: 16px 12px 8px; }
.pop--who { min-width: 400px; padding: 4px 24px; }

.pop__heading {
  margin: 0; padding: 8px 16px 4px;
  font-size: 12px; font-weight: 400; color: var(--fg);
}

/* ------------------------------------------------------ destinations list */
.pop__list { max-height: 420px; overflow-y: auto; }
.pop__row {
  display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 5px 16px; height: 66px;
  border: 0; background: none; text-align: left;
  border-radius: var(--r-pill);
  transition: background-color var(--t-colour);
}
.pop__row:hover, .pop__row:focus-visible { background: var(--bg-subtle); }
.pop__tile {
  flex: none; display: grid; place-items: center;
  width: 56px; height: 56px; border-radius: var(--r-sm);
  background: var(--pill-track); color: var(--fg);
}
/* Explicit dimensions, not `font-size`. The tile used to hold an emoji, which
   sized itself off the type scale; an SVG does not, and inherits nothing useful
   if you only set font-size. Same note as the sprite conversion in 02. */
.pop__tile svg { width: 24px; height: 24px; }
.pop__row-title { font-size: 14px; font-weight: 500; color: var(--fg); }
.pop__row-sub { font-size: 14px; font-weight: 400; color: var(--fg-secondary); }

/* ------------------------------------------------------- segmented toggle */
.seg {
  display: inline-flex; gap: 4px; margin: 0 auto 8px; padding: 5px;
  background: var(--pill-track); border-radius: 100px;
}
.seg { display: flex; width: max-content; }
.seg__btn {
  padding: 8px 26px; border: 0; border-radius: 100px;
  background: transparent; color: var(--fg);
  font-size: 14px; font-weight: 500;
  transition: background-color var(--t-colour), box-shadow var(--t-shadow);
}
.seg__btn.is-on { background: var(--bg); box-shadow: var(--sh-sm); }
.pop--wide > .seg { margin-left: auto; margin-right: auto; }

/* ---------------------------------------------------------------- calendar */
.cal { position: relative; padding: 8px 4px 0; }
.cal__months { display: flex; gap: 48px; justify-content: center; }
.cal__month { width: 320px; }
.cal__title {
  text-align: center; margin-bottom: 14px;
  font-size: 16px; font-weight: 500; color: var(--fg);
}
.cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.cal__dow {
  height: 30px; display: grid; place-items: center;
  font-size: 12px; font-weight: 500; color: var(--fg-secondary);
}
.cal__day {
  aspect-ratio: 1; border: 0; background: none; border-radius: 50%;
  font-size: 14px; font-weight: 500; color: var(--fg);
  transition: background-color var(--t-colour), color var(--t-colour),
              transform var(--t-press);
}
.cal__day:hover:not(:disabled) { background: var(--bg); box-shadow: 0 0 0 1px var(--fg) inset; }
.cal__day:active:not(:disabled) { transform: scale(.92); }
.cal__day:disabled { color: var(--fg-tertiary); cursor: default; }
.cal__day.is-edge { background: var(--fg); color: #fff; }
.cal__day.is-edge:hover { background: var(--fg); box-shadow: none; }
.cal__day.is-mid { background: var(--bg-subtle); border-radius: 0; }
.cal__spacer { visibility: hidden; }

.cal__nav {
  position: absolute; top: 8px; z-index: 2;
  display: grid; place-items: center;
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: none; color: var(--fg);
  transition: background-color var(--t-colour), transform var(--t-move);
}
.cal__nav:hover { background: var(--bg-subtle); transform: scale(1.06); }
.cal__nav:disabled { color: var(--fg-tertiary); }
.cal__nav--prev { left: 8px; }
.cal__nav--next { right: 8px; }

.pop__flex { padding: 14px 12px 6px; gap: 8px; }
.pop__flex .chip.is-active {
  background: var(--bg); color: var(--fg);
  border-color: var(--fg); box-shadow: 0 0 0 1px var(--fg) inset;
}

/* ---------------------------------------------------------------- steppers */
.steppers { display: block; }
.stepper {
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  padding: 24px 0;
}
.stepper + .stepper { border-top: 0.8px solid var(--border-subtle); }
.stepper__title { font-size: 16px; font-weight: 500; color: var(--fg); }
.stepper__sub { font-size: 14px; font-weight: 400; color: var(--fg-secondary); }
.stepper__controls { display: flex; align-items: center; gap: 14px; }
.stepper__btn {
  display: grid; place-items: center;
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: var(--grey-btn); color: var(--fg);
  transition: background-color var(--t-colour), transform var(--t-press),
              color var(--t-colour);
}
.stepper__btn:hover:not(:disabled) { background: #e4e4e4; }
.stepper__btn:active:not(:disabled) { transform: scale(.9); }
.stepper__btn:disabled { color: #c1c1c1; cursor: default; }
.stepper__value {
  min-width: 24px; text-align: center;
  font-size: 16px; font-weight: 400; color: var(--fg);
}

@media (prefers-reduced-motion: reduce) {
  .pop { transform: none !important; }
}

@media (max-width: 900px) {
  .pop--wide { max-width: calc(100vw - 24px); }
  .cal__months { gap: 20px; }
  .cal__month:nth-child(2) { display: none; }
  .cal__month { width: min(320px, calc(100vw - 80px)); }
}
@media (max-width: 760px) {
  .pop, .pop--who { min-width: 0; width: calc(100vw - 24px); }
}

/* =========================================================================
   H4 — header menu. Deliberately the same .pop shell as the search popovers
   so every surface on the site appears with one motion.
   ========================================================================= */
/* Header menu — every number below read off the reference's open menu panel.
   The panel does NOT use any of the three elevation tiers: its shadow is
   `0 2px 16px rgba(0,0,0,.12)` with NO 1px hairline, which is the first
   exception found to "every Airbnb shadow carries the hairline". Recorded in
   02 and added to the QA sweep's known list rather than rounded to the nearest
   tier, because rounding it would have made the panel sit heavier than it does. */
.pop--menu {
  min-width: 265px; width: 265px; padding: 12px 0;
  border-radius: var(--r-md);
  box-shadow: var(--sh-menu);
}
.menu { display: block; }
/* These must sit AFTER `.menu` above. They were first written 900 lines earlier
   beside the rest of the auth state, where `.menu { display: block }` — equal
   specificity, later in the file — quietly won and both menus rendered at once.
   Grouping by topic is usually right; with display it loses to source order. */
.menu--in { display: none; }
body[data-auth="in"] .menu--out { display: none; }
body[data-auth="in"] .menu--in  { display: block; }
/* Rows are 36px: 9px of padding either side of an 18px line box. The generous
   24px horizontal inset is what gives the panel its calm feel — 16px read
   cramped against the reference. */
.menu__item {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 24px; font-size: 14px; font-weight: 400; line-height: 18px;
  color: var(--fg);
  transition: background-color var(--t-colour);
}
.menu__item:hover, .menu__item:focus-visible { background: var(--menu-hover); }
/* 16px, measured on the reference's leading icons. Explicit dimensions because
   an SVG does not size itself off font-size the way the emoji it replaced did. */
.menu__item svg { width: 16px; height: 16px; flex: none; }
/* The last row is a <button> (it opens the login modal) while the rest are
   anchors, and the global reset only fixes `font-family` and `cursor`. So it
   was drawing the UA's border and grey fill, sitting inset from the panel edge
   and reading as a form control in a list of links. Everything a button brings
   that an anchor does not is cleared here. */
button.menu__item {
  width: 100%; border: 0; background: none; text-align: left;
  font-size: inherit; color: inherit;
}
button.menu__item:hover, button.menu__item:focus-visible { background: var(--menu-hover); }
/* The final row is NOT emphasised on the reference — "Log in or sign up" is the
   same 14px/400 as everything else. Ours had it at 600. */
.menu__item--strong { font-weight: 400; }
/* Separators are INSET to match the row padding, not full-bleed: 217px inside a
   265px panel is exactly 24px clear either side. */
.menu__sep { height: 1px; margin: 8px 24px; background: var(--border); }

.menu__promo {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 4px 24px; transition: background-color var(--t-colour);
}
.menu__promo:hover { background: var(--menu-hover); }
.menu__promo-title {
  display: block; font-size: 14px; font-weight: 500; line-height: 18px; color: var(--fg);
}
.menu__promo-sub {
  display: block; margin-top: 2px;
  font-size: 12px; font-weight: 400; color: var(--fg-secondary); line-height: 16px;
}
.menu__promo-art { flex: none; line-height: 1; color: var(--fg); }
.menu__promo-art svg { width: 32px; height: 32px; display: block; }

/* the menu is available on every page, unlike the search popovers */
body:not([data-search]) .pop--menu { display: block; }

/* =========================================================================
   H5 — card rail polish
   ========================================================================= */
/* arrows only appear on row hover, and disable at each end */
.rail__nav { opacity: 0; transition: opacity var(--t-colour); }
[data-rail]:hover .rail__nav,
[data-rail]:focus-within .rail__nav { opacity: 1; }
.rail__btn:disabled {
  opacity: .35; cursor: default; background: var(--grey-btn);
}
.rail__btn:disabled:hover { transform: none; background: var(--grey-btn); }

/* images fade in rather than pop — every photo is a remote fetch */
.card__img { opacity: 0; transition: opacity var(--t-colour); }
.card__img.is-loaded, .card__img[data-broken] { opacity: 1; }

/* paging dots */
.rail__dots {
  display: flex; justify-content: center; gap: 6px; margin-top: 14px;
}
.rail__dot {
  width: 6px; height: 6px; padding: 0; border: 0; border-radius: 50%;
  background: #d4d4d4; transition: background-color var(--t-colour), transform var(--t-move);
}
.rail__dot.is-on { background: var(--fg); transform: scale(1.15); }

@media (prefers-reduced-motion: reduce) {
  .rail__nav { opacity: 1 !important; }
  .card__img { opacity: 1 !important; }
}

/* =========================================================================
   Search results page — measured on the reference.
   Search cards are NOT home cards: wider text (15px throughout), a 4:3 image
   rather than 20:17, and a 292px column with 40px/24px grid gaps.
   ========================================================================= */

/* filter chips are smaller here than the home page's category chips */
.filterbar .chip {
  padding: 8px 12px; border-radius: 24px;
  border: 0.8px solid var(--border);
  font-size: 12px; font-weight: 400; min-height: 32px;
}

.results-head {
  font-size: 20px; font-weight: 600; letter-spacing: -0.18px; color: var(--fg);
}

.grid--results {
  /* measured: two columns of ~328px, gap 40px row / 24px column */
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 40px 24px;
}
.grid--results .card__media { aspect-ratio: 4 / 3; }
.grid--results .card__title { font-size: 15px; font-weight: 500; }
.grid--results .card__meta { font-size: 15px; font-weight: 400; }
.grid--results .card__price { font-size: 15px; color: var(--fg); }
.grid--results .card__price b { font-weight: 400; }
.grid--results .rating { font-size: 15px; font-weight: 400; }
.grid--results .card__body { gap: 1px; }

/* ------------------------------------------------------------------- map */
.map__pin { cursor: pointer; }
/* the card the pointer is over lights its pin, and vice versa */
.map__pin.is-linked {
  background: var(--fg); color: #fff;
  transform: translate(-50%, -50%) scale(1.09);
  z-index: 3;
}
.card.is-linked .card__media { box-shadow: 0 0 0 2px var(--fg); }

.map__empty {
  position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--fg-secondary); font-size: 14px; text-align: center; padding: 24px;
}

/* =========================================================================
   Car detail page — measured on the reference listing page.
   ========================================================================= */
.detail-title { font-size: 26px; font-weight: 500; letter-spacing: normal; }
.detail-sub { font-size: 22px; font-weight: 500; letter-spacing: -0.44px; }
.detail-meta { font-size: 16px; font-weight: 400; color: var(--fg); }

/* sticky sub-nav — appears once the gallery has scrolled past */
/* The detail page hands the top of the screen over. Measured on a reference
   listing: the main chrome is `position: static` — it genuinely scrolls away
   rather than shrinking — and an 80px FIXED bar carrying the section links
   takes the slot, white, with a 1px hairline drawn as a shadow rather than a
   border (`0 1px 0 rgba(0,0,0,.1)`).
   Header behaviour is therefore per-page: sticky everywhere else, static here.
   See `body[data-page="car"] .header` below. */
.subnav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 55;
  height: var(--subnav-h);
  background: var(--bg);
  box-shadow: 0 1px 0 rgba(0, 0, 0, .1);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity var(--t-move), transform var(--t-move), visibility var(--t-move);
}
.subnav.is-on { opacity: 1; visibility: visible; transform: none; }
.subnav__inner {
  display: flex; align-items: center; gap: 28px; height: 100%;
  max-width: calc(1120px + 2 * var(--page-pad));
  margin: 0 auto; padding: 0 var(--page-pad);
}
/* The underline belongs under the LABEL, not at the foot of an 80px bar.
   Stretching the links to full height put a 30px gap between the two. */
.subnav__link {
  display: inline-flex; align-items: center;
  padding-bottom: 8px; margin-top: 8px;
  font-size: 14px; font-weight: 400; color: var(--fg);
  border-bottom: 2px solid transparent;
  transition: border-color var(--t-colour);
}
.subnav__link:hover { border-bottom-color: var(--fg); }
.subnav__link.is-current { border-bottom-color: var(--fg); font-weight: 500; }

/* the rating summary card above the fold */
.ratecard {
  display: flex; align-items: center; gap: 24px;
  padding: 18px 24px; margin: 24px 0 0;
  border: 1px solid var(--border); border-radius: var(--r-md);
}
.ratecard__badge {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  font-size: 15px; font-weight: 600; line-height: 1.2; text-align: center;
}
.ratecard__icon { width: 24px; height: 24px; }
.ratecard__blurb { flex: 1; font-size: 14px; color: var(--fg); line-height: 1.35; }
.ratecard__stat { text-align: center; }
.ratecard__stat b { display: block; font-size: 22px; font-weight: 600; }
.ratecard__stat span { font-size: 12px; color: var(--fg-secondary); }
.ratecard__rule { width: 1px; align-self: stretch; background: var(--border-subtle); }

/* "Show more" expander — measured: #f2f2f2, 12px radius, 14/24 padding, 16px/500 */
.showmore {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 14px 24px; border: 0; border-radius: var(--r-md);
  background: var(--grey-btn); color: var(--fg);
  font-size: 16px; font-weight: 500;
  transition: background-color var(--t-colour), transform var(--t-press);
}
.showmore:hover { background: #e6e6e6; }
.showmore:active { transform: scale(.97); }

/* collapsed description */
.clamped {
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* gallery: clicking a tile opens the lightbox */
.gallery img { cursor: zoom-in; }
.lightbox {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center;
  background: rgba(0, 0, 0, .92);
  opacity: 0; visibility: hidden;
  transition: opacity var(--t-move), visibility var(--t-move);
}
.lightbox.is-open { opacity: 1; visibility: visible; }
.lightbox__img {
  max-width: min(1100px, 92vw); max-height: 84vh;
  object-fit: contain; border-radius: var(--r-sm);
}
.lightbox__close, .lightbox__nav {
  position: absolute; display: grid; place-items: center;
  width: 44px; height: 44px; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .12); color: #fff;
  transition: background-color var(--t-colour), transform var(--t-move);
}
.lightbox__close:hover, .lightbox__nav:hover {
  background: rgba(255, 255, 255, .24); transform: scale(1.06);
}
.lightbox__close { top: 20px; left: 20px; }
.lightbox__nav--prev { left: 24px; top: 50%; margin-top: -22px; }
.lightbox__nav--next { right: 24px; top: 50%; margin-top: -22px; }
.lightbox__count {
  position: absolute; top: 28px; left: 50%; transform: translateX(-50%);
  color: #fff; font-size: 14px;
}

@media (max-width: 760px) {
  .subnav { display: none; }
  .ratecard { flex-wrap: wrap; gap: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .subnav, .lightbox { transform: none !important; }
}

/* =========================================================================
   Site-wide page transitions
   The reference is a client-side app, so navigating never flashes white — the
   header stays put and the content swaps. Soko is server-rendered (and will be
   Flask), so the honest equivalent is the View Transitions API: one line, no
   router, and browsers without it simply navigate normally.
   ========================================================================= */

@view-transition { navigation: auto; }

/* The header and footer are the same on every page — naming them keeps them
   still while the middle changes, which is what makes it read as one app
   rather than two pages. */
.header { view-transition-name: site-header; }
.footer { view-transition-name: site-footer; }

::view-transition-old(site-header),
::view-transition-new(site-header),
::view-transition-old(site-footer),
::view-transition-new(site-footer) {
  animation: none;                 /* persistent chrome: do not cross-fade */
}

::view-transition-old(root) {
  animation: vt-out .18s var(--ease) both;
}
::view-transition-new(root) {
  animation: vt-in .26s var(--ease) both;
}

@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; transform: translateY(6px); } }

/* Fallback for browsers without view transitions: the same idea, applied to
   the main content on load. Harmless where transitions are supported. */
main { animation: vt-in .26s var(--ease) both; }
@supports (view-transition-name: none) { main { animation: none; } }

/* ------------------------------------------------------------- skeletons
   Card grids reserve their space before the remote photos arrive, so nothing
   jumps as they load. */
.skeleton {
  position: relative; overflow: hidden;
  background: var(--bg-subtle); border-radius: var(--r-md);
}
.skeleton::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.65), transparent);
  animation: shimmer 1.4s infinite;
}
@keyframes shimmer { to { transform: translateX(100%); } }
.skeleton-card__media { aspect-ratio: 20 / 19; }
.grid--results .skeleton-card__media { aspect-ratio: 4 / 3; }
.skeleton-card__line {
  height: 12px; margin-top: 8px; border-radius: 4px; background: var(--bg-subtle);
}
.skeleton-card__line--short { width: 55%; }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root),
  main { animation: none !important; }
  .skeleton::after { animation: none; }
}

/* =========================================================================
   Auth — modelled on the reference's login modal, kept as a page so Flask can
   serve it as a route. Measured: heading 26px/600/-0.52px centred, Continue
   uses the rausch gradient at 12px radius / 48px tall / 16px-500, social
   buttons are 64px rounded squares, "or" rule at 14px.
   ========================================================================= */
/* Log in / sign up MODAL. Measured on the reference: a 480 x 488 card at a
   **32px** radius carrying the raised shadow tier, centred over a 25% black
   scrim, with the close control in the top-RIGHT corner. Ours had been a
   full page with a titled header bar; the reference has neither. */
.authmodal {
  position: fixed; inset: 0; z-index: 95;
  display: grid; place-items: center;
  padding: 24px;
}
.authmodal[hidden] { display: none; }
.authmodal__scrim { position: absolute; inset: 0; background: rgba(0, 0, 0, .25); }
.authmodal__card {
  position: relative; z-index: 1;
  width: 480px; max-width: 100%; max-height: calc(100vh - 48px);
  overflow: auto;
  padding: 24px;
  border-radius: 32px;
  background: var(--bg);
  box-shadow: var(--sh-xl);
  animation: authIn .22s var(--ease);
}
@keyframes authIn {
  from { opacity: 0; transform: translateY(8px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .authmodal__card { animation: none; } }
.authmodal__close {
  position: absolute; top: 20px; right: 20px;
  display: grid; place-items: center;
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: none; color: var(--fg);
  transition: background var(--t-colour);
}
.authmodal__close:hover { background: var(--bg-subtle); }
body.auth-open { overflow: hidden; }

.auth__title {
  font-size: 26px; font-weight: 600; letter-spacing: -0.52px;
  text-align: center; margin-bottom: 24px;
}
.auth__mark { display: grid; place-items: center; margin-bottom: 12px; color: var(--rausch); }
.auth__mark svg { height: 40px; width: auto; }   /* same reasoning as .logo svg */

.auth__field {
  width: 100%; padding: 14px 16px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  font: inherit; font-size: 16px; color: var(--fg); background: var(--bg);
  transition: border-color var(--t-colour), box-shadow var(--t-shadow);
}
.auth__field::placeholder { color: var(--fg-secondary); }
.auth__field:focus {
  outline: none; border-color: var(--fg);
  box-shadow: 0 0 0 1px var(--fg) inset;
}
.auth__submit {
  width: 100%; height: 48px; border: 0; border-radius: var(--r-md);
  background: var(--rausch-grad); color: #fff;
  font-size: 16px; font-weight: 500;
  transition: filter var(--t-colour), transform var(--t-press);
}
.auth__submit:hover { filter: brightness(1.06); }
.auth__submit:active { transform: scale(.985); }

.auth__or {
  display: flex; align-items: center; gap: 14px;
  margin: 22px 0; font-size: 14px; color: var(--fg);
}
.auth__or::before, .auth__or::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}

.auth__socials { display: flex; justify-content: center; gap: 12px; }
.auth__social {
  display: grid; place-items: center;
  width: 60px; height: 60px;
  border: .8px solid var(--border); border-radius: 12px;
  background: var(--bg); color: var(--fg);
  transition: border-color var(--t-colour), transform var(--t-move),
              box-shadow var(--t-shadow);
}
.auth__social:hover {
  border-color: var(--fg); transform: translateY(-1px); box-shadow: var(--sh-sm);
}
.auth__social:active { transform: scale(.95); }

.auth__error {
  display: none; margin: 10px 0 0;
  font-size: 13px; color: #c0113a;
}
.auth__error.is-on { display: block; }
.auth__field.is-invalid { border-color: #c0113a; box-shadow: 0 0 0 1px #c0113a inset; }

/* =========================================================================
   Checkout — no public reference page (its booking flow is behind a login),
   so this is built from the listing page's booking box, which carries the same
   patterns: 22px/500 section headings, 10px/700 uppercase field labels, the
   rausch gradient CTA at 12px radius / 48px tall, and a bordered summary card.
   ========================================================================= */
.checkout__title { font-size: 26px; font-weight: 600; letter-spacing: -0.52px; }
.checkout h2 { font-size: 22px; font-weight: 500; letter-spacing: -0.44px; }

.summary {
  border-radius: var(--r-md); box-shadow: var(--sh-md);
  padding: 24px;
}
.summary__car {
  display: flex; gap: 16px; align-items: flex-start;
  padding-bottom: 20px; border-bottom: 1px solid var(--border-subtle);
}
.summary__thumb {
  width: 124px; height: 100px; flex: none;
  border-radius: var(--r-md); object-fit: cover; background: var(--bg-subtle);
}

.option { border-radius: var(--r-md); }
.option:first-child { border-radius: var(--r-md) var(--r-md) 0 0; }
.option:last-child { border-radius: 0 0 var(--r-md) var(--r-md); }
.option:only-child { border-radius: var(--r-md); }

.pay-cta {
  min-width: 220px; height: 48px; border: 0; border-radius: var(--r-md);
  background: var(--rausch-grad); color: #fff;
  font-size: 16px; font-weight: 500;
  transition: filter var(--t-colour), transform var(--t-press);
}
.pay-cta:hover { filter: brightness(1.06); }
.pay-cta:active { transform: scale(.985); }
.pay-cta:disabled { filter: grayscale(.6) brightness(1.1); cursor: default; }

.edit-link {
  background: none; border: 0; padding: 0;
  font-size: 15px; font-weight: 600; color: var(--fg);
  text-decoration: underline; text-underline-offset: 2px;
}
.edit-link:hover { color: var(--fg-secondary); }

/* =========================================================================
   Destinations — the "Inspiration for future getaways" block above the footer.
   Measured: heading 22px/500/-0.44px, tabs 14px/500 with 0 16px padding and an
   underline on the active one, 6-column grid at 24px/8px gaps, and each cell a
   two-line link: place 14px/500 #222 over category 14px/400 #6c6c6c.
   ========================================================================= */
.destinations { padding: 48px 0 8px; border-top: 1px solid var(--border-subtle); }
.destinations__title {
  font-size: 22px; font-weight: 500; letter-spacing: -0.44px; margin-bottom: 18px;
}
.destinations__tabs {
  display: flex; gap: 0; overflow-x: auto; scrollbar-width: none;
  border-bottom: 1px solid var(--border-subtle); margin-bottom: 26px;
}
.destinations__tabs::-webkit-scrollbar { display: none; }
.destinations__tab {
  padding: 0 16px 14px; border: 0; background: none; white-space: nowrap;
  font-size: 14px; font-weight: 500; color: var(--fg-secondary);
  border-bottom: 2px solid transparent;
  transition: color var(--t-colour), border-color var(--t-colour);
}
.destinations__tab:first-child { padding-left: 0; }
.destinations__tab:hover { color: var(--fg); }
.destinations__tab.is-on { color: var(--fg); border-bottom-color: var(--fg); }

.destinations__grid {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 24px 8px;
}
.destinations__cell { display: flex; flex-direction: column; padding-right: 8px; }
.destinations__place { font-size: 14px; font-weight: 500; color: var(--fg); }
.destinations__kind { font-size: 14px; font-weight: 400; color: var(--fg-secondary); }
.destinations__cell:hover .destinations__place { text-decoration: underline; }

@media (max-width: 1100px) { .destinations__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 760px)  { .destinations__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ------------------------------------------------------------ footer tune
   Measured: surface #f7f7f7, column headings 14px/500, links 14px/400 #222
   with no underline until hover. */
.footer { background: var(--bg-subtle); padding-bottom: 80px; }
.footer__title { font-size: 14px; font-weight: 500; margin-bottom: 16px; }
.footer__links { gap: 14px; font-size: 14px; font-weight: 400; color: var(--fg); }
.footer__links a { color: var(--fg); }
.footer__bar { font-size: 14px; color: var(--fg); }
.footer__bar nav a:hover { text-decoration: underline; }

/* =========================================================================
   Vendor, profile and success.
   No public reference exists for any of these — host profiles and account
   settings are behind a login, and there is no public booking confirmation.
   Rather than sign in, these are built from the tokens and patterns already
   measured elsewhere on the site, so they stay consistent by construction.
   ========================================================================= */
.page-title { font-size: 26px; font-weight: 600; letter-spacing: -0.52px; }
.page-sub { font-size: 16px; color: var(--fg-secondary); }

/* ------------------------------------------------------------- vendor */
.vendor__card {
  position: sticky; top: calc(var(--header-h) + 24px);
  padding: 28px; text-align: center;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--sh-md);
}
.vendor__stats { display: grid; gap: 14px; margin-top: 24px; text-align: left; }
.vendor__stat {
  display: flex; justify-content: space-between; align-items: baseline;
  padding-bottom: 12px; border-bottom: 1px solid var(--border-subtle);
}
.vendor__stat:last-child { border-bottom: 0; padding-bottom: 0; }
.vendor__stat span { font-size: 13px; color: var(--fg-secondary); }
.vendor__stat b { font-size: 17px; font-weight: 600; }

/* ------------------------------------------------------------ profile */
.tile { box-shadow: none; }
.tile:hover { box-shadow: var(--sh-md); }
.profile__ident {
  display: flex; align-items: center; gap: 16px; margin-bottom: 28px;
}
.profile__avatar {
  display: grid; place-items: center;
  width: 64px; height: 64px; border-radius: 50%;
  background: var(--fg); color: #fff; font-size: 24px; font-weight: 600;
}

/* ------------------------------------------------------------ success */
.hero-confirm__mark { box-shadow: var(--sh-md); }
.confirm-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.confirm-ref {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px; margin-bottom: 20px;
  border-radius: var(--r-pill); background: var(--bg-subtle);
  font-size: 13px; color: var(--fg-secondary);
}
.confirm-ref b { color: var(--fg); font-weight: 600; letter-spacing: .04em; }

@media (max-width: 1024px) { .vendor__card { position: static; } }

/* =========================================================================
   "See all" card — every rail on the reference homepage ends with one.
   Measured: same footprint as a card image (182×173 at 1536), white,
   20px radius, the STANDARD shadow tier, label 14px/400.
   ========================================================================= */
/* The end-of-rail card. Measured on the reference: a white 20px-radius surface
   carrying the standard shadow, with three fanned photo tiles above a 13px/600
   label. The 28px top padding is not arbitrary — the tiles translate UPWARD out
   of their grid cell, so centring the cell would push the artwork too high. The
   padding rebalances it so the artwork, not the box, sits centred. */
.rail__seeall {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding-top: 28px; box-sizing: border-box;
  aspect-ratio: 20 / 19; width: 100%;
  border-radius: 20px; background: var(--bg);
  box-shadow: var(--sh-md);
  color: var(--fg);
  transition: box-shadow var(--t-shadow), transform var(--t-move);
}
.seeall__stack {
  display: grid;
  grid-template-columns: var(--seeall-tile);
  grid-template-rows: var(--seeall-tile);
}
.seeall__tile {
  grid-area: 1 / 1;
  width: var(--seeall-tile); height: var(--seeall-tile);
  box-sizing: border-box;
  border: 2.4px solid #fff; border-radius: 9px;
  background: #8c8c8c 50% 50% / cover no-repeat;
  box-shadow: var(--sh-sm);
}
.seeall__tile:nth-child(1) { translate: -17.1429% -42.8571%; rotate: -2.5deg; z-index: 1; }
.seeall__tile:nth-child(2) { translate:  37.1429% -25.7143%; rotate:    5deg; z-index: 2; }
.seeall__tile:nth-child(3) { translate: -37.1429%  -5.7143%; rotate:   -5deg; z-index: 3; }
.seeall__label { font-size: 13px; font-weight: 600; line-height: 29px; }
.rail__seeall:hover {
  box-shadow: 0 0 0 1px rgba(0,0,0,.02), 0 4px 12px rgba(0,0,0,.06), 0 8px 16px rgba(0,0,0,.12);
  transform: translateY(-2px);
}
.rail__seeall:active { transform: scale(.98); }

/* The compact pill keeps its measured tracks while there is room for them, then
   goes fluid rather than pushing the header wider than the viewport. */
@media (max-width: 900px) {
  .pill-mini {
    width: min(var(--mini-w), 100%);
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1fr) 37px;
  }
}
@media (max-width: 1440px) { :root { --tab-icon: 60px; } .tabs { gap: 14px; } }
@media (max-width: 1240px) { :root { --tab-icon: 46px; } .tabs { gap: 10px; } }
@media (max-width: 1100px) { :root { --pill-w: 780px; } }
@media (max-width: 900px)  { :root { --pill-w: 100%; } }
@media (max-width: 760px) {
  :root { --pill-h: auto; }
  .pill { height: auto; }
  .pill__field:last-of-type,
  .pill.is-focused .pill__field:last-of-type { padding-right: 24px; }
  .pill__search { position: static; transform: none; margin: 0 0 12px auto; margin-right: 12px; }
  .pill__search:hover, .pill__search:active { transform: none; }
}

/* =========================================================================
   Map — the reference has a real Google map. Soko has no map provider yet, so
   this is an honest placeholder rather than an imitation: a plausible surface
   with the same *furniture* (zoom controls, expand, attribution) in the same
   positions, so the layout is correct and dropping in a real provider later is
   a swap rather than a redesign.
   ========================================================================= */
/* One map surface, used by the search split AND the product page's location
   block, so the two can never drift apart. Soko has no map provider yet — this
   is an honest illustration with the right furniture, not an imitation of
   Google's tiles. */
.split__map,
.locmap__surface {
  background:
    /* faint street grid */
    repeating-linear-gradient(0deg, rgba(255,255,255,.55) 0 1px, transparent 1px 68px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.55) 0 1px, transparent 1px 84px),
    /* a couple of arterial roads */
    linear-gradient(107deg, transparent 0 38%, rgba(255,255,255,.8) 38% 39.1%, transparent 39.1%),
    linear-gradient(-72deg, transparent 0 61%, rgba(255,255,255,.7) 61% 61.9%, transparent 61.9%),
    /* water and green space */
    radial-gradient(38% 26% at 82% 88%, #cfe0e8 0%, #cfe0e8 60%, transparent 61%),
    radial-gradient(22% 18% at 16% 24%, #dfe9d8 0%, #dfe9d8 62%, transparent 63%),
    linear-gradient(160deg, #eaeeea 0%, #e3e9e2 45%, #dde6e1 100%);
}

/* Measured on the reference: the expand circle sits 16px in from the map's top
   and right, and the zoom stack starts 16px below it — so the zoom-in button's
   top edge lands 72px from the map's top. */
.map__controls {
  position: absolute; top: 16px; right: 16px; z-index: 4;
  display: grid; gap: 16px; justify-items: end;
}
.map__btn {
  display: grid; place-items: center;
  width: 40px; height: 40px; border: 0;
  background: var(--bg); color: var(--fg);
  box-shadow: var(--sh-sm);
  transition: background-color var(--t-colour), transform var(--t-move);
}
.map__btn:hover { background: var(--bg-subtle); }
.map__btn:active { transform: scale(.94); }
/* The expand control is a CIRCLE on the reference, and it carries the raised
   shadow tier rather than the tight one the zoom stack uses. */
.map__btn--expand { border-radius: 50%; box-shadow: var(--sh-xl); }
.map__zoom { display: grid; border-radius: var(--r-sm); overflow: hidden; box-shadow: var(--sh-sm); }
.map__zoom .map__btn { box-shadow: none; }
.map__zoom .map__btn + .map__btn { border-top: 1px solid var(--border-subtle); }
.map__btn:disabled { color: var(--fg-tertiary); cursor: default; }

.map__attrib {
  position: absolute; bottom: 8px; left: 12px; z-index: 4;
  font-size: 11px; color: var(--fg-secondary);
}
.map__terms {
  position: absolute; bottom: 8px; right: 12px; z-index: 4;
  font-size: 11px; color: var(--fg-secondary);
}

/* pins scale with zoom so the control does something visible */
#map { transition: transform var(--t-move); transform-origin: center; }

@media (max-width: 1024px) { .map__controls { display: none; } }

/* ---------------------------------------------------- "Where you'll be"
   Measured on a reference listing: an h2 at 22px/500, the place and address
   at 16px beneath it, then a 1120 x 480 map with a 20px radius. The pin is a
   single dark disc with a white centre — not the price labels the search map
   uses, because there is only one thing to point at here. */
.locsec { padding: 32px 0 8px; }
.locsec__place { margin: 24px 0 2px; font-size: 16px; font-weight: 400; }
.locsec__addr { margin: 0 0 20px; font-size: 16px; color: var(--fg-secondary); }
.locmap {
  position: relative; height: 480px;
  border-radius: 20px; overflow: hidden;
  background: #e3e9e2;
}
.locmap__surface { position: absolute; inset: 0; transition: transform var(--t-move); }
.locmap__pin {
  position: absolute; left: 50%; top: 50%;
  translate: -50% -50%;
  display: grid; place-items: center;
  width: 50px; height: 50px; border-radius: 50%;
  background: var(--fg); box-shadow: var(--sh-md);
  z-index: 3;
}
.locmap__pin::after {
  content: ''; width: 16px; height: 16px; border-radius: 50%; background: #fff;
}
@media (max-width: 760px) { .locmap { height: 340px; } }

/* expanded map: the list narrows to one column rather than disappearing */
body.map-expanded .split { grid-template-columns: minmax(0, 380px) minmax(0, 1fr); }
body.map-expanded .grid--results { grid-template-columns: 1fr; }
body.map-expanded .split__list { padding-left: 24px; padding-right: 24px; }
.split { transition: grid-template-columns var(--t-move); }

/* =========================================================================
   Profile — modelled on the reference's signed-in profile screen.

   That screen is LOGIN-GATED, so unlike the homepage and the search page none
   of this was read off a live DOM. Structure comes from the supplied
   screenshots; every value is a token already measured elsewhere in this file.
   Treat the numbers here as system-consistent, NOT as reference-measured.
   ========================================================================= */

.prof {
  display: grid; grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
  align-items: start;
  max-width: var(--page-max); margin: 0 auto;
  min-height: calc(100vh - var(--header-h));
}
/* The rule between the columns runs the full height of the page, not just the
   content — on the reference it reads as a page division rather than a border
   on a box. A border on .prof__rail would stop at the last nav item. */
.prof__body { border-left: 1px solid var(--border-subtle); min-height: inherit; }

.prof__rail { padding: 40px var(--page-pad) 60px; }
.prof__title { font-size: 32px; font-weight: 600; letter-spacing: -0.02em; margin: 0 0 24px; }

.prof__nav { display: grid; gap: 4px; }
.prof__navitem {
  display: flex; align-items: center; gap: 16px;
  padding: 12px 16px; border-radius: var(--r-lg, 16px);
  font-size: 16px; font-weight: 400; color: var(--fg);
  transition: background var(--t-colour);
}
.prof__navitem:hover { background: var(--menu-hover); }
.prof__navitem.is-active { background: var(--bg-subtle); font-weight: 500; }

/* The active row's mark is the user's initial; the others carry a line icon.
   Same 32px footprint either way so the labels stay on one optical line. */
.prof__navmark, .prof__navicon {
  display: grid; place-items: center; flex: none;
  width: 32px; height: 32px; border-radius: 50%;
}
.prof__navmark { background: #d8f0e2; color: #0d6b3f; font-size: 13px; font-weight: 600; }
.prof__navicon { background: var(--grey-btn); color: var(--fg); }
.prof__navicon svg { width: 16px; height: 16px; }

.prof__body { padding: 40px var(--page-pad) 60px; }
.prof__head { display: flex; align-items: center; gap: 16px; margin-bottom: 28px; }
.prof__h2 { font-size: 28px; font-weight: 600; letter-spacing: -0.02em; margin: 0; }
.prof__edit {
  height: 32px; padding: 0 14px; border: 0; border-radius: 8px;
  background: var(--grey-btn); color: var(--fg);
  font-size: 13px; font-weight: 500;
  transition: background var(--t-colour);
}
.prof__edit:hover { background: #e6e6e6; }

.prof__grid {
  display: grid; grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
  gap: 40px; align-items: center;
}
/* The standard shadow tier, not a one-off — the QA sweep would flag anything
   outside the measured set, and rightly. */
.prof__card {
  display: grid; justify-items: center; gap: 2px;
  padding: 36px 24px 28px; border-radius: 20px;
  background: var(--bg); box-shadow: var(--sh-md);
}
.prof__face {
  display: grid; place-items: center;
  width: 104px; height: 104px; border-radius: 50%; margin-bottom: 14px;
  background: #ffe1e8; color: var(--logo-red);
  font-size: 44px; font-weight: 600; line-height: 1;
}
.prof__name { font-size: 26px; font-weight: 600; letter-spacing: -0.02em; }
.prof__role { font-size: 13px; color: var(--fg-secondary); }

.prof__pitch-title { font-size: 20px; font-weight: 600; letter-spacing: -0.018em; margin: 0 0 10px; }
.prof__pitch-text { font-size: 14px; color: var(--fg-secondary); line-height: 1.5; margin: 0 0 20px; max-width: 42ch; }

.prof__reviews {
  display: inline-flex; align-items: center; gap: 14px;
  font-size: 16px; color: var(--fg);
}
.prof__reviews svg { width: 20px; height: 20px; flex: none; }
.prof__reviews:hover { text-decoration: underline; }

@media (max-width: 900px) {
  .prof { grid-template-columns: 1fr; }
  .prof__body { border-left: 0; border-top: 1px solid var(--border-subtle); }
  .prof__grid { grid-template-columns: 1fr; gap: 24px; }
}

/* ------------------------------------------- profile first-visit explainer */
/* Same scrim and card language as the login dialog so the two read as one
   family; the close sits top-LEFT here, which is where the reference puts it
   on this particular dialog. */
.pmodal { position: fixed; inset: 0; z-index: 90; display: grid; place-items: center; padding: 24px; }
.pmodal[hidden] { display: none; }
.pmodal__scrim { position: absolute; inset: 0; background: rgba(0, 0, 0, .25); }
.pmodal__card {
  position: relative; width: 100%; max-width: 540px;
  padding: 28px 32px 24px; border-radius: 16px;
  background: var(--bg); box-shadow: var(--sh-xl);
  text-align: center;
}
.pmodal__close {
  position: absolute; top: 16px; left: 16px;
  display: grid; place-items: center;
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: none; color: var(--fg);
  transition: background var(--t-colour);
}
.pmodal__close:hover { background: var(--bg-subtle); }

/* Soko's own artwork. The reference puts three of Airbnb's 3D figures here and
   we do not copy those, so this echoes the profile card's avatar instead —
   the same motif the dialog is talking about. */
.pmodal__art { position: relative; display: grid; place-items: center; margin: 12px 0 22px; }
.pmodal__face {
  display: grid; place-items: center;
  width: 96px; height: 96px; border-radius: 50%;
  background: #ffe1e8; color: var(--logo-red);
  font-size: 40px; font-weight: 600; line-height: 1;
}
.pmodal__spark { position: absolute; border-radius: 50%; background: var(--logo-red); opacity: .25; }
.pmodal__spark--a { width: 10px; height: 10px; transform: translate(-74px, -26px); }
.pmodal__spark--b { width: 6px; height: 6px; transform: translate(68px, 30px); }

.pmodal__title { font-size: 22px; font-weight: 600; letter-spacing: -0.018em; margin: 0 0 20px; }
.pmodal__points { display: grid; gap: 16px; margin: 0 0 26px; text-align: left; }
.pmodal__points li { display: flex; align-items: flex-start; gap: 16px; font-size: 14px; line-height: 1.45; }
.pmodal__points svg { width: 20px; height: 20px; flex: none; margin-top: 1px; color: var(--fg); }

.pmodal__go {
  width: 100%; height: 52px; border: 0; border-radius: 10px;
  background: var(--fg); color: #fff; font-size: 16px; font-weight: 600;
  transition: background var(--t-colour);
}
.pmodal__go:hover { background: #000; }
.pmodal__more {
  width: 100%; height: 44px; margin-top: 6px; border: 0; border-radius: 10px;
  background: none; color: var(--fg); font-size: 15px; font-weight: 500;
  transition: background var(--t-colour);
}
.pmodal__more:hover { background: var(--bg-subtle); }

body.pmodal-open { overflow: hidden; }

/* ---------------------------------------------------------------- combobox
   Make / model type-ahead on the listing form.

   Tokens only — this reuses the elevation, radius and border already defined
   above rather than introducing a fourth panel style. The shadow is --sh-md,
   the same tier the header's account popover uses, because this is the same
   kind of thing: a transient layer over the page, opened deliberately. */
.combo { position: relative; }

.combo__panel {
  position: absolute; z-index: 40; left: 0; right: 0; top: calc(100% + 6px);
  max-height: 264px; overflow-y: auto;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--sh-md);
  padding: 6px;
}

.combo__option {
  padding: 9px 12px;
  border-radius: var(--r-sm);
  font-size: 14px;
  line-height: 1.3;
  cursor: pointer;
  color: var(--fg);
}

/* Hover and keyboard selection share one appearance on purpose: the row the
   arrow keys are on should look no different from the row under the pointer,
   or keyboard users get a second-class version of the same control. */
.combo__option:hover,
.combo__option.is-active { background: var(--bg-subtle); }

.combo__option[aria-selected="true"] { font-weight: 600; }

.field__input:disabled {
  background: var(--bg-subtle);
  color: var(--fg-muted);
  cursor: not-allowed;
}

/* -------------------------------------------------- empty & new-listing states
   States the static build never had, because its data was seeded and every car
   arrived with photos, a rating and reviews already attached. Real listings
   start with none of that, and the page has to say so honestly rather than
   render a blank star or an empty grid that reads as broken.

   Tokens only — no new colours, radii or shadow tiers. */

.empty {
  max-width: 460px;
  margin: 72px auto;
  text-align: center;
}
.empty__title {
  font-size: 20px; font-weight: 600; letter-spacing: -0.18px;
  margin: 0 0 8px; color: var(--fg);
}
.empty__text {
  font-size: 15px; line-height: 1.55; color: var(--fg-secondary);
  margin: 0 0 20px;
}

/* A car nobody has rented yet. "New" rather than a 0.00 star, which would read
   as a bad rating rather than an absent one. */
.rating--new {
  font-size: 13px; font-weight: 500; color: var(--fg-secondary);
}

/* Listings can exist before their photos do. A neutral block keeps the card's
   20:17 ratio so the grid does not jump. */
.card__img--empty {
  width: 100%; aspect-ratio: 20 / 17;
  background: var(--bg-subtle);
  border-radius: var(--r-md);
}

/* Avatar fallback: an initial, for accounts with no uploaded picture. */
.avatar--letter {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--fg); color: var(--bg);
  font-weight: 600; text-transform: uppercase;
}

.pager {
  display: flex; align-items: center; justify-content: center; gap: 16px;
  padding: 32px 0 8px;
}
.pager__link {
  font-size: 14px; font-weight: 600; color: var(--fg);
  text-decoration: underline; text-underline-offset: 3px;
}
.pager__status { font-size: 13px; color: var(--fg-secondary); }

.chip.is-on {
  background: var(--fg); color: var(--bg); border-color: var(--fg);
}

/* File input. The native control cannot be styled, so the button half is
   restyled through ::file-selector-button and the rest inherits the field
   treatment — tokens only, matching .field__input above. */
.field__file {
  width: 100%;
  font-size: 14px;
  color: var(--fg-secondary);
  padding: 10px 0;
}
.field__file::file-selector-button {
  margin-right: 12px;
  padding: 9px 16px;
  border: 1px solid var(--fg);
  border-radius: var(--r-sm);
  background: var(--bg);
  color: var(--fg);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.field__file::file-selector-button:hover { background: var(--bg-subtle); }
