/*
 * THE page layout, the only one: a grid on the dynamic viewport with three
 * areas and four modes. A game fills the areas and never lays out the page.
 *
 *   <div class="shell">
 *     <header class="shell-header">…brand bar, price strip, stages…</header>
 *     <main class="shell-board">…the plot…</main>
 *     <section class="shell-controls">…</section>
 *   </div>
 *
 * Portrait phone: three rows; the board takes every pixel the header and
 * controls leave (never under --plot-min-h, below that the page scrolls).
 * Short frame: an operator's frame is as tall as it is, and the stake must
 * stay reachable without scrolling — so the spacing goes first and the board
 * follows, down to --plot-min-h-tight. See the block at the end.
 * Landscape phone: the header across the top, controls beside the board.
 * Desktop: the column widens with the window; the controls stay at the
 * source's 600px column, centred under the board.
 */

.shell {
  /* the column the game lives in */
  --shell-column: 600px;
  --shell-pad: 18px;
  --shell-pad-bottom: 16px;

  display: grid;
  min-height: 100vh;
  min-height: 100dvh;
  grid-template-columns: minmax(0, var(--shell-column));
  grid-template-rows: auto minmax(var(--plot-min-h), 1fr) auto;
  grid-template-areas:
    "header"
    "board"
    "controls";
  justify-content: center;
  /* the top padding is the demo notch's height, if any */
  padding:
    var(--fun-mode-height, 0px)
    max(var(--shell-pad), env(safe-area-inset-right, 0px))
    calc(var(--shell-pad-bottom) + env(safe-area-inset-bottom, 0px))
    max(var(--shell-pad), env(safe-area-inset-left, 0px));
}

.shell-header {
  grid-area: header;
  min-width: 0;
}

/* Positioned: canvases and tap targets fill it absolutely. Clipped: glows
   and the head's halo may reach past the edge. */
.shell-board {
  grid-area: board;
  position: relative;
  min-width: 0;
  min-height: var(--plot-min-h);
  overflow: hidden;
}

.shell-controls {
  grid-area: controls;
  justify-self: center;
  width: 100%;
  max-width: calc(600px - 2 * var(--shell-pad));
  min-width: 0;
}

/* Demo mode: a notch above the header; the shell reserves its height. */
.shell.is-demo {
  --fun-mode-height: calc(28px + env(safe-area-inset-top, 0px));
}

@media (max-width: 639.98px) {
  .shell {
    --shell-pad: 12px;
    --shell-pad-bottom: 12px;
  }
}

@media (min-width: 1024px) {
  .shell {
    --shell-column: min(960px, 70vw);
  }
}

/*
 * NOTE ON SPECIFICITY. index.html loads core/layout.css BEFORE core/kit.css,
 * so a rule here that targets the same element with the same specificity as
 * one in kit.css LOSES to it -- quietly, since both are valid. The short-frame
 * and band rules below therefore qualify their selectors with .shell, which
 * kit.css does not use for these elements. Measured on 2026-10-11: without
 * this the whole 750x176 band block had no effect at all (the price strip
 * stayed 62px and the stage bar 48px, exactly as kit.css sets them), while an
 * injected copy of the same CSS worked -- because injection appends last.
 */
/* ---- the short frame: an operator's box, not a phone's screen ----
 *
 * Measured on the baseline (2026-10-10), portrait 390×498, the common
 * Parimatch phone frame: header 182 = topbar 50 + price 28 + stages 48, plus
 * 70px of pure spacing (topbar padding-top 14, price margins 18+12, stages
 * margin-bottom 12, stake-rack margin-bottom 14); controls 88–166; board
 * pinned at --plot-min-h 220. 182 + 220 + 166 = 568 in a 402-tall frame is
 * where the player's 216px of scrolling came from.
 *
 * So the order of sacrifice is: the spacing, which costs nothing; then the
 * board, which is the one thing a player can read less of and still bet. The
 * stake, the balance and the round state never move out of the frame: a bet
 * the player must scroll to is the defect this mode exists to remove.
 *
 * Height, not device width, is the trigger: the same frame on a phone, a
 * tablet and a desktop is the same problem. 760px covers every measured
 * Parimatch frame (402…673) and the desktop 1200×588, and leaves a full-size
 * phone screen alone.
 */
@media (max-height: 760px) {
  .shell {
    --shell-pad-bottom: 8px;
    /* the board may give up more than the roomy floor, but not all of itself:
       below this a plot is no longer a plot */
    --plot-min-h: var(--plot-min-h-tight, 132px);
    grid-template-rows: auto minmax(var(--plot-min-h), 1fr) auto;
  }
  .shell .shell-board {
    min-height: var(--plot-min-h);
  }
  /* the spacing goes first: 70px of margins and padding, no content lost */
  .shell .topbar {
    padding-top: 8px;
  }
  .shell .price-header {
    margin: 8px 0 6px;
  }
  .shell .stages {
    margin-bottom: 6px;
  }
  .shell .stake-rack {
    margin-bottom: 6px;
  }
}

/* Shorter still (the 320×402 iPhone SE frame, and a phone turned sideways):
   the price strip's own row is the last thing that can go. The price itself
   stays -- it rides in the plot -- but the strip stops spending a row on it. */
@media (max-height: 460px) {
  .shell {
    --plot-min-h: var(--plot-min-h-tight, 104px);
  }
  .shell .price-header {
    margin: 4px 0 4px;
  }
  .shell .topbar {
    padding-top: 4px;
  }
  /* the round bar gives up a few pixels of its 48 */
  .shell .stages {
    height: 40px;
  }
  /* an empty notice slot reserved 24px + 4px here too: at 320×402 that was
     the difference between the page scrolling by 2px and not scrolling */
  .notice-row:disabled {
    display: none;
  }
}

/* A phone on its side, and a wide short frame (the 750×176 band).
 *
 * The board shares the row with the controls, so it is the header that has to
 * give: at 320–390px of height the old rules let it keep its full stack and
 * the board collapsed to nothing, labels overlapping. Here the header
 * is one line -- the brand bar -- and the price strip and the round state move
 * into the controls column, which scrolls. The board keeps a floor, so it is
 * a plot and not a sliver, and the stake stays beside it without scrolling.
 */
@media (orientation: landscape) and (max-height: 500px) {
  .shell {
    --shell-pad: 12px;
    --shell-pad-bottom: 10px;
    height: 100dvh;
    grid-template-columns: minmax(0, 1fr) minmax(220px, 34%);
    grid-template-rows: auto minmax(var(--plot-min-h-land, 96px), 1fr);
    grid-template-areas:
      "header header"
      "board controls";
    column-gap: var(--shell-pad);
  }
  .shell .shell-board {
    min-height: var(--plot-min-h-land, 96px);
  }
  .shell .shell-controls {
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* one line of header: the rest of its stack is spacing the board needs */
  .shell .topbar {
    padding-top: 6px;
  }
  .shell .price-header {
    margin: 4px 0;
  }
  .shell .stages {
    margin-bottom: 4px;
  }
  .shell .stake-rack {
    margin-bottom: 6px;
  }
}

/* The letterbox band (750×176 of Parimatch) and a small phone sideways.
 *
 * Measured at 750×176: the header alone took 116 of the 176px (topbar 50 +
 * price strip + stages 48, stacked), which left the board overflowing and the
 * stake rack hanging 38–110px below the frame. A band this short cannot spend
 * a row per header block, so here the header IS the brand bar: the price strip
 * is gone (the price rides in the plot) and the round state moves in beside
 * the stake, in the controls column that scrolls. Everything that takes money
 * -- stake, chips, the bet button -- stays inside the frame. */
@media (orientation: landscape) and (max-height: 320px) {
  .shell {
    --shell-pad: 8px;
    --shell-pad-bottom: 4px;
    grid-template-columns: minmax(0, 1fr) minmax(230px, 40%);
    grid-template-rows: auto minmax(var(--plot-min-h-land, 56px), 1fr);
  }
  /* The demo notch is a tab hanging from the top edge, and .shell.is-demo
     reserves its full height above the game: 28px, a sixth of a 176px band,
     spent on a label that only exists in demo play, while the board sat under
     its floor. The notch keeps its place and overlaps the brand bar, which
     has room for it. Two classes on purpose -- .shell.is-demo is what sets
     the variable, and a single .shell in a media query loses to it, which is
     why the first attempt moved the board by 2px instead of 28. */
  .shell.is-demo {
    --fun-mode-height: 0px;
  }
  .shell .shell-board {
    min-height: var(--plot-min-h-land, 56px);
  }
  .shell .price-header {
    display: none;
  }
  .shell .topbar {
    padding-top: 2px;
  }
  /* The round state shares the brand bar's line instead of taking one of its
     own: in a band the header has room for one row, and the timer is narrow.
     The header is already a block, so the two sit side by side in it. */
  .shell .shell-header {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .shell .topbar {
    flex: 1 1 auto;
    min-width: 0;
    padding-top: 0;
  }
  .shell .stages {
    flex: 0 1 46%;
    min-width: 0;
    height: 28px;
    margin-bottom: 0;
  }
  /* the other header blocks are out in a band: the price rides in the plot,
     and an empty notice slot must not take a place in the row */
  .shell .notice-row {
    flex: 0 0 auto;
    width: auto;
    max-width: 30%;
    margin-top: 0;
  }
  /* The notice row reserves 24px + 4px for a message that is usually absent
     (it is only visibility: hidden, so the space stands empty). In a band that
     is the margin between the stake fitting and not: let it take its height
     only when it has something to say. A standing notice is money news -- the
     wallet refused, the session ended -- so it still gets its row then. */
  .notice-row:disabled {
    display: none;
  }
  /* The stake rack stacks its stepper over its chips (98px measured), which in
     a 176px band left the chips below the fold -- reachable only by scrolling
     the column, and a bet the player must scroll to is the whole defect. Side
     by side they fit the one row the band has: the stepper takes the width it
     needs, the chips wrap in what is left. */
  .shell .shell-controls {
    padding-right: 2px;
    overflow-y: auto;
  }
  .shell .stake-rack {
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    gap: 4px;
    margin-bottom: 2px;
  }
  /* the stepper asks for the whole column by default, which pushed the chips
     onto a second row and out of the band: here it takes only what it needs */
  .shell .stake-stepper {
    flex: 0 1 auto;
    min-width: 0;
  }
  .shell .stake-step {
    min-width: 34px;
  }
  /* The stake rack has to fit one short row beside the board. Stacked, its
     chips hung 134px into a 104px column; on one line, the last two ran 29 and
     83px past the right edge of a 750px band. So in a band the rack is the
     stepper on top and the chips under it, each row full width, and the chips
     share the width they have instead of keeping their natural size. */
  .shell .stake-rack {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 2px;
    margin-bottom: 0;
  }
  .shell .stake-stepper {
    flex: 0 0 auto;
    width: 100%;
  }
  .shell .stake-chips {
    display: flex;
    flex: 0 0 auto;
    flex-wrap: nowrap;
    gap: 3px;
    min-width: 0;
    width: 100%;
  }
  /* kit.css gives a chip min-height: 42px, and a min-height beats a smaller
     height -- which is why trimming the height alone kept leaving a few
     pixels over the frame. The floor has to come down with it. */
  .shell .stake-chip {
    flex: 1 1 0;
    min-width: 0;
    height: 30px;
    min-height: 0;
    padding-left: 2px;
    padding-right: 2px;
    font-size: 13px;
  }
  /* 48px of stepper plus 42px of chips is more than a band's column has: the
     stake field stays the widest, tappable thing in the row, just not as tall
     as it is on a phone held upright. */
  .shell .stake-step,
  .shell .stake-field,
  .shell .stake-field input {
    height: 34px;
    min-height: 0;
  }
  /* the gaps between the three control rows, last: Pulse stacks a leverage
     row the other four games do not have, and without this its chips end 9px
     below a 176px band */
  .shell .levtabs {
    margin-bottom: 2px;
  }
  .shell .shell-controls {
    padding-bottom: 0;
  }
}
