/* ============================================================================
   3D WORD SCRAMBLE — game-specific layer
   ----------------------------------------------------------------------------
   Only the play stage is styled here. The site top bar, breadcrumb and the
   fixed game sidebar are shared chrome and deliberately untouched: this sheet
   adds the in-stage HUD, the coach mark, the slot legend, the floating score
   labels and the completion recap.

   Visual language mirrors the shared newspaper system in unified-3d-game.css
   (paper surfaces, ink text, square corners, hard offset shadows) so the
   scramble reads as the same product as the other eight 3D games.
   ========================================================================= */

/* The stage is the positioning context for every HUD layer. */
#gameContainer {
  --ws3d-chip: 48px;
}

/* ---------------------------------------------------------------------------
   1. CANVAS — pointer ownership and focus
   ------------------------------------------------------------------------ */

/* The canvas owns every gesture inside the frame: block drags, camera orbit
   and pinch zoom. touch-action:none stops the browser from stealing a drag as
   a scroll, and `cursor` communicates the two affordances. */
#gameContainer #canvas {
  touch-action: none;
  outline: none;
}

#gameContainer #canvas:focus-visible {
  outline: 3px solid var(--news-accent);
  outline-offset: -3px;
}

/* ---------------------------------------------------------------------------
   2. TARGET WORD PANEL
   The shared .word-panel styling (wordladder3d.css) is kept, but the panel is
   tightened so it never covers the letter yard on short viewports.
   ------------------------------------------------------------------------ */

#gameContainer .word-display-overlay-top {
  top: 12px;
}

#gameContainer .word-panel {
  min-width: 210px;
  padding: 8px 16px 9px;
  box-shadow: var(--shadow-hard);
}

#gameContainer .word-panel-label {
  margin-bottom: 0;
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
}

#gameContainer .target-word {
  font-size: clamp(1.5rem, 3.4vw, 2.5rem);
  line-height: 1.1;
  letter-spacing: 0.22em;
  /* The letter-spacing adds a trailing gap; pull the word back to optical
     centre so it sits dead centre under the label. */
  text-indent: 0.22em;
}

/* One span per letter, so the panel ticks letters off as they land. */
.ws3d-tw-letter {
  display: inline-block;
  transition: color 220ms ease, transform 220ms ease;
}

.ws3d-tw-letter.is-placed {
  color: var(--ws3d-correct);
  transform: translateY(-0.08em);
}

/* Solved state: the panel flips from accent to the success ink. */
#gameContainer .word-panel.is-solved .target-word {
  color: var(--news-correct);
}

/* ---------------------------------------------------------------------------
   3. PROGRESS RAIL — sits directly under the target word panel
   ------------------------------------------------------------------------ */

/* Sits INSIDE .word-panel, so the track and its labels are ink-on-paper in
   both themes (previously the labels used paper-ink tokens straight onto the
   dark canvas and measured 1.06:1 in light theme). */
.ws3d-progress {
  width: 100%;
  margin-top: 8px;
  pointer-events: none;
}

.ws3d-progress-track {
  position: relative;
  height: 7px;
  background: var(--news-bg);
  border: 1px solid var(--news-rule-light);
  overflow: hidden;
}

.ws3d-progress-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  background: repeating-linear-gradient(
    135deg,
    var(--news-accent) 0 6px,
    color-mix(in srgb, var(--news-accent) 72%, var(--news-paper)) 6px 12px
  );
  transition: width 320ms cubic-bezier(0.22, 1, 0.36, 1);
}

.ws3d-progress-meta {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 4px;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--news-ink-light);
}

.ws3d-progress-meta strong {
  color: var(--news-ink);
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   4. HUD CHIP ROW — Undo / Shuffle / Sound
   Thumb-zone anchored bottom-left, clear of the shared help FAB (bottom-right)
   and the mobile timer pill (top-right).
   ------------------------------------------------------------------------ */

/* --ws3d-inset-* are published by the game module from the canvas rectangle,
   so the chips align to the picture rather than to the frame that contains it
   (at 1920 the chip row used to bleed ~3px over the double rule). */
.ws3d-hud {
  position: absolute;
  left: calc(var(--ws3d-inset-x, 10px) + 10px);
  bottom: calc(var(--ws3d-inset-bottom, 10px) + 8px);
  display: flex;
  gap: 8px;
  z-index: 45;
}

.ws3d-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-width: var(--ws3d-chip);
  height: var(--ws3d-chip);
  padding: 0 14px;
  font-family: var(--news-font-body);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--news-ink);
  background: var(--news-paper);
  border: 2px solid var(--news-ink);
  border-radius: 0;
  box-shadow: var(--shadow-hard);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 120ms ease, background 120ms ease, color 120ms ease;
}

.ws3d-chip svg {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.ws3d-chip:hover:not(:disabled) {
  background: var(--news-highlight);
}

.ws3d-chip:active:not(:disabled) {
  transform: translate(1px, 1px);
  box-shadow: none;
}

.ws3d-chip:focus-visible {
  outline: 3px solid var(--news-accent);
  outline-offset: 2px;
}

.ws3d-chip:disabled {
  opacity: 0.42;
  cursor: not-allowed;
  box-shadow: var(--shadow-hard);
}

.ws3d-chip.is-active {
  background: var(--news-active-bg);
  color: var(--news-paper);
  border-color: var(--news-active-bg);
}

.ws3d-chip-label {
  display: none;
}

/* Labels only where the row fits the stage: on a 820 px tablet the four
   labelled chips overran the canvas edge by 49 px and the last one tucked 8 px
   under the fixed sidebar. */
@media (min-width: 1024px) {
  .ws3d-chip-label {
    display: inline;
  }
}

/* ---------------------------------------------------------------------------
   5. LIVE REGION / TOAST
   The sidebar has no room for a verbose status line and is shared chrome, so
   the play-by-play lives here. It is a polite live region for screen readers.
   ------------------------------------------------------------------------ */

.ws3d-toast {
  position: absolute;
  left: 50%;
  /* Sits above the HUD chip row rather than beside it: the chips are a fixed
     width, so a centred toast eventually collided with them on narrow
     desktops. It is pointer-events:none, so a brief overlap with the yard is
     harmless. */
  bottom: calc(var(--ws3d-inset-bottom, 10px) + 70px);
  transform: translateX(-50%) translateY(6px);
  max-width: min(520px, calc(100% - 32px));
  padding: 9px 16px;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--news-paper);
  background: var(--news-ink);
  border: 2px solid var(--news-ink);
  box-shadow: var(--shadow-hard);
  opacity: 0;
  visibility: hidden;
  transition: opacity 160ms ease, transform 160ms ease, visibility 160ms ease;
  z-index: 46;
  pointer-events: none;
  text-align: center;
}

/* While the first-run coach mark is open the toast stacks above it, offset by
   the coach's measured height (it wraps to two lines plus a button on
   phones). --ws3d-coach-h is published by the game module. */
#gameContainer.has-coach .ws3d-toast {
  bottom: calc(var(--ws3d-inset-bottom, 10px) + 88px + var(--ws3d-coach-h, 0px));
}

.ws3d-toast.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

.ws3d-toast.is-error {
  background: var(--news-incorrect);
  border-color: var(--news-incorrect);
  color: #fff;
}

/* Screen-reader-only narration of gameplay events. */
.ws3d-sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------------
   6. FLOATING SCORE LABELS (projected from 3D slot positions)
   ------------------------------------------------------------------------ */

.ws3d-floater {
  position: fixed;
  transform: translate(-50%, -50%);
  font-family: var(--news-font-display);
  font-size: 1.25rem;
  font-weight: 900;
  color: var(--news-correct);
  text-shadow: 0 2px 0 var(--news-paper), 0 0 10px var(--news-paper);
  pointer-events: none;
  z-index: 44;
  animation: ws3dFloater 900ms cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
}

.ws3d-floater.is-penalty {
  color: var(--news-incorrect);
}

@keyframes ws3dFloater {
  0% { opacity: 0; transform: translate(-50%, -30%) scale(0.7); }
  25% { opacity: 1; transform: translate(-50%, -50%) scale(1.08); }
  100% { opacity: 0; transform: translate(-50%, -140%) scale(1); }
}

/* ---------------------------------------------------------------------------
   7. COMBO / STREAK BADGE
   ------------------------------------------------------------------------ */

.ws3d-combo {
  position: absolute;
  top: 168px;
  left: 50%;
  transform: translateX(-50%) scale(0.8);
  padding: 5px 14px;
  font-family: var(--news-font-display);
  font-size: 0.9375rem;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* Success colour, not the accent red: a reward badge sitting next to a red
     error toast read as a second alert. */
  color: var(--ws3d-on-correct);
  background: var(--ws3d-correct);
  border: 2px solid var(--news-ink);
  box-shadow: var(--shadow-hard);
  opacity: 0;
  visibility: hidden;
  transition: opacity 180ms ease, transform 180ms ease, visibility 180ms ease;
  z-index: 44;
  pointer-events: none;
}

.ws3d-combo.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) scale(1);
}

/* ---------------------------------------------------------------------------
   8. FIRST-RUN COACH MARK
   ------------------------------------------------------------------------ */

/* The coach is an opaque DOM layer over the canvas. Without this a drag that
   started on the card never reached the board at all. Only the dismiss button
   is interactive; a tap anywhere on the board also dismisses it. */
.ws3d-coach {
  pointer-events: none;
  position: absolute;
  left: 50%;
  bottom: calc(var(--ws3d-inset-bottom, 10px) + 74px);
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 12px;
  width: max-content;
  max-width: min(620px, calc(100% - 24px));
  padding: 10px 14px;
  background: var(--news-paper);
  border: 2px solid var(--news-ink);
  box-shadow: var(--shadow-hard-lg);
  z-index: 47;
  transition: opacity 220ms ease, transform 220ms ease;
}

.ws3d-coach[hidden] {
  display: none;
}

.ws3d-coach-text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.875rem;
  line-height: 1.4;
  color: var(--news-ink);
}

.ws3d-coach-text strong {
  font-weight: 800;
}

.ws3d-coach-dismiss {
  pointer-events: auto;
  flex: 0 0 auto;
  padding: 7px 12px;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--news-paper);
  background: var(--news-ink);
  border: 2px solid var(--news-ink);
  cursor: pointer;
}

.ws3d-coach-dismiss:focus-visible {
  outline: 3px solid var(--news-accent);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   9. LOADING / ERROR VEIL
   ------------------------------------------------------------------------ */

.ws3d-veil {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 24px;
  text-align: center;
  background: color-mix(in srgb, var(--news-bg) 88%, transparent);
  z-index: 60;
  transition: opacity 200ms ease, visibility 200ms ease;
}

.ws3d-veil[hidden] {
  display: none;
}

.ws3d-veil-title {
  font-family: var(--news-font-display);
  font-size: 1.25rem;
  font-weight: 900;
  color: var(--news-ink);
}

.ws3d-veil-copy {
  max-width: 420px;
  font-size: 0.9375rem;
  color: var(--news-ink-light);
}

.ws3d-spinner {
  width: 34px;
  height: 34px;
  border: 3px solid var(--news-rule-light);
  border-top-color: var(--news-accent);
  border-radius: 50%;
  animation: ws3dSpin 800ms linear infinite;
}

@keyframes ws3dSpin {
  to { transform: rotate(360deg); }
}

.ws3d-retry {
  padding: 10px 20px;
  font: inherit;
  font-weight: 700;
  color: var(--news-paper);
  background: var(--news-ink);
  border: 2px solid var(--news-ink);
  cursor: pointer;
}

/* ---------------------------------------------------------------------------
   10. KEYBOARD LEGEND — shown when the canvas holds focus
   ------------------------------------------------------------------------ */

.ws3d-keys {
  position: absolute;
  right: calc(var(--ws3d-inset-x, 10px) + 10px);
  bottom: calc(var(--ws3d-inset-bottom, 10px) + 8px);
  padding: 8px 12px;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--news-ink-light);
  background: var(--news-paper);
  border: 1px solid var(--news-rule-light);
  box-shadow: var(--shadow-hard);
  opacity: 0;
  visibility: hidden;
  transition: opacity 160ms ease, visibility 160ms ease;
  z-index: 44;
  pointer-events: none;
  max-width: 260px;
}

.ws3d-keys.is-visible {
  opacity: 1;
  visibility: visible;
}

.ws3d-keys kbd {
  display: inline-block;
  min-width: 18px;
  padding: 0 4px;
  font-family: var(--font-family-mono);
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--news-ink);
  background: var(--news-bg);
  border: 1px solid var(--news-rule-light);
  text-align: center;
}

/* ---------------------------------------------------------------------------
   11. COMPLETION RECAP
   ------------------------------------------------------------------------ */

#completionModal .modal-dialog {
  max-width: 460px;
}

/* The shared dark-theme dialog shadow is rgba(0,0,0,.35) on a #15141a page —
   invisible. A paper rule keeps the dialog separated from the backdrop. */
html[data-theme='dark'] #completionModal .modal-dialog {
  border: 2px solid var(--news-ink);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6), 10px 10px 0 rgba(0, 0, 0, 0.55);
}

.ws3d-recap-word {
  font-family: var(--news-font-display);
  font-size: 1.75rem;
  font-weight: 900;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--news-accent);
  margin-bottom: 4px;
}

.ws3d-stars {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin: 14px 0 6px;
  font-size: 2.25rem;
  line-height: 1;
}

/* The row is complete from the first frame — three muted stars — and the
   earned ones turn gold in sequence. Starting from opacity:0 made the rating
   look empty for the first few hundred milliseconds. */
.ws3d-star {
  color: var(--news-rule-light);
  opacity: 1;
  transform: scale(0.92);
  transition: transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1), color 200ms ease;
}

.ws3d-star.is-earned {
  color: #d8a12a;
  transform: scale(1.06);
}

.ws3d-recap-banner {
  margin: 6px auto 0;
  padding: 5px 14px;
  display: inline-block;
  font-size: 0.8125rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--news-paper);
  background: var(--news-correct);
  border: 2px solid var(--news-ink);
  box-shadow: var(--shadow-hard);
}

.ws3d-recap-grid {
  display: grid;
  /* Four stats, one row: a three-column grid left a lone cell beside two
     empty tracks, which read as a rendering fault. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  margin: 18px 0;
  background: var(--news-rule-light);
  border: 1px solid var(--news-rule-light);
}

.ws3d-recap-cell {
  padding: 10px 6px;
  background: var(--news-paper);
  text-align: center;
}

.ws3d-recap-label {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--news-ink-muted);
}

.ws3d-recap-value {
  margin-top: 2px;
  font-family: var(--news-font-display);
  font-size: 1.25rem;
  font-weight: 900;
  color: var(--news-ink);
  font-variant-numeric: tabular-nums;
}

.ws3d-recap-best {
  margin-top: 10px;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--news-correct);
}

.ws3d-recap-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 16px;
}

.ws3d-recap-actions .btn {
  min-height: 46px;
}

/* ---------------------------------------------------------------------------
   12. MOBILE
   ------------------------------------------------------------------------ */

/* The collapsed mobile bottom sheet keeps its padding and top rule even at
   max-height: 0, leaving a dead strip across the bottom of the stage. */
body.game-3d-wrapper .game-sidebar:not(.menu-open) {
  padding: 0;
  border-top-width: 0;
  box-shadow: none;
}

@media (max-width: 768px) {
  #gameContainer {
    --ws3d-chip: 52px;
  }

  .ws3d-chip {
    padding: 0 12px;
  }

  /* Icon-only chips: 52px is a comfortable thumb target and keeps the row
     clear of the 68px help FAB parked bottom-right. */
  .ws3d-hud {
    gap: 7px;
  }

  /* 10px was below the 12px floor for the only numeric progress readout. */
  .ws3d-progress-meta {
    font-size: 0.75rem;
  }

  #gameContainer .word-panel-label,
  .ws3d-recap-label {
    font-size: 0.75rem;
  }

  .ws3d-toast {
    max-width: calc(100% - 24px);
    font-size: 0.8125rem;
  }

  .ws3d-combo {
    top: 150px;
  }

  .ws3d-keys {
    display: none;
  }

  /* Stack the coach on narrow screens: side by side, the copy column gets
     squeezed to a few characters per line and the card becomes a tower. */
  .ws3d-coach {
    bottom: calc(var(--ws3d-inset-bottom, 10px) + 78px);
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 10px 12px;
  }

  .ws3d-coach-text {
    font-size: 0.8125rem;
  }

  .ws3d-coach-dismiss {
    align-self: flex-end;
  }

  .ws3d-recap-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------------------------------------------------------------------------
   13. REDUCED MOTION
   ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .ws3d-progress-fill,
  .ws3d-star,
  .ws3d-toast,
  .ws3d-combo {
    transition-duration: 1ms !important;
  }

  .ws3d-floater {
    animation-duration: 1ms !important;
  }

  .ws3d-spinner {
    animation-duration: 2s !important;
  }
}

/* ---------------------------------------------------------------------------
   14. SCOPED CONTRAST CORRECTIONS

   Two shared-token defects are worked around here rather than in the shared
   sheets, because this file only loads on this page:

   · `--news-correct` (#5a8a4a) measures 3.94:1 on the light theme's paper
     surface, under the 4.5:1 WCAG 2.2 AA floor for the small text it is used
     for (the sidebar status line, the "new best time" line and the flawless
     banner). A slightly darker green keeps the hue at 4.9:1.
   · `#difficultySelect` in the shared sidebar suppresses the outline and adds
     no replacement, so it had no keyboard focus indicator at all.
   ------------------------------------------------------------------------ */

:root {
  --ws3d-correct: var(--news-correct);
  /* Ink that sits ON the success colour. White on the dark theme's bright
     green measured 1.83:1, the worst ratio measured anywhere in this product. */
  --ws3d-on-correct: #16141c;
}

html[data-theme='light'] {
  --ws3d-correct: #4a7a3c;
  --ws3d-on-correct: #ffffff;
}

#message.game-message-success,
#message.game-message-ready,
.ws3d-recap-best,
.ws3d-floater {
  color: var(--ws3d-correct);
}

.ws3d-recap-banner {
  background: var(--ws3d-correct);
  color: var(--ws3d-on-correct);
}

.ws3d-toast.is-success {
  background: var(--ws3d-correct);
  border-color: var(--ws3d-correct);
  color: var(--ws3d-on-correct);
}

.ws3d-progress.is-complete .ws3d-progress-fill {
  background: var(--ws3d-correct);
}

#difficultySelect:focus-visible {
  outline: 3px solid var(--news-accent);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   15. PLATFORM OVERRIDES SCOPED TO THIS PAGE

   Two shared-layout behaviours break the game on real devices. Both are
   corrected here rather than in the shared sheets, so the other eight 3D games
   are untouched:

   · `@media (hover:none) and (pointer:coarse) { .game-sidebar { width:100% } }`
     in unified-3d-game.css makes the fixed sidebar cover the entire viewport on
     any touch device wider than the 768px breakpoint — an iPad, or a phone in
     landscape. Measured: 100% of the canvas covered at 820x1180, 51.5% at
     844x390, with 0 of 7 letter blocks reachable.
   · On a short viewport the shared `min-height: 300px` on the stage pushes the
     HUD chip row below the fold, and the canvas' `touch-action: none` makes the
     page hard to scroll to reach it. Shrinking the stage floor keeps the whole
     play area AND its controls inside the viewport.
   ------------------------------------------------------------------------ */

@media (hover: none) and (pointer: coarse) and (min-width: 769px) {
  body.game-3d-wrapper .game-sidebar {
    width: 300px !important;
  }
}

@media (max-height: 620px) {
  body.game-3d-wrapper .game-canvas-container {
    min-height: 170px !important;
  }
}

/* ---------------------------------------------------------------------------
   16. SHORT VIEWPORTS (landscape phones)

   The shared framed stage is only ~190 px tall on a 390 px-tall phone, and the
   target card is opaque — at full size it sat directly over the letter yard and
   nothing could be picked up. Everything in the stage goes compact: the card
   loses its label and its numeric readout, and the chips shrink to icons.
   ------------------------------------------------------------------------ */

@media (max-height: 620px) {
  #gameContainer .word-display-overlay-top {
    top: 6px;
  }

  #gameContainer .word-panel {
    min-width: 140px;
    padding: 4px 10px 5px;
  }

  #gameContainer .word-panel-label,
  .ws3d-progress-meta {
    display: none;
  }

  #gameContainer .target-word {
    font-size: 1.25rem;
    letter-spacing: 0.16em;
    text-indent: 0.16em;
  }

  .ws3d-progress {
    margin-top: 4px;
  }

  .ws3d-chip {
    height: 40px;
    min-width: 40px;
    padding: 0 9px;
  }

  .ws3d-chip-label {
    display: none;
  }

  .ws3d-keys,
  .ws3d-coach {
    display: none;
  }

  .ws3d-toast {
    font-size: 0.75rem;
  }

}

/* Narrow phones: four 52 px chips plus gaps ran into the 68 px help FAB parked
   bottom-right (82% of the Sound chip was under it at 320x568, and a real touch
   opened Help instead of toggling sound). */
@media (max-width: 420px) {
  /* Two rows of two keeps the row clear of the 68 px help FAB parked
     bottom-right, which it otherwise fouls by up to 82% of a chip on a 320 px
     screen. */
  .ws3d-hud {
    display: grid;
    grid-template-columns: repeat(2, 44px);
    gap: 6px;
  }

  #gameContainer .ws3d-chip {
    height: 44px;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    justify-content: center;
  }

  /* The toast used to be drawn straight over the grid's top-right cell. */
  .ws3d-toast {
    bottom: calc(var(--ws3d-inset-bottom, 10px) + 112px);
  }
}

/* ---------------------------------------------------------------------------
   17. LANDSCAPE PHONES — the chips move to a side grid

   On a 390 px-tall viewport the shared header takes ~200 px and the framed
   stage yields a canvas of only ~232x144. Reserve a 44 px chip row at the
   bottom of that and the board is left a 32 px band — 7 px cubes, which is not
   playable. Treated as a 2x2 grid pinned to the left edge the same four chips
   cost width instead of height, and the board — which is wide and shallow —
   gets roughly 2.5x the cube size for the same 38 px touch targets.
   ------------------------------------------------------------------------ */

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

  /* THE big one. Above the 768 px breakpoint the shared framed stage caps its
     width at `min(100% - 300px sidebar - gutters, (100vh - header) * 1.5)` and
     translates itself by half the sidebar, which on an 844x390 phone yields a
     232x144 canvas — 1.9x smaller than the SAME viewport gets below the
     breakpoint, where the stage is full-bleed. Taking the stage full-bleed here
     (the override already used for the sidebar and the stage min-height, both
     page-scoped) takes the letter cubes from ~18 px to ~34 px and gives the
     board room to clear the chips entirely. The header and top bar are
     untouched. */
  body.game-3d-wrapper .game-canvas-container {
    width: auto !important;
    height: calc(100dvh - var(--site-header-height, 80px) - 16px) !important;
    height: calc(100vh - var(--site-header-height, 80px) - 16px) !important;
    min-height: 150px !important;
    margin: 4px 6px 0 !important;
    translate: none !important;
    padding: 6px !important;
    border-width: 2px !important;
    box-shadow: var(--shadow-hard) !important;
  }

  .ws3d-hud {
    left: calc(var(--ws3d-inset-x, 8px) + 8px);
    top: 50%;
    bottom: auto;
    transform: translateY(-50%);
    display: grid;
    grid-template-columns: repeat(2, 44px);
    gap: 6px;
  }

  /* body.ui-touch button (0,1,2) otherwise forces 44x44 with 10/14 padding
     inside the tracks; the id gives these rules the specificity to win. */
  #gameContainer .ws3d-chip {
    height: 44px;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    justify-content: center;
  }

  #gameContainer .ws3d-chip svg {
    width: 18px;
    height: 18px;
  }
}

/* ---------------------------------------------------------------------------
   18. LANDSCAPE NUDGE

   On a 390 px-tall phone the board is height-limited: portrait gives roughly
   2.7x the letter-cube size. Nothing in the landscape layout makes that
   discoverable, so a one-line hint says it once, without taking layout space.
   ------------------------------------------------------------------------ */

.ws3d-rotate-hint {
  display: none;
  position: absolute;
  right: calc(var(--ws3d-inset-x, 8px) + 14px);
  top: calc(var(--ws3d-inset-bottom, 8px) + 12px);
  max-width: 46%;
  padding: 6px 10px;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--news-ink);
  background: var(--news-paper);
  border: 1px solid var(--news-rule-light);
  box-shadow: var(--shadow-hard);
  pointer-events: none;
  z-index: 46;
}

.ws3d-rotate-hint[hidden] {
  display: none !important;
}
