/* MDRLB V2 — shared visual system.
   Restores the proven V1 (v10.php) dark "conversion shell" on top of the V2
   Renderer markup: a cinematic first screen (background + two-column hero +
   selected-offer card + offer stage) followed by the V2 SEO article.
   Plain CSS only — no framework, no CDN, no webfont. */

:root {
  --c1: #60ff88;
  --c2: #1de39a;
  --c3: #0b2c1d;
  --surface: #07130d;
  --bg: #050708;
  --ink: #f7fbf8;
  --muted: #a9b4ae;
  --hair: rgba(255, 255, 255, .10);
  --wrap: 1240px;
  --read: 880px;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

html, body {
  margin: 0;
  min-height: 100%;
  max-width: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: Inter, "Segoe UI", Roboto, Arial, Helvetica, sans-serif;
  line-height: 1.55;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; }
a { color: var(--c1); }
a, button { font: inherit; }

a:focus-visible,
button:focus-visible {
  outline: 3px solid var(--c1);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ------------------------------------------------------------------ shell */

.page {
  position: relative;
  min-height: 100vh;
  overflow: hidden;
  overflow-x: clip;
  max-width: 100%;
  isolation: isolate;
  background:
    linear-gradient(90deg,
      rgba(2, 6, 12, .93) 0%,
      rgba(3, 8, 14, .84) 40%,
      rgba(3, 7, 12, .50) 72%,
      rgba(2, 4, 8, .70) 100%),
    url("/assets/bg/casino-slots.jpg") center / cover fixed no-repeat;
}

.page::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(circle at 72% 26%,
      color-mix(in srgb, var(--c1) 20%, transparent), transparent 32%),
    linear-gradient(180deg, rgba(2, 5, 10, .05), rgba(2, 5, 10, .62));
}

.page::after {
  content: "";
  position: absolute;
  right: -10%;
  bottom: -30%;
  width: 54%;
  height: 54%;
  z-index: -1;
  pointer-events: none;
  background: url("/assets/bg/roulette.webp") center / cover no-repeat;
  border-radius: 50%;
  opacity: .16;
  filter: saturate(1.15) contrast(1.05);
  transform: rotate(-7deg);
  -webkit-mask-image: radial-gradient(circle, #000 40%, transparent 73%);
  mask-image: radial-gradient(circle, #000 40%, transparent 73%);
}

/* --------------------------------------------------------------- top bar */

.top {
  position: relative;
  z-index: 2;
  width: min(var(--wrap), calc(100% - 48px));
  margin: auto;
  min-height: 84px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.brand { display: flex; align-items: center; gap: 12px; min-width: 0; }

.brand-logo {
  display: block;
  max-width: 150px;
  max-height: 42px;
  width: auto;
  object-fit: contain;
  filter: drop-shadow(0 4px 12px rgba(0, 0, 0, .45));
}

.mark {
  width: 42px;
  height: 42px;
  border-radius: 13px;
  display: grid;
  place-items: center;
  font-weight: 900;
  color: #061009;
  background: linear-gradient(135deg, var(--c1), var(--c2));
  box-shadow: 0 0 30px color-mix(in srgb, var(--c1) 18%, transparent);
}

.brandtext { font-size: 13px; letter-spacing: .15em; font-weight: 800; }

.age {
  flex: none;
  font-size: 12px;
  font-weight: 800;
  color: var(--c1);
  border: 1px solid color-mix(in srgb, var(--c1) 28%, transparent);
  padding: 8px 12px;
  border-radius: 999px;
}

/* ----------------------------------------------------------------- hero */

.hero {
  position: relative;
  z-index: 2;
  width: min(var(--wrap), calc(100% - 48px));
  max-width: 100%;
  margin: auto;
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(460px, .98fr);
  align-items: center;
  gap: 40px;
  min-height: clamp(520px, calc(100vh - 84px), 820px);
  padding: 30px 0 44px;
}

.copy { max-width: 700px; min-width: 0; }
.copy > * { min-width: 0; }

/* Only the no-valid-primary safety fallback: no primary means no secondary
   "Другие варианты" selector either (Rule B), so there is nothing for a
   right column — the hero collapses to one column instead of reserving an
   empty one. The primary card itself always lives inline in .copy (below),
   never in its own column, so its presence alone never forces two columns.
   Any page with a resolved primary AND eligible orbit offers gets the real
   two-column hero: .copy left, .alt-offers (the selector) right — see
   below. */
.hero--solo {
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  min-height: auto;
  padding-bottom: 16px;
}
.hero--solo .copy { max-width: min(820px, 100%); }

.eyebrow {
  margin: 0 0 16px;
  font-size: 11px;
  letter-spacing: .18em;
  font-weight: 800;
  text-transform: uppercase;
  color: var(--c1);
}

.hero h1 {
  margin: 0;
  font-size: clamp(40px, 4.7vw, 68px);
  line-height: 1.02;
  letter-spacing: -.035em;
  font-weight: 900;
  overflow-wrap: anywhere;
  word-break: break-word;
  hyphens: auto;
  -webkit-hyphens: auto;
}

.lead {
  max-width: min(60ch, 100%);
  margin: 22px 0 0;
  color: var(--muted);
  font-size: 17px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------- selected-offer card */

.offer-card {
  margin-top: 28px;
  max-width: 520px;
  border-radius: 22px;
  padding: 18px 20px;
  background: linear-gradient(180deg, rgba(9, 11, 14, .70), rgba(4, 6, 9, .55));
  border: 1px solid color-mix(in srgb, var(--c1) 26%, var(--hair));
  box-shadow: 0 22px 60px rgba(0, 0, 0, .32), inset 0 1px rgba(255, 255, 255, .05);
  -webkit-backdrop-filter: blur(9px);
  backdrop-filter: blur(9px);
}

.offer-card__label {
  margin: 0 0 12px;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  font-weight: 800;
  color: #8b978f;
}

.offer-head {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 76px;
}

.offer-logo {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  min-width: 64px;
}

.offer-head.has-logo .offer-logo { min-width: 190px; }

.offer-logo img {
  display: block;
  max-width: 210px;
  max-height: 74px;
  width: auto;
  object-fit: contain;
  filter: drop-shadow(0 5px 14px rgba(0, 0, 0, .4));
}

.offer-name {
  font-size: clamp(24px, 3.4vw, 32px);
  line-height: 1;
  font-weight: 900;
  letter-spacing: -.02em;
  color: #fff;
  overflow-wrap: anywhere;
}

/* With a logo present, keep the real destination brand as a small visible
   caption (never image-only) — the big wordmark treatment is only for the
   logo-less fallback. */
.offer-head.has-logo .offer-name {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #aeb8b1;
}

.actions {
  display: flex;
  flex-wrap: nowrap;
  gap: 10px;
  margin-top: 18px;
}

/* Desktop: the primary CTA ("Забрать бонус — {Brand}") and the secondary
   switch ("Показать другой приз") always stay side by side on one row, for
   any brand-name length (APEX Casino, Play Fortuna, Joy Casino, Casino X,
   1xSlots, GAMA, R7, RamenBet, …).

   Word integrity: never break inside a word. An earlier revision added
   `overflow-wrap: anywhere` to the CTA as an overflow guard, but that also
   collapses the CTA's min-content to a single glyph, so flex handed it
   almost no width and chopped brand names mid-word ("GAM"/"A",
   "RamenB"/"et") while the switch label was squeezed onto 2-3 lines. The
   guard is dropped here and replaced with a width budget that always fits:
     * the switch takes its natural one-line width and never grows/shrinks
       or steals the row (flex: 0 0 auto + nowrap);
     * the CTA takes all remaining space (flex: 1 1 auto); its min-content
       is now the longest whole word, so it can only ever wrap at real
       spaces — the action prefix drops to a second line, the brand name
       stays intact;
     * horizontal padding is trimmed 24 -> 16 and the gap 12 -> 10 to keep
       that budget comfortable on the narrowest desktop card (the ~460px
       "Другие варианты" column).
   The <=760px rule below still switches this whole block to a stacked
   single column for narrow mobile. */
.actions > .cta {
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.15;
}

.actions > .switch {
  flex: 0 0 auto;
  min-width: 0;
  white-space: nowrap;
}

.actions > .cta,
.actions > .switch {
  padding-left: 16px;
  padding-right: 16px;
  overflow-wrap: normal;
  word-break: normal;
  hyphens: none;
}

.cta, .switch {
  min-height: 52px;
  border-radius: 14px;
  padding: 14px 24px;
  font-weight: 800;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  text-decoration: none;
}

.cta {
  background: linear-gradient(90deg, var(--c1), var(--c2));
  color: #061009;
  border: none;
  min-width: 200px;
}

.switch {
  background: transparent;
  color: #fff;
  border: 1px solid color-mix(in srgb, var(--c1) 34%, transparent);
  min-width: 170px;
}

/* ---------------------------------------------------------------- stage */

.stage {
  position: relative;
  min-width: 0;
  height: 700px;
  align-self: center;
}

.machine {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 520px;
  height: 520px;
  transform: translate(-50%, -50%);
  border-radius: 42px;
  border: 1px solid var(--hair);
  background:
    linear-gradient(color-mix(in srgb, var(--c1) 13%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--c2) 11%, transparent) 1px, transparent 1px),
    radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--c1) 22%, transparent), #08100c 40%);
  background-size: 34px 34px, 34px 34px, auto;
  box-shadow: inset 0 0 80px rgba(0, 0, 0, .25), 0 30px 90px rgba(0, 0, 0, .34);
}

.machine::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 136px;
  height: 136px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, var(--c1), var(--c2) 36%, #101714 38% 58%, transparent 60%);
  box-shadow: 0 0 42px color-mix(in srgb, var(--c1) 26%, transparent);
}

.ball {
  position: absolute;
  width: 218px;
  height: 218px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .38);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  text-decoration: none;
  color: #fff;
  isolation: isolate;
  overflow: hidden;
  background: radial-gradient(circle at 35% 28%, var(--accent, var(--c1)), #0b1110 72%);
  box-shadow:
    inset -27px -34px 54px rgba(0, 0, 0, .58),
    inset 18px 14px 28px rgba(255, 255, 255, .18),
    0 30px 64px rgba(0, 0, 0, .56),
    0 0 34px color-mix(in srgb, var(--c1) 18%, transparent);
  transition: transform .25s ease, filter .25s ease, box-shadow .25s ease;
  animation: floatBall 5.6s ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * -1.12s);
}

.ball::before {
  content: "";
  position: absolute;
  z-index: 2;
  left: 15%;
  top: 9%;
  width: 49%;
  height: 31%;
  border-radius: 50%;
  background: linear-gradient(180deg, rgba(255, 255, 255, .82), rgba(255, 255, 255, .17) 38%, rgba(255, 255, 255, 0));
  filter: blur(2px);
  transform: rotate(-20deg);
  opacity: .78;
  pointer-events: none;
}

.ball::after {
  content: "";
  position: absolute;
  z-index: 1;
  inset: 6%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 72% 78%, rgba(255, 255, 255, .08), transparent 30%),
    linear-gradient(135deg, rgba(255, 255, 255, .08), transparent 36%);
  border: 1px solid rgba(255, 255, 255, .08);
  pointer-events: none;
}

.ball:hover,
.ball:focus-visible,
.ball.active {
  transform: scale(1.075);
  filter: brightness(1.1) saturate(1.08);
  box-shadow:
    inset -27px -34px 54px rgba(0, 0, 0, .54),
    inset 18px 14px 30px rgba(255, 255, 255, .2),
    0 34px 72px rgba(0, 0, 0, .6),
    0 0 46px color-mix(in srgb, var(--c1) 30%, transparent);
}

.ball.active { border-color: color-mix(in srgb, var(--c1) 65%, #fff); }

.ball-logo {
  position: relative;
  z-index: 3;
  display: block;
  width: 86%;
  height: 62%;
  object-fit: contain;
  filter: drop-shadow(0 4px 12px rgba(0, 0, 0, .5)) brightness(1.06);
  pointer-events: none;
}

.ball-name {
  position: relative;
  z-index: 3;
  display: block;
  max-width: 150px;
  padding: 0 8px;
  font-size: 22px;
  font-weight: 900;
  line-height: 1.05;
  letter-spacing: -.02em;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .5);
}

.ball-logo + .ball-name {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Source-specific contrast fix for the one dark-artwork local logo.
   assets/logos/stake.webp is a near-black "Stake" wordmark; on the dark V2
   shell (brand header, selected-offer card, selector ball) it is otherwise
   invisible — and .offer-head.has-logo hides the text fallback. Force it to a
   white silhouette (transparency preserved -> a wordmark, not a rectangle),
   matching V1's .logo-stake treatment. The [src$=] selector matches only this
   asset, which no other brand or offer uses, so no other logo is affected. */
img[src$="/assets/logos/stake.webp"] {
  filter: brightness(0) invert(1) drop-shadow(0 3px 10px rgba(0, 0, 0, .6)) !important;
}

.b0 { right: -1%; top: 4%; }
.b1 { right: -8%; top: 37%; }
.b2 { right: 7%; bottom: -1%; }
.b3 { left: 0; bottom: 2%; }
.b4 { left: -7%; top: 23%; }

@keyframes floatBall {
  0%, 100% { translate: 0 0; rotate: -.8deg; }
  50% { translate: 7px -23px; rotate: .8deg; }
}

/* -------------------------------------------------------- hub brand grid */

.hero--hub { align-items: start; }

.brand-grid {
  position: relative;
  z-index: 2;
  width: min(var(--wrap), calc(100% - 48px));
  margin: 8px auto 64px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px;
}

.brand-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 76px;
  padding: 16px 18px;
  border-radius: 16px;
  text-decoration: none;
  color: #fff;
  background: linear-gradient(180deg, rgba(12, 14, 18, .72), rgba(5, 7, 10, .6));
  border: 1px solid var(--hair);
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}

.brand-card:hover,
.brand-card:focus-visible {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--c1) 40%, transparent);
  box-shadow: 0 16px 40px rgba(0, 0, 0, .4);
}

.brand-card__text {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  flex: 1 1 auto;
}
/* Single line, truncated with ellipsis if a name would otherwise wrap next to
   the logo — keeps every card the SAME height (a wrapped name in one grid
   row would stretch every card sharing that row) rather than growing some
   cards taller than others. Truncation is rare at the desktop grid's minimum
   column width (the logo is sized to its own natural width below, not a
   fixed reservation) but stays as a safety net for narrow mobile cards. */
.brand-card__name {
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.brand-card__go { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--c1); font-weight: 800; }

/* Reuses each brand's existing local header-mark asset (self::BRAND_SHELL in
   Renderer.php) — no new asset. flex: 0 0 auto (not a fixed flex-basis) sizes
   this to the LOGO's own natural width at max-height, capped at 120px — an
   icon-shaped logo (e.g. R7, GAMA) takes only what it needs, so the text
   column (which has priority via .brand-card__text's flex:1) is never
   squeezed by logos that don't need the full 120px, while a wide wordmark
   still stays under the cap and never overpowers the brand name. */
.brand-card__logo {
  flex: 0 0 auto;
  max-width: 120px;
  min-width: 0;
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
}
.brand-card__logo img {
  display: block;
  max-width: 100%;
  max-height: 44px;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 3px 8px rgba(0, 0, 0, .35));
}

/* ----------------------------------------------------------- SEO article */

.article {
  position: relative;
  z-index: 2;
  width: min(calc(var(--read) + 88px), calc(100% - 32px));
  margin: 8px auto 0;
  padding: 40px 44px 60px;
  border-radius: 24px 24px 0 0;
  background: linear-gradient(180deg, rgba(6, 9, 13, .52), rgba(6, 9, 13, .82) 220px);
  border: 1px solid var(--hair);
  border-bottom: 0;
}

.article nav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 4px;
  align-items: baseline;
  font-size: 14px;
  color: var(--muted);
  padding-bottom: 22px;
  margin-bottom: 30px;
  border-bottom: 1px solid var(--hair);
}

.article nav a { color: var(--c1); text-decoration: none; }
.article nav a:hover { text-decoration: underline; }

.article section { margin: 0 0 34px; }

.article h2 {
  margin: 0 0 12px;
  font-size: clamp(21px, 2.4vw, 27px);
  line-height: 1.25;
  letter-spacing: -.01em;
  font-weight: 800;
}

.article p {
  margin: 0;
  color: #d7ded9;
  font-size: 16.5px;
  line-height: 1.75;
}

/* ------------------------------------------- secondary "Другие варианты"
   The hero's RIGHT column (product requirement, revised after live visual
   QA: visible in the first viewport, never below the article any more) — a
   compact selected-offer card and a plain wrapped row of the same selector
   balls (no big machine/orbit, which would waste the space it now
   occupies). Same selector JS drives it as before. */
.alt-offers {
  min-width: 0;
  align-self: center;
}
.alt-offers__title {
  margin: 0 0 18px;
  font-size: clamp(18px, 2.1vw, 23px);
  line-height: 1.25;
  font-weight: 800;
  letter-spacing: -.01em;
}
.alt-offers .offer-card {
  margin: 0 0 24px;
  max-width: 500px;
}
.alt-offers .stage {
  position: static;
  height: auto;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}
.alt-offers .machine { display: none; }
.alt-offers .ball,
.alt-offers .b0, .alt-offers .b1, .alt-offers .b2, .alt-offers .b3, .alt-offers .b4 {
  position: static !important;
  inset: auto !important;
  transform: none;
  width: 132px;
  height: 132px;
  margin: 0;
}
.alt-offers .ball:hover,
.alt-offers .ball:focus-visible { transform: scale(1.04); }
.alt-offers .ball.active { transform: scale(1.05); }
.alt-offers .ball-logo { width: 82%; height: 60%; }
.alt-offers .ball-name { font-size: 14px; max-width: 96px; }

@media (max-width: 760px) {
  /* Stacks 4th in source order — after the primary card, before .article
     (see the mobile .hero rules below) — so a plain top margin is enough;
     no divider/border needed since it was never "below" anything else. */
  .alt-offers { margin-top: 28px; }
  .alt-offers .offer-card { max-width: none; }
  .alt-offers .stage { justify-content: center; }
  .alt-offers .ball,
  .alt-offers .b0, .alt-offers .b1, .alt-offers .b2, .alt-offers .b3, .alt-offers .b4 {
    width: 120px;
    height: 120px;
  }
}

/* --------------------------------------------------------------- footer */

.site-footer {
  position: relative;
  z-index: 2;
  border-top: 1px solid var(--hair);
  background: #04070a;
}

.site-footer p {
  width: min(var(--wrap), calc(100% - 48px));
  margin: 0 auto;
  padding: 22px 0;
  font-size: 12px;
  color: #6a756f;
  text-align: center;
}

/* ------------------------------------------------------------------ 404 */

.page--notfound .notfound {
  position: relative;
  z-index: 2;
  width: min(var(--read), calc(100% - 40px));
  margin: auto;
  min-height: calc(100vh - 180px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 8px;
  padding: 60px 0;
}

.page--notfound h1 { margin: 0; font-size: clamp(64px, 12vw, 120px); font-weight: 900; letter-spacing: -.05em; }
.page--notfound .cta { margin-top: 18px; }

/* ------------------------------------------------------------ responsive */

@media (max-width: 1080px) {
  .hero {
    grid-template-columns: 1fr;
    gap: 26px;
    align-items: start;
    min-height: 0;
  }
  .copy { max-width: none; }
  .stage { height: 560px; }
  .machine { width: 420px; height: 420px; }
  .ball { width: 184px; height: 184px; }
  .b0 { right: 2%; }  .b1 { right: -4%; }  .b2 { right: 8%; }
  .b3 { left: 2%; }   .b4 { left: -4%; }
}

@media (max-width: 760px) {
  .page {
    background-attachment: scroll;
    min-height: 100svh;
  }

  /* the roulette flourish is a desktop-only decoration — drop it entirely on
     small screens so the browser never fetches roulette.webp on mobile */
  .page::after {
    content: none;
    display: none;
    background-image: none;
  }

  /* hard width containment: auto width + fixed side margins beats any
     calc()/min()/grid-track edge case that could exceed the viewport */
  .top,
  .hero,
  .brand-grid,
  .article {
    width: auto;
    max-width: 100%;
    margin-left: 14px;
    margin-right: 14px;
  }
  .alt-offers, .alt-offers__grid { max-width: 100%; min-width: 0; }
  .site-footer p { width: auto; max-width: 100%; }

  .top { min-height: 62px; }
  .brand-logo { max-width: 118px; max-height: 32px; }

  /* single column, plain block flow — no grid min-track overflow */
  .hero {
    display: block;
    min-height: 0;
    padding: 14px 0 36px;
  }
  .hero > * { max-width: 100%; min-width: 0; }
  .hero > .copy,
  .hero > .stage,
  .hero > .alt-offers { width: 100%; }

  .hero h1 { font-size: clamp(30px, 8.4vw, 42px); line-height: 1.06; }
  .lead { font-size: 15px; margin-top: 16px; }

  /* Stacking order on mobile (source order, per .hero markup below): SEO
     logo/title -> lead -> primary offer card (inline in .copy) ->
     "Другие варианты" (.alt-offers) -> .article. */
  .offer-card { width: 100%; max-width: 100%; margin-top: 22px; padding: 16px; }
  .offer-head.has-logo .offer-logo { min-width: 150px; }
  .offer-logo img { max-height: 60px; }
  .actions { display: grid; grid-template-columns: 1fr; }
  .cta, .switch { width: 100%; min-width: 0; }

  /* balls become a clean, centred 2-col grid — no absolute positioning */
  .stage {
    height: auto;
    margin-top: 22px;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    justify-items: center;
    align-items: start;
    padding: 0;
  }
  .machine { display: none; }
  .ball,
  .b0, .b1, .b2, .b3, .b4 {
    position: static !important;
    inset: auto !important;
    margin: 0;
    transform: none;
    width: 100%;
    max-width: 150px;
    height: auto;
    aspect-ratio: 1 / 1;
  }
  .b4 { grid-column: 1 / -1; }
  .ball:hover, .ball:focus-visible { transform: none; }
  .ball.active { transform: scale(1.04); }
  .ball-name { font-size: clamp(15px, 4.4vw, 19px); max-width: 108px; }

  .article { padding: 26px 16px 44px; border-radius: 18px 18px 0 0; }
  .article nav { overflow-wrap: anywhere; }
  .brand-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }

  /* Compact cards at 2-column mobile width: smaller padding/min-height and a
     noticeably smaller logo cap ("where space allows") so text stays fully
     readable and nothing overflows; height barely changes from the
     logo-less card. */
  .brand-card { min-height: 68px; padding: 12px 14px; gap: 8px; }
  .brand-card__name { font-size: 16px; }
  .brand-card__logo { max-width: 56px; }
  .brand-card__logo img { max-height: 28px; }
}

@media (max-width: 400px) {
  .hero h1 { font-size: clamp(27px, 8.6vw, 34px); }
  .ball, .b0, .b1, .b2, .b3, .b4 { max-width: 138px; }
  .ball-name { font-size: 15px; max-width: 92px; }
}

@media (max-width: 330px) {
  .brand-grid { grid-template-columns: 1fr; }
  .stage { grid-template-columns: 1fr; }
  .b4 { grid-column: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .ball { animation: none; }
  .ball:hover, .ball:focus-visible, .ball.active { transform: none; }
  .brand-card { transition: none; }
}
