/* ══════════════════════════════════════════
  GATE OF OLYMPUS — CuatroBet brand palette
   ══════════════════════════════════════════ */
/* ── Local fonts — Zalando Sans Expanded (variable, regular + italic) ── */
@font-face {
  font-family: "Zalando Sans Expanded";
  src: url("../fonts/zalando-sans-expanded-variable.ttf") format("truetype");
  font-weight: 400 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Zalando Sans Expanded";
  src: url("../fonts/zalando-sans-expanded-italic-variable.ttf") format("truetype");
  font-weight: 400 900;
  font-style: italic;
  font-display: swap;
}

:root {
  --brand-black:  #0c0c18;
  --brand-orange: #fc6200;
  --brand-white:  #ffffff;
  --orange-dark:  #ef5d00;
  --orange-deep:  #ca4e00;
  --black-mid:    #0b0b17;
  --glow:         rgba(252, 98, 0, 0.55);
  /* Heading: local Zalando Sans Expanded (assets/fonts, @font-face below) —
     bold/italic/uppercase display type for headlines, CTAs, badges, titles.
     Body: Manrope, loaded from Google Fonts (no local file exists for it) —
     clean, readable text for copy, form fields, labels, small print. */
  --font-heading: "Zalando Sans Expanded", "Arial Black", system-ui, sans-serif;
  --font-body:    "Manrope", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* Sizing knobs shared across breakpoints — each breakpoint below
     overrides only the ones that actually need to change for that
     viewport band, instead of repeating the whole property. Base values
     here are the desktop (≥1101px, no media query matched) look. */
  --hero-gap:      clamp(14px, 3vw, 64px);
  --brand-logo-w:  clamp(260px, 18vw, 380px);
  --headline-size: clamp(40px, 5.4vw, 92px);
  --gold-logo-w:   clamp(220px, 30vw, 560px);
  --slot-w:        min(100%, 1000px);
  --cta-w:         clamp(230px, 22vw, 380px);
  --cta-h:         clamp(58px, 6.4vw, 96px);
  --cta-font:      clamp(18px, 2.3vw, 34px);
  /* Zeus GIF is sized as a % of .slot's own width (its containing
     block, since it's position:absolute inside .slot) — clamp just
     keeps it from getting comically small/large at extreme widths.
     The GIF's real canvas is 608×979 (tall, mostly transparent margin
     around a narrower opaque figure — the opaque figure itself spans
     only ~14%-83% of that canvas width and ~18%-100% of its height),
     so the same pixel width reads much taller than a plain box would.
     ~1.5x bigger than the old 200/31%/340 here — a literal 2x (per the
     brief) doesn't fit at this band's narrower widths (1440–1600ish):
     his opaque figure's WIDTH alone would then exceed the entire gap
     between the headline text and the frame's first vertical divider,
     making zero-overlap-with-text and zero-overlap-with-the-divider
     mutually impossible regardless of --zeus-x. This is the largest
     size that still clears the text (a hard requirement — it's real
     copy) while only grazing column 1 the same way the previous,
     smaller Zeus already did (never crossing the first divider into
     column 2) — see --zeus-x/-y below for the position tuned to
     match. */
  --zeus-w:     clamp(320px, 50%, 460px);
}

/* ========================================
   ZEUS POSITION CONTROLS
   Міняй тільки ці значення вручну.

   --zeus-x / --zeus-y → Зевс (стоїть зліва внизу біля слота)

   Це зсув ПОВЕРХ поточних left/bottom (через transform: translate) —
   самі якорі позиції нижче й у tablet/mobile блоках не займає.

   щоб посунути лівіше: x відʼємний,  напр. -20px
   щоб посунути правіше: x додатний,  напр.  20px
   щоб підняти вище:      y відʼємний, напр. -20px
   щоб опустити нижче:    y додатний,  напр.  20px

   Є окремі копії цього блоку нижче — в @media (max-width: 1100px) (той
   самий breakpoint, що вмикає мобільну/вертикальну композицію) і в двох
   short-height landscape-блоках — щоб можна було задати іншу позицію на
   інших екранах, а не тільки на desktop.
======================================== */
:root {
  --zeus-x: -130px;
  --zeus-y: -6px;
}

/* ── Reset ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* ── No scroll – page is exactly one screen ── */
html {
  height: 100dvh;
  overflow: hidden;
  background: var(--brand-black);
}

body {
  height: 100dvh;
  overflow: hidden;
  font-family: var(--font-body);
  color: var(--brand-white);
  background: var(--brand-black);
  -webkit-font-smoothing: antialiased;
  text-rendering: geometricPrecision;
}

button, a { -webkit-tap-highlight-color: transparent; }

img {
  display: block;
  max-width: 100%;
  height: auto;
  user-select: none;
  -webkit-user-drag: none;
}

/* ══════════════════════════════════════════
   LANDING WRAPPER
   ══════════════════════════════════════════ */
.landing {
  position: relative;
  height: 100dvh;
  overflow: hidden;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  background-image:
    linear-gradient(180deg, rgba(12, 12, 24, 0.28), rgba(8, 8, 20, 0.76)),
    url("../img/page-bg-desktop.webp");
  background-position: center;
  background-size: cover;
}

/* orange glow bloom behind slot */
.landing::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(ellipse at 60% 65%, rgba(252, 98, 0, 0.14), transparent 50%),
    radial-gradient(ellipse at 18% 22%, rgba(252, 98, 0, 0.06), transparent 38%);
  pointer-events: none;
}

/* ══════════════════════════════════════════
   HERO — fills the entire 100dvh of .landing and centers .hero__content
   as a single unit, both axes. Top/bottom padding is kept symmetric
   (just a safe-area floor) so the centered row isn't pulled off true
   vertical center.
   align-content (not just place-items) is set explicitly: with a
   single auto-sized row, align-items alone leaves positioning of the
   row itself to the browser's default overflow-safety heuristic, which
   can flush it to the top instead of centering even when there's
   plenty of spare room (observed at 768x1024). align-content:center
   pins the row itself to the middle, independent of that heuristic.
   ══════════════════════════════════════════ */
.hero {
  flex: 1;
  min-height: 0;
  position: relative;
  z-index: 2;
  display: grid;
  place-items: center;
  align-content: center;
  padding: max(18px, env(safe-area-inset-top, 0px)) 16px 18px;
}

/* Two-column on desktop, single on mobile — this is the group that
   .hero centers as one block; text and game live inside it. */
.hero__content {
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(440px, 1.22fr);
  align-items: center;
  gap: var(--hero-gap);
  width: min(1700px, 92vw);
}

.hero__copy {
  max-width: 560px;
  text-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
}

.hero__brand-logo {
  display: block;
  width: var(--brand-logo-w);
  height: auto;
  margin-bottom: clamp(12px, 1.4vw, 20px);
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  padding: 7px 14px;
  border: 1px solid rgba(252, 98, 0, 0.36);
  border-radius: 999px;
  background: rgba(12, 12, 24, 0.72);
  backdrop-filter: blur(12px);
  font-family: var(--font-heading);
  font-size: clamp(11px, 0.88vw, 13px);
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.eyebrow::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--brand-orange);
  box-shadow: 0 0 12px var(--brand-orange);
}

h1 {
  font-family: var(--font-heading);
  font-size: var(--headline-size);
  line-height: 0.94;
  font-style: italic;
  font-weight: 1000;
  letter-spacing: -0.04em;
  text-transform: uppercase;
}

/* Forced 4-line desktop/tablet headline break — each segment is its own
   line so the layout is deterministic instead of depending on natural
   text reflow at an arbitrary container width. Mobile switches these back
   to inline (see mobile query) so the shorter font size wraps naturally.
   The 72px cap (not 78px) is load-bearing: .hero__copy stops growing past
   ~450px once .hero__content hits its 1200px max-width, but 4.6vw keeps
   scaling with the raw viewport — past ~1565px wide, an uncapped font
   makes "Gira los" (the longest line) exceed that fixed 450px box and
   wrap into a 5th line. 72px keeps it under with margin at any width. */
.h1-line {
  display: block;
  white-space: nowrap;
}

/* Groups the 4 .h1-line words into 2 pairs (see index.html) — display:
   contents by default so it introduces no box of its own and desktop/
   tablet's 4-line stack above is unaffected by the extra markup level.
   Mobile (see mobile query) turns this into the actual line break
   instead, pinning the headline to exactly 2 lines regardless of
   viewport width. */
.h1-row { display: contents; }

/* ══════════════════════════════════════════
   GAME COLUMN
   ══════════════════════════════════════════ */
.game {
  position: relative;
  display: grid;
  justify-items: center;
  align-content: center;
  min-width: 0;
  min-height: 0;
}

.game__logo {
  position: relative;
  z-index: 4;
  width: var(--gold-logo-w);
  margin-bottom: clamp(5px, 0.9vh, 14px);
  filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.45));
}

/* ══════════════════════════════════════════
   SLOT MACHINE
   ══════════════════════════════════════════ */
.slot {
  position: relative;
  width: var(--slot-w);
  aspect-ratio: 905 / 556;
  display: grid;
  place-items: center;
  filter: drop-shadow(0 22px 30px rgba(0, 0, 0, 0.3));
}

/* subtle spinning decoration behind reels */
.slot::before {
  content: "";
  position: absolute;
  width: 86%;
  height: 86%;
  border-radius: 50%;
  background: url("../img/glow-burst.webp") center / contain no-repeat;
  opacity: 0.22;
  mix-blend-mode: screen;
  animation: softSpin 12s linear infinite;
  pointer-events: none;
}

/* ══════════════════════════════════════════
   SLOT AURA — layered neon glow behind the slot machine. First child
   of .slot (still painted at z-index 0, behind reels(1)/frame(3)/
   character(4)/winline(5)), but its box is no longer sized flush to
   .slot's own outer edge — it's pinned to .slot__reels' own inset/
   width/height/border-radius instead (duplicated here per breakpoint,
   since this element can't move inside .slot__reels itself without its
   box-shadow bloom getting clipped by that element's own
   overflow:hidden, which exists to mask the spinning reel strips).
   Because box-shadows always paint outward from the box edge
   regardless of the box's own position, matching this box to the
   reels' real geometry means the glow now starts flush from the
   reels' own edge — same edge the frame's inner window sits right on
   top of — instead of from .slot's much larger outer edge, which used
   to leave a visible gap between the reels/frame and the glow. Three
   slim layers instead of one blurred blob: a crisp near-edge stroke, a
   mid neon halo and a wide soft bloom — all outlines/box-shadow rings,
   so the result stays a defined contour, not a filled smear. Sizing/
   opacity are tuned per breakpoint below (DESKTOP/TABLET/MOBILE aura
   blocks); the reels-matching inset/radius overrides live in the same
   per-breakpoint blocks that set .slot__reels' own geometry.
   ══════════════════════════════════════════ */
.slot__aura {
  position: absolute;
  /* Matches the DESKTOP SLOT FRAME .slot__reels geometry below (left:
     3.469%, top:4.604%, width:93.343%, height:90.443%) — the default
     for ≥1101px and for the two landscape blocks that restore the same
     desktop reels geometry at narrower viewports. */
  inset: 4.604% 3.188% 4.953% 3.469%;
  z-index: 0;
  border-radius: 14px;
  pointer-events: none;
}

.slot__aura-layer {
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.slot__aura-layer--wide {
  box-shadow:
    0 0 min(16vw, 150px) min(4vw, 30px) rgba(30, 110, 255, 0.4),
    0 0 min(26vw, 240px) min(7vw, 65px) rgba(18, 70, 220, 0.26);
  animation: auraBloomWide 6s ease-in-out infinite;
}

.slot__aura-layer--mid {
  box-shadow:
    0 0 min(7vw, 65px) min(1.4vw, 11px) rgba(99, 226, 255, 0.55),
    0 0 min(12vw, 105px) min(2.5vw, 20px) rgba(40, 140, 255, 0.36);
  animation: auraBloomMid 4.2s ease-in-out infinite;
}

.slot__aura-layer--sharp {
  /* Flush with the shared inset:0 box (same as wide/mid) — this hard
     2px border needs to sit exactly on the frame's own outer edge with
     zero gap. Mobile pulls this in a few px instead (see the MOBILE aura
     override below) since its frame art's ornate corner cutouts let this
     ring show through when flush; desktop's frame doesn't have that
     problem, so flush is correct here and keeps the glow starting
     immediately at the frame edge with no dead zone before it. */
  inset: 0;
  border: 2px solid rgba(175, 240, 255, 0.8);
  box-shadow:
    0 0 14px 2px rgba(175, 240, 255, 0.75),
    0 0 28px 4px rgba(80, 190, 255, 0.4),
    inset 0 0 16px rgba(70, 180, 255, 0.35);
  animation: auraBloomSharp 3.4s ease-in-out infinite;
}

/* ══════════════════════════════════════════
   SLOT LIGHTNING — ambient decorative bolts around the slot machine
   (atmosphere only — the win-line's own lightning bolt above is a
   separate, untouched system). A small pool of bolt elements (see
   main.js's LIGHTNING_SPOTS/scheduleBolt) that JS relocates to a
   random spot around the slot's perimeter and fires one at a time —
   never a fixed wall of simultaneous bolts down the sides. Each bolt
   is a plain CSS clip-path shape, not a continuously re-rasterized SVG
   filter — only opacity/filter (brightness + drop-shadow) ever
   animate, so this stays cheap even on weak phones. Every spot lives
   on the slot's own box as a % offset (this container is inset:0 on
   .slot), so the whole system scales with the slot at every viewport
   with no breakpoint-specific CSS needed; z-index 2 sits above the
   dark reel backdrop but below the frame art/character/win-line, so a
   bolt grazing the frame's own border still reads as "behind" it,
   never on top of a symbol. */
.slot__lightning {
  position: absolute;
  inset: 0;
  z-index: 2;
  overflow: visible;
  pointer-events: none;
}

.bolt {
  /* Custom property, not a real background — the .bolt box itself
     stays fully transparent (it only drives the opacity/filter
     animation); ::before/::after below are the only things that ever
     paint, and only their clip-path-cut zigzag shape, never a plain
     rectangle. */
  --bolt-gradient: linear-gradient(180deg,
    #f2feff 0%,
    #8fe3ff 6%,
    #35c6f5 22%,
    #1d9eff 42%,
    #1f6dff 64%,
    #123bc2 85%,
    #081f7a 100%);
  --bolt-rot: 0deg;
  position: absolute;
  display: block;
  opacity: 0;
  filter: brightness(1) drop-shadow(0 0 0 transparent);
  transform: rotate(var(--bolt-rot));
  pointer-events: none;
  will-change: opacity, filter;
}

/* Base jagged silhouette — one zigzag stroke, clipped out of the
   element's own box so width/height (set per strike by main.js) scale
   the whole shape without redrawing the polygon. */
.bolt::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--bolt-gradient);
  filter: inherit;
  clip-path: polygon(56% 0%, 68% 0%, 45% 40%, 62% 40%, 28% 100%, 41% 54%, 20% 54%);
}

/* Applied to roughly a third of strikes (see main.js) for variety — a
   shorter offshoot stroke, rotated/offset, so the pair reads as one
   branched bolt instead of always the same single clean line. */
.bolt--branched::after {
  content: "";
  position: absolute;
  top: 34%;
  left: 38%;
  width: 55%;
  height: 46%;
  background: var(--bolt-gradient);
  filter: inherit;
  clip-path: polygon(70% 0%, 100% 0%, 55% 46%, 78% 46%, 20% 100%, 46% 55%, 10% 55%);
  transform: rotate(18deg);
  opacity: 0.9;
}

/* One-shot strike: quick bright flash, a couple of re-ignitions, a
   soft afterglow, then fade — plays once per strike (main.js adds/
   removes .is-active and picks a new spot + random gap before the
   next one), so gaps between strikes are genuinely irregular instead
   of following one fixed looping duration per bolt. */
.bolt.is-active {
  animation: boltFlash 1s linear 1;
}

@keyframes boltFlash {
  0%     { opacity: 0;    filter: brightness(1)   drop-shadow(0 0 0 transparent); }
  4.6%   { opacity: 1;    filter: brightness(2.4) drop-shadow(0 0 7px #eafcff) drop-shadow(0 0 18px #6fe0ff) drop-shadow(0 0 34px rgba(20, 80, 255, 0.7)); }
  9.2%   { opacity: 0.3;  filter: brightness(1.4) drop-shadow(0 0 5px #6fe0ff) drop-shadow(0 0 12px #2f8bff); }
  13.8%  { opacity: 1;    filter: brightness(2.1) drop-shadow(0 0 6px #eafcff) drop-shadow(0 0 15px #6fe0ff) drop-shadow(0 0 28px rgba(20, 80, 255, 0.6)); }
  19.2%  { opacity: 0.45; filter: brightness(1.3) drop-shadow(0 0 4px #6fe0ff) drop-shadow(0 0 10px #2f8bff); }
  25%    { opacity: 0.9;  filter: brightness(1.5) drop-shadow(0 0 5px #6fe0ff) drop-shadow(0 0 12px #2f8bff); }
  34.6%  { opacity: 0.5;  filter: brightness(1.1) drop-shadow(0 0 4px rgba(47, 139, 255, 0.5)); }
  61.5%  { opacity: 0.24; filter: brightness(1)   drop-shadow(0 0 3px rgba(111, 224, 255, 0.35)); }
  100%   { opacity: 0;    filter: brightness(1)   drop-shadow(0 0 0 transparent); }
}

.slot__frame {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}

.slot__frame--mobile { display: none; }

/* ── Reels container ── */
.slot__reels {
  position: relative;   /* contains absolute children (winline) */
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  /* column-gap mirrors the divider gutters painted into slot__frame's
     artwork (measured ~1.55% of frame width) — keeps every column's
     visible window aligned with the frame's window. width/height below
     are sized to the frame's inner window itself (measured on frame.webp),
     so no padding is added here — padding would inset the 3-row viewport
     from the frame edges and make symbols enter/exit late. */
  column-gap: 1.5%;
  width: 96%;
  height: 93.5%;
  padding: 0;
  overflow: hidden;
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(10, 10, 22, 0.9), rgba(7, 7, 18, 0.95));
  border: 1px solid rgba(252, 98, 0, 0.12);
}

/* ── Win-line: one clean animated energy line, same SVG on desktop and
   mobile. JS toggles which .slot__winline-group is active per spin/
   layout (PAYLINES in main.js pick desktop's up/down/straight shape;
   mobile always uses --mobile-straight, since it only ever has a
   center-row win). Each group holds a soft blurred "glow" stroke behind
   a crisp "core" stroke, both following the exact same points through
   the winning symbols' centers — a plain solid polyline, no per-frame
   SVG filter distorting it, so it reads as one steady premium beam
   instead of a jittery scribble (an earlier feTurbulence/feDisplacement
   filter used to jitter the whole group; removed — it also collapsed
   the filter region to zero height for the perfectly flat "straight"/
   "mobile-straight" shapes, so those two used to render invisible). ── */
.slot__winline {
  position: absolute;
  inset: 0;
  /* explicit 100%/100% — inset:0 alone isn't enough for an SVG (a
     replaced element with its own intrinsic 1:1 ratio from viewBox):
     without a set width/height, absolutely-positioned replaced
     elements size from that intrinsic ratio instead of stretching to
     the inset box, so the SVG would render as a 100×100 square instead
     of matching .slot__reels' actual (non-square) box. */
  width: 100%;
  height: 100%;
  z-index: 5;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

.slot__reels.has-win .slot__winline {
  opacity: 1;
}

.slot__winline-group {
  display: none;
}

.slot__winline-group.is-active {
  display: block;
}

.slot__winline-group.is-active .slot__winline-core {
  animation: winlinePulse 1.6s ease-in-out infinite;
}

.slot__winline-glow,
.slot__winline-core {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* Wide soft bloom, brand orange — reads as the "energy" around the beam. */
.slot__winline-glow {
  stroke: var(--brand-orange);
  stroke-width: 6;
  opacity: 0.55;
  filter: blur(3px);
}

/* Crisp center beam, warm gold-orange (not white) so the line clearly
   reads as brand orange rather than a plain white wire with an orange
   halo around it. */
.slot__winline-core {
  stroke: #ffb238;
  stroke-width: 2.2;
  filter:
    drop-shadow(0 0 3px rgba(255, 255, 255, 0.85))
    drop-shadow(0 0 9px rgba(252, 98, 0, 0.9));
}

/*
  ── Single reel — the visible viewport, always exactly 3 rows tall ──
  height:100% pins it to the grid row's stretched height (identical for
  every column, since .slot__reels is a single-row 5-column grid with the
  default align-items:stretch), so --reel-row-height below resolves to the
  exact same pixel value in every reel — no per-column drift possible.
*/
.reel {
  height: 100%;
  position: relative;
  overflow: hidden;
}

/* top/bottom fade masks — a thin vignette right at the clip edge only;
   symbols must read as fully visible well before crossing a row boundary
   (row height = 33.3% of reel), so this stays much shorter than one row. */
.reel::before,
.reel::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 10%;
  z-index: 4;
  pointer-events: none;
}

.reel::before {
  top: 0;
  background: linear-gradient(180deg, rgba(10, 10, 22, 0.85), transparent);
}

.reel::after {
  bottom: 0;
  background: linear-gradient(0deg, rgba(10, 10, 22, 0.85), transparent);
}

/*
  Strip — --cells prepared cells (set by JS, default 21), height = (--cells/3)
  * 100% of the reel (its containing block), i.e. exactly --cells/3 "screens".
  Cell height is then 100% of THIS strip divided by --cells, which cancels
  back out to exactly reel-height/3 — one row, no rounding drift, no manual
  offsets. Every reel uses this same formula, so row Y-positions are
  identical across every column by construction, not by eyeballing.

  Spin direction: translateY(-X% → 0) = content scrolls DOWN = top-to-bottom.
  The last cells are visible at start → cells 0,1,2 visible at end (result).
  X is always an exact multiple of one cell height (see JS TRAVEL_PERCENT),
  and the resting position is always translateY(0) — a strip can never stop
  mid-cell. JS sets transition on the strip element directly; no CSS
  animation class needed.
*/
.reel__strip {
  --cells: 21;
  height: calc(var(--cells) / 3 * 100%);
  display: flex;
  flex-direction: column;
  gap: 0;
  will-change: transform;
}

.reel__cell {
  flex-shrink: 0;
  height: calc(100% / var(--cells));       /* = reel_height / 3, every column */
  min-height: calc(100% / var(--cells));
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

/* Single centering authority: every symbol sits in an identical box,
   regardless of its own image proportions — no per-image tuning needed.
   position:relative anchors the win-highlight glow below (::before),
   which is positioned relative to this same box — nothing else here
   changes, so it doesn't affect the flex-centering of the image. */
.reel__symbol {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.reel__symbol img {
  display: block;
  max-width: 78%;
  max-height: 78%;
  width: auto;
  height: auto;
  object-fit: contain;
  margin: 0;
  filter: drop-shadow(0 3px 7px rgba(0, 0, 0, 0.28));
}

/* Win highlight — a plain round glow on its own pseudo-element, kept
   entirely separate from the <img>: the image's own position, size,
   and filter never change, so it can't shift or gain a hard-edged
   shadow. inset:4% keeps this pseudo-element's own box safely inside
   .reel__symbol's box (100%/100% of the cell) at all times — the same
   box the image already sits in without ever being clipped — instead
   of a filter:drop-shadow, whose blurred reach extends outward from
   the image's own silhouette by an amount that isn't precisely
   boundable (a wide blur can reach past .reel's own overflow:hidden,
   which exists to mask the spinning strip and can't be loosened,
   getting flattened off at that edge — this was the dark/cut-off edge
   under the bottom row's symbol). A radial-gradient circle here can
   never do that: it never grows past this box, so it never reaches
   that edge, and border-radius:50% keeps it a clean circle regardless
   of the icon's own shape (a plain drop-shadow instead traces the
   icon's own outline, which isn't necessarily round). */
.reel__symbol::before {
  content: "";
  position: absolute;
  inset: 10%;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(255, 170, 60, 0.55) 0%,
    rgba(255, 130, 20, 0.24) 42%,
    rgba(255, 130, 20, 0) 65%);
  opacity: 0;
  pointer-events: none;
}

/* win pulse — only the landing cell JS marks as the winning one per
   reel (see .is-winning in main.js), not a fixed row. */
.slot.is-win .reel__cell.is-winning .reel__symbol::before {
  animation: winPulse 1.2s ease-in-out infinite;
}

/* ══════════════════════════════════════════
   ZEUS HERO — one animated foreground character, anchored to .slot (not
   .game) so it always sits relative to the slot's own box regardless of
   how much space the logo/CTA take above/below it. Sits bottom-left,
   anchored via the breakpoints below.

   .zeus-media is still the positioned container (kept so every
   existing desktop/tablet/mobile anchor below keeps working unchanged);
   its one child is a plain animated GIF with real alpha — no format
   branching, no JS needed, works identically in every engine.

   No chroma key, mask, mix-blend-mode or canvas is applied to it;
   nothing here has a background/poster/shadow that could show as a box
   behind it.

   z-index sits above the slot frame(3)/reels but below the CTA(6), so it
   can never cover the button even if it drifts on an odd viewport.
   ══════════════════════════════════════════ */
.zeus-media {
  position: absolute;
  z-index: 4;
  left: -7%;
  bottom: -3%;
  transform: translate(var(--zeus-x), var(--zeus-y)) translateZ(0);
  width: var(--zeus-w);
  height: auto;
  pointer-events: none;
  user-select: none;
  background: transparent;
  /* translateZ(0) above + this is enough to give the GIF its own
     compositor layer without `will-change` — that hint left on
     permanently is exactly what keeps costing memory on iPhone for as
     long as the page stays open, for a static container that never
     actually changes after load. */
  backface-visibility: hidden;
}

.zeus-gif {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
  background: transparent !important;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  backface-visibility: hidden;
  transform: translateZ(0);
}

/* ══════════════════════════════════════════
   CTA BUTTON
   ══════════════════════════════════════════ */
.cta {
  position: relative;
  z-index: 6;
  min-width: var(--cta-w);
  min-height: var(--cta-h);
  margin-top: clamp(10px, 1.8vh, 24px);
  padding: 0 clamp(20px, 3.2vw, 44px);
  border: 0;
  border-radius: 999px;
  color: var(--brand-white);
  background:
    linear-gradient(90deg, rgba(255, 255, 255, 0.16), transparent 30%, rgba(255, 255, 255, 0.11)),
    linear-gradient(180deg, #ff8c00, var(--brand-orange));
  box-shadow:
    0 0 0 3px rgba(255, 140, 0, 0.18) inset,
    0 12px 28px rgba(0, 0, 0, 0.3),
    0 0 26px var(--glow);
  cursor: pointer;
  font-family: var(--font-heading);
  font-size: var(--cta-font);
  font-style: italic;
  font-weight: 1000;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  animation: pulseButton 2s ease-in-out infinite;
}

.cta::before, .cta::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 14px;
  height: 14px;
  background: var(--brand-orange);
  transform: translateY(-50%) rotate(45deg);
}

.cta::before { left: -5px; }
.cta::after  { right: -5px; }

.cta:disabled {
  cursor: wait;
  opacity: 0.68;
  animation: none;
}

/* ══════════════════════════════════════════
   MODAL
   ══════════════════════════════════════════ */
.modal {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: clamp(12px, 4vw, 32px);
  background: rgba(0, 0, 0, 0.84);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.28s ease, visibility 0.28s ease;
}

.modal.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

.modal::before {
  content: "";
  position: absolute;
  width: min(90vw, 620px);
  aspect-ratio: 1;
  background: url("../img/glow-burst.webp") center / contain no-repeat;
  opacity: 0.3;
  mix-blend-mode: screen;
  animation: softSpin 8s linear infinite reverse;
}

.modal__card {
  position: relative;
  z-index: 1;
  width: min(90vw, 480px);
  max-height: calc(100dvh - clamp(24px, 8vw, 64px));
  overflow-y: auto;
  padding: clamp(20px, 4.5vw, 44px) clamp(16px, 4.5vw, 44px);
  border: 1px solid rgba(252, 98, 0, 0.26);
  border-radius: 26px;
  background: linear-gradient(180deg, rgba(13, 13, 25, 0.94), rgba(8, 8, 20, 0.98));
  box-shadow:
    0 22px 64px rgba(0, 0, 0, 0.52),
    0 0 56px rgba(252, 98, 0, 0.09);
  backdrop-filter: blur(20px);
  text-align: center;
}

.modal__card.is-animating {
  animation: modalPop 0.32s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.modal__card.is-closing {
  animation: modalPopOut 0.32s ease both;
}

.modal__logo {
  width: min(78%, 320px);
  margin: 0 auto 16px;
}

.modal__label {
  display: flex;
  position: relative;
  left: auto;
  right: auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 100%;
  margin: 0 auto;
  padding: 0;
  transform: none;
  font-family: var(--font-heading);
  /* Capped lower than the old 40px: at 40px the longest line ("DESBLOQUEADO!")
     measured wider than the card's own content box (432px of text vs ~390px
     available), so it overflowed past the card edge instead of wrapping —
     that overflow, not a transform/margin, was the "text drifts right" bug. */
  font-size: clamp(16px, 3.1vw, 30px);
  line-height: 1.15;
  font-style: italic;
  font-weight: 1000;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

.modal__label span {
  display: block;
  width: 100%;
  max-width: 100%;
  margin: 0 auto;
  text-align: center;
  overflow-wrap: break-word;
}

.modal__bonus {
  margin: 10px auto 4px;
  max-width: 30ch;
  color: var(--brand-orange);
  font-family: var(--font-heading);
  font-size: clamp(22px, 6vw, 42px);
  line-height: 1.05;
  font-style: italic;
  font-weight: 1000;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  text-wrap: balance;
  text-shadow: 0 0 28px rgba(252, 98, 0, 0.52), 0 2px 0 rgba(255, 255, 255, 0.08);
}

/* Keeps the leading number glued to the word right after it (see
   formatBonusHTML in js/main.js) so a line break never stands a bare
   number alone — only remaining words are free to wrap. */
.modal-bonus__nowrap {
  white-space: nowrap;
}

/* Narrow phones: the longest bonus copy ("4 giros gratis por
   verificación") needs a touch less size to settle into 2 balanced
   lines instead of 3, without shrinking the card's own padding. */
@media (max-width: 360px) {
  .modal__bonus {
    font-size: clamp(17px, 5.4vw, 42px);
  }
}

/* ══════════════════════════════════════════
   KEYFRAMES
   ══════════════════════════════════════════ */
@keyframes pulseButton {
  0%, 100% {
    box-shadow: 0 0 0 3px rgba(255, 140, 0, 0.18) inset, 0 12px 28px rgba(0, 0, 0, 0.3), 0 0 26px var(--glow);
  }
  50% {
    box-shadow: 0 0 0 3px rgba(255, 140, 0, 0.18) inset, 0 12px 28px rgba(0, 0, 0, 0.3), 0 0 50px var(--glow), 0 0 76px rgba(252, 98, 0, 0.26);
  }
}

@keyframes softSpin {
  to { transform: rotate(360deg); }
}

@keyframes auraBloomWide {
  0%, 100% { opacity: 0.65; }
  45%      { opacity: 0.85; }
  60%      { opacity: 1; }
  75%      { opacity: 0.7; }
}

@keyframes auraBloomMid {
  0%, 100% { opacity: 0.7; }
  50%      { opacity: 1; }
}

@keyframes auraBloomSharp {
  0%, 100% { opacity: 0.75; }
  50%      { opacity: 1; }
}

/* Pulses the round glow pseudo-element's opacity only (see
   .reel__symbol::before above) — its size/position never change, so
   this can't grow into .reel's clip edge at any point in the cycle,
   at any row, on any breakpoint. */
@keyframes winPulse {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1; }
}

/* Smooth breathing glow — a gentle brightness pulse (not a flicker),
   read through drop-shadow strength on the core so the beam itself
   never dims or steps, only its energy "breathes". Clean and premium
   rather than an electrical flicker. */
@keyframes winlinePulse {
  0%, 100% {
    filter:
      drop-shadow(0 0 3px rgba(255, 255, 255, 0.85))
      drop-shadow(0 0 9px rgba(252, 98, 0, 0.9));
  }
  50% {
    filter:
      drop-shadow(0 0 5px rgba(255, 255, 255, 0.95))
      drop-shadow(0 0 16px rgba(252, 98, 0, 1));
  }
}

@keyframes modalPop {
  from { opacity: 0; transform: scale(0.88) translateY(12px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

@keyframes modalPopOut {
  from { opacity: 1; transform: scale(1) translateY(0); }
  to   { opacity: 0; transform: scale(0.9) translateY(8px); }
}

/* ══════════════════════════════════════════
   TABLET ≤1100px — single column. Widened from ≤1080px to match the
   MOBILE breakpoint below (both moved together so the single-column
   switch here and the mobile-composition rules below always cover the
   exact same width range — see that block's comment for why 1100). */
@media (max-width: 1100px) {
  .hero__content {
    grid-template-columns: 1fr;
    gap: 5px;
    text-align: center;
  }

  .hero__copy { justify-self: center; }
  .hero__brand-logo { margin-inline: auto; }
}

/* ══════════════════════════════════════════
   MOBILE / VERTICAL LAYOUT ≤1100px — widened from ≤699px. At ~900–1100px
   the two-column desktop composition (bigger headline, bigger slot, both
   Zeus figure) no longer fits: the headline clips, the slot drifts right, Zeus
   spills off-screen and a horizontal scrollbar appears. Rather than tune a
   third, in-between composition, this range now gets the same proven
   mobile stack (logo → badge → headline → slot → CTA, single Zeus figure)
   just earlier than before. The old dedicated "TABLET PORTRAIT 700–1100"
   block (iPad-sized bump of the 5-reel desktop look) has been removed —
   its whole width range is now inside this mobile block instead, so
   keeping both would have meant two competing compositions fighting over
   the same viewports.
   ══════════════════════════════════════════ */
@media (max-width: 1100px) {
  :root {
    --brand-logo-w:  clamp(190px, 55vw, 260px);
    /* 7.2vw (not the previous 8.5vw) — at 390–480px wide, 8.5vw pinned
       "Gira los reels y" wide enough (up to 455px) to badly overflow
       hero__copy's box (widened below to 400px, still not wide enough
       on its own), reading as a lopsided headline. 7.2vw keeps the
       longer row inside that box down to 360px wide. */
    --headline-size: clamp(30px, 7.2vw, 46px);
    --gold-logo-w:   clamp(188px, 70vw, 294px);
    --slot-w:        min(92vw, 430px);
    --cta-w:         min(88vw, 390px);
    --cta-h:         clamp(58px, 15vw, 74px);
    /* Much bigger than before — Zeus now stands bottom-left beside the
       slot (see .zeus-media below) instead of small and centered
       under it, so his visible height reaches roughly up to the
       boundary between the middle and top symbol rows. */
    --zeus-w:     clamp(174px, 69%, 365px);

    /* Zeus position controls for this breakpoint — see the main copy of
       this block near the top of the file for how to use x/y. */
    --zeus-x: 0px;
    --zeus-y: 0px;
  }

  .landing {
    background-image:
      linear-gradient(180deg, rgba(12, 12, 24, 0.1), rgba(8, 8, 20, 0.68)),
      url("../img/page-bg-mobile.webp");
    background-position: top center;
  }

  /* Centering itself is inherited from the base .hero rule — its safe-
     alignment fallback already anchors content to the top on short
     phones where it doesn't fit, so no manual override is needed here. */
  .hero {
    padding: max(14px, env(safe-area-inset-top)) 0 max(14px, env(safe-area-inset-bottom));
  }

  .hero__content {
    width: min(100% - 18px, 490px);
  }

  /* Widened from 350px — at 390–480px wide the 2-line nowrap headline
     below needs more room than 350px gives it before it starts
     overflowing this box (and centered overflow this large reads as
     the headline drifting/spilling, not just "a bit bigger"). Explicit
     centering here too instead of relying only on the inherited
     text-align/justify-self from the ≤1100px block. */
  .hero__copy {
    max-width: 400px;
    margin-inline: auto;
    text-align: center;
  }

  .hero__brand-logo { margin-bottom: 8px; }

  /* Pinned to exactly 2 lines — "Gira los reels y" / "gana tu regalo"
     (see the .h1-row pairing in index.html) — instead of the natural
     reflow this replaced, which wrapped to anywhere from 2 to 4 lines
     depending on viewport width. Each .h1-row is its own block (forces
     the break between the two rows); nowrap on both row and line stops
     either row from wrapping again internally, so --headline-size
     above is the thing keeping "Gira los reels y" (the longer row) on
     one line — it's sized to fit inside .hero__copy's 400px cap down
     to 360px-wide phones. */
  .h1-row  { display: block; white-space: nowrap; }
  .h1-line { display: inline; white-space: nowrap; }


  .game__logo { margin-bottom: clamp(2px, 0.7vh, 8px); }

  /* slot-frame-mobile.webp's real canvas is 1141×1021 — matching that
     exactly here (like the desktop block below) means object-fit:contain
     fills .slot edge-to-edge with zero letterboxing, so no scale() hack
     or reel-area guesswork is needed to close a gap. */
  .slot { aspect-ratio: 1141 / 1021; }

  .slot__frame--desktop { display: none; }
  .slot__frame--mobile  { display: block; }

  /* Matches this breakpoint's own .slot__reels geometry (left:5.828%,
     top:5.436%, width:88.301%, height:88.983%, border-radius:11px) —
     see the base .slot__aura rule's comment for why this is duplicated
     here instead of moved inside .slot__reels itself. */
  .slot__aura {
    inset: 5.436% 5.871% 5.581% 5.828%;
    border-radius: 11px;
  }

  /* The desktop-tuned wide/mid glow layers' blur/spread reach far enough
     past the box edge that on mobile they (a) bleed back through the
     frame art's own ornate corner/edge cutouts, and (b) mostly fall
     outside the ~15px of room between the slot and the viewport edge on
     narrow phones (.landing is overflow:hidden, so anything past the
     viewport edge is just clipped and wasted) — most of each layer's
     soft falloff never gets to render at all, reading as a weak/near-
     absent glow right where the frame edge is. Both layers get a much
     shorter, denser falloff here instead: same total look, but packed
     into the space that's actually visible instead of spilling past it. */
  .slot__aura-layer--wide {
    box-shadow:
      0 0 min(3vw, 13px) min(1vw, 4px) rgba(30, 110, 255, 0.55),
      0 0 min(5vw, 21px) min(1.6vw, 7px) rgba(18, 70, 220, 0.35);
  }

  .slot__aura-layer--mid {
    box-shadow:
      0 0 min(3vw, 14px) min(1vw, 4px) rgba(99, 226, 255, 0.65),
      0 0 min(5vw, 22px) min(1.6vw, 8px) rgba(40, 140, 255, 0.42);
  }

  /* Sharp layer's hard border only needs to pull in from the frame edge
     here on mobile (see the base rule's comment) — its ornate corner
     cutouts let a flush ring show through otherwise. */
  .slot__aura-layer--sharp {
    inset: 3px;
  }

  /* Corner-anchored bottom-left like desktop, not centered under the
     slot: Zeus stands partially beside the slot instead of deep over
     its center, so the reels stay readable. Off-screen bleed on the
     left/bottom at the narrowest phones is fine — nothing below/left
     of the slot needs to stay visible there. */
  .zeus-media {
    left: -18%;
    right: auto;
    bottom: -6%;
    transform: translate(var(--zeus-x), var(--zeus-y)) translateZ(0);
  }

  /* Reels area pinned by percentage straight off slot-frame-mobile.webp's
     own measured inner window (pixel-level alpha edge/centroid detection):
     window left 66.5/top 55.5/right 1074/bottom 964 of its 1141×1021
     canvas. Column widths (319/365/323.5fr) are the gaps between the
     frame's two painted dividers, measured at x≈385.5 and x≈750.5, so
     each of the 3 symbols lands centered in its section — same technique
     as the desktop block below, just against the mobile frame's own
     geometry. */
  .slot__reels {
    position: absolute;
    left: 5.828%;
    top: 5.436%;
    width: 88.301%;
    height: 88.983%;
    grid-template-columns: 319fr 365fr 323.5fr;
    column-gap: 0;
    padding: 0;
    border-radius: 11px;
  }

  /* hide reels 4 and 5 on mobile */
  .reel:nth-child(n+4) { display: none; }

  /* In flow, right under the slot — never pinned to the viewport edge, so
     it can never drift away from the game block or land far from it. */
  .cta { margin-top: clamp(8px, 1.6vh, 18px); }

}

/* ══════════════════════════════════════════
   DESKTOP SLOT FRAME ≥1101px — slot-frame-desktop.webp's real canvas is
   1427×858, so the aspect-ratio here matches it exactly (no letterboxing
   under object-fit:contain). .slot__reels is then pinned by percentage
   straight off the frame's own measured inner window — re-measured
   pixel-by-pixel (alpha-channel edge/centroid detection, not eyeballed):
   window left 49.5/top 39.5/right 1381.5/bottom 815.5 of that canvas —
   the fr column widths (220.3/267.4/323.2/269.2/252) are the gaps
   between the frame's painted gold dividers, whose measured centers are
   x≈269.8/537.2/860.4/1129.6, so every column's center lands under the
   middle of its section, and the win-line SVG's x-percentages (below,
   main.js) are the same divider-derived centers. Mobile/tablet
   (≤1100px, block above) are untouched by any of this — this block
   only ever applies from 1101px up.
   ══════════════════════════════════════════ */
@media (min-width: 1101px) {
  .slot {
    aspect-ratio: 1427 / 858;
  }

  .slot__reels {
    position: absolute;
    left: 3.469%;
    top: 4.604%;
    width: 93.343%;
    height: 90.443%;
    grid-template-columns: 220.3fr 267.4fr 323.2fr 269.2fr 252fr;
    column-gap: 0;
  }

  /* Desktop only — noticeably bigger than the shared 78% base/mobile
     size, but still short of 100% so symbols keep a small clear gap
     from the frame's painted column dividers and from each other
     (adjacent cells touch edge-to-edge with zero gap/padding, so
     anything under 100% here can never actually overlap a neighbor —
     this margin is purely so symbols don't look like they're touching
     the divider lines or each other). Centering is untouched: both
     .reel__cell and .reel__symbol still just flex-center whatever size
     the image resolves to. */
  .reel__symbol img {
    max-width: 94%;
    max-height: 94%;
  }

  /* Whole-composition zoom — text column, Zeus, slot, game logo and CTA
     all scale together as one unit, since they're all just this one
     grid item (.hero__content, see its rule above) centered by .hero's
     own place-items:center. Scaling around the item's own center (the
     transform default) keeps that centering exactly where it already
     was; nothing about width/columns/gap/layout changes, so every
     proportion and relative position inside stays identical, just
     bigger. 1.08 is the largest value that still clears the viewport
     at the narrowest required desktop widths (1280–1512px, where
     .hero__content's own min(1700px, 92vw) sizing already leaves only
     a ~51–60px margin per side) with a few px of safety margin still
     spare — 1920px alone has much more room, but one shared value has
     to hold at the tightest width too. */
  .hero__content {
    transform: scale(1.06);
  }
}

/* ══════════════════════════════════════════
   INTERMEDIATE DESKTOP 1101–1600px — .zeus-media's left/bottom (base
   rule above) are already percentages of .slot, not the viewport, so
   they scale down in lockstep with the slot itself and never drift
   toward the text column on their own. This band exists because these
   desktop widths (1280/1366/1440/1512) leave only a ~170–200px corridor
   between the headline text and the frame's first vertical divider —
   not enough room for the base rule's much bigger ≥1601px size without
   crossing into either one, so this band caps Zeus a bit smaller and
   pulls him left/up (--zeus-x/--zeus-y) to center him in that
   corridor: his opaque figure clears the text on one side and stays out
   of the reels (past the first divider) on the other, while still
   standing roughly to twice his old on-screen size. Verified with
   positive textGap/dividerGap margins at 1280, 1366, 1440 and 1512.
   No width upper bound is needed above 1600px: the base rule's own
   numbers already leave a clean gap there (verified at 1920).
   ══════════════════════════════════════════ */
@media (min-width: 1101px) and (max-width: 1600px) {
  .zeus-media {
    left: -5%;
  }

  :root {
    --zeus-w: clamp(210px, 31.5%, 290px);
    --zeus-x: -21px;
    --zeus-y: -20px;
  }

}

/* ══════════════════════════════════════════
   TALL NARROW TABLETS/PHABLETS ≤699px wide, height ≥900px (e.g.
   BlackBerry PlayBook 600x1024) — still the 3-reel MOBILE layout
   above (nothing here touches reel count, slot, CTA or Zeus sizing),
   but at this width the mobile headline's font-size formula is
   already pinned at its 46px ceiling (reached above ~541px wide),
   and 46px no longer fits inside hero__copy's fixed 350px box —
   "Gira los reels y" renders at ~513px and the ~163px excess spills
   out past both edges of that box, reading as a lopsided/off-center
   headline rather than a small overflow. Widens the text column and
   dials the font back down to actually fit inside it.
   ══════════════════════════════════════════ */
@media (max-width: 699px) and (min-height: 900px) {
  :root {
    --headline-size: clamp(28px, 6.2vw, 36px);
  }

  .hero__copy {
    margin-inline: auto;
    max-width: min(85%, 440px);
    text-align: center;
  }

  h1 { margin-inline: auto; max-width: 100%; }
}

/* ══════════════════════════════════════════
   IPAD / LARGE TABLETS PORTRAIT 768–1100px wide, height ≥900px (iPad,
   iPad Air, iPad Pro, Galaxy Tab, etc. — 768x1024, 810x1080, 820x1180,
   834x1194, 1024x1366). Still the same single-column, 3-reel MOBILE
   composition above (reel count/slot logic untouched) — this band only
   scales the whole stack up and re-centers the text, since at these
   sizes the mobile-derived floor sizes read as a small, off-to-one-side
   composition stranded in the middle of a much bigger screen. Placed
   after the MOBILE block so its overrides win; doesn't touch phones
   (<768px) or desktop (>1100px) at all.
   ══════════════════════════════════════════ */
@media (min-width: 768px) and (max-width: 1100px) and (min-height: 900px) {
  :root {
    /* Every floor here is set above what the inherited MOBILE formula
       already produces across this whole 768–1100px band (that block's
       own vw-slopes are steep enough to hit their ceiling well before
       768px, e.g. --brand-logo-w flatlines at 260px, --headline-size at
       46px) — so each of these is a genuine increase at every width in
       the range, not just at the top end. */
    --brand-logo-w:  clamp(270px, 30vw, 340px);
    --headline-size: clamp(48px, 5.4vw, 60px);
    --gold-logo-w:   clamp(300px, 34vw, 400px);
    --slot-w:        min(72vw, 800px);
    --cta-w:         min(52vw, 520px);
    --cta-h:         clamp(76px, 9.5vw, 96px);
    --cta-font:      clamp(24px, 3vw, 34px);
    /* Much bigger than before — same reasoning as the MOBILE block:
       Zeus's visible height should reach roughly to the boundary
       between the middle and top symbol rows. x is inherited from the
       MOBILE block; y gets a bit more lift here since this band's
       taller slot puts the container's bottom closer to the CTA. */
    --zeus-w:     clamp(310px, 68%, 550px);
    --zeus-y: -12px;
  }

  /* Tablets have much more headroom below the slot than phones do at the
     shared mobile -3.5% anchor (taller slot, roomier CTA gap), so this
     band pulls Zeus down further on its own — same left offset/transform
     as the inherited mobile rule, only bottom changes. */
  .zeus-media {
    bottom: -6%;
  }

  .hero__content { width: 100%; }

  .hero__brand-logo { margin-bottom: clamp(10px, 1.2vw, 18px); }

  .hero__copy {
    max-width: min(90%, 760px);
    margin-inline: auto;
    text-align: center;
  }

  h1 {
    line-height: 0.92;
    text-align: center;
    margin-inline: auto;
    max-width: 100%;
  }

  .game__logo { margin-bottom: clamp(6px, 1vh, 14px); }
}

/* ══════════════════════════════════════════
   LARGE TABLETS / FOLD WIDTHS 700–900px (e.g. 712x1138, 768x1024,
   820x1180, 853x1280) — sits between the TALL NARROW TABLETS block
   above (≤699px wide) and the IPAD block above (≥768px AND ≥900px
   tall): widths in this 700–900 gap could fall through both (e.g.
   712px wide is >699 but <768) and land back on the plain MOBILE
   block's centering alone, which read as off-center next to the other
   tablet sizes. Re-asserts centering explicitly here — still the same
   3-reel MOBILE composition, reel count/slot/CTA untouched — and bumps
   Zeus a bit past the IPAD block's size. Placed after the IPAD
   block so it wins for the widths the two share.
   ══════════════════════════════════════════ */
@media (min-width: 700px) and (max-width: 900px) {
  .hero__content {
    width: 100%;
    margin-inline: auto;
    text-align: center;
    align-items: center;
    left: auto;
    right: auto;
    transform: none;
  }

  .hero__copy {
    width: 100%;
    max-width: min(90%, 760px);
    margin-inline: auto;
    text-align: center;
    left: auto;
    right: auto;
    transform: none;
  }

  h1 {
    text-align: center;
    margin-inline: auto;
    max-width: 100%;
  }

  :root {
    /* Same as the IPAD block above (this range overlaps and wins over
       it — see comment on that block) — Zeus only, nothing else here
       touched. */
    --zeus-w: clamp(310px, 68%, 550px);
    --zeus-y: -12px;
  }

  /* Same lower anchor as the IPAD block above (this range overlaps and
     wins over it). */
  .zeus-media {
    bottom: -6%;
  }
}

/* ══════════════════════════════════════════
   SMALL PHONES / SHORT SCREENS
   ══════════════════════════════════════════ */
@media (max-width: 380px), (max-height: 636px) {
  :root {
    --brand-logo-w:  clamp(160px, 46vw, 205px);
    --headline-size: clamp(25px, 8.2vw, 38px);
    --gold-logo-w:   clamp(160px, 56vw, 238px);
    --slot-w:        min(83vw, 302px);
  }

  .hero { padding-top: max(10px, env(safe-area-inset-top)); }

  .hero__brand-logo { margin-bottom: 5px; }

  .eyebrow {
    margin-bottom: 5px;
    padding: 5px 10px;
    font-size: 10px;
  }

  .game__logo { margin-bottom: 2px; }
}

/* ══════════════════════════════════════════
   COMPACT-HEIGHT PHONES/FOLDABLES 637–760px tall (e.g. Surface Duo
   540x720) — taller than the short-screen band above so it keeps the
   normal mobile look, but not tall enough for the full mobile sizing:
   unshrunk, the stack (logo+badge+headline+Gold Party logo+slot+CTA)
   runs to ~784px and the CuatroBet logo/CTA get clipped top and bottom
   by the no-scroll 100dvh + overflow:hidden rule. Trims each piece a
   little so the whole stack fits with room to spare, without dropping
   to the much smaller short-screen sizes.
   ══════════════════════════════════════════ */
@media (max-width: 699px) and (min-height: 637px) and (max-height: 760px) {
  :root {
    --brand-logo-w:  clamp(160px, 42vw, 220px);
    --headline-size: clamp(22px, 6.4vw, 36px);
    --gold-logo-w:   clamp(150px, 46vw, 220px);
    --slot-w:        min(78vw, 320px);
    --cta-h:         clamp(42px, 6vh, 62px);
  }

  .hero { padding: max(8px, env(safe-area-inset-top)) 0 max(8px, env(safe-area-inset-bottom)); }

  .hero__brand-logo { margin-bottom: 6px; }

  .eyebrow {
    margin-bottom: 6px;
    padding: 5px 12px;
    font-size: 11px;
  }

  .game__logo { margin-bottom: 4px; }

  .cta { margin-top: clamp(6px, 1.4vh, 12px); }
}

/* ══════════════════════════════════════════
   TABLET LANDSCAPE / LOW-HEIGHT DESKTOP-WIDTH (e.g. Nest Hub 1024x600,
   generic 1024x639) — wide enough to afford the two-column desktop
   layout, but too short for the portrait tablet stack above (logo +
   badge + headline + Gold Party logo + slot + CTA) to fit without
   clipping against the no-scroll 100dvh + overflow:hidden rule. Switches
   back to side-by-side like the short-landscape-phones block below, but
   this band is wide enough to keep the full 5-reel slot and a proper
   two-column reading layout instead of that block's phone-cramped one.
   min-width is 1101px (not the old 900px) so this never overlaps the
   MOBILE block above, which now runs through 1100px at any height.
   Placed after the SMALL PHONES block above — that block's
   `(max-height: 636px)` half also matches viewports like 1024x600, so
   this block re-declares every variable the two share in its own
   `:root` here; same-specificity `:root` declarations resolve by source
   order, and this block sits later in the file, so its values win.
   ══════════════════════════════════════════ */
@media (min-width: 1101px) and (max-height: 700px) {
  :root {
    --hero-gap:      clamp(16px, 3vw, 36px);
    --brand-logo-w:  clamp(160px, 13vw, 220px);
    --headline-size: clamp(28px, 3.6vw, 44px);
    --gold-logo-w:   clamp(160px, 18vw, 260px);
    --slot-w:        min(46vw, 460px);
    --cta-w:         clamp(200px, 18vw, 280px);
    --cta-h:         clamp(48px, 8vh, 64px);
    --cta-font:      clamp(16px, 1.8vw, 24px);
    --zeus-w:     clamp(140px, 28%, 220px);
    --zeus-x: 20px;
    --zeus-y: -30px;
  }

  .hero { padding: max(10px, env(safe-area-inset-top)) 16px; }

  .hero__content {
    grid-template-columns: minmax(220px, 0.8fr) minmax(340px, 1.2fr);
    text-align: left;
  }

  .hero__copy { justify-self: start; max-width: 380px; }

  .hero__brand-logo { margin-bottom: 10px; }

  .eyebrow {
    margin-bottom: 8px;
    padding: 7px 14px;
    font-size: clamp(11px, 1.1vw, 13px);
  }

  h1 { line-height: 1; }


  .game__logo { margin-bottom: 6px; }

  .cta { margin-top: clamp(8px, 1.6vh, 16px); }
}

/* ══════════════════════════════════════════
   LANDSCAPE TABLETS / SMALL DESKTOP WINDOWS 700–1100px wide, landscape,
   431–820px tall (e.g. Nest Hub 1024x600, iPad classic 1024x768 rotated,
   a browser window resized to ~1000x700). This exact band used to fall
   through every other breakpoint: narrower than the ≥1101px TABLET
   LANDSCAPE block above, but wider/taller than the ULTRA-COMPACT/SHORT
   LANDSCAPE PHONE blocks below — so with nothing here, the MOBILE block
   (unconditional on height, ≤1100px wide) kept applying its portrait
   stack even though there's plenty of width for the two-column desktop
   layout. `orientation: landscape` is explicit (unlike the ≥1101px
   block above, which only inferred it from min-width/max-height) since
   this band's width alone isn't enough to assume landscape.
   min-height 431px keeps this from ever overlapping the ULTRA-COMPACT
   block below (≤430px tall) — no two blocks here fight over a pixel.
   ══════════════════════════════════════════ */
@media (orientation: landscape) and (min-width: 700px) and (max-width: 1100px) and (min-height: 431px) and (max-height: 820px) {
  :root {
    --hero-gap:      clamp(16px, 3vw, 36px);
    --brand-logo-w:  clamp(150px, 14vw, 210px);
    --headline-size: clamp(26px, 3.8vw, 42px);
    --gold-logo-w:   clamp(150px, 18vw, 250px);
    --slot-w:        min(48vw, 440px);
    --cta-w:         clamp(190px, 18vw, 270px);
    --cta-h:         clamp(46px, 7.5vh, 62px);
    --cta-font:      clamp(15px, 1.8vw, 23px);
    --zeus-w:     clamp(172px, 43%, 315px);

    --zeus-x: -15px;
    --zeus-y: -15px;
  }

  .hero { padding: max(10px, env(safe-area-inset-top)) 16px; }

  .hero__content {
    grid-template-columns: minmax(210px, 0.8fr) minmax(320px, 1.2fr);
    text-align: left;
    width: 100%;
  }

  .hero__copy {
    justify-self: start;
    max-width: 360px;
    text-align: left;
    margin-inline: 0;
  }

  h1 { line-height: 1; }
  .h1-row  { display: block; white-space: nowrap; }
  .h1-line { display: inline; white-space: nowrap; }


  .game__logo { margin-bottom: 6px; }

  /* Mobile's 3-reel slot/frame swap doesn't apply past 1100px width in
     the first place, but this band overlaps mobile's ≤1100px range, so
     every property that block touches on these elements needs an
     explicit reset back to the desktop values here — same precise
     frame-window percentages as the main DESKTOP SLOT FRAME block. */
  .slot { aspect-ratio: 1427 / 858; }
  .slot__frame--desktop { display: block; }
  .slot__frame--mobile  { display: none; }

  .slot__reels {
    position: absolute;
    left: 3.469%;
    top: 4.604%;
    width: 93.343%;
    height: 90.443%;
    grid-template-columns: 220.3fr 267.4fr 323.2fr 269.2fr 252fr;
    column-gap: 0;
    border-radius: 14px;
  }

  /* This band restores the desktop reels geometry above (it also falls
     inside the ≤1100px MOBILE block's width range, which pins the aura
     to that block's own reels geometry instead) — re-match the aura to
     the desktop geometry actually in effect here. */
  .slot__aura {
    inset: 4.604% 3.188% 4.953% 3.469%;
    border-radius: 14px;
  }

  .reel:nth-child(n+4) { display: block; }

  .cta { margin-top: clamp(8px, 1.6vh, 16px); }

  /* Corner-anchored like desktop — mobile centers Zeus under the
     slot instead; reset back to the un-mediaed base-rule positioning
     (left/bottom anchor, no translateX centering). */
  .zeus-media {
    left: -9%;
    right: auto;
    bottom: -3%;
    transform: translate(var(--zeus-x), var(--zeus-y)) translateZ(0);
  }

}

/* ══════════════════════════════════════════
   WIDE LOW-HEIGHT DESKTOP-STYLE WINDOWS (e.g. 1024×600) — narrower than
   1101px so it still falls inside the ≤1100px mobile bucket and inside
   the previous block's own width range too, but short enough (≤700px
   tall) that the real 2-column desktop composition fits comfortably
   with room to spare, so there's no reason to use the mobile stack or
   the previous block's smaller compact-desktop sizing here — this band
   is deliberately AFTER that block so its overrides win for this
   narrower height slice, while 1024×768 (768px tall, outside the
   ≤700px cut here) still falls through to that block untouched.
   Sizing knobs below are bigger than the previous block's (slot/logo/
   CTA/headline) since the height budget here has clear headroom for it
   — verified no clipping/scroll at 1024×600 with hero's ~36px vertical
   padding plus this column's logo+gap+slot+gap+cta stack. */
@media (min-width: 900px) and (max-width: 1100px) and (max-height: 700px) and (orientation: landscape) {
  :root {
    --hero-gap:      clamp(16px, 3vw, 32px);
    --brand-logo-w:  clamp(170px, 16vw, 220px);
    --headline-size: clamp(24px, 3.4vw, 34px);
    --gold-logo-w:   clamp(190px, 20vw, 260px);
    --slot-w:        min(56vw, 580px);
    --cta-w:         clamp(210px, 20vw, 290px);
    --cta-h:         clamp(52px, 8vh, 66px);
    --cta-font:      clamp(16px, 2vw, 24px);
    --zeus-w:     clamp(200px, 46%, 330px);

    --zeus-x: -6px;
    --zeus-y: -18px;
  }

  .hero { padding: max(10px, env(safe-area-inset-top)) 16px; }

  .hero__content {
    grid-template-columns: minmax(210px, 0.8fr) minmax(320px, 1.2fr);
    text-align: left;
    width: 100%;
  }

  .hero__copy {
    justify-self: start;
    max-width: 400px;
    text-align: left;
    margin-inline: 0;
  }

  h1 { line-height: 1; }
  .h1-row  { display: block; white-space: nowrap; }
  .h1-line { display: inline; white-space: nowrap; }

  .game__logo { margin-bottom: 6px; }

  /* Same desktop frame swap/geometry as the true ≥1101px block — the
     frame image and its measured inner-window percentages don't depend
     on viewport width, only on which frame asset is showing. */
  .slot { aspect-ratio: 1427 / 858; }
  .slot__frame--desktop { display: block; }
  .slot__frame--mobile  { display: none; }

  .slot__reels {
    position: absolute;
    left: 3.469%;
    top: 4.604%;
    width: 93.343%;
    height: 90.443%;
    grid-template-columns: 220.3fr 267.4fr 323.2fr 269.2fr 252fr;
    column-gap: 0;
    border-radius: 14px;
  }

  .slot__aura {
    inset: 4.604% 3.188% 4.953% 3.469%;
    border-radius: 14px;
  }

  .reel:nth-child(n+4) { display: block; }

  .cta { margin-top: clamp(8px, 1.6vh, 16px); }

  /* Corner-anchored like desktop, not centered under the slot — pulled
     in from the previous block's -8% since this bucket's text column is
     narrower (~390px) than that block's, so a smaller offset is what
     actually clears the headline here. */
  .zeus-media {
    left: -3%;
    right: auto;
    bottom: -3%;
    transform: translate(var(--zeus-x), var(--zeus-y)) translateZ(0);
  }
}

/* ══════════════════════════════════════════
   SHORT LANDSCAPE PHONES (e.g. 640x360) — width comfortably exceeds
   height here, so the mobile single-column stack (logo+badge+headline+
   Gold Party logo+slot+CTA) can never fit without clipping top and
   bottom against the no-scroll 100dvh + overflow:hidden rule — even the
   compact-height band above only buys ~150px, and this needs ~270.
   Switches back to a desktop-style side-by-side layout instead, since
   there's plenty of width to spend even though height is scarce.
   Placed after every other breakpoint (including "tablet" and
   "mobile", both of which also match a 767px-wide landscape phone) so
   its overrides win regardless of source order elsewhere in the file.
   ══════════════════════════════════════════ */
@media (orientation: landscape) and (max-height: 480px) {
  :root {
    --brand-logo-w:  clamp(85px, 15vw, 130px);
    --headline-size: clamp(14px, 4.8vh, 22px);
    --gold-logo-w:   clamp(64px, 13vw, 110px);
    --slot-w:        min(30vh, 40vw, 200px);
    --cta-w:         clamp(220px, 34vw, 280px);
    --cta-h:         clamp(44px, 12vh, 54px);
    --cta-font:      clamp(10px, 3.4vh, 14px);
    --zeus-w:     clamp(75px, 38%, 175px);

    --zeus-x: 0px;
    --zeus-y: -20px;
  }

  .hero { padding: max(6px, env(safe-area-inset-top)) 14px max(6px, env(safe-area-inset-bottom)); }

  .hero__content {
    grid-template-columns: minmax(160px, 0.85fr) minmax(180px, 1.15fr);
    align-items: center;
    gap: clamp(10px, 3vw, 28px);
    text-align: left;
    width: 100%;
  }

  .hero__copy {
    max-width: 260px;
    justify-self: start;
    text-align: left;
    margin-inline: 0;
  }

  .hero__brand-logo { margin-bottom: 4px; margin-inline: 0; }

  .eyebrow {
    margin-bottom: 4px;
    padding: 3px 9px;
    font-size: 9px;
  }

  h1 { line-height: 1; }

  .h1-line { display: inline; white-space: normal; }


  .game__logo { margin-bottom: 2px; }

  .cta {
    padding: 0 clamp(14px, 3vw, 22px);
    margin-top: clamp(4px, 1.2vh, 8px);
  }

  .zeus-media {
    left: 50%;
    right: auto;
    bottom: clamp(-30px, -10vw, -16px);
    transform: translateX(-50%) translate(var(--zeus-x), var(--zeus-y)) translateZ(0);
  }
}

/* ══════════════════════════════════════════
   ULTRA-COMPACT LANDSCAPE, DESKTOP-STYLE (e.g. Microsoft Lumia 550
   640x360) — narrower/shorter than the SHORT LANDSCAPE PHONES block
   above, so it wins there. That block still inherits the ≤699px
   MOBILE block's 3-reel slot and mobile-derived Zeus sizing, which at
   this size reads as a small slot machine stranded on the right rather
   than a real composition. This restores the full 5-reel desktop
   layout instead — same 2-column grid, same reel frame/grid, same
   corner Zeus placement as desktop and the tablet 5-reel block — just
   scaled down to fit 360px of height.
   ══════════════════════════════════════════ */
@media (orientation: landscape) and (max-height: 430px) and (max-width: 700px) {
  :root {
    --brand-logo-w:  clamp(95px, 17vw, 140px);
    --headline-size: clamp(18px, 4vw, 28px);
    --gold-logo-w:   clamp(85px, 15vw, 130px);
    --slot-w:        min(46vw, 320px);
    --cta-w:         clamp(260px, 34vw, 320px);
    --cta-h:         clamp(44px, 12vh, 52px);
    --cta-font:      clamp(12px, 3vh, 16px);
    --zeus-w:     clamp(100px, 38%, 165px);

    --zeus-x: 0px;
    --zeus-y: -25px;
  }

  .hero { padding: 10px 24px; }

  .hero__content {
    grid-template-columns: 0.9fr 1.1fr;
    align-items: center;
    gap: clamp(12px, 3vw, 24px);
    text-align: left;
    width: 100%;
  }

  .hero__copy { max-width: 300px; justify-self: start; text-align: left; margin-inline: 0; }

  .hero__brand-logo { margin-bottom: 4px; margin-inline: 0; }

  .eyebrow {
    margin-bottom: 4px;
    padding: 3px 9px;
    font-size: 9px;
  }

  /* Pinned to exactly 2 lines, same technique as the mobile portrait
     headline fix (see .h1-row in index.html): "Gira los reels y" /
     "gana tu regalo", never 3 or 4. */
  h1 { line-height: 1.02; }
  .h1-row  { display: block; white-space: nowrap; }
  .h1-line { display: inline; white-space: nowrap; }


  .game__logo { margin-bottom: 4px; }

  /* Restore the full 5-reel desktop slot — the ≤699px MOBILE block
     above also matches this viewport's width and drops to 3 reels
     with the mobile frame art, so every property it touches on these
     elements needs an explicit override back to the desktop values —
     same precise frame-window percentages as the main DESKTOP SLOT
     FRAME block. */
  .slot { aspect-ratio: 1427 / 858; }
  .slot__frame--desktop { display: block; }
  .slot__frame--mobile  { display: none; }

  .slot__reels {
    position: absolute;
    left: 3.469%;
    top: 4.604%;
    width: 93.343%;
    height: 90.443%;
    grid-template-columns: 220.3fr 267.4fr 323.2fr 269.2fr 252fr;
    column-gap: 0;
    border-radius: 14px;
  }

  /* This band restores the desktop reels geometry above (it also falls
     inside the ≤1100px MOBILE block's width range, which pins the aura
     to that block's own reels geometry instead) — re-match the aura to
     the desktop geometry actually in effect here. */
  .slot__aura {
    inset: 4.604% 3.188% 4.953% 3.469%;
    border-radius: 14px;
  }

  .reel:nth-child(n+4) { display: block; }

  .cta {
    padding: 0 clamp(14px, 3vw, 22px);
    margin-top: clamp(4px, 1.2vh, 8px);
  }

  .zeus-media {
    left: 50%;
    right: auto;
    bottom: clamp(-26px, -8vw, -14px);
    transform: translateX(-50%) translate(var(--zeus-x), var(--zeus-y)) translateZ(0);
  }
}

/* ══════════════════════════════════════════
   REDUCED MOTION
   ══════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ══════════════════════════════════════════
   ZEUS — FINAL MOBILE/TABLET OVERRIDE. Deliberately last in the file
   (wins the cascade over every earlier ≤1100px rule touching
   .zeus-media/--zeus-w/--zeus-x/--zeus-y — mobile base,
   IPAD, FOLD — without needing !important) and deliberately NOT
   percentage-of-.slot: every earlier pass at "lower/bigger" (including
   bottom:-3%, -3.5%, -6% in those blocks above) was still a percentage
   of .slot's own height, which is only ~30-45% of the hero's total
   vertical stack — no percentage of that box can ever reach "the
   bottom of the screen", it can only ever move Zeus a few px at a
   time no matter how the number is tuned.
   .slot is unavoidably the containing block here (position:relative,
   see .slot's own rule) — .zeus-media lives inside it in the DOM,
   and moving that DOM relationship would also change desktop, which
   this pass must leave untouched. position:fixed does NOT sidestep
   this either: .slot also carries filter:drop-shadow(...) for its own
   shadow, and per spec an ancestor with `filter` establishes the
   containing block for fixed-positioned descendants exactly like
   `transform` does — so a fixed .zeus-media here would silently
   resolve against .slot's box anyway, not the viewport (confirmed by
   inspecting its computed bottom/rect: bottom lands near .slot's own
   edge, not the screen's).
   The actual fix: keep position:absolute (still against .slot, that
   part was never the problem) but stop expressing bottom/left/height
   as a % of .slot's box — vh/vw are viewport-relative regardless of
   which element the offset itself is applied to, so a vh-sized
   negative bottom reaches down toward the real screen edge no matter
   how small .slot itself is. Height (not width) drives sizing, with
   aspect-ratio keeping width proportional — a vh number is what makes
   "reaches roughly up to the slot's own height" a direct, legible
   value instead of a side-effect of .slot's box. orientation:portrait
   scopes this to the portrait phones/tablets required here, leaving
   the separate landscape exotics (small-screen desktop-style 5-reel
   layouts, already tuned on their own) alone. */
@media (max-width: 1100px) and (orientation: portrait) {
  .zeus-media {
    position: absolute;
    z-index: 4;
    left: -25vw;
    bottom: -20vh;
    top: auto;
    right: auto;
    width: auto;
    height: 52vh;
    aspect-ratio: 608 / 979;
    transform: translateZ(0);
  }
}
