/* ── OCTOPONG · main menu ────────────────────────────────────
   menu.js appends a second copy of this sheet at the end of
   <head>, after theme.css AND ui.css, so every rule here wins a
   specificity tie against both.  Nothing below borrows a shared
   class: the screen is built from `mn-` parts of its own, because
   the shared `.btn`/`.panel`/`.topbar` language is tuned for text
   buttons and this screen's buttons are finished artwork.  Tokens
   are still the shared ones, with literal fallbacks, so a
   coherence pass on theme.css lands here too and a half-saved
   theme.css cannot take the screen down.

   THE OUTLINE RULE (theme.css, TRAP at "the outline"): never draw
   an outline with a `z-index:-1` pseudo-element inside a clipped
   or filtered box — it floods the face.  Chained zero-blur
   drop-shadows outline the clipped silhouette instead, and because
   every plate here is opaque the chain never touches the text
   inside it.

   THE VIDEO: `.mn-vid` is the only compositor-heavy thing on the
   screen.  Nothing is allowed to blend with it — no
   `mix-blend-mode`, no `backdrop-filter` — because either forces a
   read-back of the video layer every frame.  The scrims over it
   are plain alpha.
   ─────────────────────────────────────────────────────────── */

.menu{
  /* deterministic stacking: without this the screen is a stacking
     context only while its opacity transition is mid-flight, and
     the theme vignette's z-index:-1 lands somewhere different at
     rest than it does during a screen change */
  isolation:isolate;
  /* minmax(0,…), never a bare 1fr — see the .screen note in theme.css.
     A bare 1fr floors at min-content, which on a phone is the whole
     eight-bar stack plus both cards, so the row grew past the fold and
     .menu's own overflow:hidden ate the end of it instead of letting
     .mn-stage scroll. */
  grid-template-rows:auto minmax(0,1fr) auto;
  overflow:hidden;

  --mn-ink:#f4fbff;
  --mn-dim:#c6dded;          /* secondary copy — measured, see report */
  --mn-edge:var(--outline,#050814);
  --mn-aqua:var(--aqua-hi,#7ff5ea);
  --mn-gold:var(--gold,#ffc63d);
  --mn-hot:var(--hot,#ff3d8b);

  --mn-pad:clamp(10px,1.3vw,24px);
  --mn-gap:clamp(3px,.7vh,10px);

  /* The measured bar-body crop.  menu.js sets both of these from its
     ART constant, which is the real source of truth; these are the
     fallbacks that keep the sheet readable on its own. */
  --mn-at:.2375;
  --mn-band:.515;

  /* One button box is the drawn bar body and nothing else, so its
     shape is the 3:1 canvas divided by the band. */
  --mn-ar:calc(3 / var(--mn-band));
}

/* ── HOW THE LEFT COLUMN IS SIZED ───────────────────────────────
   NOT from a vh formula.  The first version of this screen guessed
   the chrome at "100vh - 190px" and at 1600x900 the stack ran 65px
   past the bottom of the window with QUIT underneath the news bar.

   Instead the height is handed down: .menu is a 3-row grid, so
   .mn-stage has a definite height; .mn-left fills it; the eight
   buttons are `flex:1 1 0` inside it, so they SPLIT whatever is
   left after the wordmark, and each one takes its WIDTH from that
   height through `aspect-ratio`.  PLAY simply grows harder than
   the rest, which makes it both taller and wider — the hero
   treatment the mockup asks for, from one number.
   The stack cannot overflow the fold at any window size, because
   the fold is the input. */

/* theme.css paints its own vignette here as a z-index:-1 pseudo.
   This screen has a video background and its own scrim stack, so
   that layer is dead weight (and, under `isolation`, invisible). */
.menu::before{ content:none; }

/* ══ background ═════════════════════════════════════════════ */

.mn-bg{ position:absolute; inset:0; z-index:0; overflow:hidden; pointer-events:none; }

/* The still.  Not an asset — a painted undersea arena, so there is
   always something behind the DOM even before the first video
   frame lands, when the file 404s, and whenever motion is off. */
.mn-still{
  position:absolute; inset:0;
  background:
    radial-gradient(ellipse 52% 46% at 50% -8%,  rgba(255,216,146,.40), rgba(255,190,110,.12) 46%, transparent 74%),
    radial-gradient(ellipse 96% 62% at 50% 6%,   rgba(44,168,196,.28), transparent 64%),
    radial-gradient(ellipse 70% 46% at 16% 92%,  rgba(88,42,140,.34), transparent 70%),
    radial-gradient(ellipse 70% 46% at 86% 88%,  rgba(20,120,150,.30), transparent 70%),
    radial-gradient(ellipse 130% 70% at 50% 124%, rgba(4,7,20,.96), transparent 62%),
    linear-gradient(180deg,#0b2657 0%,#0c1c43 32%,#091331 60%,#050a1c 100%);
}

.mn-vidwrap{
  position:absolute; inset:0;
  opacity:1; transition:opacity .5s var(--ease-out,cubic-bezier(.4,0,.6,1));
}
.menu.mn-still-on .mn-vidwrap{ opacity:0; }
.mn-vid{
  width:100%; height:100%; display:block; object-fit:cover;
  /* NOTE: do not try to fix the sign clipping with scale/translate here.
     Measured: the loop is 16:9 into a wider box, so cover already shows
     the full width and object-position has no horizontal slack; scaling
     up only enlarges the hero and crowds the right column further. The
     fix is a re-cut loop with the subject centred and no baked-in
     signage — see HANDOFF. */
  /* the video is a 2560x1440 master; it is never the thing the eye
     should be reading, so it sits a shade back from full strength */
  filter:saturate(1.05) brightness(.94);
}

/* warm god-rays, top centre.  Plain alpha over whatever is behind —
   deliberately NOT `screen`, see the header note. */
.mn-rays{
  position:absolute; inset:-10% -10% auto -10%; height:86%;
  background:repeating-conic-gradient(from 166deg at 50% -16%,
    rgba(255,228,168,0) 0deg, rgba(255,228,168,.11) 1.4deg,
    rgba(255,228,168,.02) 2.6deg, rgba(255,228,168,0) 4.6deg);
  -webkit-mask-image:radial-gradient(ellipse 62% 88% at 50% -4%, #000 0%, rgba(0,0,0,.5) 46%, transparent 82%);
          mask-image:radial-gradient(ellipse 62% 88% at 50% -4%, #000 0%, rgba(0,0,0,.5) 46%, transparent 82%);
  opacity:.9;
}

/* Readability plating.  The left and right thirds carry text over
   moving video, so they are darkened before a single glyph lands
   on them; the middle stays open so the arena reads.

   The bottom half of the vertical pass is heavier than it needs to
   be for the news bar alone, on purpose: the delivered loop paints
   its OWN "welcome to the octo arena" sign down there, and with the
   mockup's plinth sign in front of it the screen said it twice.
   Sinking the lower third leaves one legible sign — ours — and the
   arena floor still reads through it. */
.mn-scrim{
  position:absolute; inset:0;
  background:
    linear-gradient(90deg, rgba(4,8,20,.90) 0%,  rgba(4,8,20,.70) 22%, rgba(4,8,20,.12) 40%,
                           rgba(4,8,20,.12) 60%, rgba(4,8,20,.66) 78%, rgba(4,8,20,.90) 100%),
    linear-gradient(180deg, rgba(4,8,20,.80) 0%, rgba(4,8,20,.16) 13%, rgba(4,8,20,0) 34%,
                            rgba(4,8,20,0) 52%,  rgba(4,8,20,.34) 72%,
                            rgba(4,8,20,.70) 88%, rgba(4,8,20,.95) 100%);
}

/* ══ shared bits ════════════════════════════════════════════ */

.menu .mn-top, .menu .mn-stage, .menu .mn-foot{ position:relative; z-index:2; min-width:0; }

.menu button{ font-family:var(--ui,"Nunito",system-ui,sans-serif); }

/* One focus treatment, on every control on the screen.  Two
   signals, because one of them has to survive whatever the art
   behind it is doing: a hard aqua ring, and a dark halo under it
   so the ring never lands aqua-on-aqua. */
.menu :is(button,[tabindex]):focus{ outline:none; }
.menu :is(button,[tabindex]):focus-visible{
  outline:3px solid var(--mn-aqua);
  outline-offset:3px;
  border-radius:4px;
  box-shadow:0 0 0 6px rgba(4,8,20,.85), 0 0 22px rgba(127,245,234,.6);
}

/* ══ top bar ════════════════════════════════════════════════ */

.mn-top{
  display:flex; align-items:center; gap:clamp(8px,1.4vw,22px);
  /* the LEFT inset has a floor of 14px, and it is not cosmetic: the
     level badge is `position:absolute; left:-12.46px` off the avatar,
     so any inset under 13px puts it through the left edge of a screen
     that clips. Measured at 744x1133, where --mn-pad bottoms out at
     10px and the badge landed at x=-2. */
  padding:clamp(6px,.9vh,12px) var(--mn-pad)
          clamp(6px,.9vh,12px) max(var(--mn-pad), 14px);
  background:linear-gradient(180deg, rgba(3,6,18,.95), rgba(3,6,18,.88));
  box-shadow:0 2px 0 rgba(47,230,214,.20), 0 10px 22px rgba(0,0,0,.45);
}
/* a short feather so the plate does not end on a hard line */
.mn-top::after{
  content:""; position:absolute; left:0; right:0; top:100%; height:22px;
  background:linear-gradient(180deg, rgba(3,6,18,.72), transparent);
  pointer-events:none;
}

.mn-id{ display:flex; align-items:center; gap:clamp(8px,.9vw,14px); min-width:0; }

/* THE HEX AVATAR.  Three elements, and all three are load-bearing:
   .mn-avatar is the unclipped box the level badge hangs off,
   .mn-face is the hexagon that clips the portrait, and the <img>
   inside it is a head crop.  Do not merge the first two — see the
   note in menu.js's markup. */
.mn-avatar{
  position:relative; flex:none;
  width:clamp(40px,5vh,58px); aspect-ratio:1;
}
.mn-face{
  position:absolute; inset:0; overflow:hidden;
  /* a pointy-top hexagon, the same silhouette as the icon caps on
     the button art */
  clip-path:polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
  background:radial-gradient(circle at 38% 26%, #2b4d8f, #0a1330 78%);
  /* The rim follows the CUT, not the box.  A filter runs after the
     clip, so a zero-blur drop-shadow chain outlines the hexagon
     itself — which an inset box-shadow cannot do, and which a
     z-index:-1 pseudo would not survive (theme.css, "the outline"). */
  filter:
    drop-shadow(2px 0 0 var(--mn-aqua))  drop-shadow(-2px 0 0 var(--mn-aqua))
    drop-shadow(0 2px 0 var(--mn-aqua))  drop-shadow(0 -2px 0 var(--mn-aqua))
    drop-shadow(0 3px 0 rgba(3,6,16,.85));
}
/* the sheet is a 1400 square with the octopus floating in it; this is
   a head crop of the same file the hero uses, so it decodes once.
   The numbers come off the alpha channel: the head sits at
   0.156–0.55 of the canvas, centred on x 0.50. */
.mn-face img{
  position:absolute; width:270%; height:270%; max-width:none;
  left:-85%; top:-42%;
  image-rendering:auto;
}
.mn-lvl{
  position:absolute; left:-22%; bottom:-10%; z-index:2;
  min-width:1.9em; height:1.9em; padding:0 .28em;
  display:grid; place-items:center;
  background:linear-gradient(180deg, var(--gold-hi,#ffe08a), var(--mn-gold));
  color:#2a1500; font:900 clamp(9.5px,1.2vh,12px)/1 var(--ui,sans-serif);
  border-radius:50%;
  box-shadow:0 0 0 2px var(--mn-edge), 0 2px 0 rgba(0,0,0,.5);
}

.mn-idtxt{ display:flex; flex-direction:column; gap:4px; min-width:0; }
.mn-name{
  font:800 clamp(13px,1.9vh,18px)/1 var(--display,sans-serif);
  letter-spacing:.04em; color:var(--mn-ink);
  text-shadow:0 2px 0 rgba(0,0,0,.6);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.mn-tag-sample{
  align-self:flex-start; margin-top:-2px; padding:2px 6px;
  background:#243a63; color:#dceaf7;
  font:800 9px/1 var(--ui,sans-serif); letter-spacing:.13em;
  border-radius:3px; box-shadow:0 0 0 1px var(--mn-edge);
}
.mn-tag-sample[hidden]{ display:none; }

/* THE XP BAR CARRIES ITS OWN LABEL TWICE.  --p is the fill, set by
   menu.js; the light copy owns the dark track and the dark copy is
   clipped to exactly the fill, so the number is measurably readable
   on both halves instead of white-on-aqua at 1.1:1 in the middle. */
.mn-xp{
  --p:0%;
  position:relative; width:clamp(120px,13vw,190px); height:14px;
  /* NOT #07102a.  The top rail is rgba(3,6,18,.9x), so a near-black
     track vanished into it and the unfilled half of the bar read as
     "the label has fallen off the end of the bar". */
  background:#16264a; border-radius:99px; overflow:hidden;
  /* the hairline is what makes the empty half of the bar a SHAPE:
     3.6:1 against the rail behind it, measured */
  box-shadow:inset 0 0 0 2px var(--mn-edge), 0 0 0 1px rgba(127,245,234,.45);
}
.mn-xp i{
  position:absolute; left:0; top:0; height:100%; width:var(--p);
  background:linear-gradient(90deg, var(--aqua,#2fe6d6), var(--mn-aqua));
}
.mn-xp span{
  position:absolute; inset:0; display:grid; place-items:center;
  font:800 9.5px/14px var(--ui,sans-serif); letter-spacing:.05em;
  white-space:nowrap;
}
.mn-xp-lo{ color:#eaf6ff; }
.mn-xp-hi{ color:#04222b; clip-path:inset(0 calc(100% - var(--p)) 0 0); }

.mn-curs{
  display:flex; align-items:center; gap:clamp(6px,.7vw,12px);
  margin-inline:auto;
}
.mn-cur-sample{ align-self:center; margin-top:0; }
.mn-cur{
  display:flex; align-items:center; gap:7px;
  padding:4px 4px 4px 9px; border-radius:999px;
  background:linear-gradient(180deg,#16305e,#0a1734);
  box-shadow:0 0 0 2px var(--mn-edge), 0 3px 0 rgba(0,0,0,.5);
}
.mn-tok{ width:clamp(17px,2.1vh,21px); height:clamp(17px,2.1vh,21px); flex:none; display:block; }
.mn-tok svg{ width:100%; height:100%; display:block; }
.mn-cur-coins  .mn-tok{ color:var(--mn-gold); }
.mn-cur-pearls .mn-tok{ color:#e9f7ff; }
.mn-cur-stars  .mn-tok{ color:var(--mn-hot); }
.mn-curn{
  font:800 clamp(11px,1.5vh,14px)/1 var(--ui,sans-serif); letter-spacing:.02em;
  color:var(--mn-ink); white-space:nowrap;
}
.mn-cur-stars{ padding-right:11px; }
.mn-plus{
  width:21px; height:21px; flex:none; border:0; padding:0; cursor:pointer;
  display:grid; place-items:center; border-radius:50%;
  background:linear-gradient(180deg,#4ee39f,#189060); color:#04220f;
  box-shadow:0 0 0 2px var(--mn-edge), 0 2px 0 rgba(0,0,0,.5);
  transition:transform var(--dur-fast,.12s) var(--ease-pop,cubic-bezier(.3,1.5,.5,1));
}
.mn-plus svg{ display:block; }
.mn-plus:hover{ transform:translateY(-2px); }

.mn-tools{ display:flex; align-items:center; gap:clamp(4px,.5vw,10px); }
.mn-tool{
  width:clamp(30px,4.2vh,38px); height:clamp(30px,4.2vh,38px);
  display:grid; place-items:center; padding:0; border:0; cursor:pointer;
  background:transparent; color:var(--mn-aqua); border-radius:8px;
  transition:color var(--dur-fast,.12s), background var(--dur-fast,.12s),
             transform var(--dur-fast,.12s) var(--ease-pop,cubic-bezier(.3,1.5,.5,1));
}
.mn-tool svg{ display:block; width:70%; height:70%; }
.mn-tool:hover{ color:var(--mn-gold); background:rgba(127,245,234,.12); transform:translateY(-2px); }

/* ══ the three columns ══════════════════════════════════════ */

.mn-stage{
  display:grid;
  grid-template-columns:minmax(240px,38%) 1fr minmax(210px,22%);
  /* stretch, not start: the left column has to be handed the row's
     height or the button stack has nothing to divide up */
  align-items:stretch; gap:clamp(10px,1.6vw,26px);
  padding:clamp(6px,1.2vh,16px) var(--mn-pad) clamp(4px,.8vh,10px);
  min-height:0; position:relative;
}

/* ── left: wordmark + the stack ───────────────────────────── */

.mn-left{
  position:relative; z-index:2;
  display:flex; flex-direction:column; align-items:flex-start;
  gap:clamp(4px,1vh,14px);
  min-width:0; height:100%; min-height:0;
}
/* Sized by HEIGHT so it cannot eat the stack's space; the width
   follows the 3:1 wordmark and is capped by the column. */
.mn-logo{
  display:block; flex:none;
  height:clamp(44px, 21%, 214px); width:auto; max-width:100%;
  object-fit:contain; object-position:left center;
  filter:drop-shadow(0 6px 0 rgba(3,6,16,.5)) drop-shadow(0 14px 26px rgba(0,0,0,.55));
}
.mn-stack{
  display:flex; flex-direction:column; align-items:flex-start;
  gap:var(--mn-gap); width:100%; min-width:0;
  flex:1 1 auto; min-height:0;
}

/* One button box == the drawn bar body, nothing more.  The PNG is
   absolutely positioned and pulled up by the measured top padding,
   so the artwork's badge, lightning and glow overflow the box and
   the boxes themselves stack on a single rhythm. */
.mn-btn{
  position:relative; display:block; padding:0; border:0; cursor:pointer;
  background:none; -webkit-appearance:none; appearance:none;
  /* height comes from the flex line, width comes from the height */
  flex:1 1 0; min-height:0; height:auto;
  width:auto; max-width:100%;
  aspect-ratio:var(--mn-ar);
  transition:transform var(--dur-fast,.12s) var(--ease-pop,cubic-bezier(.3,1.5,.5,1)),
             filter var(--dur-fast,.12s);
}
.mn-btn > img{
  position:absolute; left:0; top:calc(var(--mn-at) / var(--mn-band) * -100%);
  width:100%; height:auto; display:block; pointer-events:none;
  filter:drop-shadow(0 5px 0 rgba(3,6,16,.42)) drop-shadow(0 10px 16px rgba(0,0,0,.45));
}
/* PLAY is the hero: one number, and because the width is derived
   from the height it comes out both taller AND wider than the blue
   bars, which is the read the mockup wants. */
.mn-btn.is-hero{ flex-grow:1.38; margin-bottom:calc(var(--mn-gap) * .8); }

.mn-btn:hover{ transform:translateX(6px) scale(1.015); }
.mn-btn:active{ transform:translateX(6px) scale(.985); }
.mn-btn:hover > img{
  filter:drop-shadow(0 5px 0 rgba(3,6,16,.42)) drop-shadow(0 10px 16px rgba(0,0,0,.45))
         drop-shadow(0 0 14px rgba(127,245,234,.55)) brightness(1.09);
}
.mn-btn.is-hero:hover > img{
  filter:drop-shadow(0 5px 0 rgba(3,6,16,.42)) drop-shadow(0 10px 16px rgba(0,0,0,.45))
         drop-shadow(0 0 18px rgba(255,198,61,.7)) brightness(1.07);
}
/* the focus ring is a rectangle around a hex bar, so the art gets a
   halo too — the ring alone reads as "a box near the button" */
.mn-btn:focus-visible > img{
  filter:drop-shadow(2px 0 0 var(--mn-aqua)) drop-shadow(-2px 0 0 var(--mn-aqua))
         drop-shadow(0 2px 0 var(--mn-aqua)) drop-shadow(0 -2px 0 var(--mn-aqua))
         drop-shadow(0 0 18px rgba(127,245,234,.75));
}

/* ── centre: the spacer the hero stands in ────────────────── */
.mn-centre{ min-width:0; }

/* ── right: season + daily ────────────────────────────────── */

.mn-right{
  position:relative; z-index:2; justify-self:end; width:100%;
  display:flex; flex-direction:column; gap:clamp(8px,1.4vh,16px);
  min-width:0; min-height:0;
  /* Pushed down the column rather than pinned to the top: at the top the
     two cards crowd the hero and the logo, and the mockup sits them lower
     against the arena. `auto` on top only — a margin-top:auto with a
     flex-end justify would fight the gap, and the cards must still be
     free to shrink, so the column keeps its own height. */
  justify-content:flex-end;
  padding-bottom:clamp(4px,1vh,12px);
}

.mn-card{
  /* Do not grow. The column is stretched to the stage height, so a
     growing card fills it and justify-content has nothing left to push
     — which is why flex-end alone did not move them. */
  flex:0 0 auto;
  position:relative;
  padding:clamp(9px,1.3vh,15px) clamp(11px,.9vw,17px) clamp(10px,1.4vh,16px);
  background:linear-gradient(180deg, rgba(26,52,104,.96), rgba(9,20,46,.97));
  clip-path:polygon(14px 0,100% 0,100% calc(100% - 14px),
                    calc(100% - 14px) 100%, 0 100%, 0 14px);
  /* the outline follows the cut corners; the plate is opaque, so the
     chain never outlines the text sitting on it */
  filter:
    drop-shadow(2px 0 0 var(--mn-edge))  drop-shadow(-2px 0 0 var(--mn-edge))
    drop-shadow(0 2px 0 var(--mn-edge))  drop-shadow(0 -2px 0 var(--mn-edge))
    drop-shadow(0 6px 0 rgba(3,6,16,.55)) drop-shadow(0 14px 24px rgba(0,0,0,.5));
}

/* The dark end of this green was #22964a, which put the tag's ink at
   4.37:1 — measurably short of 4.5.  #2aa355 is the same green one
   step up and lands it at 5.1:1. */
.mn-tag{
  display:inline-block; padding:3px 9px; border-radius:3px;
  background:linear-gradient(180deg,#63e06a,#2aa355); color:#04240f;
  font:900 clamp(9.5px,1.15vh,11px)/1 var(--ui,sans-serif); letter-spacing:.14em;
  box-shadow:0 0 0 2px var(--mn-edge);
}
.mn-season-name{
  margin:clamp(5px,.9vh,10px) 0 clamp(3px,.5vh,7px);
  font:900 clamp(19px,3.1vh,32px)/.94 var(--display,sans-serif);
  letter-spacing:-.01em; color:#ff5a9c;
  -webkit-text-stroke:3px var(--mn-edge); paint-order:stroke fill;
  text-shadow:0 3px 0 rgba(3,6,16,.5);
}
.mn-card-copy{
  margin:0 0 clamp(7px,1.1vh,12px);
  font:700 clamp(10.5px,1.3vh,12px)/1.4 var(--ui,sans-serif);
  letter-spacing:.05em; color:var(--mn-dim);
}
.mn-cta{
  width:100%; display:flex; align-items:center; justify-content:space-between;
  gap:8px; padding:clamp(6px,.95vh,10px) 12px; border:0; cursor:pointer;
  background:linear-gradient(180deg,#ffe08a,var(--mn-gold) 42%,#e39a1c);
  color:#2a1500; font:900 clamp(10px,1.35vh,13px)/1 var(--display,sans-serif);
  letter-spacing:.09em; text-align:left;
  clip-path:polygon(0 0,calc(100% - 10px) 0,100% 50%,calc(100% - 10px) 100%,0 100%);
  filter:
    drop-shadow(2px 0 0 var(--mn-edge))  drop-shadow(-2px 0 0 var(--mn-edge))
    drop-shadow(0 2px 0 var(--mn-edge))  drop-shadow(0 -2px 0 var(--mn-edge))
    drop-shadow(0 3px 0 rgba(3,6,16,.5));
  transition:transform var(--dur-fast,.12s) var(--ease-pop,cubic-bezier(.3,1.5,.5,1)),
             background var(--dur-fast,.12s);
}
.mn-cta:hover{ transform:translateY(-2px); background:linear-gradient(180deg,#fff3c4,#ffd867 42%,#f0a922); }
.mn-chev{ width:13px; height:13px; display:block; flex:none; }
.mn-chev svg{ width:100%; height:100%; display:block; }

.mn-dots{ display:flex; gap:6px; justify-content:center; margin-top:clamp(6px,1vh,11px); }
.mn-dots i{ width:7px; height:7px; border-radius:99px; background:#2d4573; box-shadow:0 0 0 1px rgba(0,0,0,.5); }
.mn-dots i.on{ background:var(--mn-hot); box-shadow:0 0 0 1px rgba(0,0,0,.5), 0 0 8px rgba(255,61,139,.8); }

.mn-card-head{
  margin:0 0 clamp(6px,.9vh,10px);
  font:800 clamp(10px,1.35vh,13px)/1 var(--display,sans-serif);
  letter-spacing:.14em; text-transform:uppercase; color:var(--mn-aqua);
}
.mn-daily-row{ display:flex; align-items:flex-start; gap:10px; }
.mn-daily-txt{ flex:1; min-width:0; display:flex; flex-direction:column; }
.mn-daily-name{
  font:900 clamp(12px,1.75vh,17px)/1 var(--display,sans-serif);
  letter-spacing:.03em; color:var(--mn-gold); text-shadow:0 2px 0 rgba(3,6,16,.55);
}
.mn-daily-what{
  margin:4px 0 clamp(6px,.9vh,10px);
  font:600 clamp(10.5px,1.25vh,12px)/1.35 var(--ui,sans-serif); color:var(--mn-dim);
}
.mn-meter{
  height:12px; background:#07102a; border-radius:99px; overflow:hidden;
  box-shadow:inset 0 0 0 2px var(--mn-edge);
}
.mn-meter i{ display:block; height:100%; background:linear-gradient(90deg,var(--mn-gold),var(--gold-hi,#ffe08a)); }
.mn-daily-n{
  margin-top:5px; font:800 clamp(10.5px,1.3vh,12px)/1 var(--ui,sans-serif);
  letter-spacing:.08em; color:var(--mn-dim);
}
.mn-daily-n b{ color:var(--mn-ink); }
.mn-prize{ flex:none; display:flex; flex-direction:column; align-items:center; gap:2px; }
.mn-prize-art{ width:clamp(24px,3.6vh,34px); height:clamp(24px,3.6vh,34px); display:block;
  filter:drop-shadow(0 0 9px rgba(180,230,255,.55)); }
.mn-prize-art svg{ width:100%; height:100%; display:block; }
.mn-prize b{ font:900 clamp(10px,1.3vh,13px)/1 var(--display,sans-serif); color:var(--mn-ink); }

.mn-refresh{
  display:flex; align-items:center; gap:6px; margin-top:clamp(7px,1.1vh,12px);
  padding-top:clamp(6px,.9vh,10px); border-top:1px solid rgba(127,245,234,.16);
  font:800 clamp(9.5px,1.15vh,11px)/1 var(--ui,sans-serif);
  letter-spacing:.10em; text-transform:uppercase; color:var(--mn-dim);
}
.mn-refresh b{ color:var(--mn-gold); font-variant-numeric:tabular-nums; }
.mn-rf-ico{ width:13px; height:13px; display:block; flex:none; color:var(--mn-gold); }
.mn-rf-ico svg{ width:100%; height:100%; display:block; }

/* ══ the hero ═══════════════════════════════════════════════
   Bottom-anchored, centred, and behind both rails.  It takes no
   pointer events: the arena is behind it and the two columns must
   keep every click they own. */
.mn-hero{
  position:absolute; left:50%; bottom:0; transform:translateX(-50%);
  width:clamp(300px,40vw,760px); aspect-ratio:1/.94;
  max-height:100%;
  z-index:1; pointer-events:none;
}
/* A pool of dark behind him.  Two jobs: it separates his silhouette
   from a busy moving arena (the reason he reads at a glance at all),
   and it travels WITH the hero, so it keeps sinking whatever the loop
   has painted behind him at any window aspect — which a fixed scrim
   cannot do, because object-fit:cover slides the frame around. */
.mn-hero::before{
  content:""; position:absolute; z-index:-1;
  left:-15%; right:-15%; top:4%; bottom:-2%;
  background:radial-gradient(ellipse 46% 54% at 50% 54%,
    rgba(3,6,18,.74) 0%, rgba(3,6,18,.44) 44%, rgba(3,6,18,0) 74%);
}

.mn-char{
  position:absolute; left:0; width:100%; height:auto; bottom:2.5%;
  /* warm rim from the god-rays overhead, then the cast shadow */
  filter:drop-shadow(0 -3px 0 rgba(255,226,170,.34))
         drop-shadow(0 24px 30px rgba(0,0,0,.62));
  animation:mn-bob 6.2s ease-in-out infinite;
  will-change:transform;
}
@keyframes mn-bob{
  0%,100%{ transform:translate3d(0,0,0) rotate(0deg); }
  50%    { transform:translate3d(0,-10px,0) rotate(-.6deg); }
}

/* The pearl he is balancing — the brightest thing on the screen,
   which is the same rule the arena plays by.  It sits ON the curl of
   his upper-left tentacle: the tip is at 0.245 x, 0.381 y of this box
   (read off the art's alpha channel against the placed size), so the
   pearl's CENTRE goes one radius above that and the two share one
   animation, or they drift apart as they bob. */
.mn-pearl{
  position:absolute; left:19.6%; top:27.8%; width:9.5%; aspect-ratio:1; z-index:2;
  border-radius:50%;
  background:
    radial-gradient(circle at 34% 26%, #ffffff 0%, #eaf8ff 18%, #bfe6ff 46%, #7fa8d8 72%, #3d5a91 100%);
  box-shadow:
    0 0 0 2px rgba(4,8,20,.55),
    0 0 14px 4px rgba(190,235,255,.8),
    0 0 44px 12px rgba(120,205,255,.45);
  animation:mn-pearl 6.2s ease-in-out infinite;
}
@keyframes mn-pearl{
  0%,100%{ transform:translate3d(0,0,0); }
  50%    { transform:translate3d(0,-10px,0); }
}

/* a pool of shade so he sits ON the plinth instead of in front of it.
   Bottom lands on the cap, not below it — the tentacles read as
   touching stone only if the darkest part of the pool is where they
   actually meet it. */
.mn-shade{
  position:absolute; left:20%; right:20%; bottom:21.5%; height:6.5%;
  background:radial-gradient(ellipse at 50% 60%, rgba(3,6,16,.78), rgba(3,6,16,.28) 52%, transparent 74%);
}

/* the plinth's own contact shadow, spreading onto the arena floor.
   It has to be a pseudo of .mn-hero, not of .mn-plinth: the plinth is
   clip-path'd, so anything it draws outside its own trapezoid is cut
   off — including the shadow that makes it sit in the scene. */
.mn-hero::after{
  content:""; position:absolute; z-index:-1;
  left:2%; right:2%; bottom:-1.5%; height:9%;
  background:radial-gradient(ellipse at 50% 62%, rgba(2,4,12,.82) 0%, rgba(2,4,12,.45) 44%, transparent 72%);
}

/* ── the stone ────────────────────────────────────────────────
   Cut ashlar, not a dark slab: mortar courses, a light on the top
   of each course, a warm wash from the god-rays above and a deep
   base.  Layer order is top-down = front-to-back. */
.mn-plinth{
  position:absolute; left:7.5%; right:7.5%; bottom:0; height:23%;
  background:
    /* vertical joints */
    repeating-linear-gradient(90deg, rgba(5,9,24,.62) 0 3px, transparent 3px 19.5%),
    /* the lit top lip of each course, then the mortar under it */
    repeating-linear-gradient(180deg,
      rgba(214,232,255,.10) 0 2px, transparent 2px 3px,
      transparent 3px 29px, rgba(5,9,24,.55) 29px 32px),
    /* warm key from the rays overhead */
    linear-gradient(180deg, rgba(255,214,150,.13) 0%, rgba(255,214,150,0) 34%),
    /* the stone itself */
    linear-gradient(180deg, #4b5c88 0%, #3a4a78 22%, #27355f 58%, #141e42 100%);
  clip-path:polygon(4.5% 0, 95.5% 0, 100% 100%, 0 100%);
  box-shadow:inset 0 0 54px rgba(4,8,20,.55);
}
/* grain + the darkening towards both cut edges, so the block turns */
.mn-plinth::before{
  content:""; position:absolute; inset:0;
  background:
    linear-gradient(90deg, rgba(4,8,20,.55) 0%, transparent 16%,
                           transparent 84%, rgba(4,8,20,.55) 100%),
    repeating-linear-gradient(114deg, rgba(255,255,255,.035) 0 1px, transparent 1px 5px);
}
.mn-plinth-top{
  position:absolute; left:-4%; right:-4%; top:-6.5%; height:13%;
  background:linear-gradient(180deg,#8e9fca 0%,#6b7cb0 30%,#44548a 66%,#222f5b 100%);
  clip-path:polygon(2.5% 0, 97.5% 0, 100% 100%, 0 100%);
  box-shadow:0 4px 0 rgba(4,8,20,.62);
}
/* the warm lip where the cap catches the light from above */
.mn-plinth-top::after{
  content:""; position:absolute; left:2.5%; right:2.5%; top:0; height:26%;
  background:linear-gradient(180deg, rgba(255,232,186,.42), rgba(255,232,186,0));
}

/* ── the neon sign on the plinth face ─────────────────────────
   A board bolted to the stone: dark glass, an aqua tube inside the
   frame, and a bloom that spills onto the stone around it. */
.mn-sign{
  position:absolute; left:7%; right:7%; top:20%; bottom:11%;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:.1em; text-align:center;
  background:
    radial-gradient(ellipse 80% 120% at 50% 50%, rgba(24,58,86,.55), rgba(4,8,20,.94) 78%),
    linear-gradient(180deg, rgba(6,11,28,.94), rgba(3,6,18,.96));
  border-radius:5px;
  box-shadow:
    inset 0 0 0 2px rgba(127,245,234,.45),
    inset 0 0 26px rgba(47,230,214,.22),
    0 0 0 3px rgba(5,9,24,.92),
    0 0 34px rgba(47,230,214,.30);
}
.mn-sign-sm{
  font:800 clamp(7px,1.15vw,13px)/1 var(--ui,sans-serif);
  letter-spacing:.3em; color:#a8f0ff;
  text-shadow:0 0 10px rgba(47,230,214,.9);
}
.mn-sign-a, .mn-sign-b{
  font:900 clamp(13px,2.5vw,30px)/1 var(--display,sans-serif);
  letter-spacing:.05em; text-transform:uppercase;
}
.mn-sign-a{ color:#8ef7ec; text-shadow:0 0 8px rgba(47,230,214,.85), 0 0 24px rgba(47,230,214,.55); }
.mn-sign-b{ color:#ff8ec0; text-shadow:0 0 8px rgba(255,61,139,.9), 0 0 26px rgba(255,61,139,.55); }

/* ══ the echoed answer ══════════════════════════════════════
   Only ever visible when the shell's own toast is display:none —
   see _echo() in menu.js.  Gold plate, same voice as the toast it
   is standing in for, and it never takes a click. */
.mn-say{
  /* Under the top rail, not above the news bar where a toast usually
     lives: the bottom centre of this screen is the plinth sign, and a
     plate there lands straight on the word ARENA. */
  position:absolute; left:50%; top:calc(clamp(38px,5.2vh,58px) + 26px);
  transform:translate(-50%,-10px);
  z-index:6; pointer-events:none; opacity:0;
  max-width:min(560px,84vw); text-align:center;
  padding:11px 22px;
  background:linear-gradient(180deg,var(--gold-hi,#ffe08a),var(--mn-gold));
  color:#2a1500;
  font:900 clamp(11px,1.5vh,14px)/1.25 var(--display,sans-serif);
  letter-spacing:.09em; text-transform:uppercase;
  clip-path:polygon(12px 0,100% 0,calc(100% - 12px) 100%,0 100%);
  filter:
    drop-shadow(2px 0 0 var(--mn-edge))  drop-shadow(-2px 0 0 var(--mn-edge))
    drop-shadow(0 2px 0 var(--mn-edge))  drop-shadow(0 -2px 0 var(--mn-edge))
    drop-shadow(0 6px 0 rgba(3,6,16,.55));
  transition:opacity .2s, transform .2s var(--ease-pop,cubic-bezier(.3,1.5,.5,1));
}
.mn-say.on{ opacity:1; transform:translate(-50%,0); }
html.op-a11y-still .mn-say{ transition:none !important; }

/* ══ bottom bar ═════════════════════════════════════════════ */

.mn-foot{
  display:flex; align-items:center; gap:clamp(8px,1.3vw,22px);
  padding:clamp(6px,.9vh,12px) var(--mn-pad);
  background:linear-gradient(180deg, rgba(3,6,18,.86), rgba(3,6,18,.96));
  box-shadow:0 -2px 0 rgba(47,230,214,.16);
}

.mn-feed{ display:flex; align-items:center; gap:9px; flex:1 1 0; min-width:0; }
.mn-feed-ico{
  width:clamp(16px,2.2vh,20px); height:clamp(16px,2.2vh,20px); flex:none; display:block;
  color:var(--mn-aqua);
}
.mn-feed-tip .mn-feed-ico{ color:var(--mn-hot); }
.mn-feed-ico svg{ width:100%; height:100%; display:block; }
.mn-feed-txt{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.mn-feed-txt b{
  font:800 clamp(9px,1.1vh,10.5px)/1 var(--ui,sans-serif); letter-spacing:.15em;
  color:var(--mn-aqua);
}
.mn-feed-tip .mn-feed-txt b{ color:#ff8ec0; }
.mn-feed-txt em{
  font:600 clamp(10.5px,1.25vh,12px)/1.3 var(--ui,sans-serif); font-style:normal;
  color:var(--mn-dim);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

.mn-short{ display:flex; align-items:center; gap:clamp(4px,.6vw,10px); flex:none; }
.mn-sc{
  display:flex; flex-direction:column; align-items:center; gap:3px;
  padding:clamp(4px,.6vh,7px) clamp(7px,.8vw,13px); border:0; cursor:pointer;
  background:linear-gradient(180deg, rgba(31,60,114,.9), rgba(14,28,58,.92));
  color:var(--mn-ink);
  font:800 clamp(9px,1.05vh,10.5px)/1 var(--ui,sans-serif); letter-spacing:.09em;
  border-radius:7px;
  box-shadow:0 0 0 2px var(--mn-edge), 0 3px 0 rgba(0,0,0,.5);
  transition:transform var(--dur-fast,.12s) var(--ease-pop,cubic-bezier(.3,1.5,.5,1)),
             background var(--dur-fast,.12s);
}
.mn-sc:hover{ transform:translateY(-3px); background:linear-gradient(180deg,#2b5490,#16305f); }
.mn-sc-ico{ width:clamp(16px,2.3vh,20px); height:clamp(16px,2.3vh,20px); display:block; color:var(--mn-aqua); }
.mn-sc-ico svg{ width:100%; height:100%; display:block; }
.mn-sc:nth-child(1) .mn-sc-ico{ color:var(--mn-hot); }
.mn-sc:nth-child(2) .mn-sc-ico{ color:var(--mn-gold); }

.mn-invite{
  display:flex; align-items:center; gap:9px; flex:none;
  padding:clamp(4px,.6vh,7px) clamp(9px,.9vw,14px) clamp(4px,.6vh,7px) clamp(5px,.5vw,8px);
  border:0; cursor:pointer; border-radius:999px;
  background:linear-gradient(180deg, rgba(31,60,114,.9), rgba(14,28,58,.92));
  color:var(--mn-ink);
  font:800 clamp(9px,1.1vh,10.5px)/1 var(--ui,sans-serif); letter-spacing:.10em;
  box-shadow:0 0 0 2px var(--mn-edge), 0 3px 0 rgba(0,0,0,.5);
  transition:transform var(--dur-fast,.12s) var(--ease-pop,cubic-bezier(.3,1.5,.5,1));
}
.mn-invite:hover{ transform:translateY(-3px); }
.mn-faces{ display:flex; flex:none; }
/* one sheet, three discs: the chip clips, the <img> inside it is a
   head crop of the same 1400px file the hero already decoded */
.mn-face-chip{
  position:relative; flex:none; overflow:hidden;
  width:clamp(20px,2.9vh,27px); height:clamp(20px,2.9vh,27px);
  border-radius:50%; background:#132750;
  box-shadow:0 0 0 2px var(--mn-edge);
}
.mn-face-chip img{
  position:absolute; width:270%; height:270%; max-width:none;
  left:-85%; top:-42%;
}
.mn-face-chip + .mn-face-chip{ margin-left:-9px; }

/* ══ short viewports ════════════════════════════════════════
   1400x560 is the shape that breaks this layout: eight bars, two
   cards and two rails in 560px.  Everything above is already
   height-derived; these trim the parts that are not. */
@media (max-height:640px){
  /* the wordmark gives its share to the bars, which are the things
     you came here to press */
  .mn-logo{ height:clamp(34px, 17%, 96px); }
  .mn-left{ gap:clamp(3px,.7vh,8px); }
  .mn-hero{ width:clamp(240px,32vw,520px); }
  .mn-card-copy{ display:none; }
  .mn-refresh{ margin-top:6px; padding-top:5px; }
  .mn-feed-txt em{ font-size:9.5px; }
  .mn-top, .mn-foot{ padding-block:5px; }
}
@media (max-height:470px){
  .mn-dots{ display:none; }
  .mn-hero{ display:none; }
}

/* ══ narrow ═════════════════════════════════════════════════ */
@media (max-width:1080px){
  .mn-stage{ grid-template-columns:minmax(0,1fr) minmax(200px,32%); }
  .mn-centre{ display:none; }
  .mn-hero{ display:none; }
  .mn-feed{ display:none; }
}

@media (max-width:760px){
  .mn-top{ flex-wrap:wrap; row-gap:8px; }
  .mn-curs{ order:3; margin-inline:0; width:100%; justify-content:space-between; }
  .mn-tools{ margin-left:auto; }
  /* NOT A GRID HERE.  With a definite height and auto rows, the row
     the left column sits in resolved to 284px against 740px of
     buttons and the season card printed straight over JOIN ROOM.
     A block box in a scroller has no track sizing to get wrong. */
  .mn-stage{
    display:block;
    overflow-y:auto; overscroll-behavior:contain;
    padding-bottom:clamp(10px,2vh,20px);
  }
  /* THE MODEL FLIPS HERE.  The phone layout scrolls, so there is no
     fixed height to divide up: the bars take the full column width
     and their height comes back from the same aspect ratio. */
  .mn-left{ align-items:stretch; height:auto; min-height:auto; }
  .mn-logo{ height:auto; width:100%; max-width:100%; }
  .mn-stack{ flex:none; }
  .mn-btn{ flex:none; width:100%; height:auto; }
  .mn-right{ margin-top:clamp(8px,1.6vh,16px); }
  .mn-foot{ flex-wrap:wrap; row-gap:8px; justify-content:center; }
  .mn-short{ flex:1; justify-content:center; }
  .mn-invite{ flex:none; }
  .mn-scrim{
    background:linear-gradient(180deg, rgba(4,8,20,.86) 0%, rgba(4,8,20,.62) 30%,
                                       rgba(4,8,20,.62) 70%, rgba(4,8,20,.92) 100%);
  }
}

/* ══ motion ═════════════════════════════════════════════════
   The video is paused in JS (see _syncVideo) rather than only
   here, because a paused <video> is the only version of it that
   actually stops costing decode time. */
@media (prefers-reduced-motion:reduce){
  .menu .mn-char, .menu .mn-pearl{ animation:none; }
  .menu .mn-btn, .menu .mn-sc, .menu .mn-invite,
  .menu .mn-tool, .menu .mn-plus, .menu .mn-cta{ transition:none; }
  .menu .mn-btn:hover, .menu .mn-sc:hover, .menu .mn-invite:hover,
  .menu .mn-tool:hover, .menu .mn-plus:hover, .menu .mn-cta:hover{ transform:none; }
  .menu .mn-vidwrap{ transition:none; }
}
html.op-a11y-still .menu .mn-char,
html.op-a11y-still .menu .mn-pearl{ animation:none; }
html.op-a11y-still .menu *{ transition:none !important; }
html.op-a11y-still .menu :is(.mn-btn,.mn-sc,.mn-invite,.mn-tool,.mn-plus,.mn-cta):hover{ transform:none; }

/* high-contrast mode turns the scrims into plates */
html.op-a11y-contrast .menu .mn-scrim{
  background:
    linear-gradient(90deg, rgba(2,4,12,.97) 0%, rgba(2,4,12,.94) 34%, rgba(2,4,12,.55) 46%,
                           rgba(2,4,12,.55) 54%, rgba(2,4,12,.94) 66%, rgba(2,4,12,.97) 100%),
    linear-gradient(180deg, rgba(2,4,12,.95) 0%, rgba(2,4,12,.4) 16%, rgba(2,4,12,.4) 78%, rgba(2,4,12,.97) 100%);
}
html.op-a11y-contrast .menu{ --mn-dim:#e6f4ff; }
html.op-a11y-contrast .menu .mn-card{
  background:linear-gradient(180deg,#12254c,#060d22);
}

/* ── touch targets ───────────────────────────────────────────
   See the TOUCH TARGETS note in theme.css for why these grow the box
   instead of drawing a hit pad: every one of these shapes is
   clip-pathed, and a clip-path takes the pseudo-element with it.
   Measured before: the five header tools were 31px, the two currency
   "+" buttons 21px, VIEW SEASON 27px and INVITE FRIENDS 30px. */
@media (pointer:coarse){
  .mn-tool{ width:44px; height:44px; }
  /* 36, not 44: the "+" lives INSIDE the currency pill, so 44 would set
     the whole three-pill row 20px taller for a shop shortcut. 36px is
     the compromise, and it is the one control on the screen still under
     the bar — recorded rather than quietly rounded up. */
  .mn-plus{ width:36px; height:36px; }
  .mn-cta,.mn-sc,.mn-invite{ min-height:44px; }
  /* the fatter pills no longer fit three-across on a 360px handset */
  .mn-curs{ flex-wrap:wrap; row-gap:6px; }
}

/* ── phone: give the STACK the room ──────────────────────────
   The eight bars are what this screen is for, and on a 360x740
   handset the header, wordmark and dock were taking 410px of 740
   before the first one was drawn. Nothing here hides anything —
   .mn-stage still scrolls — it just stops the chrome from being
   two thirds of the screen. Measured before/after in the report. */
@media (max-width:560px){
  .mn-top{ padding-block:5px; row-gap:6px; }
  .mn-curs{ gap:6px; }
  .mn-cur{ padding:3px 3px 3px 8px; gap:5px; }
  .mn-logo{ width:min(100%,268px); height:auto; }
  .mn-foot{ padding-block:6px; }
  .mn-sc{ padding:7px 10px; }
}
