/* =========================================================================
   RedPlum Games - shared site styles
   Loaded by every page: tokens, layout primitives, buttons, header, footer,
   the card system and every section component. Page-only styles live in
   their own file after this one (home.css holds the 3D stage and acts).
   Every colour, size, radius and duration below resolves to a token.
   ========================================================================= */

@import url("tokens/fonts.css");
@import url("tokens/color.css");
@import url("tokens/type.css");
@import url("tokens/space.css");
@import url("tokens/effects.css");
@import url("tokens/base.css");

/* ---------- Page-level additions ------------------------------------- */
:root {
  /* One step above display-xl. The brief asks for large type; this is the
     only size added to the DS scale and it is used once, in the hero. */
  --fs-display-2xl: clamp(46px, 8.2vw, 124px);
  --text-display-2xl: var(--fw-extrabold) var(--fs-display-2xl) / 0.94 var(--font-sans);

  /* The mark gradient - the warm end of the signature ramp, compressed for
     small surfaces so chips and icon tiles read as one family. It starts at
     a deep orange rather than the brand amber because the label on top is
     white and has to clear 4.5:1 across the whole sweep: white on amber-400
     is 1.9:1, which the system rules out outright ("never white on amber").
     This sweep is 5.2:1 at its lightest point and 9.1:1 at its darkest. */
  --gradient-mark: linear-gradient(135deg, #C2410C 0%, var(--red-500) 65%, var(--red-700) 100%);

  /* The stage the product renders sit on: a soft warm studio sweep built
     from the system's own light surfaces, white at the top falling to
     surface-sunken at the floor. The home stage and .section--hero share it. */
  --stage-bg: #EFEBE5;
  --stage-bg-2: #FFFFFF;
}

/* In-page links glide, but only once the page has loaded (site.js sets
   data-loaded). Arriving on a URL with an #anchor has to jump, not glide:
   a glide aims at where the target was before the web fonts reflowed the
   page, and lands short of it. */
:root[data-loaded] { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  :root[data-loaded] { scroll-behavior: auto; }
}

body { overflow-x: hidden; }

/* ---------- Layout primitives ---------------------------------------- */
.rail      { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); }
.rail-wide { width: 100%; max-width: var(--container-wide); margin-inline: auto; padding-inline: var(--gutter); }
.section   { padding-block: var(--section-y); }
.section--tight { padding-block: var(--section-y-tight); }
.section--sunken { background: var(--surface-sunken); }
.section--subtle { background: var(--surface-subtle); }

/* ---------- Hero ground ------------------------------------------------
   The home stage's ground for every inner-page hero that has no background
   image of its own (text-only heroes and the kiosk, cabinet and software
   product heroes; game pages keep their blurred key art): the same warm
   studio sweep, pulled up under the floating header so the page starts on
   it, and the same halftone dust. On home the dust gathers on the floor
   under the product; here it gathers in the right-hand column, behind the
   product render where there is one, and fades out well before the
   copy. Same deeper amber as home, for the same reason (the token's
   amber does not resolve on a near-white ground).
   Both layers are pseudo-elements that reach up under the header, so the
   class never touches the hero's own padding and works on any hero
   (.section, .product-hero, ...). The sweep settles back to the page
   colour at the bottom, so a white section can follow without a seam.
   The games hub and collection heroes take it by their own class rather
   than by .section--hero, because sync_games.py writes those pages and
   matches their <section> tags exactly. */
.section--hero, .games-hero, .collection-hero { position: relative; isolation: isolate; }
:is(.section--hero, .games-hero, .collection-hero)::before,
:is(.section--hero, .games-hero, .collection-hero)::after {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset: calc(-1 * (var(--header-h) + 12px)) 0 0;
}
:is(.section--hero, .games-hero, .collection-hero)::before {
  background:
    linear-gradient(180deg, transparent 58%, var(--surface-page) 100%),
    radial-gradient(125% 95% at 50% 8%, var(--stage-bg-2) 0%, var(--stage-bg) 74%);
}
:is(.section--hero, .games-hero, .collection-hero)::after {
  background-image: radial-gradient(rgba(168,113,0,.42) 1.5px, transparent 1.6px);
  background-size: var(--motif-halftone-size);
  opacity: .8;
  -webkit-mask-image: radial-gradient(44% 62% at 82% 56%, #000 0%, #000 22%, transparent 74%);
  mask-image: radial-gradient(44% 62% at 82% 56%, #000 0%, #000 22%, transparent 74%);
}
/* One column: the copy runs full width, so the dust drops to a low band
   under it instead of sitting behind the text, ending before the hero
   does. A product hero stacks its render on top, so there the dust
   gathers round the product instead, as it does on home. */
@media (max-width: 720px) {
  :is(.section--hero, .games-hero, .collection-hero)::after {
    -webkit-mask-image: radial-gradient(80% 13% at 72% 89%, #000 0%, transparent 78%);
    mask-image: radial-gradient(80% 13% at 72% 89%, #000 0%, transparent 78%);
  }
  .product-hero.section--hero::after {
    -webkit-mask-image: radial-gradient(70% 18% at 62% 26%, #000 0%, transparent 76%);
    mask-image: radial-gradient(70% 18% at 62% 26%, #000 0%, transparent 76%);
  }
}

.eyebrow {
  display: inline-flex; align-items: center;
  font: var(--text-overline); letter-spacing: var(--ls-overline);
  text-transform: uppercase; color: var(--text-accent);
}
.eyebrow--inverse { color: var(--amber-300); }

.display-lg { font: var(--text-display-lg); letter-spacing: var(--ls-display); text-wrap: balance; }
.display-md { font: var(--text-display-md); letter-spacing: var(--ls-display); text-wrap: balance; }
.lead { font: var(--text-lead); color: var(--text-secondary); text-wrap: pretty; }
.lead--inverse { color: var(--text-on-dark-dim); }
.mono { font: var(--text-spec); font-variant-numeric: tabular-nums; }
/* Keeps a model name like "F600-V" from breaking at its hyphen in a heading. */
.nowrap { white-space: nowrap; }

/* ---------- Buttons --------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: var(--control-h); padding-inline: var(--control-pad-x);
  font: var(--text-button); letter-spacing: -.005em;
  border-radius: var(--radius-sm); border: 1px solid transparent;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: var(--transition-control);
}
.btn:hover { text-decoration: none; }
.btn--lg { height: var(--control-h-lg); padding-inline: 28px; font-size: var(--fs-body); gap: 10px; }
.btn--primary { background: var(--action-primary); color: var(--text-on-brand); }
.btn--primary:hover { background: var(--action-primary-hover); color: var(--text-on-brand); }
.btn--primary:active { background: var(--action-primary-active); }
.btn--outline { background: transparent; color: var(--text-primary); border-color: var(--border-strong); }
.btn--outline:hover { background: var(--action-ghost-hover); color: var(--text-primary); }
.btn--inverse { background: var(--n-0); color: var(--n-900); }
.btn--inverse:hover { background: var(--n-100); color: var(--n-900); }
.btn--inverse-outline { background: transparent; color: var(--text-on-dark); border-color: var(--border-inverse); }
.btn--inverse-outline:hover { background: rgba(255,255,255,.12); color: var(--text-on-dark); }
.btn .i { flex: 0 0 auto; }

/* ---------- Site header ----------------------------------------------- */
/* A detached, floating bar: inset from the viewport edges, rounded, and
   slightly translucent with a blur so the page reads through it without
   costing the nav its contrast. */
.site-header {
  position: fixed; z-index: 60;
  inset-block-start: 12px; inset-inline: 12px;
  max-width: calc(var(--container-wide) + 24px); margin-inline: auto;
  border: 1px solid rgba(255, 255, 255, .6);
  border-radius: var(--radius-lg);
  background: rgba(255, 255, 255, .72);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
  backdrop-filter: saturate(1.6) blur(14px);
  box-shadow: var(--shadow-md);
  color: var(--text-primary);
  transition: background-color var(--dur-3) var(--ease-out),
              border-color var(--dur-3) var(--ease-out),
              color var(--dur-3) var(--ease-out);
}
.site-header__inner {
  display: flex; align-items: center; gap: var(--sp-7);
  height: var(--header-h);
  padding-inline: clamp(16px, 2.4vw, 28px);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header { background: rgba(255, 255, 255, .94); }
}

.logo { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; color: inherit; }
.logo:hover { text-decoration: none; color: inherit; }
.logo img { width: 34px; height: 34px; }
/* The header shows the client's grey lockup (wheel + wordmark) as one image.
   The mark + .logo__word pair below is still what the share images use. */
.logo:has(.logo__lockup) { flex: none; }
.logo img.logo__lockup { width: auto; height: 38px; }
.logo__word { display: grid; line-height: 1; }
.logo__word b { font: var(--fw-extrabold) 16px/1 var(--font-sans); letter-spacing: .02em; }
.logo__word span { font: var(--fw-medium) 9px/1 var(--font-sans); letter-spacing: var(--ls-wordmark); opacity: .74; margin-top: 3px; }

.nav { display: flex; align-items: center; gap: 2px; margin-left: var(--sp-2); }
/* Each section: the hub link and its chevron read as one pill. */
.nav__item { position: relative; display: flex; align-items: center; border-radius: var(--radius-sm); transition: var(--transition-control); }
.nav__item--mega { position: static; }
.nav__link {
  display: inline-flex; align-items: center; height: 38px; padding-inline: 10px 2px;
  font: var(--text-button); white-space: nowrap;
  color: currentColor; opacity: .74; text-decoration: none;
  transition: var(--transition-control);
}
.nav__link:hover { opacity: 1; color: currentColor; text-decoration: none; }
.nav__toggle {
  display: grid; place-items: center; width: 24px; height: 38px; padding: 0 6px 0 2px;
  border: 0; border-radius: var(--radius-sm); background: none; color: inherit; opacity: .6; cursor: pointer;
}
.nav__toggle svg { transition: transform var(--dur-2) var(--ease-out); }
.nav__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.nav__item:hover, .nav__item[data-open] { background: var(--surface-sunken); }
.nav__item:hover .nav__toggle, .nav__item[data-open] .nav__toggle { opacity: 1; }
/* The current section, marked by site.js from the URL. */
.nav__item[data-current] .nav__link { opacity: 1; color: var(--text-brand); }

/* The submenu. Solid rather than frosted: a backdrop-filter nested inside
   the header's own would only blur the header. */
.nav__panel {
  position: absolute; z-index: 1; top: calc(100% + 10px); left: 0;
  display: grid; gap: var(--sp-3); width: 300px; padding: var(--sp-4);
  border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
  background: var(--surface-raised); box-shadow: var(--shadow-lg); color: var(--text-primary);
  visibility: hidden; opacity: 0; transform: translateY(-4px);
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out), visibility 0s linear var(--dur-2);
}
/* Bridges the gap under the pill so the pointer can travel into the panel. */
.nav__panel::before { content: ""; position: absolute; inset: -12px 0 auto; height: 12px; }
.nav__panel--narrow { width: 230px; }
.nav__panel--wide { width: 560px; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-5); }
.nav__panel--end { left: auto; right: 0; }
/* Games spans the whole header bar. */
.nav__panel--mega {
  top: calc(100% + 8px); left: 0; right: 0; width: auto;
  grid-template-columns: minmax(150px, 1fr) minmax(130px, 1fr) minmax(0, 3.4fr);
  gap: var(--sp-6); padding: var(--sp-6) var(--sp-7);
}
.nav__item[data-open] > .nav__panel { visibility: visible; opacity: 1; transform: none; transition-delay: 0s; }
@media (hover: hover) {
  .nav__item:hover > .nav__panel { visibility: visible; opacity: 1; transform: none; transition-delay: 0s; }
}
/* A panel opened from the keyboard or a tap stays put; one open by hover
   gives way to the next section the pointer reaches. */
.nav:has(.nav__item:hover) .nav__item[data-open]:not(:hover) > .nav__panel { visibility: hidden; opacity: 0; }
.nav__item[data-hush] > .nav__panel { visibility: hidden; opacity: 0; }

.menu-col { display: grid; align-content: start; gap: var(--sp-2); }
.menu-head {
  margin-top: var(--sp-2); padding-inline: 10px;
  font: var(--text-overline); letter-spacing: var(--ls-overline); text-transform: uppercase; color: var(--text-tertiary);
}
.menu-col > .menu-head:first-child, .nav__panel > .menu-head:first-child { margin-top: 0; }
.menu-list { display: grid; gap: 1px; margin: 0; padding: 0; list-style: none; }
.menu-list--cols { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: var(--sp-3); }
.menu-list a, .menu-card {
  display: block; padding: 7px 10px; border-radius: var(--radius-sm);
  font: var(--text-label); color: var(--text-primary); text-decoration: none;
  transition: var(--transition-control);
}
.menu-card { display: grid; gap: 2px; padding-block: 9px; }
.menu-card b { display: inline-flex; align-items: center; gap: 8px; font-weight: var(--fw-semibold); }
.menu-card > span { font: var(--text-caption); color: var(--text-secondary); }
.menu-card .chip, .mobile-nav .chip { height: 20px; padding-inline: 8px; font-size: 10px; }
.menu-list a:hover, .menu-card:hover { background: var(--surface-sunken); color: var(--text-primary); text-decoration: none; }
.menu-list a[aria-current="page"], .menu-card[aria-current="page"], .menu-card[aria-current="page"] b { color: var(--text-brand); }
.menu-foot {
  grid-column: 1 / -1; justify-self: end; display: inline-flex; align-items: center; gap: 8px;
  font: var(--text-button); color: var(--text-brand); text-decoration: none;
}
.menu-foot:hover { text-decoration: underline; color: var(--text-brand); }

.header__end { margin-left: auto; display: flex; align-items: center; gap: var(--sp-4); }
.header__phone {
  display: inline-flex; align-items: center; gap: 8px;
  font: var(--text-button); color: currentColor; text-decoration: none; white-space: nowrap;
}
.header__phone:hover { color: currentColor; text-decoration: none; }
.header__phone .i { color: var(--amber-400); }

.burger {
  display: none; place-items: center; width: 44px; height: 44px;
  border: 1px solid currentColor; border-radius: var(--radius-sm);
  background: transparent; color: inherit; cursor: pointer; opacity: .5;
}
.mobile-nav {
  display: none; border-top: 1px solid var(--border-subtle);
  padding: var(--sp-3) clamp(16px, 2.4vw, 28px) var(--sp-4);
  /* The whole map can be taller than the phone, so it scrolls inside the bar. */
  max-height: calc(100dvh - var(--header-h) - 36px); overflow-y: auto; overscroll-behavior: contain;
}
.mobile-nav[data-open="true"] { display: grid; gap: 2px; }
/* Open, the menu is long enough that the page showing through would fight it. */
.site-header:has(.mobile-nav[data-open="true"]) { background: var(--surface-raised); }
.mnav__toggle {
  display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 12px 8px;
  border: 0; border-radius: var(--radius-sm); background: none; text-align: left;
  font: var(--text-h4); color: var(--text-primary); cursor: pointer;
}
.mnav__toggle svg { opacity: .6; transition: transform var(--dur-2) var(--ease-out); }
.mnav__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.mnav[data-current] .mnav__toggle { color: var(--text-brand); }
.mnav__body:not([hidden]) { display: grid; gap: 1px; padding: 0 0 var(--sp-3) var(--sp-3); }
.mnav__body .menu-head { margin-top: var(--sp-3); padding-inline: 8px; }
.mnav__cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px var(--sp-2); }
.mnav__body a {
  display: flex; align-items: center; gap: 8px; padding: 9px 8px; border-radius: var(--radius-sm);
  font: var(--text-label); color: var(--text-primary); text-decoration: none;
}
.mnav__body a[aria-current="page"] { color: var(--text-brand); }
.mnav__cta { padding: 12px 8px; border-radius: var(--radius-sm); font: var(--text-h4); color: var(--text-brand); text-decoration: none; }

/* Scroll-linked reveal. Driven by JS adding [data-inview]; no transform on
   the reduced-motion path. */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity var(--dur-4) var(--ease-out), transform var(--dur-4) var(--ease-out); }
.reveal[data-inview="true"] { opacity: 1; transform: none; }
.reveal[data-delay="1"] { transition-delay: 70ms; }
.reveal[data-delay="2"] { transition-delay: 140ms; }
.reveal[data-delay="3"] { transition-delay: 210ms; }
.reveal[data-delay="4"] { transition-delay: 280ms; }
.reveal[data-settled="true"] { transition-delay: 0ms; }
/* A hero's reveal is the page's first, largest text, so it plays from CSS on
   load rather than waiting for site.js: the same rise and fade, but the
   headline paints with the page and still shows if the script never runs. */
.section--hero .reveal { opacity: 1; transform: none; transition: none; animation: reveal-in var(--dur-4) var(--ease-out) backwards; }
@keyframes reveal-in { from { opacity: 0; transform: translateY(18px); } }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .section--hero .reveal { animation: none; }
}

/* ---------- Inner-page main ------------------------------------------
   The header is fixed and floats over the page, so a page whose first
   section is ordinary content clears it here. The home page does not use
   this: its acts sit under the header by design. */
.page-main { padding-top: calc(var(--header-h) + 12px); }

/* =========================================================================
   THE CARD SYSTEM
   One card, everywhere: white, hairline, soft shadow, 12px corners. The
   brand ramp lives on the section backgrounds behind them, not on the
   cards, so every section reads the same way.
   ========================================================================= */
.format,
.bundle,
.spec-block,
.kiosk,
.pin-card,
.eco-step {
  position: relative; overflow: hidden; isolation: isolate;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  color: var(--text-primary);
}

/* ---------- Section band ------------------------------------------------
   The signature ramp as a section surface. Header copy goes white and sits
   over the scrim; the white cards float on top. Alternates with plain
   white sections so the page has rhythm without changing the vocabulary. */
.section--band {
  position: relative; isolation: isolate;
  background: var(--gradient-signature);
  color: var(--text-on-dark);
}
.section--band::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--scrim-signature);
}
.section--band::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: var(--motif-halftone); background-size: var(--motif-halftone-size);
  opacity: .35;
  -webkit-mask-image: linear-gradient(90deg, transparent 50%, #000 100%);
  mask-image: linear-gradient(90deg, transparent 50%, #000 100%);
}
.section--band h2, .section--band h3 { color: var(--text-on-dark); }
.section--band .lead { color: var(--text-on-dark-dim); }
.section--band .eyebrow { color: var(--amber-300); }
.section--band .footnote { color: rgba(255,255,255,.7); }
.section--band .btn--outline { color: var(--text-on-dark); border-color: var(--border-inverse); }
.section--band .btn--outline:hover { background: rgba(255,255,255,.12); color: var(--text-on-dark); }
.section--band .stat b, .section--band .stat u { color: var(--text-on-dark); }
.section--band .stat p { color: var(--text-on-dark-dim); }
.section--band .proof { border-top-color: var(--border-inverse); }
.section--band .stat + .stat { border-left-color: var(--border-inverse); }
.section--band .stat::before { background: var(--amber-300); }
.section--band .game__meta b { color: var(--text-on-dark); }
.section--band .game__meta i { color: var(--text-on-dark-dim); }
.section--band .trust__item b { color: var(--text-on-dark); }
.section--band .trust__item p { color: var(--text-on-dark-dim); }
.section--band .game__screen { border-color: rgba(255,255,255,.18); }

/* ---------- Trust bar -------------------------------------------------- */
.trust {
  position: relative; z-index: 1;
  background: var(--surface-subtle);
  border-block: 1px solid var(--border-subtle);
}
.trust__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: var(--sp-8); padding-block: var(--sp-9); }
.trust__item { display: grid; gap: var(--sp-3); justify-items: start; padding-block-start: var(--sp-6); }

/* The icon tile. Same family as the chip: the mark gradient, a white glyph,
   drawn a stop heavier than body icons. */
.icon-tile {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 52px; height: 52px; border-radius: var(--radius-md);
  background: var(--gradient-mark); border: 0;
  color: var(--text-on-brand);
}
.icon-tile svg { width: 26px; height: 26px; stroke-width: 1.9; }
.trust__icon { margin-bottom: var(--sp-2); }
.trust__item b { font: var(--text-h4); color: var(--text-primary); }
.trust__item p { font: var(--text-body-sm); color: var(--text-secondary); }

/* ---------- Page body (light surfaces) --------------------------------- */
.page-body { position: relative; z-index: 1; background: var(--surface-page); }

.section-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-7); flex-wrap: wrap; }
.section-head__text { max-width: 720px; }
.section-head h2 { margin-top: var(--sp-3); font: var(--text-display-md); letter-spacing: var(--ls-display); text-wrap: balance; }
.section-head p { margin-top: var(--sp-4); }

/* ---------- Game formats ------------------------------------------------
   Each format carries a real diagram of its reel grid - an operator's
   customer will not learn the difference from the name alone. */
.formats { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--grid-gap); margin-top: var(--sp-9); }
/* Tag and title on the left, the reel grid beside them on the right - it
   buys back the ~90px the grid used to cost above the title. The copy
   underneath spans both columns. */
.format {
  padding: var(--card-pad);
  display: grid; grid-template-columns: minmax(0, 1fr) max-content;
  column-gap: var(--sp-5); align-content: start; justify-items: start;
  /* The description row absorbs spare height so the links line up across cards. */
  grid-template-rows: auto auto 1fr auto;
}
.format .chip { grid-area: 1 / 1; }
.format b { grid-area: 2 / 1; align-self: start; display: block; margin-top: var(--sp-3); font: var(--text-h3); }
.format .reelgrid { grid-area: 1 / 2 / span 2 / auto; margin-bottom: 0; }
.format p { grid-area: 3 / 1 / auto / span 2; margin-top: var(--sp-5); font: var(--text-body-sm); color: var(--text-secondary); }
.format__link { grid-area: 4 / 1 / auto / span 2; margin-top: var(--sp-4); display: inline-flex; align-items: center; gap: 6px; font: var(--text-body-sm); font-weight: var(--fw-semibold); color: var(--text-accent); text-decoration: none; }
.format__link:hover { text-decoration: underline; }

/* The reel grid: 3 rows of cells, with the centre line called out. */
.reelgrid { display: grid; gap: 4px; margin-bottom: var(--sp-6); width: max-content; }
.reelgrid[data-cols="3"] { grid-template-columns: repeat(3, 26px); }
.reelgrid[data-cols="5"] { grid-template-columns: repeat(5, 26px); }
.reelgrid i {
  display: block; height: 26px; border-radius: var(--radius-xs);
  background: var(--n-100); border: 1px solid var(--border-default);
}
.reelgrid i[data-pay] { background: var(--amber-400); border-color: var(--amber-500); }
.reelgrid i[data-nudge] {
  background: var(--red-500); border-color: var(--red-600);
  box-shadow: 0 -4px 0 -1px var(--red-200);
}

/* ---------- Game bundles ------------------------------------------------ */
.bundles-head { margin-top: var(--sp-12); max-width: 720px; }
.bundles-head h3 { margin-top: var(--sp-3); font: var(--text-display-md); letter-spacing: var(--ls-display); text-wrap: balance; }
.bundles-head p { margin-top: var(--sp-4); }
/* All five on one line: each card is the bundle's own slider background with
   its wordart on top, so the card carries the artwork instead of describing
   it. The only card on the page that is not white - the art is the point. */
.bundles { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--sp-4); margin-top: var(--sp-8); }
.bundle {
  display: grid; place-items: center;
  aspect-ratio: 16 / 9; padding: var(--sp-3);
  background: var(--n-900); border-color: rgba(255, 255, 255, .14);
  color: var(--text-on-dark); text-decoration: none;
  transition: var(--transition-lift), border-color var(--dur-2) var(--ease-out);
}
.bundle:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: rgba(255, 255, 255, .34); }

/* The artwork layer and its scrim. Behind the content, inside the card's own
   stacking context, clipped by the card's radius. */
.bundle__art { position: absolute; inset: 0; z-index: -1; overflow: hidden; }
.bundle__art::before {
  content: ""; position: absolute; inset: 0;
  background-size: cover; background-position: center;
  transform: scale(1.02); transform-origin: center;
}
/* The image is named here, not passed in through a custom property: a url()
   inside a var() resolves against the stylesheet that substitutes it, not the
   document, and browsers disagree about which that is. */
.bundle[data-bundle="prime"]     .bundle__art::before { background-image: url("../img/bundles/prime-bg.webp"); }
.bundle[data-bundle="xtreme"]    .bundle__art::before { background-image: url("../img/bundles/xtreme-bg.webp"); }
.bundle[data-bundle="xtreme-2"]  .bundle__art::before { background-image: url("../img/bundles/xtreme-2-bg.webp"); }
.bundle[data-bundle="supernova"] .bundle__art::before { background-image: url("../img/bundles/supernova-bg.webp"); }
.bundle[data-bundle="horizon"]   .bundle__art::before { background-image: url("../img/bundles/horizon-bg.webp"); }
/* A light, even scrim: there is no copy to protect here, it just settles
   the artwork behind the wordart and lets the card sit on the band. */
.bundle__art::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(8, 4, 12, .34) 0%, rgba(8, 4, 12, .22) 50%, rgba(8, 4, 12, .52) 100%);
}

/* The wordarts run from 1.7:1 to 4.5:1, so both axes are capped and the
   intrinsic ratio decides which one binds. */
.bundle__word {
  max-width: 84%; max-height: 56%;
  width: auto; height: auto; object-fit: contain;
  filter: drop-shadow(0 8px 22px rgba(0, 0, 0, .55));
}

/* ---------- Cabinet spec columns --------------------------------------- */
.spec-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--grid-gap); margin-top: var(--sp-10); }
.spec-block { padding: var(--card-pad) var(--card-pad) var(--sp-5); }
.spec-block h3 { display: flex; align-items: center; gap: 10px; font: var(--text-h3); }
.spec-block h3 { gap: var(--sp-3); }
/* Dotted leaders, the way a printed spec sheet sets a label against a value. */
.spec-block dl > div { position: relative; }
.spec-block dt { background: var(--surface-raised); padding-inline-end: 6px; z-index: 1; }
.spec-block dd { background: var(--surface-raised); padding-inline-start: 6px; z-index: 1; }
.spec-block dl > div::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: 7px; z-index: 0;
  border-bottom: 1px dotted var(--border-strong);
}
.spec-block dl { margin-top: var(--sp-5); display: grid; }
.spec-block dl > div {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-4);
  padding-block: var(--sp-3); border-top: 1px solid var(--border-subtle);
}
.spec-block dt { font: var(--text-body-sm); color: var(--text-tertiary); flex: 0 0 auto; }
.spec-block dd { margin: 0; font: var(--text-spec); color: var(--text-primary); text-align: right; }
/* A spec we don't have yet reads "On request", set quieter than a real figure. */
.spec-block dd.is-pending { color: var(--text-tertiary); font-family: var(--font-sans); }
/* The product-sheet link under a page's spec blocks. */
.spec-sheet { margin-top: var(--sp-7); font: var(--text-body-sm); color: var(--text-secondary); }
.spec-sheet a { color: var(--text-brand); font-weight: var(--fw-semibold); }
.badge--brand  { background: var(--red-50); color: var(--text-brand); }
.badge--mono   { font: var(--text-spec); font-size: var(--fs-caption); letter-spacing: 0; text-transform: none; background: var(--surface-sunken); color: var(--text-secondary); }
.badge--inverse { background: rgba(255,255,255,.14); color: var(--text-on-dark); }

/* ---------- Kiosk lineup ------------------------------------------------
   Six near-identical spec cards are impossible to compare by reading. The
   capacity meter is drawn to a shared 7,200-bill scale, so the one decision
   an operator actually makes - how much cash the room needs to hold - is
   legible across the row at a glance. */
.kiosks { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--grid-gap); margin-top: var(--sp-9); }
.kiosk {
  display: grid; gap: var(--sp-5); padding: var(--card-pad);
  text-decoration: none;
  transition: var(--transition-lift), border-color var(--dur-2) var(--ease-out);
}
/* The model number, set oversize and nearly out, as a watermark. */
.kiosk:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--border-default); text-decoration: none; }

.kiosk__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); }
.kiosk__id { display: grid; gap: var(--sp-3); justify-items: start; }
.kiosk__id b { font: var(--fw-bold) 34px/1 var(--font-sans); letter-spacing: var(--ls-display); color: var(--text-primary); }


.kiosk__meter { display: grid; gap: var(--sp-2); }
.kiosk__meter-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); }
.kiosk__meter-head span:first-child { font: var(--text-caption); color: var(--text-tertiary); text-transform: uppercase; letter-spacing: var(--ls-overline); }
.kiosk__meter-head span:last-child { font: var(--text-spec); color: var(--text-primary); }
.kiosk__bar { display: block; height: 6px; border-radius: var(--radius-pill); background: var(--n-100); overflow: hidden; }
.kiosk__bar i {
  display: block; height: 100%; width: var(--fill, 0%);
  border-radius: var(--radius-pill); background: var(--motif-rule-accent);
}

.kiosk__spec { display: grid; }
.kiosk__spec > span {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-4);
  padding-block: var(--sp-3); border-top: 1px solid var(--border-subtle);
}
.kiosk__spec > span > span:first-child { font: var(--text-body-sm); color: var(--text-tertiary); }
.kiosk__spec > span > span:last-child { font: var(--text-spec); color: var(--text-primary); text-align: right; }
.kiosk__for { font: var(--text-body-sm); color: var(--text-secondary); }
.kiosk__go {
  display: inline-flex; align-items: center; gap: 8px;
  font: var(--text-button); color: var(--text-brand);
}
.kiosk:hover .kiosk__go { gap: 12px; }

/* ---------- Ecosystem flow ----------------------------------------------
   Four steps that are genuinely sequential, so they are drawn as a flow:
   a rule runs behind the row and each node sits on it. */
.eco { position: relative; overflow: hidden; }
.eco::before {
  content: ""; position: absolute; inset-inline-end: -6%; inset-block-start: -14%;
  width: 620px; height: 620px; border-radius: 50%;
  background: var(--motif-halftone); background-size: var(--motif-halftone-size);
  -webkit-mask-image: radial-gradient(closest-side, #000 20%, transparent 82%);
  mask-image: radial-gradient(closest-side, #000 20%, transparent 82%);
}
.eco > * { position: relative; }

.eco-flow { margin-top: var(--sp-10); display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--grid-gap); }
.eco-step { padding: var(--card-pad); }
.eco-step__n { display: block; margin-top: var(--sp-4); font: var(--text-overline); letter-spacing: var(--ls-overline); text-transform: uppercase; color: var(--text-accent); margin-bottom: var(--sp-2); }
.eco-step b { display: block; font: var(--text-h3); color: var(--text-primary); text-wrap: balance; }
.eco-step p { margin-top: var(--sp-3); font: var(--text-body-sm); color: var(--text-secondary); }
.eco-step a { display: inline-flex; align-items: center; gap: 6px; margin-top: var(--sp-4); font: var(--text-button); color: var(--text-brand); }
.eco-step a:hover { color: var(--red-600); }
/* A link inside the copy stays a plain inline link, not the "Learn more" button-link above. */
.eco-step p a { display: inline; margin-top: 0; font: inherit; }

/* ---------- Proof ------------------------------------------------------- */
.proof {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 0; border-top: 1px solid var(--border-default);
}
.stat { position: relative; padding: var(--sp-9) var(--sp-6) var(--sp-7) 0; }
.stat + .stat { padding-inline-start: var(--sp-7); border-left: 1px solid var(--border-subtle); }
.stat::before {
  content: ""; position: absolute; inset-block-start: -2px; inset-inline-start: 0;
  width: 56px; height: 3px; background: var(--motif-rule-accent);
}
.stat + .stat::before { inset-inline-start: var(--sp-7); }
.stat b {
  display: block; font: var(--fw-extrabold) clamp(48px, 5.6vw, 78px)/1 var(--font-sans);
  letter-spacing: -.04em; font-variant-numeric: tabular-nums;
}
.stat u { display: block; margin-top: var(--sp-4); text-decoration: none; font: var(--text-h4); }
.stat p { margin-top: 4px; font: var(--text-body-sm); color: var(--text-secondary); }
@media (max-width: 620px) {
  .stat + .stat { padding-inline-start: 0; border-left: 0; border-top: 1px solid var(--border-subtle); }
  .stat + .stat::before { inset-inline-start: 0; }
}

/* ---------- Contact ---------------------------------------------------- */
.contact-grid { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); gap: clamp(32px, 6vw, 80px); align-items: start; }
.field { display: grid; gap: var(--sp-2); }
.field > span { font: var(--text-label); color: var(--text-primary); }
.field input, .field select, .field textarea {
  height: var(--control-h); padding-inline: var(--field-pad-x);
  border: 1px solid var(--border-default); border-radius: var(--radius-sm);
  background: var(--surface-page); color: var(--text-primary);
  font: var(--text-body); transition: var(--transition-control);
}
.field textarea { height: auto; padding-block: 12px; resize: vertical; min-height: 128px; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--n-900); box-shadow: 0 0 0 3px var(--n-100);
}
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-5); }
.form-grid .field--full { grid-column: 1 / -1; }
.contact-aside { display: grid; gap: var(--sp-6); }
.contact-aside a { display: inline-flex; align-items: center; gap: 10px; font: var(--text-h4); color: var(--text-primary); }
.contact-aside a .i { color: var(--text-brand); }

/* ---------- Footer ----------------------------------------------------- */
.site-footer { position: relative; z-index: 1; background: var(--surface-inverse); color: var(--text-on-dark); }
/* Brand block, then the link columns in their own grid. Five columns is
   more than a single auto-fit track list can place cleanly next to the
   brand block, so the count is explicit and steps down. */
.footer-grid { display: grid; grid-template-columns: minmax(230px, 260px) minmax(0, 1fr); gap: var(--sp-9) var(--sp-8); }
.footer-links { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--sp-9) var(--sp-6); }
.footer-col--stack { display: grid; gap: var(--sp-8); align-content: start; }
.footer-col b { display: block; font: var(--text-overline); letter-spacing: var(--ls-overline); text-transform: uppercase; color: var(--amber-300); margin-bottom: var(--sp-5); }
.footer-col ul { display: grid; gap: var(--sp-3); }
.footer-col a { font: var(--text-body-sm); color: var(--text-on-dark-dim); text-decoration: none; }
.footer-col a:hover { color: var(--text-on-dark); text-decoration: underline; }
.footer-contact { display: grid; gap: var(--sp-2); margin-top: var(--sp-6); }
.footer-contact a, .footer-contact div { display: inline-flex; gap: 10px; align-items: center; font: var(--text-body-sm); color: var(--text-on-dark); text-decoration: none; }
.footer-contact .i { color: var(--amber-300); flex: 0 0 auto; }
.footer-legal {
  display: flex; flex-wrap: wrap; gap: var(--sp-4); justify-content: space-between;
  margin-top: var(--sp-11); padding-top: var(--sp-6); border-top: 1px solid var(--border-inverse);
  font: var(--text-caption); font-weight: var(--fw-regular); color: rgba(255,255,255,.62);
}
.footer-legal a { color: inherit; text-decoration: none; }
.footer-legal span { display: flex; flex-wrap: wrap; gap: var(--sp-5); }
.footer-legal__btn { padding: 0; border: 0; background: none; font: inherit; color: inherit; cursor: pointer; }
.footer-legal a:hover, .footer-legal__btn:hover { color: var(--text-on-dark); }

/* ---------- Cookie consent --------------------------------------------
   The opt-in banner from partials/footer.html, driven by consent.js.
   Bottom-left like the live site's Complianz banner, and above the header
   so nothing on a page can cover it. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.consent {
  position: fixed; z-index: 70; inset-block-end: 12px; inset-inline-start: 12px;
  display: grid; gap: var(--sp-4);
  width: min(526px, calc(100vw - 24px)); max-height: calc(100dvh - 24px); overflow-y: auto;
  padding: var(--sp-6); background: var(--surface-raised); color: var(--text-primary);
  border: var(--hairline); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}
.consent[hidden], .consent [hidden] { display: none; }
.consent__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); }
.consent__title { font: var(--text-h4); }
.consent__close {
  display: grid; place-items: center; width: 32px; height: 32px; margin: -6px -6px -6px 0;
  padding: 0; border: 0; border-radius: var(--radius-sm); background: none; color: var(--text-secondary); cursor: pointer;
}
.consent__close:hover { background: var(--action-ghost-hover); color: var(--text-primary); }
.consent__msg { font: var(--text-body-sm); color: var(--text-secondary); }
.consent__cats { display: grid; border-top: 1px solid var(--border-default); }
.consent__cat {
  display: grid; grid-template-columns: 1fr auto; align-items: start; gap: var(--sp-4);
  padding-block: var(--sp-3); border-bottom: 1px solid var(--border-default);
}
.consent__cat summary {
  display: flex; align-items: center; gap: var(--sp-2); min-height: 24px;
  font: var(--text-label); cursor: pointer; list-style: none;
}
.consent__cat summary::-webkit-details-marker { display: none; }
.consent__cat summary::after {
  content: ""; width: 7px; height: 7px; margin-left: 2px;
  border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
  transform: translateY(-2px) rotate(45deg); transition: transform var(--dur-2) var(--ease-out);
}
.consent__cat details[open] summary::after { transform: translateY(1px) rotate(-135deg); }
.consent__cat details p { margin-top: var(--sp-2); font: var(--text-caption); font-weight: var(--fw-regular); color: var(--text-secondary); }
.consent__always { font: var(--text-caption); line-height: 24px; color: var(--text-tertiary); }
.consent__switch { position: relative; display: block; width: 40px; height: 24px; cursor: pointer; }
.consent__switch input {
  appearance: none; position: absolute; inset: 0; margin: 0; cursor: pointer;
  border-radius: var(--radius-pill); background: var(--n-300); transition: background var(--dur-2) var(--ease-out);
}
.consent__switch input::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--n-0); box-shadow: var(--shadow-xs);
  transition: transform var(--dur-2) var(--ease-out);
}
.consent__switch input:checked { background: var(--action-primary); }
.consent__switch input:checked::after { transform: translateX(16px); }
.consent__switch input:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.consent__btns { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.consent__btns .btn { flex: 1 1 auto; }
/* Save gets a row of its own above the others, right under the toggles. The banner is pinned to
   the bottom, so a row added below would push the preferences toggle out from under the pointer. */
.consent__btns [data-consent="save"] { flex-basis: 100%; order: -1; }
.consent__docs { display: flex; gap: var(--sp-5); font: var(--text-caption); font-weight: var(--fw-regular); }
.consent__docs a { color: var(--text-secondary); }
.consent__docs a:hover { color: var(--text-primary); }

.footnote { margin-top: var(--sp-6); font: var(--text-caption); font-weight: var(--fw-regular); color: var(--text-tertiary); }

/* ---------- Responsive ------------------------------------------------- */
@media (max-width: 1100px) {
  /* Five columns stop holding a readable measure here; 3 + 2 keeps
     Games+Formats / Bundles / Hardware together on the first row. */
  .footer-links { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  /* Still one line on a phone: the row scrolls sideways and snaps per card
     rather than wrapping or shrinking the art past legibility. */
  .bundles {
    grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 68%;
    overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
    margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); padding-block: 4px;
    scroll-padding-inline: var(--gutter);
  }
  .bundles::-webkit-scrollbar { display: none; }
  .bundle { scroll-snap-align: start; }
}
/* Seven sections with chevrons need the room: the phone number goes first
   (it's on every page's contact band and in the footer), then the bar
   hands over to the burger. Both breakpoints allow for the 153px logo. */
@media (max-width: 1340px) {
  .header__phone { display: none; }
  .site-header__inner { gap: var(--sp-4); }
}
@media (max-width: 1140px) {
  .nav { display: none; }
  .burger { display: grid; }
}
@media (max-width: 900px) {
  .footer-grid { grid-template-columns: minmax(0, 1fr); }
  .contact-grid { grid-template-columns: minmax(0, 1fr); }
}

/* A phone fits the logo, the quote button and the burger by shrinking the
   logo and dropping the button's arrow. */
@media (max-width: 480px) {
  .site-header__inner, .header__end { gap: var(--sp-3); }
  .logo img.logo__lockup { height: 30px; }
  .btn--header { padding-inline: 16px; }
  .btn--header .i { display: none; }
}

@media (max-width: 620px) {
  .footer-links { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .spec-block dl > div { flex-direction: column; gap: 2px; }
  .spec-block dd { text-align: left; }
}


/* =========================================================================
   RICHNESS + MOTION
   One card treatment, animated the same way everywhere:
     - a signature rule that draws across the top as the card arrives
     - a chip in the same corner (format, index, model form factor)
     - lift + deeper shadow on hover, arrow nudge on links
   Every animation sits under prefers-reduced-motion: no-preference.
   ========================================================================= */
.chip {
  display: inline-flex; align-items: center; height: 26px; padding-inline: 10px;
  width: max-content; justify-self: start;
  border-radius: var(--radius-pill);
  background: var(--gradient-mark); border: 0;
  color: var(--text-on-brand);
  font: var(--text-overline); letter-spacing: var(--ls-overline); text-transform: uppercase;
}
.chip.mono { font: var(--text-spec); font-size: var(--fs-caption); letter-spacing: 0; text-transform: none; }

/* The rule. Sits inside the card's top edge, scales in from the left. */
.format::before, .bundle::before, .spec-block::before, .kiosk::before, .eco-step::before, .pin-card::before {
  content: ""; position: absolute; inset-block-start: 0; inset-inline: 0; height: 3px;
  background: var(--motif-rule-accent); transform-origin: left center; z-index: 2;
}
/* Hover: the whole card lifts, the rule thickens. */
.format, .bundle, .spec-block, .kiosk, .eco-step {
  transition: transform var(--dur-3) var(--ease-out), box-shadow var(--dur-3) var(--ease-out);
}
.format:hover, .bundle:hover, .spec-block:hover, .kiosk:hover, .eco-step:hover {
  transform: translateY(-4px); box-shadow: var(--shadow-lg);
}
.btn .i, .kiosk__go .i, .bundle__go .i, .eco-step a .i { transition: transform var(--dur-2) var(--ease-out); }
.btn:hover .i, .kiosk:hover .kiosk__go .i, .bundle:hover .bundle__go .i, .eco-step a:hover .i { transform: translateX(3px); }

@media (prefers-reduced-motion: no-preference) {
  /* Rule draws in as the card reveals. */
  .reveal::before { transform: scaleX(0); transition: transform var(--dur-4) var(--ease-out) 120ms; }
  .reveal[data-inview="true"]::before { transform: scaleX(1); }

  /* Kiosk capacity meters fill when the card arrives. */
  .kiosk__bar i { width: 0; transition: width 900ms var(--ease-out) 220ms; }
  .kiosk.reveal[data-inview="true"] .kiosk__bar i { width: var(--fill, 0%); }

  /* Reel cells light up one by one; the payline lands last. */
  .reelgrid i { opacity: 0; transform: scale(.6); transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out), background-color var(--dur-3) var(--ease-out); }
  .reveal[data-inview="true"] .reelgrid i { opacity: 1; transform: none; }
  .reelgrid i:nth-child(1) { transition-delay: 60ms } .reelgrid i:nth-child(2) { transition-delay: 90ms } .reelgrid i:nth-child(3) { transition-delay: 120ms }
  .reelgrid i:nth-child(4) { transition-delay: 150ms } .reelgrid i:nth-child(5) { transition-delay: 180ms } .reelgrid i:nth-child(6) { transition-delay: 210ms }
  .reelgrid i:nth-child(7) { transition-delay: 240ms } .reelgrid i:nth-child(8) { transition-delay: 270ms } .reelgrid i:nth-child(9) { transition-delay: 300ms }
  .reelgrid i:nth-child(10) { transition-delay: 330ms } .reelgrid i:nth-child(11) { transition-delay: 360ms } .reelgrid i:nth-child(12) { transition-delay: 390ms }
  .reelgrid i:nth-child(13) { transition-delay: 420ms } .reelgrid i:nth-child(14) { transition-delay: 450ms } .reelgrid i:nth-child(15) { transition-delay: 480ms }
  .reelgrid i[data-pay], .reelgrid i[data-nudge] { transition-delay: 560ms !important; }

  /* Bundle cards: hover pushes into the artwork and lifts the wordart.
     Every layer runs on one duration and curve so they move as one, and
     only transform and opacity animate - both stay on the compositor. The
     wordart's drop shadow is static: animating a filter repaints the image
     every frame, which is what made the hover stutter. */
  .bundle {
    transition: opacity var(--dur-4) var(--ease-out), transform var(--dur-4) var(--ease-out),
                box-shadow var(--dur-4) var(--ease-out), border-color var(--dur-4) var(--ease-out);
  }
  .bundle__art::before { transition: transform var(--dur-4) var(--ease-out); will-change: transform; }
  .bundle__word { transition: transform var(--dur-4) var(--ease-out); will-change: transform; }
  .bundle__art::after { transition: opacity var(--dur-4) var(--ease-out); }
  .bundle:hover .bundle__art::before { transform: scale(1.06); }
  .bundle:hover .bundle__word { transform: translateY(-4px) scale(1.04); }
  .bundle:hover .bundle__art::after { opacity: .72; }

  /* Chips and trust tiles pop in a beat after their card. */
  .reveal .chip, .reveal .trust__icon { opacity: 0; transform: translateY(6px); transition: opacity var(--dur-3) var(--ease-out) 200ms, transform var(--dur-3) var(--ease-out) 200ms; }
  .reveal[data-inview="true"] .chip, .reveal[data-inview="true"] .trust__icon { opacity: 1; transform: none; }

  /* Section bands breathe: the halftone drifts, very slowly. */
  .section--band::after { animation: drift 60s linear infinite; }
  @keyframes drift { to { background-position: 120px 60px; } }
}


/* =========================================================================
   INNER PAGES
   Shared by every page below the home page: the quick-facts strip under a
   hero, the FAQ list, and radio groups inside the quote form.
   ========================================================================= */

/* ---------- Quick facts ------------------------------------------------ 
   The figures an operator skims before scrolling. The number sits on top
   visually; in the markup the label (dt) comes first so it reads right. */
.facts {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  margin: 0; border-top: 1px solid var(--border-default);
}
.facts > div { display: flex; flex-direction: column-reverse; justify-content: flex-end; gap: var(--sp-2); padding: var(--sp-6) var(--sp-5) 0 0; position: relative; }
.facts > div + div { padding-inline-start: var(--sp-5); border-left: 1px solid var(--border-subtle); }
.facts > div::before {
  content: ""; position: absolute; inset-block-start: -2px; inset-inline-start: 0;
  width: 40px; height: 3px; background: var(--motif-rule-accent);
}
.facts > div + div::before { inset-inline-start: var(--sp-5); }
.facts dt { font: var(--text-body-sm); color: var(--text-secondary); }
.facts dd { margin: 0; font: var(--fw-extrabold) clamp(28px, 2.8vw, 38px)/1 var(--font-sans); letter-spacing: -.03em; font-variant-numeric: tabular-nums; color: var(--text-primary); }
@media (max-width: 900px) {
  .facts { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: var(--sp-6); }
  .facts > div:nth-child(4) { padding-inline-start: 0; border-left: 0; }
  .facts > div:nth-child(4)::before { inset-inline-start: 0; }
}
@media (max-width: 520px) {
  .facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .facts > div:nth-child(n) { padding-inline-start: var(--sp-5); border-left: 1px solid var(--border-subtle); }
  .facts > div:nth-child(n)::before { inset-inline-start: var(--sp-5); }
  .facts > div:nth-child(odd) { padding-inline-start: 0; border-left: 0; }
  .facts > div:nth-child(odd)::before { inset-inline-start: 0; }
}

/* ---------- Product hero ------------------------------------------------
   The opening of a hardware page: copy beside a still rendered from the
   product's 3D model with the home stage's light rig, so the product looks
   the same on every page. The quick-facts strip sits underneath. */
.product-hero { padding-block: var(--sp-7) var(--section-y-tight); }
.product-hero__grid {
  display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr);
  gap: clamp(24px, 5vw, 72px); align-items: center; margin-top: var(--sp-6);
}
.product-hero__copy { display: grid; gap: var(--sp-6); justify-items: start; }
.product-hero h1 { font: var(--text-display-lg); letter-spacing: var(--ls-display); text-wrap: balance; }
/* The H1 is the page's SEO heading on its own; the one-line tagline sits under
   it as a smaller second line, outside the H1 (SEO team, 13 Oct 2026). */
.product-hero__line {
  display: block; margin-top: var(--sp-4);
  font: var(--text-h2); letter-spacing: -.01em; color: var(--text-secondary);
}
.product-hero .lead { max-width: 52ch; }
.product-hero__ctas { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.product-hero__call { font: var(--text-body-sm); color: var(--text-secondary); }
.product-hero__call a { color: var(--text-primary); font-weight: var(--fw-semibold); text-decoration: none; }
.product-hero__call a:hover { text-decoration: underline; }
.product-hero__call a[href^="tel:"] { white-space: nowrap; }
.product-hero__art { margin: 0; justify-self: center; width: 100%; max-width: 540px; }
.product-hero__art img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; }
.product-hero .facts { margin-top: var(--sp-9); }

@media (max-width: 860px) {
  .product-hero__grid { grid-template-columns: minmax(0, 1fr); }
  .product-hero__art { order: -1; max-width: 360px; margin-block: calc(var(--sp-6) * -1) calc(var(--sp-7) * -1); }
}

/* ---------- Feature grid: the trust-bar item, with two lines of copy --- */
.features { padding-block: 0; margin-top: var(--sp-8); }
.features .trust__item { align-content: start; }

/* ---------- FAQ -------------------------------------------------------- */
.faq { margin-top: var(--sp-9); border-top: 1px solid var(--border-default); max-width: 880px; }
.faq details { border-bottom: 1px solid var(--border-default); }
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5);
  padding-block: var(--sp-5); cursor: pointer; list-style: none;
  font: var(--text-h4); color: var(--text-primary); text-wrap: balance;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: 0 0 auto; width: 12px; height: 12px;
  border-right: 2px solid var(--text-brand); border-bottom: 2px solid var(--text-brand);
  transform: translateY(-3px) rotate(45deg); transition: transform var(--dur-2) var(--ease-out);
}
.faq details[open] summary::after { transform: translateY(3px) rotate(-135deg); }
.faq summary:hover { color: var(--text-brand); }
.faq details p { margin: 0 0 var(--sp-6); max-width: 68ch; font: var(--text-body); color: var(--text-secondary); }
.faq details a { color: var(--text-brand); }

/* ---------- Radio groups in forms -------------------------------------- */
.choice { margin: 0; padding: 0; border: 0; min-width: 0; }
.choice legend { padding: 0; margin-bottom: var(--sp-2); font: var(--text-label); color: var(--text-primary); }
.choice__opts { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.choice__opts label {
  display: inline-flex; align-items: center; gap: var(--sp-2); height: var(--control-h);
  padding-inline: var(--field-pad-x); border: 1px solid var(--border-default); border-radius: var(--radius-sm);
  font: var(--text-body-sm); color: var(--text-primary); cursor: pointer; transition: var(--transition-control);
}
.choice__opts label:hover { border-color: var(--border-strong); }
.field .choice__opts input { padding: 0; border: 0; width: 16px; height: 16px; accent-color: var(--red-500); margin: 0; }
.choice__opts label:has(input:checked) { border-color: var(--n-900); box-shadow: 0 0 0 1px var(--n-900); }
.choice__opts label:has(input:focus-visible) { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
