/* ==========================================================================
   metaeden-v4-game-fit.css -- the PHONE FIT of the fullscreen mode
   (TASK-1143[Q]).  Loaded only by sites/v4-game.html, AFTER
   metaeden-v4-game.css so its equal-specificity declarations win by order,
   and only at phone viewports: the <link> carries
   media="(max-width: 768px), (max-height: 480px)" and every rule inside
   sits in an @media block no wider than that gate (the frame block repeats
   it whole; the per-game blocks take one leg each), so a stale cache cannot
   paint any of this at a desktop size.  The guard suite's K section holds
   both halves of that sentence.

   WHY A THIRD FILE, when this page already has two candidates.
     * mobile-e-game.css is gated (max-width: 768px), and that gate is pinned
       verbatim in seven places across two pages -- it cannot widen.  A phone
       turned SIDEWAYS is 844x390: wider than the ceiling, so that file is
       not even fetched in landscape, and landscape is half of what this
       ticket has to fit.
     * metaeden-v4-game.css deliberately carries no @media at all; its own
       long comment says why, and two suites pin it (the selector-scope pin
       reads an at-rule prelude as an unscoped selector, and
       metaeden_net_mobile_e_game.test.js G4 asserts the absence).  That
       reasoning is about IN-PAGE column rules, which size against a
       container the viewport does not describe.  The rules below are
       different in kind: the mode's frame is position:fixed -- it lives in
       VIEWPORT space by design -- so a viewport query is the honest tool
       here in exactly the way it is not over there.
   One home for one idea: everything about how the fullscreen mode sits on a
   phone is in this file, and nothing else is.

   THE TWO HALVES OF THE GATE.  (max-width: 768px) is the same phone ceiling
   every other sheet on this page uses; it catches a phone held upright.
   (max-height: 480px) catches the same phone turned sideways, and --
   deliberately -- any desktop window squashed that flat: letterboxing 16:9
   out of a strip under 481px tall spends the scarcest axis on black bars,
   so filling is the better behaviour in both cases.

   WHAT IT DOES.  On glass this small the 16:9 letterbox is the wrong trade:
   at 390x844 the locked frame is 390x219 -- a quarter of the screen on the
   game, three quarters on bars.  So inside the mode, at these viewports
   only, the frame drops the aspect lock and fills the viewport outright,
   and the per-game rules below re-cut each cartridge's chrome so the
   playfield and the controls a player needs MID-PLAY fit with zero page
   scrolling.  Content a phone genuinely cannot hold (minesweeper's widest
   board, say) still scrolls INSIDE #gstage, never the page -- the house
   rule metaeden-v4-game.css already keeps.  Desktop is untouched: at every
   viewport both wider than 768 and taller than 480 this file is inert.

   HOUSE RULES CARRIED OVER from both siblings: every selector is scoped
   under .v4-game-page (and all but the :fullscreen override under
   .v4-game-page.gfs -- nothing here paints outside the mode); it declares
   no text colour of its own (every pair on this surface is measured in four
   themes, and a phone-only ink would be a fifth set nobody measured);
   nothing readable sits under 12px; ASCII only (CLAUDE.md rule 2).
   ========================================================================== */

@media (max-width: 768px), (max-height: 480px) {

  /* THE FRAME FILLS THE GLASS.  Same fixed box, same letterbox black, same
     z-order over the CRT wash -- only the shape changes: edge to edge
     instead of the largest 16:9.  aspect-ratio:auto releases the lock (and
     with it the automatic-minimum trap TASK-1136[Q] documented; the zero
     minimums still ride along from the base rule).  The second height line,
     100dvh, keeps the frame inside the VISIBLE glass where a phone's URL
     bar is down; a browser without the unit drops that declaration at parse
     and keeps the 100vh above it.  --gfs-h stays plain 100vh on purpose: an
     unsupported unit inside a custom property is not dropped at parse, it
     invalidates every var() that consumes it at computed-value time, which
     would take the canvas sizing rule down with it on older glass. */
  .v4-game-page.gfs #gframe {
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    aspect-ratio: auto;
    --gfs-h: 100vh;
  }

  /* AND THE ORDINARY VIEW'S LOCK IS RELEASED ON THE SAME GLASS, FOR THE SAME
     REASON (TASK-1158[Q]).  That ticket gave the non-fullscreen view a 16:9
     frame of its own, so a game is the same shape in both modes -- the user's
     ask, "keep all games at their 1920x1080 aspect ratio at all times no
     matter which mode they're in."  MODE is the word doing the work there:
     the two modes must agree with each other, which they now do.

     A PHONE IS NOT A MODE, and the trade this file exists to make does not
     change because the frame is in the page instead of over it.  Measured at
     390x844: the locked ordinary frame comes out 370x208, which is a
     letterbox spending three quarters of the glass on black in the ONE place
     there is least of it -- the same arithmetic, and the same answer, as the
     header above gives for the mode.  Releasing the ratio here puts the
     narrow layout back exactly where mobile-e-game.css (which owns this page
     at these widths) was designed against it.

     Desktop keeps the lock: this file is inert at every viewport both wider
     than 768 and taller than 480, so the ratio the ticket asked for is in
     force everywhere it is worth having. */
  .v4-game-page #gframe { min-height: 0; }

  /* ...and the cartridge sizing that rode on it goes with it.  Since
     TASK-1158[Q] the base sheet's fit rules serve BOTH modes off --gfs-h, and
     the ordinary view's --gfs-h is the 820px column's 16:9 height -- a number
     that is true at every desktop width and a fiction on a phone, where the
     column is the glass.  Left standing it would size a canvas to 461px of
     height on a 390px screen.  Width-driven is the right answer here for
     exactly the reason the block further down gives for the mode: width is
     the scarce axis, and a cartridge's own authored aspect-ratio derives a
     height that is true at any width.  The mode's own rule is more specific
     and is unaffected. */
  .v4-game-page #gstage canvas {
    box-sizing: border-box;
    width: 100%;
    height: auto;
    max-height: none;
  }

  /* THE MARQUEE, CUT DOWN TO WHAT A PHONE CAN SPARE.  The banner is authored
     for a desk: a two-column grid with the title left and the game's own
     description right.  At 390px that description wraps to four lines and the
     banner grows to 140px of an 844px screen; turned sideways it took 97px of
     390 and pushed the game into scrolling by 103px, both measured.  The
     description is the part that can go -- it is the same sentence the page
     itself carries above the frame, and a player who just pressed a button
     labelled with this game's name does not need it read back to them -- so
     what stays is the kicker and the title, which is what a marquee is. */
  .v4-game-page.gfs .gmarquee {
    padding: 5px 10px;
  }
  .v4-game-page.gfs .gmarquee h2 { font-size: 1.15rem; }
  .v4-game-page.gfs .gmarquee p:last-child { display: none; }

  /* ...AND THE CONTROL KEEPS ITS OWN ROW DOWN HERE (TASK-1163[Q]).  On a desk
     that ticket took .gfsbar out of flow and seated it in a 200px gap the
     banner's own padding holds open down its right edge, which is worth about
     46px of frame height and costs the title a column it has to spare.  The
     rule directly above is why that trade does not survive the trip: the
     tightening is a padding SHORTHAND, so it resets the reservation to 10px,
     and the plate lands on the title.  Measured at 375x812 -- plate 180px of a
     375px banner, sitting over a title that starts at 10px.

     Reserving the gap here instead would be worse than the bug.  180px of 375
     is half the glass, and what it would buy back is 46px of a 812px screen;
     the phone's problem has never been the vertical budget, it is that there
     is no horizontal room to give away.  So the control goes back to being a
     row of its own -- the layout mobile-e-game.css and this file were both
     tuned against, unchanged by that ticket -- and everything else the desk
     gained comes along regardless, because the contain fit in the base file
     reads whatever height is left rather than a fraction of the frame.

     position is the whole of the override: the plate's padding, its per-theme
     background and .gfsbar's own centred flex row are all still the base
     file's, so this cannot drift from it. */
  .v4-game-page.gfs .gfsbar {
    position: static;
  }

  /* ========================================================================
     THE IMMERSIVE CORE (TASK-1172[Q]).  The user, on the mode this file fits:
     "when in mobile mode only, fullscreen should actually be the 'hardware'
     full screen without the extra arcade frame."  body.gfsm is the adapter's
     mark that a fullscreen entry happened ON A PHONE (metaeden-v4-game.js
     stamps it beside .gfs, and only there); these rules are what the mark
     buys.  Desktop can never wear the class, so everything above and below
     this block is untouched by it -- the TASK-1158[Q] settlement stands.

     THREE JOBS, three rules:

     1. THE PAGE CANNOT SCROLL, as a guarantee rather than an achievement.
        The base sheet's overflow:hidden on body is the desktop's answer and
        phones have historically ignored it for touch scrolling; a FIXED body
        is the one lock every phone honours, and it is safe here because the
        mode's frame is itself fixed over the whole glass -- nothing behind
        the overlay is visible, so what the body does back there cannot
        matter until leave, and the adapter puts the scroll position back on
        leave.  overscroll-behavior kills pull-to-refresh and the rubber-band
        chain mid-game, which on this surface is the difference between a
        flick that steers and a flick that reloads.

     2. ALL THE CHROME GOES, the bar included (TASK-1177[Q]).  The first cut
        of this mode kept the control's bar as a row above the stage, reasoning
        that a mode with no visible way out fails a player.  The user, testing
        it live, overruled the row half of that: "i hate that ugly top bar
        that also contains the leave fullscreen button, instead move leave
        full screen into the game itself as an in game button, this will also
        give us a ton of screen realestate back."  So the way out SURVIVES but
        the row does not: the bar leaves the flow entirely (position:fixed,
        below) and the stage takes the whole glass.

     3. THE BAR BECOMES A FLOATING CLUSTER, top-right over the game: the same
        #gfsbtn with the same wiring (nothing behavioral moves), stacked over
        the turn-your-phone line when that shows.  This knowingly trades away
        the base file's stage-corner warning -- no corner of a thirteen-
        cabinet stage is reliably empty, and the button may overlap a
        cartridge's own top-row pixels -- because the user chose that trade
        explicitly, and a compact control on its own solid plate loses less
        of the game than the full-width row it replaces.

     What is NOT here: the hardware fullscreen ask.  That is the adapter's
     (document-level, refusal-swallowed, Android-only by feature existence);
     this file's rules are the whole mode on an iPhone and the backdrop the
     API entry lands on everywhere else.  Either way these rules alone must
     deliver the experience, which is why nothing in them waits on anything.
     ======================================================================== */
  .v4-game-page.gfs.gfsm {
    position: fixed;
    inset: 0;
    width: 100%;
    overflow: hidden;
    overscroll-behavior: none;
  }

  .v4-game-page.gfs.gfsm .gmarquee { display: none; }

  /* THE FLOATING CLUSTER (TASK-1177[Q]; the block comment above says why).
     The bar leaves the flow so the stage gets every pixel; the button rides
     its own themed bbtn plate exactly as before (its measured ink pairs are
     untouched), compacted to overlay size.  z-index clears the stage's own
     content; the cluster hugs the top-right and stacks downward. */
  .v4-game-page.gfs.gfsm .gfsbar {
    position: fixed;
    top: 6px;
    right: 6px;
    margin: 0;
    padding: 0;
    width: auto;
    background: none;
    border: none;
    box-shadow: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    z-index: 30;
  }

  /* THE BUTTON CARRIES ITS OWN PLATE HERE, same shape of exception as the
     chip below and for the same reason: over game art there is no theme
     plate under it, and live on the grey theme the themed bbtn painted as
     bare link-blue text over fishing's BEST readout -- unreadable and
     covering a number.  One fixed self-contained pair, boxed so what it
     covers, it covers opaquely and legibly.

     AND IT IS A CLOSE BOX, NOT A LABELLED BUTTON (TASK-1177[Q] round 4).
     Even plated, the full "leave fullscreen" label was ~110px wide and the
     user found it "in the way of some interface stuff" -- fishing's BEST
     readout sat under it.  So in this mode the control compacts to the site's
     own 1996 idiom: a small bordered box drawing the U+00D7 every close box
     on this site already draws.  The LABEL IS STILL THERE -- font-size:0
     hides the text visually while the accessible name and the suite's
     MODE_ON/MODE_OFF wiring stay exactly as they were; the glyph rides a
     ::before so no markup and no JS moved.  26x24 covers a corner scrap
     instead of a readout. */
  .v4-game-page.gfs.gfsm .gfsbar .bbtn {
    font-size: 0;
    width: 26px;
    height: 24px;
    padding: 0;
    background: #06090f;
    color: #d8fbff;
    border: 1px solid #5f8a92;
    text-decoration: none;
  }

  .v4-game-page.gfs.gfsm .gfsbar .bbtn::before {
    content: "\00d7";
    font-size: 16px;
    line-height: 22px;
  }

  /* SHARE IS NOT IN THE CORNER (TASK-1179[Q]).  The cluster is the way out and
     nothing else -- that is the whole of what the last round cleared this
     corner for -- and a second box up here would put back the chrome the user
     asked to be rid of.  The control is one press away either side of the
     mode, on the bar the page shows the rest of the time.  Rule sits after
     the ::before above so it cannot be read as styling the glyph. */
  .v4-game-page.gfs.gfsm #gsharebtn { display: none; }

  /* THE WAY HOME GOES TO THE OPPOSITE CORNER (TASK-1212[Q]).  Inside this mode
     the frame covers every link this page has -- walked at 375x812: seven
     links, none of them reachable -- so the door has to be in the mode or it
     is nowhere.  The base sheet reveals it as the leftmost control of the
     desktop cluster; here it leaves that cluster entirely.

     TWO REASONS, and the second is the one that decides it.  The rule this
     corner was cleared for is that "the cluster is the way out and nothing
     else" (TASK-1177[Q], restated by TASK-1179[Q] when share was sent away
     from it), and a second box stacked under the close box would be that rule
     broken by the one control with the best claim to break it.  And a phone is
     a thumb: two small targets 4px apart, one of which navigates off the page,
     is a mis-press that costs somebody the round they are in the middle of.
     Top-left is the far corner from the way out, it is where a site's mark
     lives on every page a visitor has ever seen, and it was measured EMPTY
     here -- the cluster occupies x343..369 of a 375px glass and nothing else
     is on the plane at all.

     ITS OWN PLATE, the third and last instance of this file's one sanctioned
     exception and taken at the same values as the close box above (#d8fbff on
     #06090f, ~15:1): off the cluster it floats over GAME ART with no theme
     plate under it, and the grey theme's .bbtn is bare link-blue, which is the
     exact unreadable pair the close box's own note records finding live.  12px
     rather than the glyph treatment its neighbours get, because a mark that
     reads "metaeden.net" tells a stranger where they are and a glyph does not,
     and that is the whole job.  The ::before is switched off for the same
     reason: the close box's U+00D7 is the MODE CONTROL's, not every button in
     the bar's, and a cross drawn over the site's own name would say the
     opposite of what this control does. */
  .v4-game-page.gfs.gfsm .gfsbar #ghome {
    position: fixed;
    top: 6px;
    left: 6px;
    width: auto;
    height: auto;
    padding: 4px 7px;
    font-size: 12px;
    line-height: 14px;
    background: #06090f;
    color: #d8fbff;
    border: 1px solid #5f8a92;
    text-decoration: none;
  }

  .v4-game-page.gfs.gfsm .gfsbar #ghome::before { content: none; }

  /* AND THE SAME TICKET'S CONTAIN FIT IS HANDED BACK HERE TOO, for the reason
     this whole file exists: it solves for a LEFTOVER HEIGHT, and a phone has
     none to solve for.  On a desk the mode's frame is locked 16:9 and the
     chrome comes out of its height, so height is the scarce axis and the fit
     is exactly right.  Turned upright the frame is the glass, the stage is
     far taller than either canvas is shaped, and the binding axis flips to
     width -- which the rule above this file's own canvas block already
     handles, and has since TASK-1143[Q].

     LEFT STANDING IT REINTRODUCES THE BUG TASK-1158[Q] FIXED, which is why
     this is not tidiness.  The holder takes the leftover height and the
     picture, keeping its own ratio, letterboxes inside it: measured at
     375x812, a 353x412 holder around a 353x199 picture, so 213px of holder
     with no game in it -- and every overlay registered to that holder goes
     with the holder, putting fishing's name plate in the black BELOW the
     picture it names.  That is the same complaint from the same direction as
     the ticket that fixed it.

     So the four declarations that discover a leftover are switched off and
     nothing else is: the base file's own centring, max-width and per-cartridge
     bypasses all still apply, and the phone lands back on exactly the geometry
     it had before TASK-1163[Q] -- verified holder and canvas equal, plate
     inside the picture, at 375x812. */
  .v4-game-page.gfs #gstage > [data-metaeden-fishing],
  .v4-game-page.gfs #gstage > [data-metaeden-stripmine] { height: auto; }

  .v4-game-page.gfs #gstage .fsx,
  .v4-game-page.gfs #gstage .smx { height: auto; }

  .v4-game-page.gfs #gstage .fsx-scr,
  .v4-game-page.gfs #gstage .smx-scr {
    flex: 0 1 auto;
    width: max-content;
    aspect-ratio: auto;
  }

  .v4-game-page.gfs #gstage canvas.fsx-cv,
  .v4-game-page.gfs #gstage canvas.smx-cv { max-height: none; }

  /* A SECOND RELEASE STOOD HERE UNTIL TASK-1158[Q], for `#gframe:fullscreen`.
     It paired with the base file's own :fullscreen re-lock: that one restored
     16:9 against the user-agent's `width:100%;height:100%`, and this one
     released it again on a phone, where the screen already IS the shape we
     want.  Both are gone, because the thing they described is gone -- this
     page no longer asks the browser for element fullscreen at all, so #gframe
     can never match that selector.  (TASK-1172[Q] did put an ask back for
     PHONES, and still nothing stands here: that ask is against the DOCUMENT,
     so no element of this page's ever matches :fullscreen and the user-agent
     has nothing of ours to restyle.  The .gfsm block above is the whole of
     what a phone entry adds.) */

}

/* ==========================================================================
   THE TURN-YOUR-PHONE LINE (TASK-1172[Q]).  The user: "it's okay for some
   games that need a wide screen to force the mobile user (direct them) to
   turn the screen sideways depending on the game."

   SHOWN BY QUERY, DISMISSED BY THE SAME QUERY.  The line paints only while
   this block's media matches -- an upright phone -- so turning the phone IS
   the dismissal: the query stops matching and the line goes with it, no
   listener, no state, nothing to restore on leave.  Which games get it is
   the row's own `wide` declaration in metaeden-v4-game.js (stamped onto the
   body as .gwide at render); which STATE gets it is .gfsm, the mobile
   fullscreen mode -- out of the mode the page scrolls normally and a prompt
   would be nagging, not directing.

   IT RIDES THE FLOATING CLUSTER NOW (TASK-1177[Q]): the first cut put it on
   a row of the bar's themed plate, and the bar's row is gone at the user's
   own instruction (see the immersive-core comment above).  As a chip under
   the button it carries its OWN plate -- one fixed near-black-on-pale pair,
   deliberately theme-independent so the ink is a measured constant (~10:1)
   over whatever game art it happens to cover, and 13px, over the readable
   floor.  The stage-corner trade-off is the cluster's, accepted once, above.

   THE GATE takes only the WIDTH leg: orientation:portrait cannot co-occur
   with the squat-landscape leg, and a phone upright is under the 768 ceiling
   by what this site means by "phone".  The guard suite's K section names
   this prelude among the allowed ones -- narrower than the link's own gate,
   like every other block in this file. */
@media (max-width: 768px) and (orientation: portrait) {

  .v4-game-page.gfs.gfsm.gwide .grotate {
    display: block;
    font-size: 13px;
    text-align: right;
    background: #06090f;
    color: #d8fbff;
    padding: 4px 8px;
  }

}

/* ==========================================================================
   PER-GAME FIT RULES (TASK-1143[Q]'s audit).  The bar for every rule below:
   playfield plus MID-PLAY controls, zero page scrolling, desktop untouched.

   A NOTE ON RESTYLING CARTRIDGES, because metaeden-v4-game.css's own rule is
   that a cartridge may be named only to turn its published knob or to hand
   its layout back -- "anything else is this stylesheet deciding what a game
   looks like".  This file RELAXES that on purpose, for this context only:
   the ticket's ask is precisely a per-game re-cut of HUD, strips and help
   chrome at phone size, and the user asked for it by name (compact, slide
   or sidebar, or drop what mid-play does not need).  The base file's rule
   still binds the base file; the phone fit is where the judgment calls
   live, each one commented where it stands.

   TWO SUB-CONTEXTS, and where they overlap the second wins by order:
     * NARROW (max-width: 768px) -- a phone upright, or any window that
       narrow.  The scarce axis is WIDTH: canvases go width-driven and
       wide strips wrap.
     * SHORT-AND-WIDE (max-height: 480px, landscape) -- a phone sideways.
       The scarce axis is HEIGHT: canvases stay height-driven and chrome
       moves BESIDE the playfield instead of under it.
   ========================================================================== */

@media (max-width: 768px) {

  /* THE RULES IN THIS BLOCK LOST THEIR .gfs IN TASK-1172[Q], all but the
     canvas one below, and the reason deserves its own paragraph because the
     gate looked deliberate and half of it was.  These re-cuts were authored
     for the fullscreen mode, and gating them there left the DEFAULT phone
     view -- the page a visitor is actually on when they tap a game -- sized
     off the base sheet's --gfs-h, an 820px-column constant that is a
     fiction on a phone.  Measured on the audit rig at 375x812: minesweeper
     cells 23px (the beginner board smaller than a fingertip), solitaire
     cards 60px wide with the seven piles panning sideways, golf's 18-hole
     strip scrolling inside the stage.  The mode is the frameless
     ESCALATION of the phone view now, not the only place the phone view is
     right; a rule that is true of the GLASS belongs to every mode on that
     glass, which is what the media query around this block already says.
     What stays .gfs-scoped: the mode's own geometry (the frame, the bars,
     the immersive core above) and the squat-landscape re-cuts below, which
     solve the mode's height budget specifically. */

  /* CANVASES GO WIDTH-DRIVEN when width is the scarce axis.  The base rule
     sizes every stage canvas by HEIGHT (68% of the frame) and lets max-width
     clamp the rest -- correct on a monitor, and measured wrong on a phone:
     for a replaced element an author height is not recomputed when max-width
     clamps, so golf's 720x400 bitmap was stretched into a 384x582 box, 2.7x
     tall.  Width-driven, the cartridge's own authored aspect-ratio derives
     the height and the drawing is true at any width.  Raycade is untouched
     by construction: its view and minimap carry more specific overrides in
     the base file, which win over this rule the same way they win over the
     base one.  (Still .gfs here only because the first block above already
     carries the ungated twin for every view; this one is the mode's own
     restatement.) */
  .v4-game-page.gfs #gstage canvas {
    box-sizing: border-box;
    width: 100%;
    height: auto;
    max-height: none;
  }

  /* ---- golf, upright ---------------------------------------------------
     The 18-hole jump strip is an 18-column grid with a 28px minimum cell:
     555px of minimum against 390 of glass, and the one thing on this
     surface that made the stage scroll sideways.  Nine columns puts it on
     two rows -- the front nine and the back nine, which is how a scorecard
     reads anyway -- and the scoreline mirrors it so hole 3's score sits
     under hole 3's button.  The console's four-across row (name, power,
     buttons, flippers) restacks two-across so nothing needs 400px of row. */
  .v4-game-page #gstage .meta-golf-hole-list,
  .v4-game-page #gstage .meta-golf-scoreline {
    grid-template-columns: repeat(9, minmax(0, 1fr));
  }
  .v4-game-page #gstage .meta-golf-console {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
  .v4-game-page #gstage .meta-golf-hole-name { grid-column: 1 / -1; }
  .v4-game-page #gstage .meta-golf-flippers { grid-column: 1 / -1; }

  /* ---- minesweeper, upright --------------------------------------------
     The base file turns the cartridge's published --mine-cell knob off the
     frame HEIGHT (5%), which on a phone made a beginner cell 42px and the
     9x9 board 402px -- twelve wider than the glass, so even BEGINNER panned
     sideways.  Here the knob follows the WIDTH so the nine-column board
     always fits exactly, clamped to stay a finger-sized target.  The
     sixteen- and thirty-column boards cannot fit a 390px screen at any
     tappable size (30 columns of 13px is not minesweeper); they keep the
     cartridge's own in-stage panning, which is the honest trade.  The
     66px is the measured overhead around the grid: stage padding, board
     padding, borders and gaps.  Controls restack two-across so the mode
     row is not three rows deep. */
  .v4-game-page #gstage .meta-mines-game {
    --mine-cell: clamp(26px, calc((100vw - 66px) / 9), 44px);
    display: grid;
    grid-template-rows: auto auto minmax(0, 1fr);
    max-height: 100%;
    box-sizing: border-box;
  }
  .v4-game-page #gstage .meta-mines-controls {
    grid-template-columns: minmax(0, 1fr) auto;
  }
  /* The header and controls stay put; the board area is the ONE scroller
     for the two board sizes that genuinely outsize a phone, so the outer
     stage never grows a second bar. */
  .v4-game-page #gstage .meta-mines-stage { min-height: 0; }

  /* ---- solitaire, upright ----------------------------------------------
     The base file turns the cartridge's published card knobs off the frame
     height, which upright meant 110px cards and an 859px board panning
     inside 390px of glass -- klondike is unplayable when you cannot see
     the seven piles at once.  Width-derived cards put all seven on screen:
     at 390 that is a 50x71 card, the same 1.41 face the cartridge's own
     phone rule (metaeden.css, 900px) draws at 68x96.  The 36px is the
     measured overhead: board padding plus six 3px gaps.  Deep late-game
     piles still scroll vertically inside the board, which is klondike. */
  /* 60px, not the mode's old 42: since this rule serves the DEFAULT view too
     (the block header above), the overhead includes the stage's own padding
     and the board's border out here, measured as 18px of sideways pan at 375
     with the old constant.  In the mode the stage padding is zero, so the
     wider allowance just letterboxes the board by a few px per card, which
     is invisible; the pan was not. */
  .v4-game-page #gstage .meta-sol-board {
    --sol-card-w: calc((100vw - 60px) / 7);
    --sol-card-h: calc(((100vw - 60px) / 7) * 1.41);
    --sol-gap: 3px;
  }

}

@media (max-height: 480px) and (orientation: landscape) {

  /* CANVASES STAY HEIGHT-DRIVEN here, restated because a window can match
     BOTH sub-contexts (a phone is one or the other, but a squat desktop
     window is not) and this block comes second so the short axis wins. */
  .v4-game-page.gfs #gstage canvas {
    width: auto;
    height: calc(var(--gfs-h) * 0.68);
    max-width: 100%;
  }

  /* ...AND THE TWO THAT NOW OUT-RANK IT HAVE TO BE SAID AGAIN (TASK-1163[Q]).
     The rule directly above carries `canvas` as a bare type selector, and that
     ticket gave fishing and strip mine a rule of their own in the base file
     naming `canvas.fsx-cv` / `canvas.smx-cv` -- one class more specific, so the
     restatement above stopped reaching the two cabinets it was most needed for
     and they fell through to the base file's width-driven sizing.  Measured at
     844x390: the picture went from 470x265 to 322x182, which is the base rule
     being right about a desk and wrong about a window this shape.

     The declarations are the ones above, verbatim, plus the max-height the
     block near the top of this file switches off; repeating them keeps this the
     only place the squat answer is written, which is what its own comment says
     it is for.  If the fraction above is ever retuned, retune it here too --
     they are one rule wearing two selectors, and the guard suite pins that the
     numbers agree. */
  .v4-game-page.gfs #gstage canvas.fsx-cv,
  .v4-game-page.gfs #gstage canvas.smx-cv {
    width: auto;
    height: calc(var(--gfs-h) * 0.68);
    max-width: 100%;
    max-height: none;
  }

  /* ---- golf, sideways --------------------------------------------------
     354px of height cannot hold the canvas AND a console stacked under it,
     so the console becomes a SIDE column -- the ticket's own suggestion --
     and the top bar goes slim: the title is the one line play never needs
     (the status line and the readout both stay, they are live), and the
     readout's five pairs sit on one row instead of a 3-row grid.  The jump
     strip and scoreline ride the side column at nine across, two rows. */
  .v4-game-page.gfs #gstage .meta-golf-game {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(230px, 300px);
    grid-template-rows: auto minmax(0, 1fr);
  }
  .v4-game-page.gfs #gstage .meta-golf-top {
    grid-column: 1 / -1;
    padding: 4px 10px;
  }
  .v4-game-page.gfs #gstage .meta-golf-top h3 { display: none; }
  .v4-game-page.gfs #gstage .meta-golf-readout {
    grid-template-columns: repeat(10, auto);
  }
  .v4-game-page.gfs #gstage .meta-golf-stage {
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .v4-game-page.gfs #gstage .meta-golf-console {
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    min-height: 0;
    overflow-y: auto;
  }
  .v4-game-page.gfs #gstage .meta-golf-hole-list,
  .v4-game-page.gfs #gstage .meta-golf-scoreline {
    grid-template-columns: repeat(9, minmax(0, 1fr));
  }

  /* ---- the shared header idiom, sideways -------------------------------
     Six cartridges share one header shape in metaeden.css (title + status
     line + readout).  Sideways, the title is the row play never needs --
     the status line and the readout are live and stay -- and the readout's
     three pairs go on one row, so the whole bar is ~30px instead of ~100.
     One rule here instead of six copies below. */
  .v4-game-page.gfs #gstage .meta-ttt-top,
  .v4-game-page.gfs #gstage .meta-pool-top,
  .v4-game-page.gfs #gstage .meta-sol-top,
  .v4-game-page.gfs #gstage .meta-art-top,
  .v4-game-page.gfs #gstage .meta-word-top,
  .v4-game-page.gfs #gstage .meta-lex-top {
    padding: 4px 10px;
  }
  .v4-game-page.gfs #gstage .meta-ttt-top h3,
  .v4-game-page.gfs #gstage .meta-pool-top h3,
  .v4-game-page.gfs #gstage .meta-sol-top h3,
  .v4-game-page.gfs #gstage .meta-art-top h3,
  .v4-game-page.gfs #gstage .meta-word-top h3,
  .v4-game-page.gfs #gstage .meta-lex-top h3 {
    display: none;
  }
  .v4-game-page.gfs #gstage .meta-ttt-readout,
  .v4-game-page.gfs #gstage .meta-pool-readout,
  .v4-game-page.gfs #gstage .meta-sol-readout,
  .v4-game-page.gfs #gstage .meta-art-readout,
  .v4-game-page.gfs #gstage .meta-word-readout,
  .v4-game-page.gfs #gstage .meta-lex-readout {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 10px;
  }

  /* ---- 3d tic tac toe, sideways ----------------------------------------
     The cartridge's own 900px rule stacks the four boards two by two --
     right for a phone upright, 881px of column sideways.  Four across puts
     every layer on the one screen at ~195px each, which is bigger than the
     portrait layers, not smaller. */
  .v4-game-page.gfs #gstage .meta-ttt-board {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  /* ---- solitaire, sideways ---------------------------------------------
     Klondike is a tall game: at finger-sized cards a fresh deal is ~420px
     of board and a late tableau more, against 316 of glass.  Cards small
     enough to fit would be 32px wide, which is not a card anybody can tap,
     so the cards STAY finger-sized, the New Deal / draw-mode controls move
     beside the board, and the board -- already its own scroll container --
     pans vertically when the piles run past the glass.  Upright is this
     game's honest phone orientation; sideways is playable with a pan. */
  .v4-game-page.gfs #gstage .meta-sol-game {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(170px, 210px);
    grid-template-rows: auto minmax(0, 1fr);
    max-height: 100%;
    box-sizing: border-box;
  }
  .v4-game-page.gfs #gstage .meta-sol-top { grid-column: 1 / -1; }
  .v4-game-page.gfs #gstage .meta-sol-board {
    grid-column: 1;
    grid-row: 2;
    min-height: 0;
  }
  .v4-game-page.gfs #gstage .meta-sol-controls {
    grid-column: 2;
    grid-row: 2;
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
    overflow-y: auto;
  }

  /* ---- neon pool, sideways ---------------------------------------------
     Table full size on the left, the two buttons and the rules line in a
     column on the right; stacked they were 44px over the glass, and the
     table is the thing that should keep the pixels. */
  .v4-game-page.gfs #gstage .meta-pool-game {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(170px, 210px);
    grid-template-rows: auto minmax(0, 1fr);
  }
  .v4-game-page.gfs #gstage .meta-pool-top { grid-column: 1 / -1; }
  .v4-game-page.gfs #gstage .meta-pool-stage {
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .v4-game-page.gfs #gstage .meta-pool-controls {
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
    overflow-y: auto;
  }

  /* ---- artillery, sideways ---------------------------------------------
     Same shape as pool for the same 50px of arithmetic: the two aim/power
     labels and the two buttons column up beside the battlefield, and the
     battlefield keeps its size. */
  .v4-game-page.gfs #gstage .meta-art-game {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(190px, 230px);
    grid-template-rows: auto minmax(0, 1fr);
  }
  .v4-game-page.gfs #gstage .meta-art-top { grid-column: 1 / -1; }
  .v4-game-page.gfs #gstage .meta-art-stage {
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .v4-game-page.gfs #gstage .meta-art-controls {
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
    overflow-y: auto;
  }

  /* ---- snakecycle, sideways --------------------------------------------
     Arena left; mode picker, rival count, Start and the help line column up
     on the right.  The header slims the same way the shared idiom does --
     its own rule because this cartridge's header classes are its own. */
  .v4-game-page.gfs #gstage .meta-snake-game {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(200px, 240px);
    grid-template-rows: auto minmax(0, 1fr) auto;
    max-height: 100%;
    box-sizing: border-box;
  }
  .v4-game-page.gfs #gstage .meta-snake-top {
    grid-column: 1 / -1;
    padding: 4px 10px;
  }
  .v4-game-page.gfs #gstage .meta-snake-top h3 { display: none; }
  .v4-game-page.gfs #gstage .meta-snake-readout {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 10px;
  }
  .v4-game-page.gfs #gstage .meta-snake-stage {
    grid-column: 1;
    grid-row: 2 / 4;
    min-width: 0;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .v4-game-page.gfs #gstage .meta-snake-controls {
    grid-column: 2;
    grid-row: 2;
    min-height: 0;
    overflow-y: auto;
  }
  .v4-game-page.gfs #gstage .meta-snake-help {
    grid-column: 2;
    grid-row: 3;
  }

  /* ---- lex trace, sideways ---------------------------------------------
     The cartridge's own 900px rule stacks board over found-words over a
     135px control block: 594px of column.  Sideways it goes back to rows:
     the board sized square off the HEIGHT (the one axis that binds), the
     found list beside it, and the trace box with its buttons in the right
     column where a thumb lives. */
  .v4-game-page.gfs #gstage .meta-lex-game {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(200px, 240px);
    grid-template-rows: auto minmax(0, 1fr);
  }
  .v4-game-page.gfs #gstage .meta-lex-top { grid-column: 1 / -1; }
  .v4-game-page.gfs #gstage .meta-lex-stage {
    grid-column: 1;
    grid-row: 2;
    min-width: 0;
    min-height: 0;
    grid-template-columns: auto minmax(0, 1fr);
  }
  .v4-game-page.gfs #gstage .meta-lex-board {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    grid-template-rows: repeat(6, minmax(0, 1fr));
    min-height: 0;
    box-sizing: border-box;
    width: calc(100vh - 120px);
    height: calc(100vh - 120px);
  }
  .v4-game-page.gfs #gstage .meta-lex-found {
    min-height: 0;
    overflow-y: auto;
  }
  .v4-game-page.gfs #gstage .meta-lex-controls {
    grid-column: 2;
    grid-row: 2;
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
    overflow-y: auto;
  }

  /* ---- word fret, sideways ---------------------------------------------
     The guitar-neck track keeps the left of the glass; Start, New Race,
     the speed slider and the word box column up on the right, which also
     puts the box a thumb can reach next to the lanes it feeds. */
  .v4-game-page.gfs #gstage .meta-word-game {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(190px, 240px);
    grid-template-rows: auto minmax(0, 1fr);
  }
  .v4-game-page.gfs #gstage .meta-word-top { grid-column: 1 / -1; }
  .v4-game-page.gfs #gstage .meta-word-stage {
    grid-column: 1;
    grid-row: 2;
    min-width: 0;
  }
  .v4-game-page.gfs #gstage .meta-word-controls {
    grid-column: 2;
    grid-row: 2;
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
    overflow-y: auto;
  }

  /* ---- dot matrix: xyz, sideways (TASK-1172[Q]) ------------------------
     The one cabinet the TASK-1143 audit never re-cut, found broken by this
     ticket's own landscape walk: its chrome rows measured 375px (top 90,
     readout 62, pad 152, message 18, help 53) inside a 275px budget, so
     the stage flexed to 2px and the playfield hung 190px below the fold,
     reachable only by scrolling inside the stage -- on the exact
     orientation this ticket's turn-your-phone line sends players to.

     The same answer every sibling above got: the top bar slims (the title
     is the one line play never needs; the status line stays, it is live),
     the readout and the touch pad column up on the right, the playfield
     keeps the left of the glass, and the help legend -- a static list of
     keys, on a surface whose keys are the pad beside it -- is the row
     that goes.  The message line auto-places into an implicit row under
     the playfield, where a one-line "jacked in" belongs.  The stage is
     stretched by the grid on both axes, which is what lets it ignore the
     cartridge's own width-derived aspect-ratio (487px tall at 812 wide,
     the very number that broke this); the view canvas inside keeps its
     shape from the height-driven rule above and centres in whatever is
     left. */
  .v4-game-page.gfs #gstage > [data-metaeden-xyz] { height: 100%; }
  /* BOTH RIGHT-COLUMN TRACKS ARE fr SHARES, NOT auto, and that is the second
     thing this block learned on the rig: an auto track grows to its content,
     and the readout's chips wrap tall in a 220px column, so an auto row
     inflated the whole grid 134px past the stage and the overflow came back.
     minmax(0, fr) tracks are rigid -- they split what is actually there and
     their content scrolls inside them -- so the playfield's span is definite
     whatever the readout wants.  The pad gets the larger share because it is
     the thing a thumb is on. */
  .v4-game-page.gfs #gstage .meta-xyz-game {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(200px, 240px);
    grid-template-rows: auto minmax(0, 0.8fr) minmax(0, 2fr);
    height: 100%;
    box-sizing: border-box;
  }
  .v4-game-page.gfs #gstage .meta-xyz-top {
    grid-column: 1 / -1;
    padding: 4px 10px;
  }
  /* The title goes the way every sideways re-cut sends it, and so does the
     TAGLINE beside it -- a static two-line blurb (measured 62px of the top
     bar's 70) that the heading and the marquee already say.  The sound and
     fullscreen buttons in the same bar are live and stay. */
  .v4-game-page.gfs #gstage .meta-xyz-top h3 { display: none; }
  .v4-game-page.gfs #gstage .meta-xyz-top p { display: none; }
  /* THE STAGE IS STRETCHED IN ONE AXIS ONLY.  Its own sheet gives it
     aspect-ratio 5/3 and its view canvas is ABSOLUTE, inset 0, 100% by 100%
     -- so the stage's box IS the picture's box, and a stage stretched on
     both axes would stretch the drawing off its own shape.  align-self
     fills the row span (the definite height this whole grid exists to
     provide); justify-self center leaves the width to the ratio, which is
     exactly how a replaced-looking box stays true.  max-width backstops a
     column too narrow for the derived width. */
  .v4-game-page.gfs #gstage .meta-xyz-stage {
    grid-column: 1;
    grid-row: 2 / 4;
    align-self: stretch;
    justify-self: center;
    width: auto;
    max-width: 100%;
    min-width: 0;
    min-height: 0;
  }
  .v4-game-page.gfs #gstage .meta-xyz-hud {
    grid-column: 2;
    grid-row: 2;
    min-height: 0;
    overflow-y: auto;
  }
  .v4-game-page.gfs #gstage .meta-xyz-pad {
    grid-column: 2;
    grid-row: 3;
    min-height: 0;
    overflow-y: auto;
  }
  .v4-game-page.gfs #gstage .meta-xyz-help { display: none; }
  /* ...and the view canvas is handed its own layout back, the same hand-back
     the raycade view got in the base file and for the same mechanism: the
     cartridge authors it absolute, inset 0, 100% by 100% of the stage, and
     the surface's id-carrying canvas rules outrank that -- the squat
     restatement above was sizing it 425x255 in whatever box the stage had,
     anchored top-left and clipped by the stage's own overflow:hidden.  With
     the stage ratio-true (previous rule) and the canvas filling it, the
     picture is whole, shaped, and exactly as big as the row leaves room
     for. */
  .v4-game-page.gfs #gstage canvas.meta-xyz-view {
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
  }

  /* ---- vanish boom 3d, the same shape of problem (TASK-1190[Q]) ---------
     Its first-person view is authored absolute/inset-0/100% by the cartridge
     exactly as the raycade one above is, and the id-carrying canvas rule in
     this file outranked it the same way -- landscape showed the top 43% of
     the picture with the crosshair over open floor.
       WRITTEN HERE RATHER THAN WON WITH !important, which is the form the
     cartridge originally reached for and could not avoid from where it sits:
     an ID selector cannot be out-specified from a stylesheet that has no id
     to name.  This file does, xyz already set the precedent, and a rule beside
     its sibling is a thing the next reader finds -- an !important buried in a
     cartridge is a thing they fight. */
  .v4-game-page.gfs #gstage canvas.meta-vanish-boom-3d-view {
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    object-fit: contain;
  }

  /* ---- minesweeper, sideways -------------------------------------------
     The scarce axis flips, so the knob follows the HEIGHT (120px is the
     board's measured vertical overhead) and the header plus the mode/reset/
     flag controls move BESIDE the board, where 354px of height could never
     stack them over it.  The board keeps the cartridge's own panning for
     the sixteen-row sizes. */
  .v4-game-page.gfs #gstage .meta-mines-game {
    --mine-cell: clamp(24px, calc((100vh - 120px) / 9), 40px);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(220px, 260px);
    grid-template-rows: auto minmax(0, 1fr);
  }
  .v4-game-page.gfs #gstage .meta-mines-stage {
    grid-column: 1;
    grid-row: 1 / 3;
    min-height: 0;
    min-width: 0;
  }
  .v4-game-page.gfs #gstage .meta-mines-top {
    grid-column: 2;
    grid-row: 1;
    padding: 6px 10px;
  }
  .v4-game-page.gfs #gstage .meta-mines-top h3 { display: none; }
  .v4-game-page.gfs #gstage .meta-mines-controls {
    grid-column: 2;
    grid-row: 2;
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
  }

}
