/* ============================================================
   INKVILLE — tetrink.css
   Tetr-Ink — the well, the side boxes and the online rival panel

   Part of the game.css split. Loaded as <link> tags from index.html in
   THIS ORDER — the cascade depends on it. Do not reorder the links.
   ============================================================ */
/* ===== TETR-INK — GB-classic standalone (v2.98) ===== */
/* v3.63 — the WHOLE SCREEN wears the level's rolled palette (JS sets --tbg1/--tbg2/--ttxt on #scr-tetris),
   so a level-up shifts the backdrop, the well, the NEXT/HOLD boxes and the stats all at once. */
/* ⚠ NO transition on these var()-driven colours: a running background transition pins the computed value
   at the var()'s FALLBACK, so the repaint silently never lands. The level-up glitch covers the snap. */
#scr-tetris{background:linear-gradient(var(--tbg1,#7d8f4d),var(--tbg2,#67793d));}
#scr-tetris .gbar-flex .gb-nm{color:var(--ttxt,#f4c542); text-shadow:none;}
#scr-tetris .gbar-stats{color:var(--ttxt,#f2ead6);}
#scr-tetris .gbar-stats .gs b{color:var(--ttxt,#f4c542);}
#tetWrap{flex:1; min-height:0; display:flex; gap:10px; justify-content:center; align-items:center; padding:4px 8px calc(236px + var(--padny,0px)); position:relative; z-index:5;}
/* v3.46 — the well runs on GB palette VARS now: --tp0 ink · --tp1 screen · --tp2 rim; every level repaints them */
#tetWell{position:relative; box-sizing:content-box; background:var(--tp1,#9bbc0f); border:3px solid var(--tp0,#0f380f); box-shadow:0 0 0 3px var(--tp2,#8bac0f), 4px 6px 0 #1b151055; image-rendering:pixelated; overflow:hidden;}   /* v3.63 — the old `transition:background/border-color` is GONE: it pinned these var()-driven colours at their fallback, so the per-level repaint never actually showed */   /* content-box: the global border-box was clipping the bottom/right cells 3px — pieces looked cut off on drop */
#tetWell .tcell{background:var(--tp0,#0f380f);}
#tetWell .tcell::after{border-color:var(--tp1,#9bbc0f);}
/* ⭐ v0.567 — THE GREY CURTAIN. `tetSweepDead()` fills the well bottom-up with these on a top-out,
   the same grey slab (and the same ✕) Ink Panik has always used, so the two games die alike.
   ⚠ !important because the palette repaint above sets .tcell's background from --tp0 per level. */
#tetWell .tcell.dead{background:#6f6f6f !important;}
#tetWell .tcell.dead::after{border-color:#454545 !important;}
/* ⭐ v0.624 — THE PIECE THAT COULD NOT FIT. Left sitting over the stack it clashed with, drawn in
   the screen colour with a hard ringed edge and a slow blink, so it reads as ON TOP of the blocks
   rather than as one of them — the real game's way of saying "this is why the run ended".
   ⚠ It must out-rank the palette repaint AND the grey curtain, hence !important on both halves. */
#tetWell .tcell.clash{background:var(--tp1,#9bbc0f) !important; z-index:4; animation:tetClash .5s steps(2) infinite;}
#tetWell .tcell.clash::after{inset:6%; border:3px solid var(--tp0,#0f380f) !important; border-style:solid !important;}
.tcell.clash{background:#9bbc0f; z-index:4;}
@keyframes tetClash{0%,100%{opacity:1}50%{opacity:.45}}
#tetWell .tcell.gh{background:transparent;}   /* v3.51 — the palette repaint was out-ranking the ghost's transparency, turning the landing preview into a solid dark slab */
#tetWell .tcell.gh::after{border:2px dashed var(--tp0,#0f380f); opacity:.45;}
#tetWell .tcell.zap{background:var(--tp1,#9bbc0f);}
#tetWell .tcell.zap::after{border-color:var(--tp0,#0f380f);}
.tcell{position:absolute; background:#0f380f;}
.tcell::after{content:''; position:absolute; inset:15%; border:2px solid #9bbc0f; box-sizing:border-box;}
.tcell.gh{background:transparent;}
.tcell.gh::after{border:2px dashed #0f380f66;}
/* ⭐ v0.388 — the two states online adds to a well.
   .jk  = a junk row that has already risen: solid, but hatched so it reads as somebody else's.
   .pend= junk that is OWED and has not risen yet, painted across the top of the well as a warning.
          It is see-through and it breathes, so it can never be mistaken for a block you can land on. */
#tetWell .tcell.jk{background:var(--tp2,#8bac0f);}
#tetWell .tcell.jk::after{border-style:dashed; border-color:var(--tp0,#0f380f);}
#tetWell .tcell.pend{background:transparent;}
#tetWell .tcell.pend::after{inset:8%; border:2px solid var(--tp0,#0f380f); background:var(--tp0,#0f380f); opacity:.34; animation:tetPend 1s ease-in-out infinite;}
@keyframes tetPend{0%,100%{opacity:.20}50%{opacity:.52}}
/* ⭐⭐⭐ v0.684 — THE RIVAL'S PIECE, STILL IN THE AIR. Only ever on #ttnMini: it marks the tetromino
   the other player is holding, so their well reads as somebody steering rather than as a pile that
   grows. It is the SAME .tcell as everything else on that little board (the v0.418 rule — a rival's
   well is the real well at a smaller size, not a chart of it); this only lifts it off the stack.
   ⚠ SCOPED TO #ttnMini. Your own well already tells you where your piece is — it is the thing you
   are moving, and it has a ghost under it — and a second highlight on your own board would be one
   more thing to read at speed. Also keeps the class from colliding with .gh / .clash / .zap, which
   are all real-well states.
   ⚠ NO ANIMATION. At 3-4px a cell a pulse is a flicker, and there are up to four of these moving
   several times a second already. Brightness and a rim are enough to separate two shades. */
/* ⭐ v0.749 — NO RING. The cream 1px rim read as a SELECTION BOX at 4px a cell — Odaroo saw it as
   Panel-Ink's `.hcur` selector wandering onto the Tetr-Ink rival board. It was never that cursor
   (Tetr-Ink draws no `.hcur` and no `.hncur`), but a bright outline chasing four cells down a well
   is indistinguishable from one. The piece is still told apart from the pile — that is the whole
   point of v0.684 and the self-test still proves it — but by SHADE alone now, with no outline. */
#ttnMini .tcell.tnfly{background:var(--tp1,#9bbc0f);}
#ttnMini .tcell.tnfly::after{border-color:var(--tp0,#0f380f);}
.tcell.zap{background:#9bbc0f;}
.tcell.zap::after{border-color:#0f380f; animation:tetZap .32s steps(2) both;}
@keyframes tetZap{0%{opacity:1}100%{opacity:0}}
.miniHud{display:flex; justify-content:space-between; align-items:center; padding:5px 10px; background:var(--ink); color:var(--cream); font-size:11px; z-index:6; position:relative; gap:6px; flex-wrap:wrap; font-family:var(--fontD); font-size:8px; letter-spacing:1px; flex:0 0 auto;}
#tetSide{display:flex; flex-direction:column; gap:8px; width:82px; flex:0 0 auto; order:-1; align-self:flex-start; margin-top:calc(var(--inkav,69px) + 48px);}
/* ⚠⚠⚠ v0.640 — THE CLEARANCE ABOVE THIS COLUMN IS DERIVED, NOT TYPED. It was a flat 150px (v0.388:
   "a worn FRAME draws outside the inkling's layout box"), measured by hand against a 58px portrait.
   The portrait is --inkav now (the main menu's size, 69/78 — see css/base.css), so the flat number
   was instantly a build out of date: the pre-flight caught TIME's "0:00" sliding under the D-pad at
   375x812 the moment the face grew. Measured with the pad forced on, the old 150 left 75px of dead
   air between the inkling's bottom edge and the word NEXT and still ran the column past the pad;
   this keeps ~50px of clearance, which covers the frame overflow, and gives the rest back to the
   figures. Anything that changes the portrait size changes this with it, automatically. */
/* ⭐ v3.88 — INK PANIK borrows Tetr-Ink's side column: NEXT (the row rising in) + HOLD (tap to stash a tile, tap to drop it back) */
#hzNextRow{display:flex; gap:2px; justify-content:center; padding:2px 0;}
#hzNextRow i{width:11px; height:11px; border-radius:2px; display:block;}
#hzHoldCell{height:26px; display:flex; align-items:center; justify-content:center;}
#hzHoldCell i{width:20px; height:20px; border-radius:3px; display:block;}
/* v3.69 — the wide-screen flex-start override is GONE: the well + side column stay CENTERED at every width, matching Ink Panik */
#scr-tetris .gink-game{top:6px !important; left:6px !important;}   /* no banner to clear — corner seat */
#scr-horror .gink-game{top:6px !important; left:6px !important;}
/* v0.422 — during an online match the marquee is gone and the names own the top edge, so both
   faces sit hard in their corners under their own name.
   ⚠⚠ `:not(.vsfoe)` IS LOAD-BEARING. The rival's portrait is built with `class="gink gink-game
   vsfoe"` — it is a gink-game too — so a bare `.gink-game` left-corner rule pulls THEIR face into
   YOUR corner and stacks the two on top of each other. Anything written for "my inkling" on these
   screens has to exclude .vsfoe explicitly. */
#scr-tetris .vsnm.vsnm-top, #scr-horror .vsnm.vsnm-top{align-items:flex-start;}
/* ⭐ v0.422 — AND THE PLAYFIELD STARTS BELOW THEM. Taking the marquee away gave the boards the top
   of the screen back, and they took it: the rival's face and the top-right corner of the well ended
   up sharing about six pixels. The name-and-face block is roughly 100px tall, so the play row is
   inset by that much while a match is on. It comes straight back off on a solo run, because the
   class only exists during a match. */
/* ⚠ v0.424 — 104px was set in v0.422 to clear the name-and-face block while the WORDMARK BAND was
   still on screen above it. The band is gone from every game now, so the block starts higher and the
   inset comes down with it — which is what gives Ink Panik's online board back the nine pixels it
   was losing to the D-pad. Tetr-Ink gets the same headroom. */
/* ⚠⚠ KEYED ON .vs-inset, WHICH THE SIZING FUNCTION ITSELF PUTS ON — never on `:has(.vsnm-top)`.
   vsNamePlace adds .vsnm-top after the first sizing pass, so a rule hung off it changed the wrap's
   padding between the first measurement and the second and the board came out two different sizes.
   tetSize/hzSize set .vs-inset from the live match before they measure anything. */
/* ⚠ v0.548 — 76 → 94. The name-and-face block grew by ~16px: the username strip went from 10px to
   13px (Odaroo wanted the names bigger) and the level tab moved from a 5px overlap to hanging 16px
   clear BELOW the frame. The inset is that block's height and has to follow it, or the well's top
   corner and the rival's level land on each other. */
#tetWrap.vs-inset, #horrorWrap.vs-inset{padding-top:calc(94px * var(--gs,1));}
#hzStageTR{position:absolute; top:44px; right:10px; z-index:8; font-family:var(--fontD); font-size:10px; letter-spacing:1px; color:#fdf6e3; text-align:right; text-shadow:1px 1px 0 #1b1510;}
#hzStageTR b{font-size:16px; color:#f4c542; margin-left:4px; text-shadow:1px 1px 0 #1b1510, 0 0 8px #f4c54288;}
/* ===== v3.47 — the two rhythm-game SPLASH pages, each with its own look ===== */
.splash-btns{display:flex; flex-direction:column; gap:10px; width:min(86%,300px); margin:14px auto 0; position:relative; z-index:6;}
.btn.splash-big span{display:block; line-height:1.4;}
.btn.splash-big span i{display:block; font-style:normal; font-size:8px; letter-spacing:.5px; opacity:.75; font-weight:normal; text-transform:none;}
/* ITH — smoky night-club: roaming spotlights + drifting notes over the moon */
.ith-spot{position:absolute; top:-10%; width:34%; height:70%; z-index:2; pointer-events:none; opacity:.16;
  background:linear-gradient(#fff8,transparent 80%); clip-path:polygon(40% 0,60% 0,100% 100%,0 100%);}
.ith-spot.l{left:4%; transform-origin:top center; animation:ithSpot 5.4s ease-in-out infinite alternate;}
.ith-spot.r{right:4%; transform-origin:top center; animation:ithSpot 6.2s ease-in-out infinite alternate-reverse;}
@keyframes ithSpot{from{transform:rotate(-16deg)}to{transform:rotate(16deg)}}
.ith-fnote{position:absolute; left:var(--fx,20%); bottom:-30px; z-index:2; font-size:22px; pointer-events:none; opacity:.8;
  text-shadow:0 0 10px currentColor; animation:ithNoteUp var(--fd,6s) linear infinite;}
@keyframes ithNoteUp{0%{transform:translateY(0) rotate(-8deg); opacity:0;}12%{opacity:.85;}100%{transform:translateY(-72vh) rotate(10deg); opacity:0;}}
/* DDI — the disco: a mirror ball over a flashing checker floor, arrows rising */
.ddi-splash .rg-jp,.ddi-splash .rg-title,.ddi-splash .rg-sub{position:relative; z-index:4;}   /* the marquee text always reads over the ball */
.ddi-ball{position:absolute; top:4%; left:50%; transform:translateX(-50%); z-index:2; width:48px; height:48px; pointer-events:none;}
.ddi-ball::before{content:''; position:absolute; left:50%; top:-24px; width:2px; height:24px; background:#0008; transform:translateX(-50%);}
.ddi-ball i{display:block; width:100%; height:100%; border-radius:50%;
  background:repeating-conic-gradient(#e8e8f4 0 10%,#9aa2c0 10% 20%), repeating-linear-gradient(0deg,#0002 0 6px,#0000 6px 12px);
  box-shadow:0 0 22px #fff8, inset -6px -8px 0 #0004; animation:ddiBallSpin 4s linear infinite;}
@keyframes ddiBallSpin{to{filter:hue-rotate(360deg)}}
.ddi-floor{position:absolute; left:0; right:0; bottom:0; height:26%; z-index:2; pointer-events:none; opacity:.5;
  background:repeating-conic-gradient(#e01b4d 0 25%, #2b1b3a 0 50%) 0 0/56px 56px; transform:perspective(220px) rotateX(48deg) scale(1.4);
  animation:ddiFloor 1.2s steps(2) infinite;}
@keyframes ddiFloor{50%{filter:hue-rotate(140deg) brightness(1.25);}}
.ddi-farrow{position:absolute; left:var(--fx,20%); bottom:-40px; z-index:2; width:30px; height:30px; pointer-events:none; opacity:.85;
  animation:ithNoteUp var(--fd,5s) linear infinite;}
.ddi-farrow svg{width:100%; height:100%;}
/* ⭐ v3.88 — ITH menu ROCKS: speaker stacks, strobing bolts, a pulsing wordmark */
.ith-amp{position:absolute; bottom:12%; width:52px; height:84px; z-index:2; background:#1c1424; border:3px solid #0c0812; border-radius:4px;
  display:flex; flex-direction:column; align-items:center; justify-content:space-evenly; box-shadow:0 0 18px #e01b4d44; animation:ithAmpThump .48s ease-in-out infinite;}
.ith-amp.l{left:4%;} .ith-amp.r{right:4%; animation-delay:.24s;}
.ith-amp i{width:30px; height:14px; border-radius:50%; background:radial-gradient(circle,#3a2c50 0 35%,#171021 70%); border:2px solid #0c0812;}
@keyframes ithAmpThump{0%,100%{transform:scale(1)}50%{transform:scale(1.05)}}
.ith-bolt{position:absolute; top:16%; font-size:34px; z-index:2; filter:drop-shadow(0 0 10px #f4c542); animation:ithBoltFlash 1.9s steps(2) infinite;}
.ith-bolt.l{left:10%; transform:rotate(-14deg);} .ith-bolt.r{right:10%; transform:rotate(14deg); animation-delay:.9s;}
@keyframes ithBoltFlash{0%,72%,100%{opacity:0}76%,92%{opacity:1}}
.ith-rocktitle{animation:ithRockPulse 1.1s ease-in-out infinite;}
@keyframes ithRockPulse{0%,100%{text-shadow:3px 3px 0 #1b1510, 0 0 10px #e01b4d66;}50%{text-shadow:3px 3px 0 #1b1510, 0 0 26px #e01b4dcc, 0 0 40px #f4c54288;}}
/* ⭐ v3.71 — the STAGE tag is OUTLINED, not tinted. It used to be painted in the old fixed GB green, so
   once the per-level palettes started rolling it could land dark-on-dark and vanish. Cream text with a hard
   ink stroke on all four sides reads on ANY backdrop the palette generator can produce. */
#tetStageTR{position:absolute; top:44px; right:10px; z-index:7; font-family:var(--fontD); font-size:10px; letter-spacing:1px; color:#fdf6e3; text-align:right;
  text-shadow:1px 1px 0 #1b1510,-1px 1px 0 #1b1510,1px -1px 0 #1b1510,-1px -1px 0 #1b1510;}
#tetStageTR b{font-size:16px; color:#f4c542; margin-left:4px;
  text-shadow:1.5px 1.5px 0 #1b1510,-1.5px 1.5px 0 #1b1510,1.5px -1.5px 0 #1b1510,-1.5px -1.5px 0 #1b1510, 0 0 8px #00000066;}
.tetLevelUp{position:absolute; left:50%; top:38%; transform:translate(-50%,-50%); z-index:6; font-family:var(--fontD); font-size:18px; letter-spacing:2px; color:var(--tp0,#0f380f); text-shadow:2px 2px 0 var(--tp1,#9bbc0f), 0 0 14px #fff; white-space:nowrap; pointer-events:none; animation:tetLvlUp 1.2s steps(6) forwards;}
@keyframes tetLvlUp{0%{opacity:0; transform:translate(-50%,-50%) scale(.5);}20%{opacity:1; transform:translate(-52%,-50%) scale(1.25);}40%{transform:translate(-48%,-50%) scale(1.1);}80%{opacity:1;}100%{opacity:0; transform:translate(-50%,-70%) scale(1);}}
/* v3.63 — NEXT / HOLD / stats ride the level palette too, so nothing is left on the old colours */
.tet-box{background:var(--tp1,#9bbc0f); border:3px solid var(--tp0,#0f380f); color:var(--tp0,#0f380f); text-align:center; padding:4px 3px 5px; font-family:var(--fontD); font-size:9px; line-height:1.6; letter-spacing:1px;}
.tet-box .tlab{opacity:.62; font-size:7px;}
.tet-stats{text-align:left; padding:5px 6px 6px;}
.tet-stats .gs{display:flex; justify-content:space-between; align-items:baseline; font-size:8px; line-height:1.8; letter-spacing:.5px;}
.tet-stats .gs b{color:var(--tp0,#0f380f);}
/* ⭐ v0.388 — TETR-INK ONLINE: the THIRD box in the left column, under NEXT and HOLD. It wears the
   level's own palette like the other two, so it belongs to the screen instead of sitting on it. */
.ttn-panel{background:var(--tp1,#9bbc0f); border:3px solid var(--tp0,#0f380f); color:var(--tp0,#0f380f);
  padding:4px 3px 5px; font-family:var(--fontD); font-size:8px; letter-spacing:.5px; line-height:1.6;
  display:flex; flex-direction:column; gap:3px; align-items:stretch; text-align:center;}
/* ⭐ v0.402 — THE COLUMN READS LIKE A SCOREBOARD, NOT A SHOPPING LIST.
   THEIR LINES / SENT / WIN used to be squeezed onto single 6px lines with the label and the number
   fighting over 76px, which is what made the column look cramped and messy in Odaroo's screenshot.
   Each stat is now a small muted CAPTION with its number on its own line underneath, hairline-ruled
   apart — same information, half the crowding, and the numbers are finally the biggest thing there. */
.ttn-vs{line-height:1.3; padding-bottom:2px;}
.ttn-vs b{display:block; opacity:.55; font-size:6px; letter-spacing:2px;}
.ttn-vs span{display:block; font-size:8px; letter-spacing:.5px; word-break:break-all;}
.ttn-mini{position:relative; margin:2px auto; background:var(--tbg1,#1e2a10);
  border:2px solid var(--tp0,#0f380f); box-sizing:content-box;}
/* ⭐⭐ v0.418 — THE RIVAL BOARDS ARE DRAWN WITH THE REAL SPRITES NOW, so the old flat <i> swatch is
   retired. What is left here is only what a MINIATURE needs: the chunky per-cell trim that reads
   fine at 40px would swallow a 6px cell whole, so it is thinned — same design, honest small scale.
   Nothing here invents a graphic; both boards emit the very elements their own game draws. */
.ttn-mini .tcell::after{border-width:1px; inset:20%;}
.ttn-mini .hpan{border-width:1px; border-radius:20%; box-shadow:inset 0 1px 0 #ffffff55, inset 0 -2px 0 #00000045;}
.ttn-mini .tcell, .ttn-mini .hpan{pointer-events:none; cursor:default;}
.ttn-mini .hpan svg{width:78%; height:78%; display:block;}
.ttn-mini.waiting{opacity:.45; animation:rknBreathe 1.5s ease-in-out infinite;}
.ttn-row{display:block; text-align:center; font-size:6px; letter-spacing:1px; line-height:1.35;
  padding-top:3px; border-top:1px solid var(--tp0,#0f380f);}
.ttn-row span{display:block; opacity:.6;}
.ttn-row b{display:block; font-size:11px; letter-spacing:.5px; line-height:1.25;}
.ttn-row.ttn-prize b{font-size:8px;}   /* "+25 CUPS" is words, not a tally — it does not need the tally size */
.ttn-warn{border-top:2px dashed var(--tp0,#0f380f); padding-top:3px; line-height:1.3; opacity:.72;}
.ttn-warn b{display:block; font-size:6px; letter-spacing:.5px;}
.ttn-warn u{display:block; text-decoration:none; font-size:6px; opacity:.75;}
.ttn-warn.on{opacity:1;}
.ttn-warn.on b{animation:rknBreathe .8s ease-in-out infinite;}
/* ⭐ v0.402 — THE FORFEIT DOORS ARE ONE SIZE. `.btn opt` already matched their WIDTH, but on the
   folded screen "KEEP PLAYING" wrapped to a second line and grew 17px taller than FORFEIT beside
   it. A fixed height and a label that never wraps make the two doors identical on both folds. */
.btn.ttn-choice{height:52px; min-height:52px; padding-left:6px; padding-right:6px;}
.btn.ttn-choice span{white-space:nowrap!important; font-size:11px; letter-spacing:1px;}
/* ⚠ v0.402 — THE BUTTON'S OWN PADDING WAS THE PROBLEM. .btn carries 14px of side padding, which in
   an 82px column leaves 40px of room for a seven-letter word — so FORFEIT hung out over both edges
   of its own button. Narrow padding here, and the label sits inside the box it belongs to. */
.ttn-out{width:100%; margin-top:4px; padding-left:2px!important; padding-right:2px!important;}
.ttn-out span{font-size:7px!important; letter-spacing:0;}
@media (min-width:640px){
  .ttn-panel{font-size:9px; gap:4px; padding:5px 4px 6px;}
  .ttn-vs span{font-size:10px;} .ttn-row{font-size:7px;} .ttn-row b{font-size:13px;}
  .ttn-row.ttn-prize b{font-size:9px;}
  .ttn-warn b,.ttn-warn u{font-size:7px;} .ttn-out span{font-size:9px!important;}
}
/* v0.390 — Ink Panik's rival board is the same miniature, but its panels carry their own colours */
.hzn-mini{margin:3px auto;}
.hzn-mini i{box-shadow:inset 0 0 0 1px #1b151066;}

/* ============================================================
   ⭐ v0.398 — THE INCOMING METER, and the flinch that goes with it.
   This is what replaced the two toasts ("X SENT YOU 2 JUNK ROWS", "X PUSHED 2 ROWS AT YOU"). It is
   a column of notches standing beside the well — one notch per row of trouble on its way to you,
   filling from the FLOOR UP because that is the end it arrives at. Nothing owed and it is a faint
   outline you never look at; the moment something is owed it lights and breathes.
   ⚠ It is a flex SIBLING of the well, never a child: #tetWell and #horrorGrid are both
   overflow:hidden, so anything hung off the inside edge is clipped clean away.
   ============================================================ */
.jgut{position:relative; flex:0 0 auto; width:10px; align-self:center;
  display:flex; flex-direction:column-reverse; gap:1px; padding:2px;
  background:#1b151055; border:2px solid #1b1510aa; border-radius:3px; box-sizing:border-box;
  transition:border-color .18s, background .18s;}
.jgut i{display:block; flex:1 1 0; min-height:2px; border-radius:1px;
  background:#ffffff10; transition:background .16s;}
.jgut i.on{background:var(--red,#c93a22);}
.jgut.warn{border-color:var(--red,#c93a22); background:#c93a2226;}
.jgut.warn i.on{animation:jgutPulse .8s ease-in-out infinite;}
.jgut.alarm{border-color:#ffd447; background:#c93a2244; box-shadow:0 0 8px #c93a2288;}
.jgut.alarm i.on{background:#ffd447;}
.jgut.bump{animation:jgutBump .55s ease-out;}
@keyframes jgutPulse{0%,100%{opacity:1} 50%{opacity:.45}}
@keyframes jgutBump{0%{transform:translateY(0)} 22%{transform:translateY(5px)} 60%{transform:translateY(-2px)} 100%{transform:translateY(0)}}
/* the board itself flinches as it lands — the other half of "show it, do not say it" */
#tetWell.jhit,#horrorGrid.jhit{animation:jHit .6s ease-out;}
@keyframes jHit{0%{transform:translateX(0)} 15%{transform:translateX(-4px)} 32%{transform:translateX(4px)}
  50%{transform:translateX(-3px)} 70%{transform:translateX(2px)} 100%{transform:translateX(0)}}
/* and their miniature flashes when YOUR junk lands on THEM */
.ttn-mini.sent{animation:jSent .5s ease-out;}
@keyframes jSent{0%{box-shadow:0 0 0 0 var(--red,#c93a22)} 30%{box-shadow:0 0 0 4px var(--red,#c93a22)}
  100%{box-shadow:0 0 0 0 #c93a2200}}

/* ⚠ v0.398 — THE LAST RESORT WHEN THE COLUMN STILL WILL NOT FIT. On the folded screen with a fully
   dressed inkling, shrinking the rival miniature is not always enough to keep THEIR LINES, SENT and
   WIN clear of the D-pad — NEXT and HOLD above them are fixed boxes. ttFit() measures, and only if
   the column genuinely still overruns does it tighten everything in one go. It is never applied on
   a screen that fits, so the roomy unfolded layout is not punished for the folded one's problem. */
/* ⭐ v0.398 — WHILE A MATCH IS ON, THE RIVAL BOARD IS THE POINT OF THIS COLUMN. NEXT and HOLD give
   up a little height to it: you are watching another person play, and a board too small to read is
   the same as no board at all. Only during an online match — the solo run keeps its roomy boxes. */
#tetSide.ttn-on .tet-mini{height:58px;}
/* ============================================================
   ⭐⭐⭐ v0.413 — THE RIVAL'S WELL IS A BOARD YOU CAN ACTUALLY READ.
   It was drawn into the same 82px column that carries NEXT and HOLD, and what was left after those
   two gave it a five-pixel cell — a 50x90 thumbnail of ten columns and eighteen rows. That is not a
   board, it is a texture: you could tell they had blocks and nothing else. You could not see a well
   filling up, you could not see a line about to go, and there was no point glancing at it.
   Online the column is widened, NEXT and HOLD go side by side instead of stacked, and the rival's
   name comes off the panel (their inkling is in the top corner now and the name is on the strip —
   it did not need saying a third time). Everything that frees up goes to the board. It roughly
   doubles in each direction, so the rival's well is drawn at about the same cell size as a solo
   player's NEXT piece — big enough to read their stack at a glance, which is the whole point.
   ============================================================ */
#tetSide.ttn-on, #hzSide.ttn-on{width:124px; margin-top:104px;}
#tetSide.ttn-on .ttn-vs, #hzSide.ttn-on .ttn-vs{display:none;}   /* the name is on the strip and the inkling is in the corner */
/* ⚠ WIDTH is what was strangling this board, not height. There was already vertical room going
   spare — the cell size is the smaller of what ten columns can have across and what eighteen rows
   can have down, and across was losing by a mile in an 82px column. So the column gets wider and
   the panel gives back its padding; the height levers were never the problem. */
#tetSide.ttn-on .ttn-panel, #hzSide.ttn-on .ttn-panel{padding:4px 3px 5px; gap:3px;}
/* ⭐ v0.418 — LESS WORDS, MORE BOARD (Odaroo). Every label down this column was costing the two
   boards height. The captions drop to the smallest size the face still reads at and the tallies
   stop being the biggest thing on the screen; the two small boxes above lose their padding. All of
   it goes to the rival board and, through the column being shorter, to your own. */
#tetSide.ttn-on .ttn-row, #hzSide.ttn-on .ttn-row{font-size:5.5px; padding-top:2px; line-height:1.2;}
#tetSide.ttn-on .ttn-row b, #hzSide.ttn-on .ttn-row b{font-size:9px; line-height:1.15;}
#tetSide.ttn-on .tet-box, #hzSide.ttn-on .tet-box{padding:2px 2px 3px; font-size:7px; line-height:1.35;}
#tetSide.ttn-on .tlab, #hzSide.ttn-on .tlab{font-size:5.5px;}
#tetSide.ttn-on .hz-val, #hzSide.ttn-on .hz-val{font-size:8px;}
/* ⚠⚠ v0.462 — NEXT AND HOLD STACK, ONLINE TOO. This row used to lay them SIDE BY SIDE to buy back
   about 60px of column height for the rival's board — which is exactly the "tiny boxes crammed into
   the left column" in Odaroo's screenshot. He wants them stacked and big enough to read the piece,
   so the row is a COLUMN now. It is kept (rather than deleted with sideRowPair) because the pairing
   is what makes the online column reversible back to a solo one; only its direction has changed. */
.tet-row2{display:flex; flex-direction:column; gap:6px; align-items:stretch;}
.tet-row2 > *{flex:0 0 auto; min-width:0;}
.tet-row2 .tet-mini{height:58px;}
.tet-row2 .tet-box{padding:3px 3px 4px; font-size:8px;}
.tet-row2 .tlab{font-size:6.5px;}
.tet-row2 .hz-val{font-size:9px;}
/* the two remaining numbers sit on ONE line under the board rather than two stacked rows */
#tetSide.ttn-on .ttn-nums, #hzSide.ttn-on .ttn-nums{display:flex; gap:6px; justify-content:space-between; align-items:flex-end;}
/* ⚠⚠ v0.624 — `flex:1 1 0` → `flex:1 1 auto`, AND THAT IS THE WHOLE FIX FOR THE LONGER LABEL.
   A basis of ZERO forces both cells to exactly half the row whatever is written in them, so the
   short label ("POPS", 24px of text in a 35px cell) sat on wasted room while the long one
   ("JUNK SENT", 41px) was clipped by 6. A basis of AUTO starts each cell at its own content and
   shares the LEFTOVER — measured 26px and 43px, both clean, in the same 72px row. Nothing else on
   the column moved. */
#tetSide.ttn-on .ttn-nums .ttn-row, #hzSide.ttn-on .ttn-nums .ttn-row{flex:1 1 auto; min-width:0; padding-top:2px;}
/* ⚠⚠ v0.624 — A TWO-WORD LABEL DOWN HERE MUST STAY ON ONE LINE. `.ttn-row span` is display:block in
   a half-width cell, so the moment PANEL-INK's "PUSHED" became "JUNK SENT" it wrapped — measured
   11.0px of label against POPS' 5.5px, which made that row 5.5px taller, made the whole panel
   taller, and sent the column that much further toward the D-pad on the folded phone. It is a
   LABEL: it may be small, it may not be two lines. Both boards get the rule, because Tetr-Ink's
   column is the same column and its labels are one word only by luck. */
#tetSide.ttn-on .ttn-nums .ttn-row span, #hzSide.ttn-on .ttn-nums .ttn-row span{white-space:nowrap;}
/* ⭐⭐⭐ v0.683 — INK PANIK'S TWO FIGURES STACK; THEY DO NOT SHARE A LINE.
   (Odaroo, 2026-08-06: the column is SPEED, then JUNK SENT under it, then HIGHEST COMBO under that.)
   The one-line rule above was written for POPS + JUNK SENT — two cells sharing a 72px row, which
   only ever worked because one of the two labels was four characters. POPS is deleted and HIGHEST
   COMBO takes its place, and thirteen characters cannot live in half of 72px at any font size worth
   reading: the pre-flight measured 41px of "JUNK SENT" in 28px and 60px of "HIGHEST COMBO" in 41px,
   on BOTH folds. Stacked, each label owns the full column and both come out clean.
   ⚠ TETR-INK IS NOT TOUCHED. Its two labels are one word each and its row still fits; changing both
   would cost Tetr-Ink's rival board height for no reason. Scoped to #hzSide only, and scoped BELOW
   the shared rule so it wins on source order as well as on specificity.
   ⚠ The extra height comes out of the rival miniature, which is exactly what hnMiniCell/hnFit are
   for — they measure the column and shrink the mini until it clears the D-pad. */
#hzSide.ttn-on .ttn-nums{display:block;}
#hzSide.ttn-on .ttn-nums .ttn-row{flex:none; width:100%; padding-top:1px;}
@media (min-width:640px){ #tetSide.ttn-on, #hzSide.ttn-on{width:184px;} }
/* the rival's well gets the same bezel as your own so it reads as a board, not a swatch */
#tetSide.ttn-on .ttn-mini, #hzSide.ttn-on .ttn-mini{border:2px solid var(--tp0,#0f380f); margin:3px auto 4px;}
/* their inkling, top-right, exactly where Crown Deluxe puts theirs */
#scr-tetris .vsfoe, #scr-horror .vsfoe{position:absolute; top:6px !important; left:auto !important;
  right:6px !important; width:62px; z-index:8; pointer-events:none;}
#scr-tetris .vsfoe svg, #scr-horror .vsfoe svg{width:100%; image-rendering:pixelated;}
#tetSide.ttn-squeeze{gap:4px;}
#tetSide.ttn-squeeze .tet-box{padding:2px 3px;}
#tetSide.ttn-squeeze .tet-mini{height:50px;}
#tetSide.ttn-squeeze .ttn-panel{padding:2px 3px 3px; gap:2px; line-height:1.35;}
#tetSide.ttn-squeeze .ttn-vs b{display:none;}
#tetSide.ttn-squeeze .ttn-row{font-size:6px; padding-top:2px;}
#tetSide.ttn-squeeze .ttn-row b{font-size:9px;}
#tetSide.ttn-squeeze .ttn-row.ttn-prize b{font-size:7px;}
#tetSide.ttn-squeeze .ttn-out{margin-top:2px;}
/* ⭐ v0.400 — the same lever for Ink Panik (hnFit). Its column is the same .ttn-panel chrome, so the
   rules are the same rules; only the box above it differs. */
#hzSide.ttn-squeeze{gap:4px;}
#hzSide.ttn-squeeze .tet-box{padding:2px 3px;}
#hzSide.ttn-squeeze .ttn-panel{padding:2px 3px 3px; gap:2px; line-height:1.35;}
#hzSide.ttn-squeeze .ttn-vs b{display:none;}
#hzSide.ttn-squeeze .ttn-row{font-size:6px;}
#hzSide.ttn-squeeze .ttn-out{margin-top:0;}
/* ⭐ v0.462 — bigger: the piece has to be readable at a glance, and tetMini() now scales the cell
   to whatever room this gives it and centres the piece's true bounding box inside it. */
.tet-mini{position:relative; height:68px;}
/* ============================================================
   ⭐⭐ v0.463 — THE RUN BOX (STAGE · SPEED · TIME) and the WIDE COLUMN.
   The stage tag used to hang alone in the top-right corner of the screen. It is here now, under
   NEXT and HOLD, with the two figures that belong beside it.
   ⚠ ON THE UNFOLDED FOLD THE WELL CANNOT GET ANY TALLER — measured, it already uses 582 of the 592
   pixels between the top of the screen and the D-pad, so the 249px of daylight either side of it is
   a consequence of a 10-wide portrait well on a short wide screen, not of the well being too small.
   What the width IS good for is the furniture: the column doubles, so NEXT, HOLD and the run box
   are big and readable instead of leaving that space blank.
   ============================================================ */
/* ⚠⚠ v0.464 — LABEL ABOVE VALUE, NEVER BESIDE IT. These were `justify-content:space-between` rows,
   which asks a label AND a number to share an 82px column on the folded phone: "STAGE 1-1" broke
   across two lines as "1-" / "1", and SPEED and TIME were cut off. Stacked, each of them gets the
   full width of the box to itself, so nothing can clip however long the figure grows (a run past
   9:59, a stage past 9-5). Same layout on both folds — one pattern, not two.
   ⚠ `min-width:0` on the value is what actually lets it shrink inside the flex column rather than
   pushing the box wider than the column it lives in. */
.tet-run{display:flex; flex-direction:column; gap:6px; padding:6px 5px 7px;}
.trun-r{display:flex; flex-direction:column; align-items:center; gap:1px; min-width:0; line-height:1.15;}
.trun-r span{font-size:6.5px; letter-spacing:.5px; opacity:.62; white-space:nowrap;}
/* ⚠ 13px, sized against the LONGEST value any of these three can show ("59:59" / "1h40" / "10-5"
   / "11.1" — five characters) inside the folded column's ~66px of usable width. 15px fitted a
   fresh run and clipped a long one. */
.trun-r b{font-size:13px; font-weight:normal; letter-spacing:0; min-width:0;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%;}
/* ============================================================
   ⭐⭐⭐ v0.483 — THE FIGURE'S SIZE COMES FROM THE COLUMN, NOT FROM THE WINDOW.
   Odaroo photographed TIME reading "0:..." on a wide desktop window. Here is the whole of it:

     · the wide breakpoint (min-width:640px) takes these figures up to 19px, on the reasoning that a
       wide screen gives the column 150px to play with — which is true in a SOLO run;
     · but an ONLINE match narrows the same column to 82px (#tetSide.ttn-on), and a short landscape
       window narrows it again — and NONE of those rules touch the font size, because the font size
       was keyed on the VIEWPORT and the width was keyed on the STATE.

   So the two disagreed: 19px figures in a 72px box, and "59:59" (95px) became "0:...".

   ⚠⚠ THE FIX IS NOT ANOTHER OVERRIDE. Adding `#tetSide.ttn-on .trun-r b{font-size:13px}` would put
   a THIRD copy of this number in the file, and the next state that narrows the column would be the
   next bug — which is exactly how this one was born. The size is now derived from the container's
   OWN width, so any rule that narrows the column brings the figures with it automatically and no
   future state can drift out of step.
   ⚠ The fixed sizes above and in the breakpoints are LEFT IN PLACE ON PURPOSE as the fallback: a
   browser with no container-query support gets exactly today's behaviour rather than nothing.
   ⚠ The floor is 11px — below that the figures stop being readable on a phone, and a column that
   narrow is a layout fault to be fixed rather than a size to be honoured.
   ============================================================ */
@supports (container-type: inline-size){
  #tetSide, #hzSide{container-type:inline-size;}
  /* ⚠ 16cqw, and the number is MEASURED rather than guessed. In this display face a five-character
     value comes out very close to 5.0x the font size ("59:59" measured 95px at 19px), and the box
     gives the text the column's width less 12px of padding and 6px of border. So the largest font
     that can never clip is (w - 18) / 5 — about 0.176w — and 16cqw sits just under it with a
     margin. The first attempt used 24cqw, which is 19.7px in an 82px column: the clamp was working
     perfectly and simply being handed a ratio that was too generous, so nothing appeared to change.
     Sized against the longest value each figure can reach ("59:59" / "1h40" / "10-5" / "11.1"),
     never a fresh run — the same worst-case rule the v0.464 note set down.
     ⚠⚠ SCOPED BY ID DELIBERATELY. The breakpoint that sets 19px is a plain `.trun-r b` further
     down this file, so an equally-specific rule up here would LOSE on source order — which is
     exactly what the first attempt at this fix did, silently. An ID beats a class wherever either
     one happens to sit, so this cannot be undone by somebody moving a block. */
  #tetSide .trun-r b, #hzSide .trun-r b{font-size:clamp(11px, 16cqw, 19px);}
  #tetSide .trun-r span, #hzSide .trun-r span{font-size:clamp(6.5px, 8cqw, 8.5px);}
  /* ⭐ v0.484 — INK PANIK'S RUN ROWS GET THE SAME TREATMENT. They are stacked now (see the block in
     games.css), so each value owns the column's full width — but the wide breakpoint takes them to
     11px on a viewport rule while the column's width is a state rule, which is precisely the drift
     that produced the Tetr-Ink half of this bug. Derive both from the column instead.
     ⚠ 11cqw, not 16: the INK figure can reach six characters where the clock reaches five, and in
     this face a character costs about 1.06x the font size. 11cqw of the folded 86px column is
     ~9.5px, which puts six figures at ~60px inside ~70px of usable width. */
  #hzSide .hz-sub b{font-size:clamp(8px, 11cqw, 12px);}
  #hzSide .hz-sub span{font-size:clamp(5.5px, 7cqw, 8px);}
  /* ============================================================
     ⭐⭐⭐ v0.485 — THE RUN BOX LIES DOWN WHEN THERE IS WIDTH FOR IT. (Odaroo: consolidate the info
     boxes and give the space to the rival's board.)
     Three stacked rows cost about 84px of a column that also has to hold NEXT, HOLD and the rival's
     miniature. Laid out as one row of three they cost about 28px, and the ~56px saved goes straight
     to the rival board — ttMiniCell sizes it from whatever height is left, so this needs no other
     change to hand the room over.
     ⚠⚠ IT IS A CONTAINER QUERY, NOT A BREAKPOINT, AND THAT IS THE WHOLE POINT. The folded column is
     82px; three figures side by side there is exactly the fault that put "TIME 0:..." on Odaroo's
     screen twice. The row only forms once the COLUMN itself is wide enough to hold five characters
     three times over — so it can never happen on a narrow column, whatever the window is doing.
     ⚠ Each cell keeps its label ABOVE its value. That rule does not bend; only the arrangement of
     the cells changes. */
  /* ⚠⚠⚠ v0.550 — IT IS A 2x2 GRID, NEVER ONE ROW OF FOUR. v0.485 laid the box down as a single row
     when the box held THREE figures; LINES was added afterwards and nobody re-measured, so the
     150px solo column was handing each of four cells 32px — "TIME 0:00" was clipping on a FRESH
     run, never mind "59:59". (Measured: 32px cells, TIME clipped at 0:00.)
     Two columns of two keeps the height saving v0.485 was after (two rows, not four) while giving
     every figure ~half the column — 66px in the solo column, which holds five characters with room
     to spare. ⚠ The same worst-case rule as ever: sized against "59:59" / "10-5" / "11.1" / a
     four-figure LINES, never a fresh run. */
  @container (min-width: 118px){
    #tetSide .tet-run, #hzSide .tet-run{
      display:grid; grid-template-columns:1fr 1fr; align-items:start; gap:5px 6px;}
    #tetSide .tet-run .trun-r, #hzSide .tet-run .trun-r{min-width:0;}
    #tetSide .tet-run .trun-r b, #hzSide .tet-run .trun-r b{font-size:clamp(10px, 7.5cqw, 16px);}
    #tetSide .tet-run .trun-r span, #hzSide .tet-run .trun-r span{font-size:clamp(6px, 4cqw, 8.5px);}
  }
}
/* ⚠⚠ v0.464 — THE WHOLE COLUMN HAS TO END ABOVE THE D-PAD, and on the unfolded Fold that is a real
   constraint, not a formality. The column starts 154px down (clearing a worn frame) and the pad's
   top edge is at 592, so NEXT + HOLD + the run box get about 438px between them. v0.463's 104px
   previews and 24px figures came to 610 and put the run box 19px UNDER the controls — caught by
   folding the phone mid-run, not by the pre-flight, whose playfield rules watch the well and not
   the column beside it. These numbers are chosen to land the column's bottom near 530. */
@media (min-width:640px){
  #tetSide{width:150px;}
  .tet-mini{height:84px;}
  .tet-box{font-size:11px; padding:5px 5px 6px;}
  .tet-box .tlab{font-size:9px;}
  .tet-run{gap:6px; padding:7px 6px 8px;}
  .trun-r span{font-size:8.5px;}
  .trun-r b{font-size:19px;}
  #tetSide.ttn-on .tet-mini, .tet-row2 .tet-mini{height:72px;}
}
.tet-mini .tcell{background:var(--tp0,#0f380f);}
#tetBuddyBox{flex:1; display:flex; flex-direction:column; min-height:60px;}
#tetBuddy{flex:1; display:flex; align-items:flex-end; justify-content:center; overflow:hidden;}
#tetBuddy svg{width:52px; height:auto; filter:grayscale(1) contrast(1.05) drop-shadow(0 0 5px #9bbc0f88); animation:tetFloat 1.8s ease-in-out infinite;}   /* the GB inklet FLOATS + glows — never static */
@keyframes tetFloat{0%,100%{transform:translateY(0) rotate(-2deg)}50%{transform:translateY(-7px) rotate(2deg)}}
.tetCombo{position:absolute; left:50%; transform:translateX(-50%); z-index:5; text-align:center; pointer-events:none; animation:tcPop 1s ease-out forwards;}
.tetCombo .tc-l{font-family:var(--fontD); font-size:15px; color:#0f380f; letter-spacing:1px; text-shadow:1px 1px 0 #9bbc0f, 0 0 8px #fff;}
.tetCombo .tc-c{font-family:var(--fontD); font-size:12px; color:#c93a22; letter-spacing:1px; text-shadow:1px 1px 0 #fff; margin-top:2px;}
@keyframes tcPop{0%{opacity:0; transform:translateX(-50%) scale(.5)}22%{opacity:1; transform:translateX(-50%) scale(1.15)}40%{transform:translateX(-50%) scale(1)}100%{opacity:0; transform:translateX(-50%) translateY(-26px) scale(1)}}
/* the battle TETR-INK mini — the SAME Game Boy green as the standalone, dropped into the boxless showstopper stage */
.ttGB{box-sizing:content-box; background:#9bbc0f; border:3px solid #0f380f; box-shadow:4px 5px 0 #1b151066; image-rendering:pixelated;}
.ttGB .ttc{position:absolute; background:#0f380f;}
.ttGB .ttc.act{background:#306230;}
.ttGB .ttc::after{content:''; position:absolute; inset:16%; border:2px solid #9bbc0f; box-sizing:border-box;}
.ttGB .ttlab{position:absolute; right:3px; top:2px; font-family:var(--fontD); font-size:9px; color:#0f380f; letter-spacing:1px;}
#tetOver{position:absolute; inset:0; display:none; align-items:center; justify-content:center; background:#0f380fd9; color:#9bbc0f; font-family:var(--fontD); font-size:13px; letter-spacing:2px; z-index:3; text-align:center; line-height:2;}
#tetWell.dead #tetOver{display:flex;}
/* ============================================================
   ⭐ v0.454 — THE STACKED RECEIPT (Tetr-Ink game over, and reusable).
   One figure a line, label left, number right, so nothing has to share a row and no length of
   number can push anything out of the card. See the note in tetOver().
   ⚠ min-width:0 on the value cell — without it a long number refuses to shrink and pushes the
   whole grid wider than the dialog, which is the exact fault this replaced.
   ============================================================ */
#modalBox .ovlist{margin:8px auto 4px; width:min(100%,260px); display:flex; flex-direction:column; gap:5px;}
#modalBox .ovr{display:grid; grid-template-columns:1fr auto; align-items:baseline; gap:10px;
  background:#00000026; border:2px solid #00000033; padding:5px 9px;}
#modalBox .ovk{font-family:var(--fontD); font-size:8px; letter-spacing:1px; opacity:.72; text-align:left; white-space:nowrap;}
#modalBox .ovv{font-family:var(--fontD); font-size:13px; text-align:right; min-width:0; word-break:break-all;}
#modalBox .ovv.hot{color:var(--gold); font-size:15px;}
#modalBox .ovsep{font-family:var(--fontD); font-size:8px; letter-spacing:3px; opacity:.6; margin:9px 0 2px;}
#modalBox .ovbest .ovv{font-size:11px; opacity:.9;}
#modalBox .ovbest .ovr{background:#00000018;}

/* ============================================================
   ⭐⭐ v0.454 — YOUR OWN WELL IS THE SAME SIZE ONLINE AS IT IS SOLO.
   Two things were taking room off the main board the moment a match started, and Odaroo's note is
   that the board is simply smaller online than it is alone — which it was, on both axes:
     · the stats column widened from 82px to 124px to make the rival's preview bigger, and the well's
       cell size is the SMALLER of what ten columns get across and eighteen rows get down, so 42px
       off the width came straight off the board;
     · #tetWrap gained a 76px top inset (.vs-inset) to clear a names-and-faces block across the top.
   Both are reversed here. The rival's well is a secondary view — a glance at their stack — and it
   is not worth a smaller board to make it larger. The names go where the universal VS HUD puts
   them (top corners), which the well passes cleanly between, so the inset buys nothing.
   ⚠ THE COLUMN WIDTH IS ALSO THE MARGIN. The .ttn-on rule set margin-top:104px alongside the width;
   putting the width back without the margin leaves the column floating 46px higher than solo's
   150px and the panel lands on the word NEXT. Both numbers come back together.
   ============================================================ */
/* v0.640 — the margin is the same derived clearance as the solo column above; the two must stay
   equal (that is what the note directly above is about), so both read --inkav. */
#tetSide.ttn-on, #hzSide.ttn-on{width:82px; margin-top:calc(var(--inkav,69px) + 48px);}
/* ============================================================
   ⭐⭐⭐ v0.485 — AND ON THE UNFOLDED SCREEN IT IS WIDE AGAIN. (Odaroo: the rival's preview is tiny
   and the wide screen is mostly wasted.)
   ⚠⚠ THIS DOES NOT REOPEN THE WOUND THE RULE ABOVE CLOSED, and the reason is measurable. That rule
   narrowed the online column back to 82px because the well's cell size is the SMALLER of what ten
   columns get across and eighteen rows get down — so on the FOLDED phone every pixel handed to the
   column came straight off the board. On the unfolded screen the well is bound entirely by HEIGHT:
   measured at 906x832, the cell is 32px and the well is 325x581 with the column at 82px, at 124px,
   at 184px AND at 220px — identical. The width was simply going unused.
   So the column takes it back where it is free, and the run box (see the container query above)
   lies down into a single row at that width, which hands its saved height to the rival's board too.
   ⚠ THE MARGIN STAYS AT 150px — it clears a worn frame, and that has nothing to do with width.
   ⚠ If the well ever stops being height-bound on a wide screen, this is the first rule to re-measure. */
@media (min-width:640px){
  #tetSide.ttn-on, #hzSide.ttn-on{width:184px;}
}
#tetWrap.vs-inset, #horrorWrap.vs-inset{padding-top:4px;}
/* the preview gives up the space instead: smaller cells, tighter panel, same information */
#tetSide.ttn-on .ttn-panel, #hzSide.ttn-on .ttn-panel{padding:3px 2px 4px; gap:2px;}
#tetSide.ttn-on .ttn-nums, #hzSide.ttn-on .ttn-nums{gap:3px;}
/* ⚠⚠ AND THE COLUMN'S TYPE HAD TO COME DOWN WITH IT. Every .ttn-on font size above was chosen for
   a 124px column; at 82px "THEIRS" wanted 39px in a 35px box and Ink Panik's "PUSHED" and the
   rival's name both overran. Narrowing a column is never only a width change — the pre-flight
   caught all three, which is exactly what it is for. */
#tetSide.ttn-on .ttn-row, #hzSide.ttn-on .ttn-row{font-size:4.6px; letter-spacing:0;}
#tetSide.ttn-on .ttn-row b, #hzSide.ttn-on .ttn-row b{font-size:8px; letter-spacing:0;}
#tetSide.ttn-on .ttn-nums .ttn-row, #hzSide.ttn-on .ttn-nums .ttn-row{overflow:hidden;}
#tetSide.ttn-on .ttn-vs, #hzSide.ttn-on .ttn-vs{display:none;}
#tetSide.ttn-on .tlab, #hzSide.ttn-on .tlab{font-size:4.6px; letter-spacing:0;}
#tetSide.ttn-on .hz-val, #hzSide.ttn-on .hz-val{font-size:7px; letter-spacing:0;}
#tetSide.ttn-on .tet-box, #hzSide.ttn-on .tet-box{font-size:6px; letter-spacing:0;}

/* ============================================================
   ⭐⭐ v0.493 — THE ONLINE COLUMN USES THE WIDE SCREEN (Odaroo: "better use of screen space on
   wide/unfolded, make the rival preview BIGGER, HOLD can be smaller").

   Three things, all of them scoped to ≥640px so the folded phone is untouched:

   1. NEXT and HOLD lie SIDE BY SIDE again — but only where there is genuinely width for it. v0.462
      stacked them because on the 124px folded column a row made two boxes too small to read the
      piece in; at 184px a row fits both at full size and hands ~70px of column height straight to
      the rival's board, which is the thing this column exists for during a match.
   2. HOLD is the SMALLER of the pair. It shows a piece you have already seen and chosen to park;
      NEXT is the one being read every few seconds. Same information, honest priority.
   3. ⚠⚠ THE TYPE GOES BACK UP. The block above this one drops every online label to 4.6px — it was
      written for the SHORT-SCREEN squeeze but sits at top level, so it was winning on the unfolded
      Fold too and shrinking a 184px column's labels to the size chosen for an 82px one. This is the
      same family of bug as v0.483's clock: a size chosen for one state leaking into another. It is
      corrected here rather than by editing that block, because that block IS right for the state it
      was written for and this rule names the state it is right for.
   ============================================================ */
@media (min-width:640px){
  #tetSide.ttn-on .tet-row2, #hzSide.ttn-on .tet-row2{flex-direction:row; gap:6px; align-items:flex-start;}
  #tetSide.ttn-on .tet-row2 > *{min-width:0;}
  #tetSide.ttn-on .tet-row2 > *:first-child{flex:1 1 auto;}
  #tetSide.ttn-on .tet-row2 > *:last-child{flex:0 0 38%;}
  #tetSide.ttn-on .tet-row2 .tet-mini{height:62px;}
  #tetSide.ttn-on .tet-row2 > *:last-child .tet-mini{height:44px;}
  /* the labels and figures are sized for THIS column, not for the squeezed one */
  #tetSide.ttn-on .tlab, #hzSide.ttn-on .tlab{font-size:9px; letter-spacing:1px;}
  #tetSide.ttn-on .tet-box, #hzSide.ttn-on .tet-box{font-size:10px; letter-spacing:.5px; padding:4px 4px 5px;}
  #tetSide.ttn-on .ttn-row, #hzSide.ttn-on .ttn-row{font-size:7px; letter-spacing:1px;}
  #tetSide.ttn-on .ttn-row b, #hzSide.ttn-on .ttn-row b{font-size:13px;}
  #tetSide.ttn-on .hz-val, #hzSide.ttn-on .hz-val{font-size:11px;}
  #tetSide.ttn-on .ttn-panel, #hzSide.ttn-on .ttn-panel{padding:5px 4px 6px; gap:3px;}
  #tetSide.ttn-on .ttn-nums, #hzSide.ttn-on .ttn-nums{gap:6px;}
}

/* ============================================================
   ⭐⭐⭐ v0.550 — NEXT AND HOLD ARE THE SAME BOX, ALWAYS. (Odaroo: "they should always be identical
   in size — same width, same height.")
   Solo they already matched. ONLINE they did not: v0.413 pairs the two boxes into a `.tet-row2`,
   and the wide rules then handed the first 1fr and the second 38% of the row, with 62px and 44px
   previews inside them — so the HOLD box was visibly the runt of the pair. That split was tuned for
   INK PANIK, whose row holds two boxes of different content (STAGE and SPEED); Tetr-Ink's row holds
   the same box twice and must be symmetrical.
   ⚠ Scoped to #tetSide on purpose — Ink Panik keeps its own proportions.
   ⚠ It sits at the END of the file deliberately: it has to outrank the `> *:last-child` rules in
   the breakpoint above, and equal specificity loses on source order (the same trap the v0.483 note
   records). Do not move it up.
   ⚠⚠ THE SELECTORS CARRY .ttn-on ON PURPOSE. The rules being beaten are
   `#tetSide.ttn-on .tet-row2 > *:last-child`, and a plain `#tetSide .tet-row2 > *:last-child` is one
   class LIGHTER — it loses on specificity wherever it sits in the file, which is exactly what the
   first attempt at this did (measured: NEXT 108x91, HOLD 70x73, unchanged). */
#tetSide.ttn-on .tet-row2{align-items:stretch;}
#tetSide.ttn-on .tet-row2 > *:first-child,
#tetSide.ttn-on .tet-row2 > *:last-child{flex:1 1 0; min-width:0;}
#tetSide.ttn-on .tet-row2 .tet-mini,
#tetSide.ttn-on .tet-row2 > *:last-child .tet-mini{height:58px;}
@media (min-width:640px){
  #tetSide.ttn-on .tet-row2 .tet-mini,
  #tetSide.ttn-on .tet-row2 > *:last-child .tet-mini{height:62px;}
}

/* ⭐ v0.552 — AN ONLINE RUN BOX HOLDS THREE FIGURES, NOT FOUR (there is no stage to be on in a
   match), so the last cell would sit alone under the other two looking like a mistake. It takes the
   whole width instead — a deliberate shape rather than an orphan.
   ⚠ NOT three columns across: 184px / 3 is 61px, and "59:59" at the grid's own font size is ~69px.
   That is the v0.485 fault again, one column narrower. */
#tetSide .tet-run[data-mode="vs"] .trun-r:last-child,
#hzSide .tet-run[data-mode="vs"] .trun-r:last-child{grid-column:1 / -1;}
