/* Zap Wrap Naples - the exotic-wrap studio of Naples.
   Lane: motorsport livery sheet in a dark studio. Reference: dark configurator
   stage + plot-template graphics. Montserrat is the single house type:
   heavy weights (700-900) carry display, regular/medium (400-600) carry body.
   Committed palette: near-black studio, electric yellow #FFD600 carries the voice,
   iridescent color-shift gradients are reserved for the film itself. */

/* ---------- Type: self-hosted Montserrat variable (v31, Google subsets) ----------
   Two subsets cover EN/ES (latin) and RU/UK (cyrillic); Hebrew has no Montserrat
   coverage and falls through to system-ui exactly as before. Self-hosting removes
   the render-blocking fonts.googleapis.com CSS chain; the metric-matched Arial
   fallback face keeps the giant hero headline from shifting layout on swap (CLS). */
/* cyrillic */
@font-face {
  font-family: "Montserrat";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("/assets/fonts/montserrat-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* latin */
@font-face {
  font-family: "Montserrat";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("/assets/fonts/montserrat-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* metric-matched fallback: Arial pretending to be Montserrat while it loads */
@font-face {
  font-family: "Montserrat Fallback";
  src: local("Arial");
  size-adjust: 113%;
  ascent-override: 85.66%;
  descent-override: 22.21%;
  line-gap-override: 0%;
}

:root {
  /* ---- Color (OKLCH) ---- */
  --bg:        oklch(0.145 0 0);            /* studio black */
  --bg-deep:   oklch(0.105 0 0);
  --surface:   oklch(0.19 0 0);
  --line:      oklch(1 0 0 / 0.14);
  --line-soft: oklch(1 0 0 / 0.07);

  --ink:    oklch(0.97 0 0);
  --ink-2:  oklch(0.82 0 0);                /* secondary, >8:1 on bg */
  --muted:  oklch(0.70 0 0);                /* labels, ≥4.5:1 on bg */

  --yellow:     oklch(0.873 0.178 100);     /* #FFD600 */
  --yellow-ink: oklch(0.17 0.02 100);       /* text on yellow */

  /* the film: iridescent shift, used ONLY where vinyl is depicted */
  --shift-a: oklch(0.55 0.22 300);
  --shift-b: oklch(0.62 0.19 350);
  --shift-c: oklch(0.68 0.14 200);

  /* ---- Type ---- */
  /* One family, Montserrat, for both display and body (owner decision 2026-07-20).
     Weight, not family, separates the two roles - see the display type system below. */
  --font-display: "Montserrat", "Montserrat Fallback", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
  --font-body: "Montserrat", "Montserrat Fallback", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;

  --text-body: clamp(1rem, 0.95rem + 0.3vw, 1.15rem);
  --text-lead: clamp(1.1rem, 1rem + 0.6vw, 1.45rem);
  --text-h3: clamp(1.35rem, 1.1rem + 1.2vw, 2rem);
  --text-h2: clamp(2.2rem, 1.5rem + 3.4vw, 4.2rem);
  --text-display: clamp(2.8rem, 1.4rem + 6.5vw, 6rem);

  /* ---- Space / layout ---- */
  /* v44: tightened from clamp(5rem, 4rem+6vw, 10rem). Gallery-grade air only
     earns its keep on visually rich sections; the text-only middle of the page
     was rendering empty screens on phones. */
  --space-section: clamp(4rem, 3rem + 4.5vw, 7.5rem);
  --gutter: clamp(1.25rem, 0.8rem + 3vw, 3rem);
  --maxw: 1240px;

  /* ---- Motion tokens: strong custom curves + a duration scale ----
     Emil/Apple doctrine baked in: built-in ease/ease-in are too weak, so the
     house runs on one strong expo-out; on-screen movement gets a real
     ease-in-out; the hero car gets a sampled spring. Motion is compositor-only
     (transform/opacity), and every effect has a reduced-motion fallback below. */
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);    /* strong expo-out: entrances, exits, hover settles */
  --ease-in-out: cubic-bezier(0.45, 0, 0.15, 1);   /* strong ease-in-out: on-screen movement (squeegee wipe) */
  /* damped spring (zeta 0.70, ~4.6% overshoot): the car arrives and settles on its suspension */
  --ease-spring: linear(0, 0.0166, 0.0604, 0.1238, 0.2002, 0.284, 0.3709, 0.4575, 0.541, 0.6195, 0.6917, 0.7568, 0.8144, 0.8644, 0.907, 0.9426, 0.9717, 0.9948, 1.0128, 1.0261, 1.0355, 1.0415, 1.0449, 1.046, 1.0454, 1.0435, 1.0407, 1.0372, 1.0334, 1.0294, 1);
  --ease: var(--ease-out);                          /* back-compat alias: every existing var(--ease) keeps its look */

  --beat: 90ms;

  /* interaction duration scale (mirrors the values already tuned in this file, so
     tokenizing changes nothing visually; signature effects keep bespoke literals) */
  --dur-1: 200ms;    /* hover, colour, border, small state */
  --dur-2: 240ms;    /* buttons, chips, icon buttons */
  --dur-3: 300ms;    /* nav border, caret rotate, swatch lift, service-row wash */
  --dur-4: 320ms;    /* on-car film-name toast */
  --dur-5: 500ms;    /* mobile channel stack */
  --dur-modal: 420ms;/* lightbox / drawer materialize */
  --dur: 700ms;      /* signature: scroll reveals + hero rise (unchanged) */

  /* ---- z-index scale ---- */
  --z-nav: 100;

  /* dark-only site: native scrollbars, autofill and select chrome must match */
  color-scheme: dark;
}

/* ---------- Reset / base ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  /* clip, not hidden: kills the sideways jiggle from off-canvas entrance
     states (hero car starts translated 60px right) without creating a
     scroll container, so the sticky nav keeps working */
  overflow-x: clip;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
::selection { background: var(--yellow); color: var(--yellow-ink); }

/* ---------- House-look: atmospheric layer (one system with Zap Wrap OS) ----------
   Vignette (body::before) frames the car as the hero; a fine film grain (body::after)
   gives the studio-black surface a physical texture. Both are fixed to the viewport,
   pointer-events:none, z-index:-1 - they paint over the near-black canvas but UNDER
   every piece of content, so text stays crisp and clicks pass straight through.
   (html sets no background, so body's --bg propagates to the canvas and the -1 layer
   sits above it - not behind an opaque body box.) The grain is an inline SVG data-uri
   (feTurbulence, ~0.3kB): no network cost, rasterized once and tiled, GPU-composited,
   no repaint. It is static, so there is no reduced-motion case to handle. */
body::before,
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: -1;
}
body::before {
  background: radial-gradient(135% 115% at 50% 32%, transparent 52%, oklch(0 0 0 / 0.42) 100%);
}
body::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='zw-grain'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23zw-grain)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
  opacity: 0.04;
}

.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.wrap--narrow { max-width: 820px; }

h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }

/* ---------- Display type system ---------- */
.section__h {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-h2);
  line-height: 1.02;
  text-transform: uppercase;
  letter-spacing: 0.01em;
}
.section__h .dot { color: var(--yellow); }
.section__lead {
  max-width: 62ch;
  margin-top: 1.1rem;
  font-size: var(--text-lead);
  color: var(--ink-2);
}

/* Montserrat carries the weight Anton used to imply: display elements that do
   not set their own font-weight get the heavy house weight here, so nothing
   renders as thin Montserrat Regular where the black display face used to be. */
.brand__word,
.ticker__track,
.step__n,
.footer__mark,
.reviews__score { font-weight: 800; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1;
  text-decoration: none;
  padding: 0.95em 1.5em;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease),
              color var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
}
.btn--solid { background: var(--yellow); color: var(--yellow-ink); }
/* pointer-only: a tap must not leave a sticky lift behind; press feedback is :active */
@media (hover: hover) and (pointer: fine) {
  .btn--solid:hover { transform: translateY(-2px); background: oklch(0.905 0.16 101); }
}
.btn--ghost { border-color: var(--line); color: var(--ink); }
.btn--ghost:hover { border-color: var(--yellow); color: var(--yellow); }
.btn:focus-visible, a:focus-visible, .fsw:focus-visible, summary:focus-visible {
  outline: 2px solid var(--yellow);
  outline-offset: 3px;
}
/* Tactile press: settle down out of the hover lift and scale in a touch, so the
   button visibly answers the finger (Emil/Apple - feedback on press, compositor-only). */
.btn:active { transform: scale(0.97); }

/* ---------- Nav ---------- */
.nav {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  display: flex;
  align-items: center;
  gap: 2rem;
  padding: 0.9rem var(--gutter);
  background: oklch(0.105 0 0 / 0.82);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-3) var(--ease);
}
.nav[data-scrolled="true"] { border-color: var(--line-soft); }

.brand { display: flex; align-items: baseline; gap: 0.6rem; text-decoration: none; }
.brand__bolt { width: 1.15rem; height: 1.15rem; align-self: center; fill: var(--yellow); }
.brand__word {
  font-family: var(--font-display);
  font-size: 1.25rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.brand__loc { font-size: 0.8rem; font-weight: 600; color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase; }

.nav__links { display: flex; gap: 1.6rem; margin-left: auto; }
.nav__links a {
  font-weight: 500;
  font-size: 0.95rem;
  text-decoration: none;
  color: var(--ink-2);
  transition: color var(--dur-1) var(--ease);
}
.nav__links a:hover { color: var(--yellow); }
.nav__cta { padding: 0.7em 1.2em; font-size: 0.95rem; }

/* Кнопка звонка и бургер существуют только на узких экранах: на десктопе
   ссылки и так все на виду. */
.nav__call { display: none; }
.nav__burger { display: none; }

@media (max-width: 720px) {
  /* gap: 2rem с десктопа даёт в сумме 435px при экране 393 - бургер уезжал
     за правый край. На телефоне шапка тесная, разрядка должна быть меньше. */
  .nav { gap: 0.6rem; }
  .nav__cta { margin-left: auto; }

  .nav__burger {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    /* 44px - минимальная зона касания. flex: 0 0 auto обязателен: шапка это
       флекс-контейнер, и без него кнопку сжимает вдвое. */
    flex: 0 0 auto;
    box-sizing: border-box;
    width: 44px;
    height: 44px;
    padding: 0 10px;
    margin-inline-start: 0.4rem;
    background: none;
    border: 1px solid var(--line-soft);
    border-radius: 8px;
    cursor: pointer;
  }
  .nav__burger-bar {
    display: block;
    height: 2px;
    background: var(--ink);
    border-radius: 2px;
    transition: transform 220ms var(--ease), opacity 160ms var(--ease);
  }
  /* Три полоски складываются в крестик, чтобы состояние читалось без текста. */
  .nav__burger[aria-expanded="true"] .nav__burger-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav__burger[aria-expanded="true"] .nav__burger-bar:nth-child(2) { opacity: 0; }
  .nav__burger[aria-expanded="true"] .nav__burger-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  /* Панель выпадает из-под шапки. display: none в закрытом состоянии - это
     принципиально: иначе ссылки остаются в порядке табуляции невидимыми,
     ровно как было до этой правки. */
  .nav__links {
    display: none;
    position: absolute;
    inset-inline: 0;
    top: 100%;
    flex-direction: column;
    gap: 0;
    margin: 0;
    padding: 0.5rem var(--gutter) 1rem;
    /* Непрозрачный фон, без прозрачности: крупный белый заголовок героя
       просвечивал даже через 0.97 и читался как дефект вёрстки. */
    background: #0a0a0b;
    border-bottom: 1px solid var(--line-soft);
  }
  .nav__links.is-open { display: flex; }
  .nav__links a {
    padding: 0.9rem 0;
    font-size: 1.05rem;
    border-bottom: 1px solid var(--line-soft);
  }
  .nav__links a:last-child { border-bottom: none; }
  /* Селектор с родителем обязателен: .nav__links a специфичнее одиночного
     класса и перекрашивал звонок обратно в серый. */
  .nav__links .nav__call {
    display: block;
    margin-top: 0.4rem;
    font-weight: 700;
    color: var(--yellow);
  }
}

@media (max-width: 720px) and (prefers-reduced-motion: reduce) {
  .nav__burger-bar { transition: none; }
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  padding: clamp(3rem, 2rem + 5vw, 7rem) var(--gutter) 0;
  max-width: var(--maxw);
  margin-inline: auto;
  overflow: clip;
}

/* studio key light */
.hero::before {
  content: "";
  position: absolute;
  inset: -20% -10% auto;
  height: 70%;
  background: radial-gradient(60% 55% at 70% 0%, oklch(0.32 0.03 100 / 0.5), transparent 70%);
  pointer-events: none;
}

.hero__intro {
  font-weight: 600;
  font-size: 0.9rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.hero__h {
  margin-top: 1rem;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-display);
  line-height: 0.96;
  text-transform: uppercase;
  letter-spacing: 0.01em;
}
.hero__line { display: block; }
.hero__h em { font-style: normal; color: var(--yellow); }

.hero__sub {
  max-width: 46ch;
  margin-top: 1.4rem;
  font-size: var(--text-lead);
  color: var(--ink-2);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: 0.9rem; margin-top: 2rem; }

/* --- hero entrance: a composed timeline, one beat apart. Text rises on the
   expo-out; the car settles on a spring (below). Fully interruptible and
   non-blocking - keyframes never touch pointer-events, so scroll, the car
   picker and the film switcher stay live the whole way through. --- */
@media (prefers-reduced-motion: no-preference) {
  .js .hero__intro, .js .hero__line, .js .hero__sub, .js .hero__actions {
    opacity: 0.001;
    translate: 0 26px;
    animation: rise var(--dur) var(--ease) forwards;
  }
  .js .hero__intro       { animation-delay: 0ms; }
  .js .hero__line:nth-child(1) { animation-delay: calc(var(--beat) * 1); }
  .js .hero__line:nth-child(2) { animation-delay: calc(var(--beat) * 2); }
  .js .hero__line:nth-child(3) { animation-delay: calc(var(--beat) * 3); }
  .js .hero__sub         { animation-delay: calc(var(--beat) * 5); }
  .js .hero__actions     { animation-delay: calc(var(--beat) * 6); }

  .js .hero__car .car {
    opacity: 0.001;
    translate: 60px 0;
    /* spring, not a linear glide: the car drives in and rocks to rest on its
       suspension. will-change is cleared on animationend in app.js so the hint
       does not outlive the one-shot entrance. */
    will-change: transform, opacity;
    animation: drive-in 900ms var(--ease-spring) calc(var(--beat) * 7) forwards;
  }
  .js .hero__filmbar {
    opacity: 0.001;
    animation: fade 600ms var(--ease) calc(var(--beat) * 12) forwards;
  }
}
@keyframes rise { to { opacity: 1; translate: 0 0; } }
@keyframes drive-in { to { opacity: 1; translate: 0 0; } }
@keyframes fade { to { opacity: 1; } }

.hero__car {
  position: relative;
  display: flex;
  flex-direction: column;
  margin-top: clamp(2rem, 1rem + 4vw, 4rem);
}
.hero__car .car { order: 2; }
.hero__car .hero__filmbar { order: 3; }

/* ---------- The car + film system ---------- */
.car { position: relative; }
.car__img { position: relative; z-index: 1; width: 100%; }

/* film layer: gradient clipped to the wrappable body via luminance mask,
   multiplied over the white template so the factory shading survives */
.car__film {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--film, linear-gradient(115deg, var(--shift-a) 8%, var(--shift-b) 42%, var(--shift-c) 80%));
  mix-blend-mode: multiply;
  -webkit-mask-image: var(--mask);
  mask-image: var(--mask);
  -webkit-mask-mode: luminance;
  mask-mode: luminance;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  pointer-events: none;
}
/* light-film sculpt pass: multiply cannot darken a white body, so a near-white
   film over the white template renders as an unwrapped car - the pearls were
   invisible and indistinguishable from each other. This layer multiplies the
   template back onto itself inside the mask, doubling the factory shading so
   the creases, shoulder line and rocker shade read again. The source is the
   car photo itself (--shade, swapped with --mask in app.js), so it follows the
   real geometry of every template with no extra art. Off (opacity 0) for every
   film dark or saturated enough to read on its own: only the light finishes
   opt in via --shade-amt, and the amount doubles as the finish cue - a gloss
   pearl carries more contrast than a satin one. */
.car__film::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--shade);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  mix-blend-mode: multiply;
  opacity: var(--shade-amt, 0);
  pointer-events: none;
}
.car__film--next::before { opacity: var(--shade-amt-next, 0); }
/* ---------- The film catalog (v40) ----------
   One global token per film, named --f-<key>. These are the ONLY place a film
   gradient is written: the car layer, the swatch tiles and the before/after
   slider all read the same token, so a swatch can never drift from the paint.
   Every colour is a screen approximation of a real, orderable SKU - the hexes
   come from wiki/concepts/material-color-samples.md, which is reconciled against
   the live Metro Restyling catalogs. Do not invent films here: if it has no
   supplier code, it does not belong on the wall.
   Naming note: the tokens are --f-*, never --film-*, precisely so the .car
   mapping below can never become self-referential. A custom property that
   references itself is an invalid cycle, and the cycle kills the WHOLE
   declaration it appears in - including the film wipe's animation shorthand,
   silently, with a clean console. That regression already happened once. */
:root {
  /* --- Color shift / flip --- */
  --f-shift:      linear-gradient(115deg, var(--shift-a) 8%, var(--shift-b) 42%, var(--shift-c) 80%);   /* 3M GP281 Flip Psychedelic */
  --f-coral:      linear-gradient(115deg, #d95f6e 8%, #f08a5a 55%, #c74b8a);                            /* 3M SP213 Satin Flip Electric Coral */
  --f-deepspace:  linear-gradient(115deg, #131c3a 8%, #3a2a6e 55%, #14343f);                            /* 3M GP278 Flip Deep Space */
  --f-aura:       linear-gradient(115deg, #b8925a 8%, #e8c878 55%, #2a2320);                            /* 3M SP264 Satin Flip Golden Aura */
  --f-sunset:     linear-gradient(115deg, #d95a2b 8%, #b83a6e 55%, #3a2a6e);                            /* Oracal 970RA-100 Gloss Sunset Shift */
  /* --- Iridescent --- */
  --f-austral:    linear-gradient(115deg, #1f6e7a 8%, #4a4fa8 55%, #6e3f8a);                            /* Hexis HX30IMAB Gloss Austral Sea Iridescent */
  --f-morpheus:   linear-gradient(115deg, #141018 8%, #3a2a4f 55%, #1a2a3a);                            /* KPMF K75470 Gloss Morpheus Black Starlight */
  --f-purpleblue: linear-gradient(115deg, #3a1f6e 8%, #2a4fa8 55%, #4a2a8a);                            /* KPMF K75466 Gloss Purple Blue Iridescent */
  /* --- Super chrome --- */
  --f-chrpurple:  linear-gradient(115deg, #6e3fa0 8%, #b08ae0 50%, #5a2f8a);                            /* Hexis HX30SCH06B Gloss Purple Super Chrome */
  --f-chrpink:    linear-gradient(115deg, #d46a9e 8%, #f7b8d4 50%, #c2528a);                            /* Hexis HX30SCH10B Gloss Pink Super Chrome */
  /* --- Metallic --- */
  --f-bluemet:    linear-gradient(115deg, #173a7a 8%, #2f5fb8 60%, #173a7a);                            /* 3M G227 Gloss Blue Metallic */
  --f-purple:     linear-gradient(115deg, #4a2472 8%, #6b3fa0 60%, #4a2472);                            /* Avery SW900-566-M Satin Purple Metallic */
  --f-charcoal:   linear-gradient(115deg, #3a3d42 8%, #5a5e66 60%, #3a3d42);                            /* 3M M211 Matte Charcoal Metallic */
  /* --- Gloss --- */
  --f-rosso:      linear-gradient(115deg, oklch(0.5 0.2 25), oklch(0.42 0.19 27) 55%, oklch(0.56 0.2 25));      /* 3M G13 Gloss Hot Rod Red */
  --f-pink:       linear-gradient(115deg, oklch(0.74 0.18 350), oklch(0.62 0.21 356) 55%, oklch(0.8 0.16 345)); /* 3M G103 Gloss Hot Pink */
  --f-envy:       linear-gradient(115deg, #3a8548 8%, #2e6e3a 55%, #245a2e);                            /* 3M G336 Gloss Green Envy */
  /* --- Satin --- */
  --f-satin:      linear-gradient(115deg, oklch(0.30 0 0), oklch(0.16 0 0) 55%, oklch(0.34 0 0));       /* 3M S12 Satin Black */
  --f-vampire:    linear-gradient(115deg, #97202e 8%, #7a1420 55%, #5c0d17);                            /* 3M SP273 Satin Vampire Red */
  --f-velvetrose: linear-gradient(115deg, #dda3ad 8%, #c98a96 55%, #ac6f7c);                            /* 3M S23 Satin Velvet Rose */
  /* --- Matte --- */
  --f-matteblack: linear-gradient(115deg, #2b2b2e 8%, #1a1a1c 55%, #121214);                            /* 3M M12 Matte Black */
  --f-graphite:   linear-gradient(115deg, oklch(0.42 0.005 260), oklch(0.33 0.005 260) 55%, oklch(0.46 0.005 260)); /* 3M M261 Matte Dark Gray */
  --f-matred:     linear-gradient(115deg, #ac2a30 8%, #8f1f24 55%, #71171b);                            /* 3M M13 Matte Red */
  /* --- High gloss --- */
  --f-nardo:      linear-gradient(115deg, oklch(0.62 0.015 250), oklch(0.53 0.015 250) 55%, oklch(0.68 0.015 250)); /* 3M HG61 High Gloss Nardo Gray */
  --f-mantis:     linear-gradient(115deg, #a3e04f 8%, #8fd435 55%, #77b526);                            /* 3M HG36 High Gloss Mantis Green */
  /* --- Pearl (rendered with the sculpt pass above: these read as flat white
         without it, which is why the two used to look identical) --- */
  --f-pearl:      linear-gradient(115deg, #e6e3dc 8%, #fbfaf6 46%, #dfe4e6 82%);                        /* Avery SW900-109-S Gloss White Pearl */
  --f-pearlsatin: linear-gradient(115deg, #e4ddd0 8%, #f2ece0 55%, #ded7c9 92%);                        /* 3M SP10 Satin Pearl White */
  /* --- Carbon --- */
  --f-carbon:     repeating-linear-gradient(45deg, #1a1a1c 0 4px, #2a2a2e 4px 8px);                     /* 3M CFS12 Black Carbon Fiber */
  /* --- Neon (level 4, ~6 month life - flagged in the UI, never sold silently) --- */
  --f-twsunset:   linear-gradient(115deg, #6a55b8 8%, #8f6fd0 45%, #a8736e 88%);            /* TeckWrap RD20PRO-HD Purple Sunset */
  --f-twcandy:    linear-gradient(115deg, #6b2872 8%, #4d1c52 55%, #35143a);                /* TeckWrap GAL03-HD Candy Purple */
  --f-twcherry:   linear-gradient(115deg, #d94a4a 6%, #93090a 48%, #5e0405 92%);            /* TeckWrap CHM04-HD Cherry Red Chrome */
  --f-twnova:     linear-gradient(115deg, #5b4fd0 6%, #2a1c7b 48%, #150e45 92%);            /* TeckWrap CHM26-HD Nova Blue Chrome */
  --f-neongreen:  linear-gradient(115deg, #7cff62 8%, #5aff3a 55%, #3fe01f);                            /* 3M VCW17120 Satin Neon Green */
  --f-neonyellow: linear-gradient(115deg, #f0ff5c 8%, #e8ff2a 55%, #cbe012);                            /* 3M VCW17076 Satin Neon Yellow */
}

.car {
  --mask: url("assets/cars/lamborghini-huracan-mask3.webp");
  --shade: url("assets/cars/lamborghini-huracan.webp");
  --film: var(--f-shift);
  --film-next: var(--f-shift);
}

/* finishes the switcher can lay on any template */
.car[data-film="shift"]      { --film: var(--f-shift); }
.car[data-film="coral"]      { --film: var(--f-coral); }
.car[data-film="deepspace"]  { --film: var(--f-deepspace); }
.car[data-film="aura"]       { --film: var(--f-aura); }
.car[data-film="sunset"]     { --film: var(--f-sunset); }
.car[data-film="austral"]    { --film: var(--f-austral); }
.car[data-film="morpheus"]   { --film: var(--f-morpheus); }
.car[data-film="purpleblue"] { --film: var(--f-purpleblue); }
.car[data-film="chrpurple"]  { --film: var(--f-chrpurple); }
.car[data-film="chrpink"]    { --film: var(--f-chrpink); }
.car[data-film="bluemet"]    { --film: var(--f-bluemet); }
.car[data-film="purple"]     { --film: var(--f-purple); }
.car[data-film="charcoal"]   { --film: var(--f-charcoal); }
.car[data-film="rosso"]      { --film: var(--f-rosso); }
.car[data-film="pink"]       { --film: var(--f-pink); }
.car[data-film="envy"]       { --film: var(--f-envy); }
.car[data-film="satin"]      { --film: var(--f-satin); }
.car[data-film="vampire"]    { --film: var(--f-vampire); }
.car[data-film="velvetrose"] { --film: var(--f-velvetrose); }
.car[data-film="matteblack"] { --film: var(--f-matteblack); }
.car[data-film="graphite"]   { --film: var(--f-graphite); }
.car[data-film="matred"]     { --film: var(--f-matred); }
.car[data-film="nardo"]      { --film: var(--f-nardo); }
.car[data-film="mantis"]     { --film: var(--f-mantis); }
.car[data-film="pearl"]      { --film: var(--f-pearl); --shade-amt: .62; }
.car[data-film="pearlsatin"] { --film: var(--f-pearlsatin); --shade-amt: .44; }
.car[data-film="twsunset"]   { --film: var(--f-twsunset); }
.car[data-film="twcandy"]    { --film: var(--f-twcandy); }
.car[data-film="twcherry"]   { --film: var(--f-twcherry); }
.car[data-film="twnova"]     { --film: var(--f-twnova); }
.car[data-film="carbon"]     { --film: var(--f-carbon); }
.car[data-film="neongreen"]  { --film: var(--f-neongreen); }
.car[data-film="neonyellow"] { --film: var(--f-neonyellow); }
.car[data-film-next="shift"]      { --film-next: var(--f-shift); }
.car[data-film-next="coral"]      { --film-next: var(--f-coral); }
.car[data-film-next="deepspace"]  { --film-next: var(--f-deepspace); }
.car[data-film-next="aura"]       { --film-next: var(--f-aura); }
.car[data-film-next="sunset"]     { --film-next: var(--f-sunset); }
.car[data-film-next="austral"]    { --film-next: var(--f-austral); }
.car[data-film-next="morpheus"]   { --film-next: var(--f-morpheus); }
.car[data-film-next="purpleblue"] { --film-next: var(--f-purpleblue); }
.car[data-film-next="chrpurple"]  { --film-next: var(--f-chrpurple); }
.car[data-film-next="chrpink"]    { --film-next: var(--f-chrpink); }
.car[data-film-next="bluemet"]    { --film-next: var(--f-bluemet); }
.car[data-film-next="purple"]     { --film-next: var(--f-purple); }
.car[data-film-next="charcoal"]   { --film-next: var(--f-charcoal); }
.car[data-film-next="rosso"]      { --film-next: var(--f-rosso); }
.car[data-film-next="pink"]       { --film-next: var(--f-pink); }
.car[data-film-next="envy"]       { --film-next: var(--f-envy); }
.car[data-film-next="satin"]      { --film-next: var(--f-satin); }
.car[data-film-next="vampire"]    { --film-next: var(--f-vampire); }
.car[data-film-next="velvetrose"] { --film-next: var(--f-velvetrose); }
.car[data-film-next="matteblack"] { --film-next: var(--f-matteblack); }
.car[data-film-next="graphite"]   { --film-next: var(--f-graphite); }
.car[data-film-next="matred"]     { --film-next: var(--f-matred); }
.car[data-film-next="nardo"]      { --film-next: var(--f-nardo); }
.car[data-film-next="mantis"]     { --film-next: var(--f-mantis); }
.car[data-film-next="pearl"]      { --film-next: var(--f-pearl); --shade-amt-next: .62; }
.car[data-film-next="pearlsatin"] { --film-next: var(--f-pearlsatin); --shade-amt-next: .44; }
.car[data-film-next="twsunset"]   { --film-next: var(--f-twsunset); }
.car[data-film-next="twcandy"]    { --film-next: var(--f-twcandy); }
.car[data-film-next="twcherry"]   { --film-next: var(--f-twcherry); }
.car[data-film-next="twnova"]     { --film-next: var(--f-twnova); }
.car[data-film-next="carbon"]     { --film-next: var(--f-carbon); }
.car[data-film-next="neongreen"]  { --film-next: var(--f-neongreen); }
.car[data-film-next="neonyellow"] { --film-next: var(--f-neonyellow); }

/* squeegee wipe: the incoming film sweeps across the body behind an angled
   edge, a light band glides with it - vinyl being laid on, not a crossfade */
.car__film--next {
  z-index: 3;
  background: var(--film-next);
  visibility: hidden;
}
.car__film--next::after { display: none; }
.car__squeegee {
  position: absolute;
  inset: 0;
  z-index: 4;
  -webkit-mask-image: var(--mask);
  mask-image: var(--mask);
  -webkit-mask-mode: luminance;
  mask-mode: luminance;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  pointer-events: none;
  overflow: hidden;
  visibility: hidden;
}
.car__squeegee::before {
  content: "";
  position: absolute;
  inset: -8% -30%;
  background: linear-gradient(103deg,
    transparent 42%,
    oklch(1 0 0 / 0.05) 47%,
    oklch(1 0 0 / 0.5) 50%,
    oklch(1 0 0 / 0.08) 53%,
    transparent 58%);
  translate: -78% 0;
}
@media (prefers-reduced-motion: no-preference) {
  .car.is-wiping .car__film--next {
    visibility: visible;
    animation: filmwipe 950ms var(--ease-in-out) both;
  }
  /* the outgoing film retreats behind the same edge - the two multiply
     layers never overlap, so no muddy double-blend mid-transition */
  .car.is-wiping .car__film:not(.car__film--next) {
    animation: filmwipeout 950ms var(--ease-in-out) both;
  }
  .car.is-wiping .car__squeegee {
    visibility: visible;
    animation: squeegeefade 950ms linear both;
  }
  .car.is-wiping .car__squeegee::before {
    animation: squeegee 950ms var(--ease-in-out) both;
  }
}
@keyframes filmwipe {
  from { clip-path: polygon(-34% 0%, -10% 0%, -26% 100%, -50% 100%); }
  to   { clip-path: polygon(-34% 0%, 122% 0%, 106% 100%, -50% 100%); }
}
@keyframes filmwipeout {
  from { clip-path: polygon(-10% 0%, 140% 0%, 140% 100%, -26% 100%); }
  to   { clip-path: polygon(122% 0%, 140% 0%, 140% 100%, 106% 100%); }
}
@keyframes squeegee {
  from { translate: -78% 0; }
  to   { translate: 82% 0; }
}
@keyframes squeegeefade {
  0% { opacity: 0; }
  12% { opacity: 1; }
  88% { opacity: 1; }
  100% { opacity: 0; }
}


/* shine sweep: the reveal beat. Runs once when a film is switched. */
.car__film::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 30%, oklch(1 0 0 / 0.55) 50%, transparent 70%);
  background-size: 300% 100%;
  background-position: 130% 0;
  opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .car.is-revealing .car__film::after {
    opacity: 1;
    animation: shine 950ms var(--ease) forwards;
  }
}
@keyframes shine {
  from { background-position: 130% 0; }
  to   { background-position: -30% 0; opacity: 0; }
}

/* studio floor: the car stands on a lit stage, not in a void. Three layers,
   all static paint (no animation): a soft light pool the key light would
   throw, the reflection puddle, and a hairline podium edge. */
.car__floor {
  position: absolute;
  left: 6%;
  right: 6%;
  bottom: -4%;
  height: 14%;
  background:
    radial-gradient(46% 130% at 50% 18%, oklch(0.42 0.015 100 / 0.3), transparent 72%),
    radial-gradient(50% 100% at 50% 0%, oklch(0 0 0 / 0.65), transparent 75%);
  z-index: 0;
  pointer-events: none;
}
.car__floor::after {
  content: "";
  position: absolute;
  left: 2%;
  right: 2%;
  top: 32%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--line) 22%, var(--line) 78%, transparent);
}

/* ---------- Film bar ---------- */
.hero__filmbar {
  display: grid;
  gap: 0.9rem;
  padding: 1.1rem 0 0;
  margin-top: 0.5rem;
  border-top: 1px solid var(--line-soft);
}
.filmbar__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem;
}
.filmbar__pitch {
  margin: 0;
  max-width: 68ch;
  color: var(--ink-2);
  font-size: 0.98rem;
  line-height: 1.55;
}
.filmbar__pitch strong { color: var(--ink); }
.filmbar__pitch a {
  color: var(--yellow);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.filmbar__row--head { gap: 0.55rem 0.9rem; align-items: baseline; }
.filmbar__label {
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
/* the credibility line next to "pick a film": these are orderable SKUs, not
   decorative screen colours - it is the whole reason the codes are on the tiles */
.filmbar__hint {
  font-size: 0.78rem;
  color: var(--muted);
  letter-spacing: 0.01em;
}

.car-select {
  -webkit-appearance: none;
  appearance: none;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink);
  background-color: transparent;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23FFD600' stroke-width='1.6' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1em center;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.55em 2.4em 0.55em 1em;
  min-width: 15rem;
  cursor: pointer;
  transition: border-color var(--dur-1) var(--ease);
}
.car-select:hover { border-color: var(--yellow); }
.car-select:focus-visible { border-color: var(--yellow); outline: 2px solid var(--yellow); outline-offset: 2px; }
.car-select option, .car-select optgroup { background: #141416; color: var(--ink); }

/* "Pick your car" in its own slot above the car: prominent, and it can
   never collide with a tall body (4Runner/Sprinter roofs reach the top) */
.car__picker {
  position: relative;
  order: 1;
  align-self: flex-end;
  margin: 0 0 0.7rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.75rem 0.85rem;
  background: rgba(12, 12, 14, 0.82);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  /* v44 yellow discipline: the accent belongs to the CTA, not to furniture.
     The transient attention ring below stays yellow; the resting frame is quiet. */
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
}
.car__picker-label {
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.car__picker .car-select { background-color: rgba(20, 20, 22, 0.9); min-width: 13rem; }
/* attention ring: compositor-only scale+fade on a ::after, three beats then
   rest - the old box-shadow pulse repainted the hero card forever */
.car__picker::after {
  content: "";
  position: absolute;
  inset: -2px;
  border: 2px solid rgba(255, 214, 0, 0.45);
  border-radius: inherit;
  opacity: 0;
  pointer-events: none;
}
@keyframes pickerring {
  from { opacity: 0.5; transform: scale(1); }
  to   { opacity: 0;   transform: scale(1.07); }
}
@media (prefers-reduced-motion: no-preference) {
  .car__picker.is-idle::after { animation: pickerring 2.4s var(--ease-in-out) 3; }
  .car__picker.is-entering::after { animation: pickerring 2.4s var(--ease-in-out) 700ms 3; }
}
/* staged entrance (same beat as before; the ring runs on the ::after) */
@keyframes pickerin {
  from { opacity: 0; transform: translateY(-12px) scale(0.94); }
  to { opacity: 1; transform: none; }
}
.car__picker.is-entering { animation: pickerin 600ms var(--ease) both; }
/* yellow underline sweep under both control labels */
.car__picker-label, .filmbar__label { position: relative; }
@keyframes labelsweep { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.label-sweep::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.3em;
  height: 2px;
  background: var(--yellow);
  transform-origin: left center;
  animation: labelsweep 480ms var(--ease) both;
}
[dir="rtl"] .label-sweep::after { transform-origin: right center; }
@media (prefers-reduced-motion: reduce) {
  .car__picker.is-idle, .car__picker.is-entering, .label-sweep::after { animation: none; }
  .car__picker.is-entering { opacity: 1; transform: none; }
}
@media (max-width: 720px) {
  .car__picker {
    order: 2;
    align-self: stretch;
    margin: 0.55rem 0 0;
    width: 100%;
    flex-direction: row;
    /* v45: label takes the first row, the Make + Model pair share the second */
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.6rem;
  }
  .hero__car .car { order: 1; }
  .car__picker .car__picker-label { flex: 1 0 100%; }
  .car__picker .car-select { flex: 1 1 auto; min-width: 0; }
  .car__picker .car-select--make { flex: 0 1 42%; }
}

/* ---------- Film wall (v40) ----------
   Replaces the flat pill chips. 29 films across 11 finish CLASSES is a catalog,
   not a chip row, so the wall is filed the way an installer files stock - by
   class (gloss / satin / matte / high gloss / metallic / color shift /
   iridescent / super chrome / pearl / carbon / neon) - and only one class is on
   screen at a time behind a tab strip. Inside a class every film is a real
   sample card: the actual film gradient on top, the name under it, the supplier
   code as the second-level detail. Color shift leads because that family
   over-indexes hardest (viral-content-playbook) and is the only one carrying
   keep verdicts in post-performance-ledger.
   Progressive enhancement: with no JS there is no .is-tabbed, so every panel
   renders stacked under its own heading - the whole catalog stays readable. */
.films { display: grid; gap: 0.75rem; }

/* desktop: every class is visible at once, wrapping to a second row - a clipped
   tab strip reads as broken, and the point of the strip is showing the range */
.films__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.films__tab {
  --tf: var(--f-shift);
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.4em 0.85em;
  cursor: pointer;
  transition: border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease),
              background-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease-out);
}
/* a pip of the class's own signature film, so the strip is scannable by colour */
.films__tab::before {
  content: "";
  width: 0.72em;
  height: 0.72em;
  border-radius: 50%;
  background: var(--tf);
  box-shadow: inset 0 1px 1px oklch(1 0 0 / 0.32);
}
.films__tab--shift  { --tf: var(--f-shift); }
.films__tab--irid   { --tf: var(--f-austral); }
.films__tab--chrome { --tf: var(--f-chrpurple); }
.films__tab--metal  { --tf: var(--f-bluemet); }
.films__tab--gloss  { --tf: var(--f-rosso); }
.films__tab--satin  { --tf: var(--f-satin); }
.films__tab--matte  { --tf: var(--f-graphite); }
.films__tab--hgloss { --tf: var(--f-nardo); }
.films__tab--pearl  { --tf: var(--f-pearl); }
.films__tab--carbon { --tf: var(--f-carbon); }
.films__tab--neon   { --tf: var(--f-neongreen); }
@media (hover: hover) and (pointer: fine) {
  .films__tab:hover { color: var(--ink); border-color: oklch(1 0 0 / 0.32); transform: translateY(-1px); }
}
.films__tab:active { transform: scale(0.96); }
.films__tab[aria-selected="true"] {
  color: var(--yellow-ink);
  background: var(--yellow);
  border-color: var(--yellow);
}

.films__panel { display: grid; gap: 0.45rem; }
.films.is-tabbed .films__panel { display: none; }
.films.is-tabbed .films__panel.is-on { display: grid; }
@media (prefers-reduced-motion: no-preference) {
  .films.is-tabbed .films__panel.is-on { animation: panelin 320ms var(--ease-out) both; }
}
@keyframes panelin {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: none; }
}
/* panel heading: the no-JS label for each class, redundant once tabs exist */
.films__ph {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  font-size: 0.67rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}
.films__ph::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--line-soft);
}
.films.is-tabbed .films__ph { display: none; }
/* the honest small print - currently the 6-month life on neon */
.films__note {
  font-size: 0.73rem;
  font-weight: 600;
  color: var(--yellow);
  letter-spacing: 0.01em;
}
.films__rail { display: flex; flex-wrap: wrap; gap: 0.5rem; }

/* one sample card */
.fsw {
  --f: var(--f-shift);
  position: relative;
  display: grid;
  align-content: start;
  flex: 0 1 9rem;
  padding: 0;
  text-align: start;
  font-family: var(--font-body);
  color: var(--ink-2);
  background: oklch(0.19 0 0 / 0.5);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  transition: border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease-out);
}
/* the paint: the exact same token the car wears, so a tile can never lie */
.fsw__paint {
  position: relative;
  display: block;
  height: 2.5rem;
  background: var(--f);
  overflow: hidden;
}
/* static vinyl body-roll shading, so a flat colour still reads as film */
.fsw__paint::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, oklch(1 0 0 / 0.17), transparent 44%, oklch(0 0 0 / 0.24));
}
/* the squeegee highlight: parked off-canvas, sweeps across on hover/focus -
   the same gesture the car gets on a wipe, scaled down to a sample card */
.fsw__paint::after {
  content: "";
  position: absolute;
  inset: -25% -45%;
  background: linear-gradient(103deg,
    transparent 42%,
    oklch(1 0 0 / 0.06) 47%,
    oklch(1 0 0 / 0.42) 50%,
    oklch(1 0 0 / 0.08) 53%,
    transparent 58%);
  translate: -85% 0;
  transition: translate 640ms var(--ease-out);
}
.fsw:focus-visible .fsw__paint::after { translate: 85% 0; }

.fsw__name {
  padding: 0.42rem 0.55rem 0;
  min-height: 2.55em;
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.25;
  transition: color var(--dur-2) var(--ease);
}
.fsw__code {
  padding: 0.1rem 0.55rem 0.45rem;
  /* the real 3M/Avery code is the credibility layer - 0.6rem was squint
     material for the 28-55 audience; contrast was never the problem */
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  color: var(--muted);
}
/* selection tick: springs in on commit - the satisfying half of the choice */
.fsw::after {
  content: "\2713";
  position: absolute;
  top: 0.4rem;
  inset-inline-end: 0.4rem;
  display: grid;
  place-items: center;
  width: 0.95rem;
  height: 0.95rem;
  border-radius: 50%;
  background: var(--yellow);
  color: var(--yellow-ink);
  font-size: 0.56rem;
  font-weight: 800;
  line-height: 1;
  transform: scale(0);
  transition: transform var(--dur-3) var(--ease-spring);
}
@media (hover: hover) and (pointer: fine) {
  .fsw:hover { border-color: oklch(1 0 0 / 0.32); color: var(--ink); transform: translateY(-3px); }
  .fsw:hover .fsw__paint::after { translate: 85% 0; }
}
.fsw:active { transform: scale(0.975); }
.fsw.is-active { border-color: var(--yellow); background: oklch(0.22 0 0 / 0.7); }
.fsw.is-active .fsw__name { color: var(--ink); }
.fsw.is-active::after { transform: scale(1); }

/* each tile points at one catalog token - no colour is written twice */
.fsw--shift      { --f: var(--f-shift); }
.fsw--coral      { --f: var(--f-coral); }
.fsw--deepspace  { --f: var(--f-deepspace); }
.fsw--aura       { --f: var(--f-aura); }
.fsw--sunset     { --f: var(--f-sunset); }
.fsw--austral    { --f: var(--f-austral); }
.fsw--morpheus   { --f: var(--f-morpheus); }
.fsw--purpleblue { --f: var(--f-purpleblue); }
.fsw--twsunset   { --f: var(--f-twsunset); }
.fsw--twcandy    { --f: var(--f-twcandy); }
.fsw--twcherry   { --f: var(--f-twcherry); }
.fsw--twnova     { --f: var(--f-twnova); }
.fsw--chrpurple  { --f: var(--f-chrpurple); }
.fsw--chrpink    { --f: var(--f-chrpink); }
.fsw--bluemet    { --f: var(--f-bluemet); }
.fsw--purple     { --f: var(--f-purple); }
.fsw--charcoal   { --f: var(--f-charcoal); }
.fsw--rosso      { --f: var(--f-rosso); }
.fsw--pink       { --f: var(--f-pink); }
.fsw--envy       { --f: var(--f-envy); }
.fsw--satin      { --f: var(--f-satin); }
.fsw--vampire    { --f: var(--f-vampire); }
.fsw--velvetrose { --f: var(--f-velvetrose); }
.fsw--matteblack { --f: var(--f-matteblack); }
.fsw--graphite   { --f: var(--f-graphite); }
.fsw--matred     { --f: var(--f-matred); }
.fsw--nardo      { --f: var(--f-nardo); }
.fsw--mantis     { --f: var(--f-mantis); }
.fsw--pearl      { --f: var(--f-pearl); }
.fsw--pearlsatin { --f: var(--f-pearlsatin); }
.fsw--carbon     { --f: var(--f-carbon); }
.fsw--neongreen  { --f: var(--f-neongreen); }
.fsw--neonyellow { --f: var(--f-neonyellow); }

/* one-shot cascade while the demo wipe plays (transform only - the border/colour
   flash the old chipwave did was a non-compositor property) */
@keyframes fswwave {
  0%   { transform: none; }
  35%  { transform: translateY(-5px) scale(1.03); }
  100% { transform: none; }
}
.fsw.is-wave { animation: fswwave 520ms var(--ease) both; }

/* mobile: the class rail stops wrapping and becomes a snap rail. A tile is
   deliberately narrower than a quarter of the viewport so the next one always
   peeks in - that peek is the only scroll affordance needed, no arrows, no
   fade masks. Same for the tab strip above it. */
@media (max-width: 720px) {
  .films__rail,
  .films__tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding-bottom: 0.3rem;
    scrollbar-width: none;
  }
  .films__rail { scroll-snap-type: x proximity; }
  .films__rail::-webkit-scrollbar,
  .films__tabs::-webkit-scrollbar { display: none; }
  .fsw { flex: 0 0 7.3rem; scroll-snap-align: start; }
  .fsw__paint { height: 2.2rem; }
  .films__tab { font-size: 0.74rem; }
}

/* full reduced-motion fallback: the tick still marks the selection, it just
   appears instead of springing; nothing translates, nothing sweeps */
@media (prefers-reduced-motion: reduce) {
  .fsw,
  .fsw__name,
  .fsw::after,
  .fsw__paint::after,
  .films__tab { transition: none; }
  .fsw:hover, .fsw:active,
  .films__tab:hover, .films__tab:active { transform: none; }
  .fsw.is-wave { animation: none; }
  .fsw__paint::after { display: none; }
  .films.is-tabbed .films__panel.is-on { animation: none; }
}

/* ---------- Ticker ---------- */
.ticker {
  margin-top: var(--space-section);
  padding: 0.9rem 0;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  overflow: hidden;
}
.ticker__track {
  display: flex;
  align-items: center;
  gap: 2.2rem;
  width: max-content;
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 1rem + 1vw, 1.7rem);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  white-space: nowrap;
}
.ticker__track i { font-style: normal; color: var(--yellow); font-size: 0.7em; }
.ticker__hot { color: var(--yellow); }
@media (prefers-reduced-motion: no-preference) {
  .ticker__track { animation: ticker 26s linear infinite; }
}
@keyframes ticker { to { translate: -50% 0; } }

/* ---------- Film brands (v44) ----------
   The only external trust we can show while the Google reviews have no text:
   the catalogs themselves. Wordmarks in the house type, muted so they read as
   a fact, not an ad; logos-only rule - no captions, no links out. */
.brands { border-bottom: 1px solid var(--line-soft); }
.brands__row {
  list-style: none;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 1.5rem var(--gutter);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: 0.9rem clamp(1.6rem, 4vw, 3.4rem);
}
.brands__mark {
  font-weight: 800;
  font-size: clamp(0.92rem, 0.8rem + 0.5vw, 1.08rem);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  transition: color var(--dur-2) var(--ease);
}
.brands__row:hover .brands__mark { color: var(--ink-2); }

/* ---------- Sections ---------- */
.services, .why, .finishes, .process, .faq, .book, .build { padding-top: var(--space-section); }

/* latest build gallery */
.build__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(0.75rem, 0.5rem + 1vw, 1.25rem);
  margin-top: 2.5rem;
}
.build__shot {
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--line-soft);
  background: var(--bg-deep);
}
.build__shot--hero { grid-column: 1 / -1; }
.build__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.build__shot:not(.build__shot--hero) { aspect-ratio: 3 / 4; }
.build__shot.build__shot--wide { grid-column: span 2; aspect-ratio: 3 / 2; }
.build__credit {
  margin-top: 1.2rem;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  color: var(--muted);
}
@media (max-width: 700px) {
  .build__grid { grid-template-columns: repeat(2, 1fr); }
  .build__shot--wide { grid-column: 1 / -1; }
  .build__shot:last-child { grid-column: 1 / -1; aspect-ratio: 16 / 10; }
}

/* ---------- Services: spec-sheet rows ---------- */
.svc { list-style: none; padding: 0; margin: 3rem 0 0; border-top: 1px solid var(--line); }
.svc__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
  gap: 1rem 2.5rem;
  align-items: baseline;
  padding: 1.6rem 0.5rem;
  border-bottom: 1px solid var(--line);
  /* wash only on the row; the content nudge below is a compositor transform,
     not an animated padding (which would relayout the row on every hover) */
  transition: background-color var(--dur-3) var(--ease);
}
.svc__row:hover { background: oklch(1 0 0 / 0.03); }
/* nudge the text, not the box: the row edge and bottom border stay put while
   the content slides right - same look as the old padding animation, on the GPU */
.svc__name, .svc__desc { transition: transform var(--dur-3) var(--ease); }
.svc__row:hover .svc__name, .svc__row:hover .svc__desc { transform: translateX(0.6rem); }
.svc__name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-h3);
  line-height: 1.05;
  text-transform: uppercase;
  letter-spacing: 0.015em;
}
.svc__tag {
  vertical-align: middle;
  margin-inline-start: 0.5rem;
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--yellow-ink);
  background: var(--yellow);
  padding: 0.25em 0.6em;
  border-radius: 999px;
  text-transform: uppercase;
}
.svc__desc { color: var(--ink-2); max-width: 52ch; }
.svc__quote {
  margin-top: 1.8rem;
  font-size: var(--text-lead);
  color: var(--ink-2);
  max-width: 58ch;
}
.svc__quote a {
  color: var(--yellow);
  text-decoration-color: var(--yellow);
  text-underline-offset: 4px;
  font-weight: 600;
}
@media (max-width: 860px) {
  .svc__row { grid-template-columns: 1fr; }
}

/* ---------- Why ---------- */
.why__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: clamp(2rem, 1.5rem + 2vw, 3.5rem) clamp(2rem, 1.5rem + 3vw, 4rem);
  margin-top: 3rem;
}
.why__item dt {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.3rem, 1.1rem + 1vw, 1.8rem);
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.015em;
}
.why__item dd { margin: 0.7rem 0 0; color: var(--ink-2); max-width: 44ch; }
/* four benefits read as a deliberate 2x2, never a ragged 3+1 */
@media (min-width: 721px) { .why__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---------- Finishes ---------- */
.swatches {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.8rem;
  padding: 0;
  margin: 3rem 0 0;
}
.swatch {
  position: relative;
  aspect-ratio: 5 / 3;
  display: flex;
  align-items: flex-end;
  padding: 0.9rem 1rem;
  border: 1px solid var(--line-soft);
  overflow: hidden;
}
.swatch span {
  position: relative;
  z-index: 1;
  font-weight: 600;
  font-size: 0.9rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  text-shadow: 0 1px 6px oklch(0 0 0 / 0.6);
}
.swatch::before { content: ""; position: absolute; inset: 0; }
.swatch--gloss::before  { background: linear-gradient(135deg, oklch(0.6 0.02 260), oklch(0.25 0.01 260) 55%, oklch(0.5 0.02 260)); }
.swatch--satin::before  { background: linear-gradient(135deg, oklch(0.42 0 0), oklch(0.22 0 0)); }
.swatch--matte::before  { background: oklch(0.3 0 0); }
.swatch--metal::before  { background: linear-gradient(135deg, oklch(0.62 0.03 80), oklch(0.4 0.02 80) 50%, oklch(0.58 0.03 80)); }
.swatch--shift::before  { background: linear-gradient(135deg, var(--shift-a), var(--shift-b) 50%, var(--shift-c)); }
.swatch--carbon::before {
  background:
    repeating-linear-gradient(45deg, oklch(0.24 0 0) 0 4px, oklch(0.16 0 0) 4px 8px),
    oklch(0.2 0 0);
}

/* ---------- Process ---------- */
.steps {
  list-style: none;
  counter-reset: step;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 2.5rem 2rem;
  padding: 0;
  margin: 3rem 0 0;
}
.step__n {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 2.4rem;
  line-height: 1;
  color: var(--yellow);
}
.step h3 {
  margin-top: 0.7rem;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.25rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.step p { margin-top: 0.5rem; color: var(--ink-2); }

/* ---------- FAQ ---------- */
.qa { border-bottom: 1px solid var(--line); }
.faq .section__h { margin-bottom: 2rem; }
.qa summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
  padding: 1.3rem 0.2rem;
  font-weight: 600;
  font-size: 1.1rem;
  cursor: pointer;
  list-style: none;
  transition: color var(--dur-1) var(--ease);
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary::after {
  content: "+";
  font-family: var(--font-display);
  font-size: 1.4rem;
  color: var(--yellow);
  transition: rotate var(--dur-3) var(--ease);
}
.qa[open] summary::after { rotate: 45deg; }
.qa summary:hover { color: var(--yellow); }
.qa p { padding: 0 0.2rem 1.4rem; color: var(--ink-2); max-width: 68ch; }

/* v44: ten questions one-per-row ran ~1500px of page. Desktop pairs them in
   two columns (the narrow cap widens to hold the pair); phones fold the list
   to five, app.js wires the un-fold. */
@media (min-width: 980px) {
  .faq .wrap--narrow {
    max-width: 1120px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 3.5rem;
    align-items: start;
  }
  .faq .section__h { grid-column: 1 / -1; }
}
.faq__more {
  display: none;
  margin-top: 1.2rem;
  padding: 0.85em 1.5em;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink);
  background: none;
  border: 1px solid var(--line);
  cursor: pointer;
  transition: border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.faq__more:hover { border-color: var(--yellow); color: var(--yellow); }
@media (max-width: 720px) {
  .faq.is-folded .qa:nth-of-type(n + 6) { display: none; }
  .faq.is-folded .faq__more { display: inline-flex; }
}

/* ---------- Book ---------- */
.book { padding-bottom: var(--space-section); }
.book__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 2rem + 3vw, 5rem);
  align-items: start;
}
@media (max-width: 860px) { .book__grid { grid-template-columns: 1fr; } }

.book__contact { list-style: none; padding: 0; margin: 2.2rem 0 0; }
.book__contact li {
  display: flex;
  gap: 1.2rem;
  padding: 0.8rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.book__k {
  flex: 0 0 6.5rem;
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  padding-top: 0.2rem;
}
.book__note {
  font-size: 0.85em;
  color: var(--muted);
  white-space: nowrap;
}
.book__contact a { color: var(--ink); text-decoration-color: var(--yellow); text-underline-offset: 3px; }
.book__contact a:hover { color: var(--yellow); }

/* form */
.form { display: grid; gap: 1.2rem; padding: clamp(1.5rem, 1rem + 2vw, 2.5rem); background: var(--bg-deep); border: 1px solid var(--line-soft); }
.field label {
  display: block;
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.45rem;
}
.field--split { display: grid; grid-template-columns: 1fr 1fr; gap: 1.2rem; }
@media (max-width: 480px) { .field--split { grid-template-columns: 1fr; } }

input, select, textarea {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  padding: 0.8em 1em;
  transition: border-color var(--dur-1) var(--ease);
}
input::placeholder, textarea::placeholder { color: var(--muted); }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--yellow); }
/* keyboard focus gets the house outline, same grammar as buttons/links;
   a 1px border tint alone is too weak an indicator on the near-black form */
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--yellow);
  outline-offset: 2px;
}
select:invalid { color: var(--muted); }
textarea { resize: vertical; min-height: 5.5em; }

.form__submit { justify-content: center; margin-top: 0.4rem; }
.form__fine { font-size: 0.85rem; color: var(--muted); text-align: center; }

/* ---------- Footer ---------- */
.footer { border-top: 1px solid var(--line-soft); padding: 2rem 0; }
.footer__grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2.5rem;
  align-items: center;
  justify-content: space-between;
  color: var(--muted);
}
.footer__mark { font-family: var(--font-display); text-transform: uppercase; letter-spacing: 0.02em; }
.footer__social { display: flex; gap: 1.4rem; }
.footer__social a { color: var(--ink-2); text-decoration: none; }
.footer__social a:hover { color: var(--yellow); }
/* Юридические ссылки: требование Meta и TikTok - они должны быть видимы. */
.footer__legal { display: flex; gap: 1.4rem; }
.footer__legal a { color: var(--ink-2); text-decoration: none; }
.footer__legal a:hover { color: var(--yellow); }

/* ---------- Scroll reveals ----------
   Content is visible by default. JS adds .will-reveal only to elements below
   the fold, and removes it when they enter the viewport. No JS = no hiding. */
@media (prefers-reduced-motion: no-preference) {
  .will-reveal { opacity: 0.001; translate: 0 30px; }
  .reveal { transition: opacity var(--dur) var(--ease), translate var(--dur) var(--ease); }
  /* transition declarations replace, never merge: without this line the
     .reveal rule above clobbers the service-row hover wash (styles v28 bug) */
  .svc__row.reveal {
    transition: background-color var(--dur-3) var(--ease),
                opacity var(--dur) var(--ease), translate var(--dur) var(--ease);
  }
}


/* ===== language switcher + RTL ===== */
.lang-select {
  -webkit-appearance: none;
  appearance: none;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  color: var(--ink-2);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.5em 0.9em;
  margin-left: 1.2rem;
  cursor: pointer;
  transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.lang-select:hover { border-color: var(--yellow); color: var(--ink); }
.lang-select:focus-visible { border-color: var(--yellow); color: var(--ink); outline: 2px solid var(--yellow); outline-offset: 2px; }
/* v45: the select now lives inside .nav__links (desktop: end of the link row;
   phone: a row of the burger panel) - the row gap replaces its old margin */
.nav__links { align-items: center; }
.nav__links .lang-select { margin-left: 0; }
/* v45: short CTA label for narrow headers; full label on desktop */
.nav__cta-short { display: none; }
@media (max-width: 720px) {
  .nav__cta-full { display: none; }
  .nav__cta-short { display: inline; }
  .nav__links .lang-select { margin: 0.9rem 0 0.2rem; align-self: center; min-height: 44px; }
}
.lang-select option { background: #141416; color: var(--ink); }
@media (max-width: 720px) {
  .lang-select { margin-left: auto; margin-right: 0.6rem; }
}

[dir="rtl"] .nav__links { margin-left: 0; margin-right: auto; }
[dir="rtl"] .lang-select { margin-left: 0; margin-right: 1.2rem; }
[dir="rtl"] .car-select {
  background-position: left 1em center;
  padding: 0.55em 1em 0.55em 2.4em;
}
[dir="rtl"] .hero__h, [dir="rtl"] .hero__sub, [dir="rtl"] .hero__intro { text-align: right; }
[dir="rtl"] .section__h .dot { display: none; }
/* the service-row hover nudge must follow the reading direction */
[dir="rtl"] .svc__row:hover .svc__name,
[dir="rtl"] .svc__row:hover .svc__desc { transform: translateX(-0.6rem); }
.lang-select { width: auto; flex: 0 0 auto; }
@media (max-width: 480px) {
  .brand__loc { display: none; }
  .nav__cta { font-size: 0.85rem; padding: 0.6em 0.9em; white-space: nowrap; }
  .lang-select { padding: 0.45em 0.7em; font-size: 0.8rem; margin-right: 0.45rem; }
}
/* 375px audit: brand + lang + CTA + burger cost ~415px - shave every fixed
   cost so the burger stops hanging off the edge; never wrap the CTA */
@media (max-width: 400px) {
  .nav { gap: 0.5rem; padding-inline: 0.6rem; }
  .brand__word { font-size: 1rem; }
  .nav__cta { font-size: 0.8rem; padding: 0.6em 0.7em; }
  .nav__burger { margin-left: 0; }
}
/* smallest phones: the bolt alone is the brand - the word costs 100px */
@media (max-width: 352px) {
  .brand__word, .brand__loc { display: none; }
}

/* ---------- Film-name toast on the car ---------- */
.car__toast {
  position: absolute;
  z-index: 6;
  left: 3%;
  bottom: 14%;
  padding: 0.5em 0.9em;
  background: rgba(12, 12, 14, 0.85);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border: 1px solid var(--line);
  border-left: 3px solid var(--yellow);
  border-radius: 10px;
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  color: var(--ink);
  opacity: 0;
  translate: 0 8px;
  pointer-events: none;
  transition: opacity var(--dur-4) var(--ease), translate var(--dur-4) var(--ease);
}
.car__toast.is-show { opacity: 1; translate: 0 0; }
[dir="rtl"] .car__toast { left: auto; right: 3%; border-left: 1px solid var(--line); border-right: 3px solid var(--yellow); }

/* ---------- Configurator CTA (appears after the 2nd film flip) ---------- */
.filmbar__cta {
  margin: 1rem 0 0;
  color: var(--ink-2);
  font-size: 0.98rem;
  opacity: 0;
  translate: 0 8px;
  transition: opacity 420ms var(--ease), translate 420ms var(--ease);
}
.filmbar__cta.is-in { opacity: 1; translate: 0 0; }
.filmbar__cta a {
  color: var(--yellow);
  font-weight: 700;
  text-underline-offset: 3px;
  margin-inline-start: 0.35em;
}

/* ---------- Google reviews band ---------- */
.reviews { padding-top: var(--space-section); }
.reviews__inner {
  max-width: var(--maxw);
  margin-inline: auto;
  padding: clamp(2.5rem, 2rem + 2vw, 4rem) var(--gutter);
  text-align: center;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
}
.reviews__score {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(3.5rem, 2.5rem + 4vw, 6rem);
  line-height: 1;
  color: var(--ink);
}
.reviews__stars {
  margin: 0.35rem 0 0;
  color: var(--yellow);
  font-size: clamp(1.2rem, 1rem + 1vw, 1.7rem);
  letter-spacing: 0.35em;
  padding-inline-start: 0.35em;
}
.reviews__h {
  margin: 0.9rem 0 0;
  font-family: var(--font-display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(1.3rem, 1.1rem + 1vw, 1.9rem);
  letter-spacing: 0.02em;
}
.reviews__lead { margin: 0.7rem auto 0; max-width: 46ch; color: var(--ink-2); }
.reviews__link { margin-top: 1.4rem; }

/* v44: the mobile FAB stack (SMS/Messenger/WhatsApp circles, bottom-right)
   is retired - the .mbar quick-contact bar carries the same three channels
   with labels and full-width tap zones. */

/* ---------- Gallery lightbox ---------- */
.build__shot img { cursor: zoom-in; }
/* The photos become buttons via JS (progressive enhancement) - give the keyboard
   focus ring. Negative offset keeps it inside the figure's overflow:hidden edge. */
.build__shot img:focus-visible { outline: 2px solid var(--yellow); outline-offset: -3px; }
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 120; /* above the sticky nav (--z-nav: 100) */
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(5, 5, 6, 0.94);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
.lightbox.is-open { display: flex; }
.lightbox img {
  max-width: 92vw;
  max-height: 84vh;
  border-radius: 6px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}
.lightbox__btn {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.8rem;
  height: 2.8rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: rgba(12, 12, 14, 0.7);
  color: var(--ink);
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color var(--dur-1) var(--ease);
}
.lightbox__btn:hover, .lightbox__btn:focus-visible { border-color: var(--yellow); outline: none; }
.lightbox__close { top: 1rem; right: 1rem; }
.lightbox__prev { left: 1rem; top: 50%; translate: 0 -50%; }
.lightbox__next { right: 1rem; top: 50%; translate: 0 -50%; }
@media (max-width: 720px) {
  .lightbox__prev { left: 0.4rem; }
  .lightbox__next { right: 0.4rem; }
}

/* Soft open: the scrim (and its backdrop blur) fades in and the photo scales up
   from the grid, materializing rather than snapping on. Pure CSS via
   @starting-style + allow-discrete, so app.js keeps sole ownership of open/close,
   data-full, Esc/arrow paging and the Tab focus-trap - this only paints over it.
   @supports-gated: browsers without it keep today's instant show (no regression). */
@media (prefers-reduced-motion: no-preference) {
  @supports (transition-behavior: allow-discrete) {
    .lightbox {
      opacity: 0;
      transition: opacity var(--dur-modal) var(--ease-out),
                  display var(--dur-modal) allow-discrete;
    }
    .lightbox.is-open { opacity: 1; }
    @starting-style { .lightbox.is-open { opacity: 0; } }

    .lightbox img {
      transform: scale(0.94);
      opacity: 0;
      transition: transform var(--dur-modal) var(--ease-out),
                  opacity var(--dur-modal) var(--ease-out);
    }
    .lightbox.is-open img { transform: scale(1); opacity: 1; }
    @starting-style { .lightbox.is-open img { transform: scale(0.94); opacity: 0; } }
  }
}
/* Reduced motion: keep the cross-fade (aids comprehension), drop the scale. */
@media (prefers-reduced-motion: reduce) {
  @supports (transition-behavior: allow-discrete) {
    .lightbox {
      opacity: 0;
      transition: opacity 180ms var(--ease-out), display 180ms allow-discrete;
    }
    .lightbox.is-open { opacity: 1; }
    @starting-style { .lightbox.is-open { opacity: 0; } }
  }
}

/* ===== v28: ten upgrades - motion by the house doctrine ===== */

/* 1) one shine sweep across the WRAP word, squeegee metaphor */
@keyframes heroshine { from { background-position: 115% 0; } to { background-position: -15% 0; } }
.hero__h em.is-shine {
  background: linear-gradient(110deg, var(--yellow) 42%, #fff 50%, var(--yellow) 58%) 115% 0 / 260% 100% no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: heroshine 1100ms var(--ease) both;
}

/* 2) gallery prints like a contact sheet - 90ms cascade */
.build__grid .reveal:nth-child(2) { transition-delay: 90ms; }
.build__grid .reveal:nth-child(3) { transition-delay: 180ms; }
.build__grid .reveal:nth-child(4) { transition-delay: 270ms; }
.build__grid .reveal:nth-child(5) { transition-delay: 360ms; }
.build__grid .reveal:nth-child(6) { transition-delay: 450ms; }

/* 3) reviews wake up at the viewport edge */
.reviews__stars span { opacity: 0.18; display: inline-block; transition: opacity var(--dur-3) var(--ease); }
@keyframes starpop { 0% { scale: 0.4; } 60% { scale: 1.25; } 100% { scale: 1; } }
.reviews__stars span.is-lit { opacity: 1; animation: starpop 420ms var(--ease); }
@media (prefers-reduced-motion: reduce) {
  .reviews__stars span { opacity: 1; transition: none; }
  .reviews__stars span.is-lit { animation: none; }
}

/* 4) swatches are doors into the configurator */
.swatch { position: relative; }
.swatch__btn {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: none;
  border: 0;
  border-radius: inherit;
  cursor: pointer;
}
.swatch__btn:focus-visible { outline: 2px solid var(--yellow); outline-offset: 3px; }
@media (hover: hover) and (pointer: fine) {
  .swatch:has(.swatch__btn:hover) { translate: 0 -4px; }
}
.swatch { transition: translate var(--dur-2) var(--ease); }

/* 5) try-this-color bridge from the build */
.build__try { margin-top: 1.4rem; }

/* 6) before/after shutter on the real build's color */
.ba { margin-top: clamp(2rem, 1.5rem + 2vw, 3rem); }
.ba__caption {
  margin: 0 0 0.7rem;
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.ba__stage {
  position: relative;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  background: oklch(0.17 0 0);
  overflow: hidden;
}
.ba__stage img { width: 100%; }
.ba__film {
  position: absolute;
  inset: 0;
  /* same catalog token the hero car and the graphite tile use (3M M261) */
  background: var(--f-graphite);
  mix-blend-mode: multiply;
  -webkit-mask-image: url("assets/cars/bmw-x6-mask3.webp");
  mask-image: url("assets/cars/bmw-x6-mask3.webp");
  -webkit-mask-mode: luminance;
  mask-mode: luminance;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  clip-path: inset(0 0 0 var(--cut));
  pointer-events: none;
}
.ba__divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--cut);
  width: 2px;
  translate: -1px 0;
  background: var(--yellow);
  box-shadow: 0 0 12px rgba(255, 214, 0, 0.5);
  pointer-events: none;
}
.ba__divider::after {
  content: "\2194";
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  display: grid;
  place-items: center;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 50%;
  background: var(--yellow);
  color: var(--yellow-ink);
  font-size: 1rem;
  font-weight: 700;
}
.ba__tag {
  position: absolute;
  top: 0.7rem;
  padding: 0.3em 0.7em;
  font-weight: 700;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background: rgba(12, 12, 14, 0.75);
  border: 1px solid var(--line);
  border-radius: 999px;
  pointer-events: none;
}
.ba__tag--l { left: 0.7rem; }
.ba__tag--r { right: 0.7rem; }
.ba__range {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
}

/* 7) the submit button charges as the form fills */
.form__submit { position: relative; }
/* v45: the charging state must still read as THE primary action - a bare ghost
   outline made the final button look secondary next to the hero CTA (the
   number-one form complaint in the 2026-07-28 usability audit). Dimmed yellow,
   not gray: clearly the same button, clearly not done yet. */
.form__submit.is-charging {
  background: rgba(255, 214, 0, 0.16);
  color: var(--yellow);
  border-color: rgba(255, 214, 0, 0.45);
}
.form__submit.is-charging::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 3px;
  /* full-width bar scaled from the left edge: a compositor transform instead of
     an animated width (--fill is now a 0-1 scale, set by app.js) */
  width: 100%;
  transform: scaleX(var(--fill, 0));
  transform-origin: left center;
  background: var(--yellow);
  transition: transform 400ms var(--ease);
}
@keyframes chargepop { 0% { scale: 1; } 50% { scale: 1.045; } 100% { scale: 1; } }
.form__submit.is-ready { animation: chargepop 450ms var(--ease); }

/* 9) the tagline gets stamped as it passes center */
@keyframes stampflash {
  0% { background: transparent; color: var(--yellow); }
  25% { background: var(--yellow); color: var(--yellow-ink); }
  100% { background: transparent; color: var(--yellow); }
}
.ticker__hot.is-stamp { animation: stampflash 800ms var(--ease); border-radius: 4px; }

/* 10) exit-intent bar (desktop, once per session) */
.exitbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 130;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 0.8rem var(--gutter);
  background: var(--yellow);
  color: var(--yellow-ink);
  translate: 0 -100%;
  transition: translate 450ms var(--ease);
}
.exitbar.is-in { translate: 0 0; }
.exitbar__text { margin: 0; font-weight: 600; font-size: 0.98rem; }
.exitbar__text a { color: inherit; font-weight: 800; text-underline-offset: 3px; margin-inline-start: 0.4em; }
.exitbar__close {
  background: none;
  border: 0;
  color: inherit;
  font-size: 1rem;
  cursor: pointer;
  padding: 0.3em;
}
@media (prefers-reduced-motion: reduce) {
  .hero__h em.is-shine { animation: none; -webkit-text-fill-color: currentColor; background: none; }
  .build__grid .reveal { transition-delay: 0ms !important; }
  .ticker__hot.is-stamp { animation: none; }
  .exitbar { transition: none; }
  .form__submit.is-ready { animation: none; }
}

/* ---------- v33: split hero on wide screens - the car earns the first
   viewport instead of an empty right half. Pure layout, DOM untouched. ---------- */
@media (min-width: 1200px) {
  .hero {
    display: grid;
    grid-template-columns: minmax(30rem, 0.9fr) minmax(0, 1.1fr);
    column-gap: clamp(2rem, 3.5vw, 4rem);
    align-items: center;
    padding-bottom: clamp(1.5rem, 2vw, 3rem);
  }
  /* The split grid hands the headline a ~530px column; the stacked-layout
     6rem cap breaks the 3-line lockup into 6 lines and shoves the CTA below
     the fold. Re-clamp to what the column actually holds. */
  /* cap must respect the fixed --maxw column: past ~1470px the column stops
     growing, so the type must too, or "wrap studio" breaks the lockup */
  .hero__h { font-size: clamp(3rem, 1rem + 3.05vw, 3.8rem); }
  .hero__car { margin-top: 0; min-width: 0; }
  /* primary CTA takes its own row; the contact trio reads as one row below it.
     v44: column layout instead of flex-basis 100% - the button keeps its
     natural width, so the yellow reads as a button, not a taxi-grade banner. */
  .hero__actions { max-width: 34rem; flex-direction: column; align-items: flex-start; }
}

/* v34: contact trio as round icon buttons - SMS, Messenger, WhatsApp,
   each under its own logo; hover lights the brand color */
.hero__channels { display: inline-flex; align-items: center; gap: 0.85rem; }
.icon-btn {
  width: 3.3rem;
  height: 3.3rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--ink);
  background: oklch(0.17 0.005 260 / 0.6);
  transition: transform var(--dur-2) var(--ease), color var(--dur-2) var(--ease),
              border-color var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease);
}
.icon-btn svg { width: 1.6rem; height: 1.6rem; fill: currentColor; }
@media (hover: hover) and (pointer: fine) {
  .icon-btn:hover { transform: translateY(-2px); }
}
.icon-btn:active { transform: scale(0.94); }
.icon-btn--sms:hover  { color: #34c759; border-color: #34c759; }
.icon-btn--msgr:hover { color: #0084ff; border-color: #0084ff; }
.icon-btn--wa:hover   { color: #25d366; border-color: #25d366; }
.icon-btn:focus-visible { outline: 2px solid var(--yellow); outline-offset: 2px; }

/* v33: film-try button - swatch dot + label, replaces the bare ghost look */
.btn--film {
  border-color: var(--line);
  color: var(--ink);
  background: oklch(0.17 0.005 260 / 0.85);
}
@media (hover: hover) and (pointer: fine) {
  .btn--film:hover { border-color: var(--yellow); color: var(--yellow); transform: translateY(-2px); }
}
.btn--film:active { transform: scale(0.97); }
.btn__swatch {
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
  border-radius: 50%;
  border: 1px solid oklch(1 0 0 / 0.28);
  box-shadow: inset 0 1px 2px oklch(1 0 0 / 0.15);
}
.btn__swatch--graphite { background: linear-gradient(135deg, #43464c, #17181b 72%); }

/* entity statement: quiet, quotable, closes the page for humans and machines */
.book__entity {
  margin-top: clamp(2.5rem, 2rem + 2vw, 4rem);
  padding-top: 1.6rem;
  border-top: 1px solid var(--line-soft);
  font-size: 0.92rem;
  line-height: 1.6;
  color: var(--muted);
  max-width: 78ch;
}

/* v33: what-happens-next steps under the consult form */
.book__next {
  list-style: none;
  counter-reset: step;
  margin: 1.3rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.6rem;
}
.book__next li {
  counter-increment: step;
  position: relative;
  padding-inline-start: 2.15rem;
  font-size: 0.92rem;
  line-height: 1.45;
  color: var(--muted);
}
.book__next li::before {
  content: counter(step);
  position: absolute;
  inset-inline-start: 0;
  top: 0.05rem;
  width: 1.45rem;
  height: 1.45rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  font-family: var(--font-display);
  font-size: 0.8rem;
  color: var(--yellow);
}

/* ===== Reduced motion: interaction layer =====
   The signature entrances (hero, film wipe, reveals, ticker, stars, exit bar)
   are already gated by (prefers-reduced-motion: no-preference) or their own
   reduce blocks. This closes the remaining gap - the hover/press lifts and the
   toast/CTA travel - the Emil/Apple way: keep colour and opacity feedback, drop
   every positional move. Not zero motion, just no vestibular motion. */
@media (prefers-reduced-motion: reduce) {
  .btn--solid:hover, .btn--film:hover, .btn--film:active,
  .icon-btn:hover, .icon-btn:active,
  .btn:active,
  .swatch:hover,
  .swatch:has(.swatch__btn:hover) { transform: none; translate: 0 0; }

  .svc__name, .svc__desc { transition: none; }
  .svc__row:hover .svc__name,
  .svc__row:hover .svc__desc { transform: none; }

  /* film-name toast + configurator CTA: cross-fade in place, no rise */
  .car__toast { transition: opacity var(--dur-4) var(--ease); translate: 0 0; }
  .car__toast.is-show { translate: 0 0; }
  .filmbar__cta { transition: opacity 420ms var(--ease); translate: 0 0; }
  .filmbar__cta.is-in { translate: 0 0; }

  /* form charge bar: show the fill state without the animated sweep */
  .form__submit.is-charging::after { transition: none; }

  /* quick-contact bar: cross-fade in place instead of sliding up */
  .mbar { translate: 0 0; opacity: 0; transition: opacity var(--dur-3) var(--ease), visibility 0s var(--dur-3); }
  .mbar.is-on { opacity: 1; transition: opacity var(--dur-3) var(--ease); }
}

/* ---------- Mobile quick-contact bar (v44) ----------
   The page runs ~14 phone screens; after the hero the next contact control
   used to be the form at the very bottom. app.js flips .is-on once the hero
   scrolls away and drops it over the booking section. visibility (not
   aria-hidden) keeps the off-screen links out of the tab order. */
.mbar {
  position: fixed;
  inset: auto 0 0;
  z-index: 60;
  display: none;
  grid-template-columns: repeat(3, 1fr);
  background: rgba(12, 12, 14, 0.92);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
  visibility: hidden;
  translate: 0 110%;
  transition: translate var(--dur-3) var(--ease), visibility 0s var(--dur-3);
}
.mbar.is-on {
  visibility: visible;
  translate: 0 0;
  transition: translate var(--dur-3) var(--ease);
}
.mbar__link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  min-height: 54px;
  padding: 0 0.4rem;
  text-decoration: none;
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--ink);
}
.mbar__link + .mbar__link { border-inline-start: 1px solid var(--line-soft); }
.mbar__link:active { background: oklch(1 0 0 / 0.06); }
.mbar__link svg { width: 18px; height: 18px; fill: currentColor; flex: none; }
/* brand color on the glyph only: instant recognition, no yellow spent */
.mbar__link--msgr svg { fill: #0866ff; }
.mbar__link--wa svg { fill: #25d366; }
@media (max-width: 720px) {
  .mbar { display: grid; }
  /* the bar rides over the footer at the very bottom - clear its height */
  .footer { padding-bottom: calc(2rem + 54px + env(safe-area-inset-bottom)); }
}

/* ============================================================
   LEGAL + A11Y FURNITURE
   Skip link, cookie notice, trademark line. Added 2026-07-23 with
   the legal pass: none of it is decorative, all of it is required
   to be reachable by keyboard and readable at 200% zoom.
   ============================================================ */

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--accent, #ffd600);
  color: #0a0a0b;
  font-weight: 700;
  text-decoration: none;
  border-radius: 0 0 6px 0;
}
.skip-link:focus {
  left: 0;
  outline: 3px solid #fff;
  outline-offset: 2px;
}

.consent {
  position: fixed;
  left: 50%;
  bottom: max(1rem, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 120;
  width: min(720px, calc(100vw - 2rem));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
  padding: 0.9rem 1.1rem;
  background: rgba(18, 18, 20, 0.97);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 12px;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(8px);
}
.consent[hidden] { display: none; }
.consent__text {
  flex: 1 1 20rem;
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.78);
}
.consent__text a { color: #fff; text-decoration: underline; }
.consent__btns { display: flex; gap: 0.5rem; margin-left: auto; }
.consent__btn {
  font: inherit;
  font-size: 0.82rem;
  font-weight: 700;
  padding: 0.55rem 1.1rem;
  border-radius: 8px;
  cursor: pointer;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: transparent;
  color: rgba(255, 255, 255, 0.82);
  transition: background 160ms ease, color 160ms ease, border-color 160ms ease;
}
.consent__btn--ok {
  background: var(--accent, #ffd600);
  border-color: var(--accent, #ffd600);
  color: #0a0a0b;
}
.consent__btn:hover { border-color: #fff; color: #fff; }
.consent__btn--ok:hover { background: #fff; border-color: #fff; color: #0a0a0b; }
.consent__btn:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }

/* The trademark line is legal text: quiet on purpose, but it still has to be
   readable. At 0.7rem it counts as small text, so WCAG wants 4.5:1 and 0.38
   alpha only reached 3.5:1 over --bg (axe 4.12.1, 2026-07-27). 0.5 composites
   to about #808080 on the studio black: ~5:1, with headroom. Do not dial it
   back down to "make it whisper" - that is what failed the audit. */
.footer__tm {
  grid-column: 1 / -1;
  max-width: 70ch;
  font-size: 0.7rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.5);
}

@media (max-width: 560px) {
  .consent { gap: 0.6rem; padding: 0.85rem 0.95rem; }
  .consent__btns { width: 100%; margin-left: 0; }
  .consent__btn { flex: 1 1 auto; }
}

/* ============================================================
   Service pages hub-and-spoke (/color-change-wrap-naples/
   /chrome-delete-naples/ /fleet-wraps-naples/): home-page hooks
   only. Page-local layout lives in service.css, loaded only on
   those pages.
   ============================================================ */
.svc__name a { color: inherit; text-decoration: none; }
.svc__name a::after {
  content: " \2192";
  color: var(--yellow);
  opacity: 0;
  transition: opacity var(--dur-3) var(--ease);
}
.svc__row:hover .svc__name a::after,
.svc__name a:focus-visible::after { opacity: 1; }
.svc__name a:hover { color: var(--yellow); }

.footer__svcs { display: flex; gap: 1.4rem; flex-wrap: wrap; }
.footer__svcs a { color: var(--muted); text-decoration: none; }
.footer__svcs a:hover { color: var(--yellow); }

/* ============================================================
   v45 - usability round, 2026-07-28 (audit: cookie/mbar conflict,
   charging submit, Make->Model split, touch targets, lightbox meta)
   ============================================================ */

/* Finish-class tabs are primary controls on the phone: give the finger a
   44px row (WCAG 2.5.8 wants 24 minimum, 44 is the comfortable standard).
   max-width joins pointer:coarse because narrow desktop windows and viewport
   emulators report a fine pointer while behaving like phones. */
@media (pointer: coarse), (max-width: 720px) {
  .films__tab { min-height: 44px; padding-block: 0.5em; }
}

/* Frame counter + caption under the lightbox photo. aria-hidden in the DOM:
   the img alt already says the same thing to screen readers. */
.lightbox__meta {
  position: absolute;
  left: 50%;
  bottom: max(0.9rem, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  display: flex;
  gap: 0.7rem;
  align-items: baseline;
  max-width: min(84vw, 64ch);
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.75);
}
.lightbox__count { font-weight: 700; color: #fff; flex: none; }
.lightbox__cap { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* v46: proof row in Reviews - one real Google quote + the owner at work */
.reviews__proof {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: 1rem;
  align-items: stretch;
  max-width: 46rem;
  margin: 1.6rem auto 1.8rem;
  text-align: start;
}
.reviews__quote {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  padding: 1.1rem 1.2rem;
  background: oklch(0.19 0 0 / 0.5);
  border: 1px solid var(--line);
  border-radius: 12px;
}
.reviews__quote-stars { margin: 0; color: var(--yellow); letter-spacing: 0.18em; font-size: 0.8rem; }
.reviews__quote-text { margin: 0; font-size: 1.12rem; line-height: 1.6; color: var(--ink); }
.reviews__quote-by {
  margin-top: auto;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1rem;
  justify-content: space-between;
  font-size: 0.82rem;
  color: var(--muted);
}
.reviews__quote-by a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 3px; min-height: 44px; display: inline-flex; align-items: center; }
.reviews__quote-by a:hover { color: var(--yellow); }
.reviews__owner {
  margin: 0;
  position: relative;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--line);
  /* cap the photo so the quote card next to it never stretches into dead air */
  max-height: 400px;
}
.reviews__owner img { display: block; width: 100%; height: 100%; object-fit: cover; }
.reviews__owner figcaption {
  position: absolute;
  inset: auto 0 0;
  padding: 2rem 0.9rem 0.8rem;
  background: linear-gradient(to top, rgba(10, 10, 11, 0.94), transparent);
  display: grid;
  gap: 0.15rem;
  text-align: start;
}
.reviews__owner strong { color: var(--ink); font-size: 0.92rem; }
.reviews__owner span { color: var(--ink-2); font-size: 0.78rem; line-height: 1.45; }
@media (max-width: 720px) {
  .reviews__proof { grid-template-columns: 1fr; max-width: 28rem; }
  .reviews__owner img { aspect-ratio: 4 / 5; height: auto; }
}
