/* main.css: Carabao storefront components.
   Visual world: layered lacquer blacks, bone ink, red as the single action
   colour, gilt yellow for figures and focus (client brief, 2026-11-11 —
   supersedes the monochrome palette in DESIGN.md; token architecture kept).
   Every interactive component documents its required states:
   default / hover / focus-visible / active / disabled / loading / error.
   Colours, radii, shadows, motion and the type/spacing scales all come from
   tokens.css via semantic aliases. Two documented exceptions, both confined
   to the sanctioned alias block below:
   1. derived calc()/clamp() aliases that keep the token scale as the source
      of truth for macro layout dimensions and display type;
   2. standard typographic weights and letter-spacing values, which are
      styling parameters the token set does not express.
   Surfaces separate by tone steps, never lines or shadows; corners are
   square, decided once. */

/* ---------- Semantic aliases ---------- */
:root {
  /* Surfaces: layered blacks */
  --color-surface-page: var(--color-black-900);
  --color-surface-raised: var(--color-black-800);
  --color-surface-input: var(--color-black-700);
  --color-surface-deep: var(--color-black-950);

  /* Ink */
  --color-ink: var(--color-bone);
  --color-ink-muted: var(--color-bone-muted);
  --color-ink-on-action: var(--color-bone);         /* text on red fill */
  --color-ink-on-highlight: var(--color-black-950); /* text on yellow fill */

  /* Accents: red owns the action, yellow owns figures + focus */
  --color-action: var(--color-red);
  --color-action-hover: var(--color-red-deep);
  --color-error-text: var(--color-red-bright);
  --color-highlight: var(--color-yellow);

  --border-field: 1px solid var(--color-line);

  /* Derived spacing: macro layout sizes the 2–12.8px token scale cannot
     express directly; each is a whole-number multiple of a token. */
  --space-gap: calc(var(--space-8) * 2);            /* 25.6px component gap */
  --space-gap-lg: calc(var(--space-8) * 3);         /* 38.4px grid gap */
  --space-block: calc(var(--space-8) * 4);          /* 51.2px block gaps */
  --space-section: clamp(calc(var(--space-8) * 9), 12vw, calc(var(--space-8) * 14));
  --container: 1240px;                              /* page measure (macro layout) */
  --frame: clamp(16px, 4vw, 56px);                  /* equal outer margins */
  --measure: 52ch;                                  /* supporting-copy measure */
  --header-h: calc(var(--space-8) * 5);             /* 64px sticky header */
  --promo-h: calc(var(--space-8) * 2.5);            /* 32px promo strip atop the header */
  --target: 48px;                                   /* ≥ WCAG 2.5.8 touch target */

  --reveal-delay: 0ms;                              /* default; JS staggers siblings */
  --ease: var(--ease-out);
}

/* ---------- Minimal reset ---------- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-family-primary);
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-base);
  line-height: var(--font-line-height-base);
  color: var(--color-ink);
  background: var(--color-surface-page);
  -webkit-font-smoothing: antialiased;
}
img { display: block; max-width: 100%; height: auto; }
h1, h2, h3, p, ul, figure { margin: 0; }
ul { padding: 0; list-style: none; }
a { color: inherit; }
section { scroll-margin-top: calc(var(--header-h) + var(--promo-h) + var(--space-8)); }
h1, h2, h3 { text-wrap: balance; }

/* Browser surfaces: themed, not defaulted */
::selection { background: var(--color-highlight); color: var(--color-ink-on-highlight); }
::-webkit-scrollbar { width: 12px; }
::-webkit-scrollbar-track { background: var(--color-surface-page); }
::-webkit-scrollbar-thumb { background: var(--color-surface-input); }
html { scrollbar-color: var(--color-surface-input) var(--color-surface-page); }

/* focus-visible: 2px gilt offset outline (WCAG 2.2 AA); gilt reads on every
   surface in this system, including the red action fills */
:focus-visible { outline: 2px solid var(--color-highlight); outline-offset: 3px; }

/* ---------- Layout ---------- */
.container {
  width: min(var(--container), 100% - var(--frame) * 2);
  margin-inline: auto;
}

/* ---------- Skip link ---------- */
/* default: off-canvas | focus-visible: pinned top, yellow slab, ink text */
.skip-link {
  position: absolute;
  top: calc(var(--space-8) * -4);
  left: var(--space-5);
  z-index: 10;
  padding: var(--space-4) var(--space-5);
  background: var(--color-highlight);
  color: var(--color-ink-on-highlight);
  font-weight: 600;
  text-decoration: none;
  transition: top var(--motion-fast) var(--ease);
}
.skip-link:focus-visible { top: var(--space-5); }

/* ---------- Visually hidden ---------- */
/* Screen-reader-only copy (e.g. the static text behind the promo marquee) */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- Promo strip ---------- */
/* Red marquee pinned above the header row inside the sticky header, so the
   sale stays in view while scrolling. The moving track is decoration
   (aria-hidden in markup); screen readers read the .visually-hidden static
   copy instead.
   default: red fill, bone ink | states: n/a — non-interactive content
   shortcut: 6 repeats per group cover viewports to ~4400px; wider screens
   would see the loop seam — bump the repeat count if that ever matters. */
.promo-strip {
  display: flex;
  align-items: center;
  min-height: var(--promo-h);
  overflow: hidden;
  background: var(--color-action);
  color: var(--color-ink-on-action);
}
.promo-strip__track {
  display: flex;
  width: max-content;
  /* 40s loop: content pacing, not a UI-state duration — outside the token scale */
  animation: promo-marquee 40s linear infinite;
}
.promo-strip__group { display: flex; flex: none; }
.promo-strip__text {
  padding-inline: var(--space-gap-lg);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
}
@keyframes promo-marquee { to { transform: translateX(-50%); } }

/* ---------- Header + primary nav ---------- */
/* Floats over the page on the deepest tone step: no border line. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--color-surface-deep);
}
.header-inner {
  display: flex;
  align-items: center;
  gap: var(--space-gap-lg);
  min-height: var(--header-h);
}
/* nav link: default: bone, invisible underline | hover: gilt underline
   focus-visible: outline | active: muted ink | disabled: n/a (static links) */
.brand {
  font-size: var(--text-md);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-decoration: none;
  transition: color var(--motion-fast) var(--ease);
}
.brand:hover { color: var(--color-highlight); }
.site-nav ul {
  display: flex;
  gap: var(--space-gap-lg);
}
.site-nav a {
  display: block;
  padding: var(--space-4) var(--space-2);
  font-size: var(--text-md);
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 6px;
  transition:
    text-decoration-color var(--motion-fast) var(--ease),
    color var(--motion-fast) var(--ease);
}
.site-nav a:hover { text-decoration-color: var(--color-highlight); }
.site-nav a:active { color: var(--color-ink-muted); }
.header-cta { margin-left: auto; }

/* nav toggle: raised tonal fill | hover: input fill, gilt text
   focus-visible: outline | active: press
   [aria-expanded="true"]: red fill */
.nav-toggle {
  display: none;
  margin-left: auto;
  min-height: var(--target);
  padding: var(--space-4) var(--space-5);
  border: 0;
  border-radius: var(--radius-0);
  background: var(--color-surface-raised);
  color: var(--color-ink);
  font: inherit;
  font-size: var(--text-md);
  font-weight: 600;
  cursor: pointer;
  transition:
    background-color var(--motion-fast) var(--ease),
    color var(--motion-fast) var(--ease);
}
.nav-toggle:hover { background: var(--color-surface-input); color: var(--color-highlight); }
.nav-toggle:active { background: var(--color-surface-raised); }
.nav-toggle[aria-expanded="true"] {
  background: var(--color-action);
  border-color: var(--color-action);
  color: var(--color-ink-on-action);
}

@media (max-width: 719px) {
  .nav-toggle { display: block; }
  .site-nav {
    display: none;
    position: absolute;
    inset: calc(var(--header-h) + var(--promo-h)) 0 auto 0;
    background: var(--color-surface-raised);
    box-shadow: var(--shadow-float); /* floating menu overlay, sanctioned */ /* taste-skill-ignore */
  }
  .site-nav.is-open { display: block; }
  .site-nav ul { flex-direction: column; gap: 0; padding: var(--space-4) 0; }
  .site-nav a { padding: var(--space-5) var(--space-8); }
  .site-header .header-cta { display: none; } /* beats the later .button display rule */
}

/* ---------- Buttons ---------- */
/* Button: flat red fill, square corners, no elevation at any state.
   default: red fill, bone text
   hover: deep red + 1px lift (motion-fast)
   focus-visible: 2px gilt outline
   active: 1px press, no lift
   disabled / [aria-disabled="true"]: 40% opacity, no hover, not-allowed
   loading (.is-loading + aria-busy): label hidden, 16px spinner, input blocked
   error: n/a: errors surface on fields/notices, never on the button itself */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--target);
  padding: calc(var(--space-8) * 1.1) calc(var(--space-8) * 2.5);
  border: 0;
  border-radius: var(--radius-0);
  font-family: inherit;
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  background: var(--color-action);
  color: var(--color-ink-on-action);
  transition:
    transform var(--motion-fast) var(--ease),
    background-color var(--motion-fast) var(--ease),
    color var(--motion-fast) var(--ease),
    border-color var(--motion-fast) var(--ease);
}
.button:hover { background: var(--color-action-hover); transform: translateY(-1px); }
.button:active { transform: translateY(1px); }
.button:disabled,
.button[aria-disabled="true"] { opacity: 0.4; cursor: not-allowed; transform: none; }
.button.is-loading { color: transparent; pointer-events: none; position: relative; }
.button.is-loading::after {
  content: "";
  position: absolute;
  width: 16px;
  height: 16px;
  border: 2px solid var(--color-ink-on-action);
  border-top-color: transparent;
  border-radius: var(--radius-round);
  animation: spin var(--motion-step6) linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Variants */
/* ghost (tonal): raised fill | hover: input fill + 1px lift
   focus-visible: gilt outline | active: press */
.button--ghost {
  background: var(--color-surface-raised);
  color: var(--color-ink);
}
.button--ghost:hover { background: var(--color-surface-input); }
.button--block { width: 100%; }
.button--sm { font-size: var(--text-base); min-height: calc(var(--target) * 0.82); }

/* ---------- Hero ---------- */
/* The photo IS the section: full-bleed under a neutral scrim (the one
   sanctioned gradient: text over a photograph). Content rides the dark left
   side; the image settles from 1.06 on load (the signature move).
   default: deep tone behind photo, bone ink | focusable children: gilt
   outlines | motion: photo settle + staggered entrances, none blocking */
.hero {
  position: relative;
  overflow: hidden;
  background: var(--color-surface-deep);
}
.hero-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: hero-drift var(--motion-gesture) var(--ease) both;
}
/* scrim values mirror black-950 at photographic overlay opacities; kept as
   rgba here because they are image-legibility treatment, not surface colour
   (neutral scrim over a photo: the sanctioned gradient exception) */
.hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, rgba(7, 6, 5, 0.86) 12%, rgba(7, 6, 5, 0.58) 50%, rgba(7, 6, 5, 0.2) 100%); /* taste-skill-ignore */
}
.hero-inner {
  position: relative;
  display: grid;
  align-items: center;
  min-height: min(92vh, 820px);
  padding-block: calc(var(--space-section) * 0.9);
  grid-template-columns: 1fr;
}
.hero-copy { max-width: 620px; }
.hero-title {
  font-family: var(--font-family-display);
  font-size: var(--text-display-1);
  font-weight: 600;
  line-height: 1.02;
  letter-spacing: -0.02em;
}
.hero-sub {
  margin-top: var(--space-block);
  max-width: var(--measure);
  font-size: var(--text-lg);
  line-height: 1.6;
  color: var(--color-ink);
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-gap);
  margin-top: var(--space-block);
}
@keyframes hero-drift { from { transform: scale(1.06); } to { transform: scale(1); } }

/* ---------- Sections ---------- */
/* Backdrops alternate black and bone for section contrast; tone steps and
   space separate content, never lines. Rhythm runs 115:179px. */
.section { padding-block: var(--space-section); }
.section--alt { background: var(--color-surface-raised); }

/* Light backdrop: re-scopes the semantic aliases so every component below
   adapts untouched. Focus falls back to red here (gilt on bone fails 3:1);
   error text falls to deep red (bright red fails 4.5:1 on light). */
.section--light {
  background: var(--color-surface-light);
  color: var(--color-black-800);
  --color-ink: var(--color-black-800);
  --color-ink-muted: var(--color-taupe-deep);
  --color-highlight: var(--color-gold-deep);
  --color-surface-raised: var(--color-surface-light-raised);
  --color-surface-input: var(--color-surface-light-input);
  --color-error-text: var(--color-red-deep-text);
  --border-field: 1px solid var(--color-line-light);
}
.section--light :focus-visible { outline-color: var(--color-action); }

.section-title {
  font-family: var(--font-family-display);
  font-size: var(--text-display-2);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.015em;
}
.section-sub {
  margin-top: calc(var(--space-8) * 2);
  max-width: 56ch;
  color: var(--color-ink-muted);
  font-size: var(--text-lg);
}

/* ---------- Product cards ---------- */
/* No boxed cards: the studio-grey photo tiles are the surfaces; text hangs
   free beneath. Card: hover: media zooms 4% | focus-visible: via children
   (link/button) | disabled/loading/error: buy button carries its own states.
   Long content: desc clamps at 2 lines. Empty lineup: use .empty block. */
.product-grid {
  display: grid;
  gap: var(--space-block) var(--space-gap-lg);
  grid-template-columns: 1fr;
  margin-top: calc(var(--space-block) * 1.5);
}
@media (min-width: 640px) { .product-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .product-grid { grid-template-columns: repeat(3, 1fr); } }

.product-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-gap);
}
.product-media {
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--color-surface-input);
}
.product-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--motion-gesture) var(--ease);
}
.product-card:hover .product-media img { transform: scale(1.04); }
.product-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  flex: 1;
}
.product-name {
  font-family: var(--font-family-display);
  font-size: var(--text-2xl);
  font-weight: 600;
  line-height: 1.15;
}
/* sentence case at a readable size: no uppercase tracking */
.product-specs { font-size: var(--text-md); color: var(--color-ink-muted); }
.product-desc {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: var(--text-base);
  color: var(--color-ink-muted);
}
.product-cta { margin-top: auto; display: grid; gap: var(--space-3); }
/* figures carry the gilt: tabular numerals so prices align */
.product-price {
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--color-highlight);
  font-variant-numeric: tabular-nums;
}
.product-price small {
  font-size: var(--text-sm);
  font-weight: 400;
  color: var(--color-ink-muted);
}

/* Empty-state fallback if the grid ever renders with no products */
.empty {
  margin-top: calc(var(--space-block) * 1.5);
  padding: calc(var(--space-block) * 1.5);
  background: var(--color-surface-raised);
  text-align: center;
  color: var(--color-ink-muted);
}

/* ---------- Feature rows ---------- */
/* Editorial rows, not icon cards: photo tile left, serif claim + proof right.
   Row hover: media zooms 3% (subtle, transform only). */
.feature-list {
  display: grid;
  gap: calc(var(--space-block) * 1.4);
  margin-top: calc(var(--space-block) * 1.5);
}
.feature-row { display: grid; gap: var(--space-gap-lg); grid-template-columns: 1fr; align-items: center; }
@media (min-width: 860px) {
  .feature-row { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); }
}
.feature-media {
  overflow: hidden;
  aspect-ratio: 3 / 2;
  background: var(--color-surface-input);
}
.feature-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--motion-gesture) var(--ease);
}
.feature-row:hover .feature-media img { transform: scale(1.03); }
.feature-row h3 {
  font-family: var(--font-family-display);
  font-size: var(--text-2xl);
  font-weight: 600;
  line-height: 1.15;
}
.feature-row p { color: var(--color-ink); max-width: 60ch; margin-top: var(--space-gap); }

/* ---------- Support ---------- */
/* Two columns on desktop so the section never lopsides. */
.support-grid { display: grid; gap: var(--space-block); grid-template-columns: 1fr; }
@media (min-width: 960px) {
  .support-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; }
}

/* ---------- Form field ---------- */
/* Field: input default: input surface, line border | hover: muted-ink border
   focus-visible: gilt outline | disabled: raised bg, muted text, not-allowed
   error: [aria-invalid="true"] 2px red border + red-bright bold message
   (colour backed by shape + weight, never colour alone). Caret is gilt. */
.field { display: grid; gap: var(--space-3); max-width: var(--measure); }
.field-label { font-size: var(--text-base); font-weight: 600; }
.field-hint { font-size: var(--text-sm); color: var(--color-ink-muted); }
.field-input {
  min-height: var(--target);
  padding: var(--space-5) var(--space-gap);
  border: var(--border-field);
  border-radius: var(--radius-0);
  background: var(--color-surface-input);
  color: var(--color-ink);
  caret-color: var(--color-highlight);
  font: inherit;
  font-size: var(--text-base);
  transition:
    border-color var(--motion-fast) var(--ease),
    background-color var(--motion-fast) var(--ease);
}
.field-input::placeholder { color: var(--color-ink-muted); }
.field-input:hover { border-color: var(--color-ink-muted); }
.field-input:disabled {
  background: var(--color-surface-raised);
  color: var(--color-ink-muted);
  cursor: not-allowed;
}
.field-input[aria-invalid="true"] {
  border: 2px solid var(--color-action);
  padding: calc(var(--space-5) - 1px) calc(var(--space-gap) - 1px);
}
.field-error { display: none; font-size: var(--text-md); font-weight: 600; color: var(--color-error-text); }
.field-input[aria-invalid="true"] + .field-error { display: block; }

/* ---------- Notices (status / error) ---------- */
/* Entrance: settles in when unhidden (display toggle restarts the
   animation); reduced motion collapses it via the global override. */
.notice {
  padding: var(--space-5) var(--space-gap);
  border-radius: var(--radius-0);
  background: var(--color-surface-raised);
  font-size: var(--text-base);
  font-weight: 500;
  animation: notice-in var(--motion-normal) var(--ease);
}
@keyframes notice-in { from { opacity: 0; transform: translateY(calc(var(--space-8) * -0.5)); } }
.notice[hidden] { display: none; }
.notice--form { margin-top: var(--space-gap); }

/* ---------- Footer ---------- */
/* A designed close: the name returns at full width, serif. */
.footer {
  background: var(--color-surface-deep);
  color: var(--color-ink);
  padding-block: var(--space-section) calc(var(--space-section) * 0.55);
}
.footer-wordmark {
  font-family: var(--font-family-display);
  font-size: clamp(64px, 11vw, 168px);
  font-weight: 600;
  line-height: 0.95;
  letter-spacing: -0.02em;
}
/* footer link: same contract as nav links */
.footer-nav { display: flex; flex-wrap: wrap; gap: var(--space-gap-lg); margin-top: var(--space-block); }
.footer-nav a {
  font-size: var(--text-md);
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 6px;
  transition:
    text-decoration-color var(--motion-fast) var(--ease),
    color var(--motion-fast) var(--ease);
}
.footer-nav a:hover { text-decoration-color: var(--color-highlight); }
.footer-nav a:active { color: var(--color-ink-muted); }
.footer-credits {
  margin-top: var(--space-block);
  max-width: 62ch;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}
.footer-legal {
  margin-top: var(--space-gap);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

/* ---------- Sale modal ---------- */
/* Black Friday announcement opened by JS shortly after initial load (the
   hero settles first); hidden by default so it stays out of the
   accessibility tree and invisible without JavaScript.
   default: scrim over page + raised panel; focus-visible: gilt outlines
   close: Escape / backdrop / close button / CTA (focus returns to page)
   states: n/a — the CTA is the standard .button; long content: panel scrolls */
.sale-modal {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: var(--frame);
}
.sale-modal[hidden] { display: none; }
.sale-modal__backdrop {
  position: absolute;
  inset: 0;
  background: var(--color-surface-deep);
  opacity: 0.78;
  animation: fade-in var(--motion-slower) var(--ease);
}
.sale-modal__panel {
  position: relative;
  width: min(520px, 100%);
  max-height: 100%;
  overflow-y: auto;
  padding: calc(var(--space-8) * 3);
  background: var(--color-surface-raised);
  box-shadow: var(--shadow-float); /* floating dialog, sanctioned */
  animation: modal-in var(--motion-slower) var(--ease);
}
.sale-modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-gap);
}
.sale-modal__eyebrow {
  padding: var(--space-2) var(--space-5);
  background: var(--color-action);
  color: var(--color-ink-on-action);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
/* close: transparent on the panel | hover: gilt | focus-visible: gilt outline
   | active/disabled/loading/error: n/a */
.sale-modal__close {
  flex: none;
  min-width: var(--target);
  min-height: var(--target);
  margin-right: calc(var(--space-8) * -2);
  border: 0;
  background: transparent;
  color: var(--color-ink-muted);
  font-size: var(--text-xl);
  line-height: 1;
  cursor: pointer;
  transition: color var(--motion-fast) var(--ease);
}
.sale-modal__close:hover { color: var(--color-highlight); }
.sale-modal__title {
  margin-top: var(--space-gap);
  font-family: var(--font-family-display);
  font-size: var(--text-2xl);
  font-weight: 600;
  line-height: 1.15;
}
/* Carousel: one item at a time, scrolled horizontally. Native scroll-snap
   carries touch swipes; arrows and dots scroll to a slide; the track's
   scroll position is the single source of truth for dot + live status.
   arrows: default: input fill, bone ink | hover: gilt ink | active: 1px press
   | disabled: 40% opacity, not-allowed | focus-visible: gilt outline
   dots: 48px targets, 11px square marker | hover/active: gilt | disabled: n/a */
.sale-carousel { margin-top: var(--space-gap-lg); }
.sale-carousel__track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.sale-carousel__track::-webkit-scrollbar { display: none; }
.sale-carousel__slide {
  flex: 0 0 100%;
  display: grid;
  grid-template-columns: min(calc(var(--space-8) * 12), 40%) 1fr;
  gap: var(--space-gap-lg);
  align-items: center;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.sale-carousel__slide img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  background: var(--color-surface-input);
}
.sale-carousel__name {
  font-family: var(--font-family-display);
  font-size: var(--text-2xl);
  font-weight: 600;
  line-height: 1.15;
}
.sale-carousel__price {
  margin-top: var(--space-3);
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--color-highlight);
  font-variant-numeric: tabular-nums;
}
.sale-carousel__controls {
  margin-top: var(--space-8);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
}
.sale-carousel__arrow {
  min-width: var(--target);
  min-height: var(--target);
  border: 0;
  background: var(--color-surface-input);
  color: var(--color-ink);
  font-family: inherit;
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
  transition:
    transform var(--motion-fast) var(--ease),
    background-color var(--motion-fast) var(--ease),
    color var(--motion-fast) var(--ease);
}
.sale-carousel__arrow:hover { color: var(--color-highlight); }
.sale-carousel__arrow:active { transform: translateY(1px); }
.sale-carousel__arrow:disabled { opacity: 0.4; cursor: not-allowed; }
.sale-carousel__dots { display: flex; }
.sale-carousel__dot {
  display: grid;
  place-items: center;
  width: var(--target);
  height: var(--target);
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}
.sale-carousel__dot::before {
  content: "";
  width: var(--space-7);
  height: var(--space-7);
  background: var(--color-ink-muted);
  transition: background-color var(--motion-fast) var(--ease);
}
.sale-carousel__dot:hover::before { background: var(--color-highlight); }
.sale-carousel__dot[aria-current="true"]::before { background: var(--color-highlight); }
.sale-modal__code {
  margin-top: calc(var(--space-8) * 2);
  font-size: var(--text-md);
  color: var(--color-ink-muted);
}
.sale-modal__code strong {
  display: inline-block;
  margin-left: var(--space-2);
  padding: var(--space-2) var(--space-5);
  background: var(--color-highlight);
  color: var(--color-ink-on-highlight);
  font-weight: 700;
  letter-spacing: 0.08em;
}
.sale-modal__cta { margin-top: var(--space-gap); }
@keyframes fade-in { from { opacity: 0; } }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(calc(var(--space-block) * 0.5)) scale(0.98); }
}

/* ---------- Reveal (opt-in via JS; skipped under reduced motion) ---------- */
/* JS finds [data-reveal] and adds .reveal before observing: markup never
   carries .reveal, so content stays visible with JavaScript disabled.
   Sibling groups stagger via --reveal-delay, set by JS. */
.reveal {
  opacity: 0;
  transform: translateY(calc(var(--space-block) * 0.5));
}
.reveal.is-visible {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--motion-slower) var(--ease),
    transform var(--motion-slower) var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  .reveal { opacity: 1; transform: none; }
  .promo-strip__track { animation: none; } /* freeze the marquee: loop shows statically */
}
