/* fit.css — making every screen fit the screen it is on.
 *
 * Split out of ui.css, which had quietly become two subjects: how things FEEL
 * (motion tokens, focus, press, reduced motion) and how things FIT. This is the
 * second one, and it is all responses to a measurement rather than to taste.
 *
 * Every rule here exists because tools/checks/ui-rules.mjs caught content being
 * lost at a specific size. It drives 16 screens across 7 viewports, including
 * two landscape shapes and 320x568, so nothing in here is speculative: each
 * block below was a red build first.
 *
 * Loaded after ui.css, last of all.
 */
/* ===================== 7. The results screen fits the phone =================
   The podium is three stacked cards ~463px tall inside a card capped at 88vh.
   On a 568px phone that leaves nothing for the standings and pushes BOTH
   buttons off the bottom, so the screen you land on after every single match
   had no way out of it. The way out is structurally the last thing that can be
   allowed to get cut.

   Short screens get a podium that is a row rather than a plinth. First, second
   and third still read, with their names and their Gem payouts, and the height
   goes back to the standings and the buttons. */
@media (max-height: 720px), (max-width: 430px) {
  .results-card { gap: 8px; padding: 16px 14px 14px; max-height: 96vh; }
  .results-crown { font-size: 24px; }
  #resultsTitle { font-size: 19px; }
  #podium { gap: 6px; margin: 2px 0; flex-wrap: nowrap; align-items: stretch; width: 100%; }
  .podium-slot { flex: 1 1 0; min-width: 0; padding: 8px 5px; }
  .podium-slot.p1 { transform: none; } /* the plinth lift costs height it cannot spare */
  .podium-slot .medal { font-size: 21px; }
  .podium-slot .pname { font-size: 11.5px; margin-top: 3px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .podium-slot .ppts, .podium-slot .preward { font-size: 11px; margin-top: 1px; }
  #resultsPanel { padding: 8px 10px; }
  #resultsNext { font-size: 12px; }
  /* Narrower columns so a long name ellipsises instead of shoving K/D off. */
  .sb-row { grid-template-columns: 20px minmax(0, 1fr) 44px 26px 26px; font-size: 12.5px; gap: 4px; }
}

/* ===================== 8. Landscape on a phone =============================
   A phone on its side has about 360px of height and plenty of width, and the
   mobile nav grid spends 98px of that height before a single panel renders.
   Every full view overflowed. So in landscape the rail goes back to being a
   RAIL: a slim vertical strip of icons down the left, which is what the shape
   of the screen was asking for. */
@media (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
  #overlay { flex-direction: row; }
  /* TWO columns of icons, not one. Twelve destinations at the 35px pitch this
     used to have need 423px of rail, and a landscape phone gives it 336 at
     844x390 and 306 at 740x360. Nothing here scrolls and the rail is not paged,
     so the difference was not "tight": Credits was drawn half, and Community and
     Tip Jar were laid out below the fold with no route to them at all. Three
     destinations, unreachable, silently.
     Six rows of two is 274px of items, so it fits the shortest shape we drive
     with room left over, and every item finally clears the 44px floor the old
     34px pitch never did. The 52px of width this takes from the stage is the
     cheapest thing on the screen. */
  #navRail {
    flex: 0 0 106px; display: grid; grid-template-columns: repeat(2, 1fr);
    grid-auto-rows: minmax(44px, auto); align-content: start; gap: 2px; padding: 4px 3px;
    border-right: 1px solid rgba(255,255,255,0.06); border-bottom: none;
  }
  .nav-item { flex: 0 0 auto; min-height: 44px; padding: 3px 1px;
    border-bottom: none; border-left: 2px solid transparent; border-radius: 8px; }
  /* The desktop rail floats the Tip Jar to the bottom with margin-top: auto, and
     that rule is still live at 844x390 (the mobile block that cancels it stops at
     760px wide). In a content-sized grid row it resolves to nothing, but it is
     one auto-flow change away from moving an item off its row, so it goes here. */
  .nav-item.nav-tip { margin-top: 0; }
  .nav-item.active { border-left-color: #5c9bff; border-bottom-color: transparent; }
  .nav-item.nav-play.active { border-left-color: #5cff8f; border-bottom-color: transparent; }
  /* Labels go, icons stay. The accessible name is on the button, so a screen
     reader still announces the destination; only the sighted label is dropped,
     and only where there is genuinely no room for it. */
  .nav-item .nav-label { display: none; }
  .nav-item .nav-ico { font-size: 17px; }
  #stage { padding: 8px 12px; }
  .tab-head h2 { font-size: 17px; }
  .tab-head p { display: none; } /* the lede is the first thing to go, not the content */
  .panel { padding: 10px; gap: 5px; }
  /* The Tip Jar is one form and cannot be paged without separating the amount
     from the button that spends it, so in landscape it sheds prose instead.
     Everything you need to give money is still on screen; the paragraph
     explaining why is not, and it is on the nav item you just pressed. */
  .donate-intro { display: none; }
  .donate-fine { font-size: 9.5px; line-height: 1.3; }
  .donate-head { font-size: 14px; }
  #donateNote { min-height: 32px; }
  #donateAmount { font-size: 17px; padding: 6px 0; }
  .donate-chip { padding: 7px 0; font-size: 13px; }
  .donate-submit { padding: 9px 22px; font-size: 15px; }

  /* The end-of-match card in landscape. A phone on its side has plenty of width
     and almost no height, so the podium stops being a plinth above the board
     and stands BESIDE it. The buttons keep the full width underneath, because
     they are the way out. */
  .results-card {
    display: grid; width: min(94vw, 760px); max-height: 94vh;
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    grid-template-areas: "title title" "podium board" "next next" "actions actions";
    align-content: start; gap: 6px 14px; padding: 10px 14px 12px;
  }
  .results-crown { display: none; } /* the trophy is the one thing the title already says */
  #resultsTitle { grid-area: title; font-size: 16px; }
  #podium { grid-area: podium; flex-direction: column; align-items: stretch; gap: 4px; margin: 0; }
  .podium-slot { display: flex; flex-direction: row; align-items: center; gap: 7px;
    text-align: left; padding: 5px 8px; }
  .podium-slot .medal { font-size: 15px; }
  .podium-slot .pname { margin-top: 0; flex: 1 1 auto; }
  .podium-slot .ppts, .podium-slot .preward { margin-top: 0; }
  #resultsPanel { grid-area: board; min-height: 0; padding: 7px 9px; }
  #resultsNext { grid-area: next; font-size: 11px; }
  #resultsActions { grid-area: actions; margin-top: 0; }

  /* Giving the per-copy melt button a real 44px target made every copy row 18px
     taller, which is correct for a control that destroys something you own and
     is height a landscape phone does not have. So the DRAWER gives it back, out
     of its own padding, and the target stays 44px. Chrome yields, never the
     thing your thumb has to hit. */
  .ld-head, .locker-stats { padding: 5px 10px; }
  .ld-copyhead, .copy-row { padding: 4px 10px; }
  .ld-note, .melt-note { font-size: 10.5px; }
  /* "Have a code?" is a label over an input over a button over a message line:
     four stacked rows on the screen shape with the least height and the most
     width in the whole app. In landscape it becomes one row, which is what the
     shape was asking for, and nothing is lost. */
  .mail-redeem { display: flex; flex-direction: row; align-items: center;
    flex-wrap: wrap; padding: 5px 9px; gap: 6px; }
  .mail-redeem label { font-size: 10.5px; margin: 0; white-space: nowrap; }
  .mail-redeem input { flex: 1 1 120px; min-width: 0; padding: 6px 9px; font-size: 12px; }
  .mail-redeem .msg, .mail-redeem #claimCodeMsg { flex: 1 0 100%; }
  /* .msg reserves a 16px line for an error that is usually not there. In
     landscape that empty reservation is the difference between fitting and not. */
  .mail-redeem .msg, #mailMsg { min-height: 0; }
  /* The Locker shows a grid of skins AND the open drawer for one of them, and in
     landscape there is not room for both at their normal size. The stats row used
     to go entirely, on the argument that every figure in it is on the skin's Shop
     card and in the preview. It is not a fair trade: those figures are why the
     drawer gets opened, and "it is somewhere else too" is how a screen ends up
     with nothing of its own. The drawer is TABBED below 860px now (locker.css), so
     the stats and the copies take turns at one height instead of one being
     deleted. The cards still shrink, which is the part that was always right. */
  #ownedGrid { grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); gap: 6px; }
  #ownedGrid .skin-card { padding: 17px 5px 7px; gap: 2px; }
  #ownedGrid .skins-grid .swatch, #ownedGrid .swatch { width: 30px; height: 30px; }
  #ownedGrid .skin-card-name { font-size: 10.5px; }
  #ownedGrid .skin-card-sub { font-size: 9.5px; }
  #ownedGrid .skin-card-kind { font-size: 6.5px; padding: 1.5px 5px; }
  /* An empty state is ONE block, so the pager cannot split it and cannot help.
     In landscape it stops being a poster and becomes a row: mark on the left,
     what happened and what it means in the middle, the way out on the right. No
     word is dropped and the button keeps its 44px. This is the shape the screen
     was asking for, and it is what was actually overflowing the Mailbox: the
     panel re-asks the server on open, and a signed-out player gets the empty
     state, not the list. */
  /* minmax(96px) + wrapping actions: `auto` column 3 with nowrap took 280px of a
     343px panel, starving column 2 to ZERO. .es-sub: 0px wide, 354px TALL. */
  .locker-empty, .mail-empty, .shop-empty {
    display: grid; grid-template-columns: auto minmax(96px, 1fr) auto;
    align-items: center; gap: 2px 12px; padding: 9px 12px; text-align: left;
  }
  .es-mark { grid-row: 1 / 3; font-size: 21px; }
  .es-line { grid-column: 2; font-size: 13px; }
  .es-sub { grid-column: 2; font-size: 11px; line-height: 1.35; max-width: none; }
  .es-actions { grid-column: 3; grid-row: 1 / 3; margin-top: 0; flex-wrap: wrap; }

  /* One message is the smallest thing the Mailbox pager can put on a page, so if
     a single card does not fit, paging cannot save it. Landscape gets a compact
     card: same subject, same date, same claim button, less air around them. */
  .mail-item { padding: 6px 9px; }

  /* Sign-in is five controls and two separators stacked into 350px, on the one
     screen shape with 290px of height and width going spare. Two columns: the
     one-tap route on the left, the email route on the right. Nothing hidden and
     no control shrinks below 44px.

     !important because #accountSignedOut carries its layout in an INLINE style
     attribute (index.html), which no stylesheet can outrank. The inline display
     is also what JS toggles to show and hide the panel, so it has to stay; only
     the layout is overridden here, never the visibility. */
  /* .panel caps at 460px, which is right for a column of controls and wrong for
     two. A landscape phone has 740px or more of width doing nothing, so the
     panel takes some of it rather than squeezing the columns into an overflow. */
  #accountPanel.panel { max-width: min(96vw, 660px); }
  /* No `!important` here any more. It was there to beat an inline display on the
     element, and it also beat the line that HIDES this block for a signed-in
     player: in landscape they saw the sign-in form under their own account card.
     The inline style is gone (index.html) and the base display lives in
     account.css, so a plain rule in this later file wins on its own. */
  #accountSignedOut {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: 4px 14px; align-items: center; align-content: start;
  }
  #accountSignedOut > .join-row { min-width: 0; }
  #accountSignedOut > .join-row input { min-width: 0; }
  #accountSignedOut > .account-note { grid-column: 1 / -1; font-size: 10px; margin: 0; }
  /* The two "or" separators go, and only here. In one column they carry real
     meaning: these are alternatives, not steps. In two columns the layout says
     that already, and each route still names itself ("Continue with Discord",
     "Send link"), so nothing is left ambiguous. They were costing two whole grid
     rows, which is the difference between this panel fitting and not. */
  #accountSignedOut > .or { display: none; }
  .account-legal { font-size: 10px; }
  #authMsg { min-height: 0; }
  .mail-head { gap: 5px; }
  .mail-subject { font-size: 12.5px; }
  .mail-from, .mail-date { font-size: 10px; }
  .mail-body { font-size: 11.5px; line-height: 1.4; }
  .mail-actions, .mail-gifts { margin-top: 4px; gap: 5px; }
}

/* Section 8b, "the Locker drawer on a small screen", used to sit here. It was the
   only single-screen section in a file organised by viewport SHAPE, and it is now
   public/css/locker.css, next to the drawer rules it argues with. What is left of
   the Locker in this file is inside the shared shape sections above, where it sits
   beside the Mailbox and the results card for the same reason they do. */

/* ===================== 9. Small and short screens ===========================
   A 320x568 phone has about 380px of stage once the top bar and the nav are
   paid for. Paging handles content that is too LONG, but it cannot help a form
   whose pieces have to stay together: splitting the Tip Jar would put the
   amount on one page and the button that spends it on another, which is worse
   than tight. So on the smallest screens the chrome gets out of the way
   instead. Nothing is hidden and nothing is cut, it is just less padded. */
@media (max-width: 420px), (max-height: 640px) {
  .panel { padding: 13px; gap: 7px; }
  .tab-head { margin-bottom: 0; }
  .tab-head h2 { font-size: 20px; }
  .tab-head p { font-size: 11.5px; line-height: 1.4; margin-top: 2px; }
  .donate-head { font-size: 16px; }
  .donate-intro { font-size: 11.5px; line-height: 1.45; }
  .donate-fine { font-size: 10px; line-height: 1.35; }
  .donate-presets { gap: 6px; }
  .donate-chip { padding: 9px 0; font-size: 14px; }
  #donateNote { min-height: 38px; }
  #donateAmount { font-size: 20px; padding: 9px 0; }
  .final-note { font-size: 10.5px; }
  .loot-sub, .gate-note { font-size: 11.5px; }
  /* The page bar is a control, not a band. Half the padding, same 44px target.
     It said 44 and set 40, and the code is what ships: measured 44x40 arrows and
     22x40 dots on Milestones, How to Play and Community, i.e. the one control the
     touch-targets rule names out loud ("including the page control") was the one
     under the floor on every paged view at once. */
  .pager-arrow { min-width: 44px; min-height: 44px; font-size: 17px; }
  .pager-dot { height: 44px; }

  /* An empty state is one block, so the pager cannot split it when it does not
     fit. It has to be the thing that gives, and it can afford to: the mark and
     the buttons carry it, the padding was only ever breathing room. */
  .locker-empty, .mail-empty, .shop-empty { padding: 15px 12px; gap: 3px; }
  .es-mark { font-size: 23px; }
  .es-line { font-size: 13.5px; }
  .es-sub { font-size: 11.5px; line-height: 1.4; }
  .es-actions { margin-top: 7px; gap: 6px; }
  .mail-redeem { gap: 5px; padding: 9px 10px; }
  .mail-redeem label { font-size: 11.5px; }

  /* Sign-in on a small phone. Two separators, a note and five controls is more
     than the screen has, and every control is at the 44px floor, so the floor is
     not what gives. The prose does: the note tightens, the separators shrink to
     what they are (a word between two options), and the panel loses its padding
     before anything loses a way to sign in. */
  /* Sign-in prose and air, at every small size. The LAYOUT is deliberately not
     set here: a short-and-wide phone is also matched by this block, and setting
     display would land after the landscape rule above and undo its two columns.
     Only the portrait block below touches layout. */
  #accountSignedOut > .account-note { font-size: 10.5px; line-height: 1.35; margin: 0; }
  #accountSignedOut > .or { font-size: 10.5px; }
  #authMsg { min-height: 0; }
  .account-legal { font-size: 10.5px; line-height: 1.3; }
  #accountPanel .skins-head { font-size: 12px; }
  #accountPanel.panel { padding: 10px; gap: 5px; }
}

/* ===================== 10. Sign-in on a portrait phone =====================
   One column is right on a tall narrow screen, so the height comes out of the
   air between the controls and never out of the controls themselves. Every
   button stays 44px: a sign-in button you cannot hit is a worse outcome than a
   sign-in panel that is tight.

   Portrait-scoped on purpose. The short-screen block above also matches a
   landscape phone, and setting a layout there would land after the landscape
   two-column rule and quietly undo it. That is exactly what happened once. */
@media (max-width: 430px) and (orientation: portrait) {
  /* !important because #accountSignedOut carries its layout in an inline style
     attribute, which no stylesheet can outrank. JS toggles that same inline
     display to show and hide the panel, so only the gap is overridden here. */
  #accountSignedOut { gap: 4px !important; }
  #accountSignedOut > .account-note { font-size: 10px; line-height: 1.3; }
  #accountPanel.panel { padding: 9px; gap: 4px; }
}

/* ===================== 11. The Shop in landscape ===========================
   The Shop grid is the one view whose blocks are each irreducible: a spotlight
   page, a week panel, a today panel, a loot row. The pager can move a block to
   another page but cannot make one shorter, and on a 360px-tall phone the
   spotlight alone is taller than the screen.

   So in landscape the Shop trades vertical air for horizontal space it has
   plenty of: two columns, and every block sheds padding. Nothing is hidden, and
   the pager still handles whatever is left over. */
@media (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
  /* minmax(0, 1fr), not 1fr: a bare 1fr track has an `auto` minimum, so a wide
     child (a skin card grid) refuses to shrink below its content and pushes the
     whole panel 6px past its own edge. */
  .shop-grid { display: grid !important; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: none !important; gap: 6px; align-content: start; }
  .shop-grid > * { min-width: 0; }
  .shop-block.panelled, .spotlight { padding: 7px 9px; }
  .shop-block-head { margin-bottom: 4px; padding-bottom: 3px; }
  .shop-block-head .sbh-name { font-size: 11.5px; }
  .shop-block-head .sbh-sub, .shop-timer { font-size: 9px; }
  .shop-dash .skins-grid { grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: 5px; }
  .shop-dash .skin-card { padding: 15px 4px 6px; gap: 2px; }
  .shop-dash .skin-card-name { font-size: 9.5px; }
  .shop-dash .skin-card-sub { font-size: 9px; }
  .shop-dash .skins-grid .swatch { width: 26px; height: 26px; }
  .spot-head, .spot-progress { margin-bottom: 3px; }
  .loot-hero-grid { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 5px; }
  .loot-crate-card { padding: 7px 5px 6px; gap: 3px; }
  .loot-crate-card .lc-bubble { font-size: 18px; }
  .final-note { font-size: 9px; }
}

/* The spotlight is the one block that cannot be paged smaller: it IS a carousel,
   showing one page at a time already, so its height is its tallest page. On a
   360px-tall phone that page alone is taller than the stage. Everything inside
   it shrinks here: the drop cards, the bundle rows, the countdown. */
@media (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
  .spotlight { grid-area: auto; }
  .alpha-grid, .alpha-mini-row { gap: 5px; }
  .alpha-item { padding: 6px 7px; gap: 5px; }
  .alpha-item.big { padding-top: 8px; }
  .alpha-swatch { width: 34px; height: 34px; }
  .alpha-name { font-size: 11px; }
  .alpha-price, .alpha-badge { font-size: 9.5px; }
  .alpha-countdown { padding: 4px 6px; }
  .alpha-countdown-label, .alpha-countdown-date { font-size: 9px; }
  .alpha-countdown-clock { font-size: 14px; }
  .spot-bundles { gap: 5px; }
  .bundle-card { padding: 7px 8px; }
  .bundle-name { font-size: 11px; }
  .bundle-sub, .bundle-ribbon { font-size: 9px; }
  .bundle-btn { padding: 7px 12px; font-size: 11.5px; min-height: 36px; }
  .beta-card, .beta-item { padding: 6px 7px; }
  .beta-name { font-size: 11px; }
  .offer-card { padding: 6px 8px; gap: 8px; }
  .offer-swatch { width: 38px; height: 38px; }
  .offer-name { font-size: 12px; }
  .offer-tag, .offer-rarity { font-size: 9.5px; }
  .offer-btn { padding: 7px 12px; font-size: 11.5px; }
}

/* ===================== 12. The Shop's chrome on a small screen ==============
   Once the inner grids page (game.js renderShop), the spotlight is one row of
   cards wrapped in a lot of furniture: a carousel head, a progress rule, a block
   heading and a page bar. At 320px that was 108px of chrome around 136px of
   actual stock. The stock is the product, so the furniture is what shrinks. */
@media (max-width: 430px), (max-height: 640px) {
  .spot-head { min-height: 0; margin-bottom: 2px; }
  .spot-arrow { font-size: 17px; padding: 0 8px; }
  .spot-dots { gap: 5px; }
  .spot-progress { margin-bottom: 2px; }
  .shop-dash .shop-block-head { margin-bottom: 4px; padding-bottom: 3px; }
  .shop-dash .shop-block-head .sbh-name { font-size: 12px; }
  .shop-block.panelled, .spotlight { padding: 8px 9px; }
  .shop-dash .final-note { font-size: 9.5px; }
  #shopPanel .tab-head h2 { font-size: 18px; }
  #shopPanel .tab-head p { display: none; }
}

/* The last 12px of the landscape Shop. The page bar keeps its 44px targets, so
   the height comes out of the card art instead: a skin card is recognised by its
   colour and its name, both of which survive a smaller disc. */
@media (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
  .spotlight, .shop-block.panelled { padding: 6px 8px; }
  .shop-dash .skin-card { padding: 13px 3px 4px; }
  .shop-dash .skins-grid .swatch { width: 22px; height: 22px; }
  .spot-head { margin-bottom: 1px; }
}

/* ===================== 13. The Play button, on the screen ==================
   The worst measurement in the shell, and the only one that stops the game from
   being played at all: at 320x568 "Play now" was laid out with its top at 558.8
   and its bottom at 615.8, i.e. entirely below a 568px screen, and
   elementFromPoint at its centre returned null. Not clipped art. No way in.

   Nothing was wrong with the button. 274.5px, 48.3% of that screen, was spent
   above it on a 58px logo, a 46px wordmark that app.css holds at 46px on every
   screen ever made, a BETA sticker and a two-line tagline, before the first
   thing you can touch. So the poster shrinks and the controls come up ~197px.

   The logo goes first. It is decoration on the one screen that has a job, the
   wordmark under it says the same word, and the top bar carries the mark
   anyway. Everything else is turned down, not removed. */
@media (max-height: 720px) {
  .play-logo { display: none; }
  #playView h1 { font-size: 30px; }
  #playView .tagline { font-size: 12.5px; }
  .beta-note { margin-top: 4px; line-height: 1.4; }
  .play-hero { gap: 8px; }
}

/* In landscape the two ways in stand side by side. A phone on its side has width
   going spare and 360px of height to spend, and stacking them spent 59px of it
   on the second one — height that was coming straight out of the first. */
@media (orientation: landscape) and (max-height: 500px) {
  .play-actions { flex-direction: row; flex-wrap: wrap; justify-content: center; }
}
