/**
 * Platform chrome: page shell, loading state and the shared completion reveal.
 *
 * State is driven by `data-pd-state` and `data-pd-phase` on <body>, written
 * only by platform/shell.js. Games never set these; they call
 * `context.ready()` and `context.setPhase()`.
 */

body.pd-game {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  background: transparent;
}

.pd-game-root {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  min-height: 280px;
  background: transparent;
}

/* Loading: paint a solid page colour (not transparent â€” iOS PWA otherwise
   shows a grey webview canvas underneath). */
body.pd-game[data-pd-state="loading"],
body.pd-game:not(.pd-content-ready) {
  background: var(--pd-colour-background, #fff) !important;
  background-color: var(--pd-colour-background, #fff) !important;
}

.pd-game-root > * {
  width: 100%;
  max-width: 100%;
}

body.pd-game .content,
body.pd-game .hl-content {
  margin-left: auto;
  margin-right: auto;
}

/* Completion: unlock document scroll and let the shell grow with results.
   Do not force min-height:0 on every child â€” that breaks games like The Middle
   that size their content with min-height. */
html.pd-done,
body.pd-done,
html:has(> body.pd-game .is-done),
body.pd-game:has(.is-done) {
  height: auto !important;
  max-height: none !important;
  min-height: 100dvh !important;
  overflow-x: hidden !important;
  overflow-y: auto !important;
  /* Beat leftover modal touch-action:none if a class races on close. */
  touch-action: manipulation !important;
}

body.pd-done .pd-game-root,
body.pd-game:has(.is-done) .pd-game-root {
  flex: none !important;
  min-height: auto !important;
  height: auto !important;
  overflow: visible !important;
  width: 100%;
}

body.pd-done .pd-play-area,
body.pd-done .content,
body.pd-done .game-shell,
body.pd-done .container,
body.pd-done .hl-content,
body.pd-done .hl-shell,
body.pd-done .hsf-content,
body.pd-done .hsf-shell,
body.pd-done .hx-content,
body.pd-done .hx-shell,
body.pd-game:has(.is-done) .pd-play-area,
body.pd-game:has(.is-done) .content,
body.pd-game:has(.is-done) .game-shell,
body.pd-game:has(.is-done) .container,
body.pd-game:has(.is-done) .hl-content,
body.pd-game:has(.is-done) .hl-shell,
body.pd-game:has(.is-done) .hsf-content,
body.pd-game:has(.is-done) .hsf-shell,
body.pd-game:has(.is-done) .hx-content,
body.pd-game:has(.is-done) .hx-shell {
  flex: none !important;
  height: auto !important;
  max-height: none !important;
  overflow: visible !important;
}

/* --- Loading ------------------------------------------------------------ */

/*
  Hold the game under the chrome until saved progress is restored, then slide
  it up as ONE block (welcome, board + completion, etc). Target `main` only â€”
  not every `.pd-game-root > *` â€” so fixed modal overlays are not transformed
  (that would break position:fixed) and the grid does not rise apart from results.
*/
body[data-pd-state="loading"] .pd-game-root > main {
  opacity: 0;
  transform: translateY(22px);
  pointer-events: none;
}

body[data-pd-state="ready"] .pd-game-root > main {
  animation: pd-game-enter 0.42s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* iOS replays CSS animations when body leaves position:fixed (sheet unlock).
   After the first enter â€” or once results are up â€” keep main painted. */
body[data-pd-state="ready"].pd-enter-settled .pd-game-root > main,
body[data-pd-state="ready"].pd-done .pd-game-root > main,
body[data-pd-state="ready"]:has(.is-done) .pd-game-root > main {
  animation: none;
  opacity: 1;
  transform: none;
}

/* Content is held via opacity until ready(); no shared page spinner. */

@keyframes pd-game-enter {
  from {
    opacity: 0;
    transform: translateY(22px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* --- Completion reveal -------------------------------------------------- */

/*
  Shared across every game: completion lines rise together when `.is-shown`.
  Games opt in by marking children `.pd-c-line`.
*/
.pd-complete .pd-c-line {
  opacity: 0;
}

.pd-complete.is-shown .pd-c-line {
  animation: pd-rise-in 0.5s var(--pd-ease-rise) both;
  animation-delay: 0s;
}

@keyframes pd-rise-in {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* --- Play stage --------------------------------------------------------- */

/*
  During play the page is one screen tall and every game is drawn on a
  stage: `.pd-play-area`, laid out at a fixed design width and scaled as one
  piece by platform/fit-viewport.js to fit the zone around it (its parent,
  which fills the space between the banners). Text, icons and board keep the
  same proportions on every screen and in any partner frame.

  Inside the stage, size everything in px against the design width:
  no vw / vh / dvh, no width or height media queries, no env(). Those
  measure the screen, not the stage, and are what make a game look
  different from one device to the next. Safe-area and banner insets
  belong to the zone, outside the stage.

  On completion (`.pd-done` / `.is-done`) the same stage keeps the scale
  it was played at, applied with `zoom` instead so the results lay out
  for real and the page can scroll. Modal cards use the same zoom, so a
  sheet's text matches the game behind it.
*/
html {
  --pd-play-top: 62px;
  --pd-play-bottom: 16px;
  --pd-stage-width: 430px;
  --pd-stage-max-scale: 1;
}

/* No banners (partner frames): the zone runs almost edge to edge, so the
   game fills the frame top to bottom. */
html:has(> body.pd-game:not(.pd-has-ads)) {
  --pd-play-top: max(12px, env(safe-area-inset-top, 0px));
  --pd-play-bottom: 12px;
}

/* :has() cannot nest, and one invalid selector drops the whole list. */
html:has(> body.pd-game):not(.pd-done):not(:has(.is-done)),
body.pd-game:not(.pd-done):not(:has(.is-done)) {
  height: 100dvh !important;
  max-height: 100dvh !important;
  min-height: 0 !important;
}

body.pd-game:not(.pd-done):not(:has(.is-done)) {
  display: flex;
  flex-direction: column;
}

body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .content,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .game-shell,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .hl-content,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .hl-shell,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .hsf-content,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .hsf-shell,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .hx-content,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .hx-shell,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .rel-content,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .rel-shell,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .xw-content,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .xw-shell,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .mx-content,
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .mx-shell {
  flex: 1 1 auto;
  min-height: 0 !important;
  height: auto !important;
  max-height: none !important;
  display: flex !important;
  flex-direction: column;
  align-items: center;
  overflow: hidden !important;
}

body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root {
  width: 100%;
}

/* Zone: fills the space between the banners and centres the stage. The
   stage's layout box can be larger than the zone before it is scaled down;
   `clip` hides that without making the zone scrollable (a focused input
   must not scroll it sideways). */
body.pd-game:not(.pd-done):not(:has(.is-done)) :is(.pd-game-root, .pd-game-root *):has(> .pd-play-area) {
  justify-content: center !important;
  align-items: center !important;
  width: 100% !important;
  max-width: none !important;
  min-width: 0;
  padding: var(--pd-play-top) 0 max(var(--pd-play-bottom), env(safe-area-inset-bottom, 0px)) !important;
  box-sizing: border-box;
  overflow: hidden !important;
  overflow: clip !important;
}

/* Stage: design width, content height, scaled about its centre. Games keep
   their own padding and inner layout; the platform owns size and scale. */
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .pd-play-area {
  flex: none !important;
  align-self: center !important;
  width: var(--pd-stage-width) !important;
  min-width: var(--pd-stage-width) !important;
  max-width: var(--pd-stage-width) !important;
  height: auto !important;
  min-height: 0 !important;
  max-height: none !important;
  margin: 0 !important;
  display: flex !important;
  flex-direction: column;
  justify-content: flex-start !important;
  align-items: center;
  box-sizing: border-box;
  overflow: visible !important;
  transform-origin: 50% 50%;
  scale: var(--pd-stage-scale, 1);
}

/* A stage with a text field (`data-pd-keyboard`) sits at the top of the
   zone on touch screens, so the soft keyboard covers empty space rather
   than the game. */
@media (pointer: coarse) {
  body.pd-game:not(.pd-done):not(:has(.is-done)) :is(.pd-game-root, .pd-game-root *):has(> .pd-play-area[data-pd-keyboard]) {
    justify-content: flex-start !important;
  }
  body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-game-root .pd-play-area[data-pd-keyboard] {
    transform-origin: 50% 0;
  }
}

body.pd-game:not(.pd-done):not(:has(.is-done)) .game-screen.screen.active,
body.pd-game:not(.pd-done):not(:has(.is-done)) .hl-play,
body.pd-game:not(.pd-done):not(:has(.is-done)) .hx-play,
body.pd-game:not(.pd-done):not(:has(.is-done)) .xw-play,
body.pd-game:not(.pd-done):not(:has(.is-done)) .mx-play {
  flex: 0 0 auto;
  width: 100%;
  min-height: 0 !important;
  display: flex !important;
  flex-direction: column;
  justify-content: flex-start !important;
  align-items: center;
  padding-top: 0;
  padding-bottom: 0;
  box-sizing: border-box;
}

/* Stage children hug their content; the stage is as tall as they are. */
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-play-area > * {
  flex: 0 0 auto;
  height: auto;
  max-height: none;
  min-height: 0;
  width: 100%;
}

/* Tutorial skip sits in the play column; do not stretch it to 100%. */
body.pd-game:not(.pd-done):not(:has(.is-done)) .pd-play-area > :is(.tut-skip, .ws-tut-skip) {
  flex: 0 0 auto;
  align-self: center;
  width: fit-content;
  max-height: none;
}

/* Inner chrome already sits in the 62px play inset â€” don't add a second gap. */
body.pd-game .game-zanagrams .play-topbar,
body.pd-game .game-themiddle .container,
body.pd-game .game-crowdle .rel-shell,
body.pd-game .game-headlines .hsf-shell,
body.pd-game .game-sunflowers .game-area,
body.pd-game .game-wordsnake .container,
body.pd-game :is(.game-18words, .game-9words) .screen.active:not(#result) {
  padding-top: 0 !important;
  margin-top: 0 !important;
}

body.pd-game .game-wordsnake .game-content {
  margin-top: 0 !important;
}

body.pd-game:not(.pd-done):not(:has(.is-done)) :is(.game-18words, .game-9words) .game-screen.screen.active {
  flex: 0 0 auto !important;
  align-self: stretch !important;
  width: 100% !important;
  min-height: auto !important;
  overflow: visible !important;
  justify-content: flex-start !important;
}

body.pd-game:not(.pd-done):not(:has(.is-done)) :is(.game-18words, .game-9words) .w18-grid-slot {
  flex: 0 0 auto;
}

/* Completion: the zone keeps the play insets (so the burger does not jump)
   and the stage keeps the scale it was played at. It is applied as zoom,
   not scale, so the results take up real space and the page scrolls. */
body.pd-game.pd-done :is(.pd-game-root, .pd-game-root *):has(> .pd-play-area),
body.pd-game:has(.is-done) :is(.pd-game-root, .pd-game-root *):has(> .pd-play-area) {
  display: flex !important;
  flex-direction: column !important;
  align-items: center !important;
  width: 100% !important;
  max-width: none !important;
  min-width: 0;
  padding: var(--pd-play-top) 0 max(var(--pd-play-bottom), env(safe-area-inset-bottom, 0px)) !important;
  box-sizing: border-box;
}

body.pd-game.pd-done .pd-game-root .pd-play-area,
body.pd-game:has(.is-done) .pd-game-root .pd-play-area {
  flex: none !important;
  align-self: center !important;
  width: var(--pd-stage-width) !important;
  min-width: 0 !important;
  max-width: 100% !important;
  margin: 0 !important;
  padding-top: 0 !important;
  justify-content: flex-start !important;
  box-sizing: border-box;
  zoom: var(--pd-stage-scale, 1);
}

/* Sunflowers: the board stack hugs the garden. */
body.pd-game:not(.pd-done):not(:has(.is-done)) .game-sunflowers .game-area,
body.pd-game:not(.pd-done):not(:has(.is-done)) .game-sunflowers .play,
body.pd-game:not(.pd-done):not(:has(.is-done)) .game-sunflowers .board-slot,
body.pd-game:not(.pd-done):not(:has(.is-done)) .game-sunflowers .board-wrap {
  flex: 0 0 auto !important;
  height: auto !important;
  max-height: none;
  min-height: 0;
}
body.pd-game:not(.pd-done):not(:has(.is-done)) .game-sunflowers :is(.game-area, .play, .board-slot) {
  justify-content: flex-start !important;
}

/* Play timer + hide (eye-slash) control, next to the burger. */
.play-timer-row {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
}

.play-timer-row > .play-timer {
  margin: 0;
}

.play-timer-hide {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  margin: 0;
  padding: 6px 4px;
  background: none;
  border: none;
  cursor: pointer;
  color: #b8b8b4;
  -webkit-tap-highlight-color: transparent;
}

.play-timer-hide svg {
  width: 20px;
  height: 20px;
  display: block;
}

.play-timer-hide:focus,
.play-timer-hide:focus-visible {
  outline: none;
}

@media (hover: hover) {
  .play-timer-hide:hover {
    color: #8a8a86;
  }
}

/* Settings hide: collapse the top-bar timer so it does not leave a
   hole beside the menu. */
.timer-hidden .play-timer {
  display: none !important;
  pointer-events: none !important;
}

.is-done .play-timer-row,
.is-tutorial .play-timer-row {
  display: none !important;
}

/* --- Ad slots ----------------------------------------------------------- */
/*
  Empty placeholders on every play page (injected by chrome-boot.js).
  Change the colour and unit sizes here; breakpoints below decide which
  unit is on screen.

  Mobile (â‰¤768px): 320Ã—50 top and bottom, each in a full-bleed page-coloured
  row with 5px padding on the game-facing edge. The bottom row drops only
  when the viewport is â‰¤600px tall. That is the visible area after the
  address bar and toolbar, not the screen: an iPhone SE (667px screen,
  ~550px visible) loses the banner; a normal phone (~700px visible with
  the bars open) keeps it.
  Desktop: 728Ã—90 fixed to the bottom, plus side rails 20px from each edge.
  Rails are 300Ã—600 only while they sit clear of that banner (1368px and up).
  Narrower desktops use 160Ã—600. Rails sit 40px out from a 700px column
  (--pd-ad-from-game / --pd-ad-column-max) and are centred above the banner.
  Same height rule as phones: at 600px tall and below (a laptop with a short
  window, a phone on its side) there is no banner and no rails, so the game
  gets the whole height.

  TEMP (ads not live yet): slots stay in the DOM for layout, but are invisible.
  To show the grey placeholders + size labels again:
    1. --pd-ad-slot-bg: #d9d9d9 (light) and #2a2a28 (dark)
    2. Restore the ::after content strings below (320 Ã— 50 / 728 Ã— 90 /
       160 Ã— 600, and 300 Ã— 600 from 1368px up)
*/

html {
  --pd-ad-slot-bg: transparent; /* TEMP: was #d9d9d9 */
  --pd-ad-z: 160;
  --pd-ad-mobile-w: 320px;
  --pd-ad-mobile-h: 50px;
  --pd-ad-mobile-pad: 5px;
  --pd-ad-row-bg: var(--pd-colour-background, #fff);
  --pd-ad-label: #5c5c5c;
  --pd-ad-leaderboard-w: 728px;
  --pd-ad-leaderboard-h: 90px;
  --pd-ad-from-game: 40px;
  --pd-ad-column-max: 700px;
  --pd-ad-column: min(
    var(--pd-ad-column-max),
    calc(100vw - 2 * (var(--pd-ad-rail-w) + var(--pd-ad-from-game)))
  );
  --pd-ad-rail-slim-w: 160px;
  --pd-ad-rail-slim-h: 600px;
  --pd-ad-rail-wide-w: 300px;
  --pd-ad-rail-wide-h: 600px;
  --pd-ad-rail-w: var(--pd-ad-rail-slim-w);
  --pd-ad-rail-h: var(--pd-ad-rail-slim-h);
  --pd-ad-top-reserve: 0px;
  --pd-ad-bottom-reserve: 0px;
}

html[data-theme="dark"] {
  --pd-ad-slot-bg: transparent; /* TEMP: was #2a2a28 */
  --pd-ad-row-bg: var(--pd-colour-background, #141412);
  --pd-ad-label: #8e8e86;
}

.pd-ad {
  display: none;
  position: fixed;
  z-index: var(--pd-ad-z);
  box-sizing: border-box;
  background: var(--pd-ad-slot-bg);
  align-items: center;
  justify-content: center;
  color: var(--pd-ad-label);
  font-family: system-ui, sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  /* Empty until a creative is dropped in â€” don't eat taps on the board. */
  pointer-events: none;
}

.pd-ad:not(:empty) {
  pointer-events: auto;
}

/* TEMP: hide size labels. Restore:
   mobile-top / mobile-bottom â†’ "320 Ã— 50"
   leaderboard               â†’ "728 Ã— 90"
   rail                      â†’ "160 Ã— 600" */
.pd-ad--mobile-top::after,
.pd-ad--mobile-bottom::after,
.pd-ad--leaderboard::after,
.pd-ad--rail::after {
  content: none;
}

.pd-ad-row {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  z-index: var(--pd-ad-z);
  box-sizing: border-box;
  background: var(--pd-ad-row-bg);
  justify-content: center;
  align-items: center;
  pointer-events: none;
}

.pd-ad-row--top {
  top: 0;
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: var(--pd-ad-mobile-pad);
}

.pd-ad-row--bottom {
  bottom: 0;
  padding-top: var(--pd-ad-mobile-pad);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

.pd-ad--mobile-top,
.pd-ad--mobile-bottom {
  position: relative;
  width: var(--pd-ad-mobile-w);
  height: var(--pd-ad-mobile-h);
  max-width: calc(100vw - 8px);
  flex: 0 0 auto;
}

.pd-ad--leaderboard {
  left: 50%;
  transform: translateX(-50%);
  bottom: env(safe-area-inset-bottom, 0px);
  width: var(--pd-ad-leaderboard-w);
  height: var(--pd-ad-leaderboard-h);
  max-width: calc(100vw - 16px);
}

.pd-ad--rail {
  width: var(--pd-ad-rail-w);
  height: var(--pd-ad-rail-h);
  /* Vertical centre of the space above the bottom banner. */
  top: max(0px, calc((100dvh - var(--pd-ad-bottom-reserve) - var(--pd-ad-rail-h)) / 2));
}

.pd-ad--rail-left {
  left: max(0px, calc(50% - var(--pd-ad-column) / 2 - var(--pd-ad-from-game) - var(--pd-ad-rail-w)));
}

.pd-ad--rail-right {
  right: max(0px, calc(50% - var(--pd-ad-column) / 2 - var(--pd-ad-from-game) - var(--pd-ad-rail-w)));
}

/* Keep the board out from under the fixed units. */
body.pd-has-ads {
  padding-bottom: var(--pd-ad-bottom-reserve);
}

@media (max-width: 768px) {
  html {
    --pd-ad-top-reserve: calc(env(safe-area-inset-top, 0px) + var(--pd-ad-mobile-h) + var(--pd-ad-mobile-pad));
    --pd-ad-bottom-reserve: calc(var(--pd-ad-mobile-h) + var(--pd-ad-mobile-pad) + env(safe-area-inset-bottom, 0px));
    --pd-play-top: calc(var(--pd-ad-top-reserve) + 12px);
  }

  body.pd-has-ads .pd-ad-row--top,
  body.pd-has-ads .pd-ad-row--bottom {
    display: flex;
  }

  body.pd-has-ads .pd-ad--mobile-top,
  body.pd-has-ads .pd-ad--mobile-bottom {
    display: flex;
  }
}

/* Viewport height, after the browser bars â€” not the device screen.
   600px is about an iPhone SE's visible area (667px screen minus the
   address bar and toolbar). A normal phone stays above this with the
   bars open, so it keeps the bottom banner. */
@media (max-width: 768px) and (max-height: 600px) {
  html {
    --pd-ad-bottom-reserve: env(safe-area-inset-bottom, 0px);
  }

  body.pd-has-ads .pd-ad-row--bottom,
  body.pd-has-ads .pd-ad--mobile-bottom {
    display: none !important;
  }
}

/* Short phones turned sideways: no banners at all, like short, wide
   screens below. An upright short phone keeps its top banner. */
@media (max-width: 768px) and (max-height: 600px) and (orientation: landscape) {
  html {
    --pd-ad-top-reserve: 0px;
    --pd-play-top: max(16px, env(safe-area-inset-top, 0px));
  }

  body.pd-has-ads .pd-ad-row--top,
  body.pd-has-ads .pd-ad--mobile-top {
    display: none !important;
  }
}

@media (min-width: 769px) and (min-height: 601px) {
  html {
    --pd-ad-bottom-reserve: calc(var(--pd-ad-leaderboard-h) + env(safe-area-inset-bottom, 0px));
  }

  body.pd-has-ads .pd-ad--leaderboard,
  body.pd-has-ads .pd-ad--rail {
    display: flex;
  }

  body.pd-has-ads {
    padding-left: max(0px, calc(50% - var(--pd-ad-column) / 2));
    padding-right: max(0px, calc(50% - var(--pd-ad-column) / 2));
  }
}

/* Short, wide screens: no banners at all, so the game only needs a small
   gap above it. */
@media (min-width: 769px) and (max-height: 600px) {
  html {
    --pd-play-top: 16px;
  }
}

/* 300px rails clear the 728px banner only from this width up. */
@media (min-width: 1368px) {
  html {
    --pd-ad-rail-w: var(--pd-ad-rail-wide-w);
    --pd-ad-rail-h: var(--pd-ad-rail-wide-h);
  }

  body.pd-has-ads .pd-ad--rail::after {
    content: none; /* TEMP: was "300 Ã— 600" */
  }
}

/* --- Article under the game ---------------------------------------------
   Off unless platform/game-seo.js adds `pd-game-seo` after the puzzle is
   ready. Embeds and partner frames never get that class.

   The play lock sizes the board by making html/body 100dvh and letting
   `.pd-game-root` flex into the body's content box (100dvh minus the ad
   padding). Once the page can scroll, that flex share would shrink the
   board, so the root is pinned to that same content-box height and taken
   out of the flex grow. The article and footer are siblings after the
   root. They are display:none until then, so they take no space during
   the first fit.
   --------------------------------------------------------------------- */

body.pd-game > .pd-game-article,
body.pd-game > .pd-site-footer {
  display: none;
}

html.pd-game-seo:not(.pd-framed):has(> body.pd-game):not(.pd-done):not(:has(.is-done)),
body.pd-game.pd-game-seo:not(.pd-done):not(:has(.is-done)) {
  height: auto !important;
  max-height: none !important;
  min-height: 0 !important;
  overscroll-behavior-y: auto !important;
}

html.pd-game-seo:not(.pd-framed):has(> body.pd-game):not(.pd-done):not(:has(.is-done)) {
  overflow-x: hidden !important;
  overflow-y: auto !important;
}

body.pd-game.pd-game-seo:not(.pd-done):not(:has(.is-done)) {
  overflow: visible !important;
}

body.pd-game.pd-game-seo.pd-has-ads {
  --pd-seo-pad: var(--pd-ad-bottom-reserve);
}

body.pd-game.pd-game-seo:not(.pd-done):not(:has(.is-done)) .pd-game-root {
  flex: 0 0 auto !important;
  height: calc(100dvh - var(--pd-seo-pad, 0px)) !important;
  min-height: calc(100dvh - var(--pd-seo-pad, 0px)) !important;
  max-height: calc(100dvh - var(--pd-seo-pad, 0px)) !important;
  overflow: hidden !important;
}

/* Results may grow past the board. They must not shrink under it, or the
   article jumps up while the completion panel animates in. */
body.pd-game.pd-game-seo.pd-done .pd-game-root,
body.pd-game.pd-game-seo:has(.is-done) .pd-game-root {
  min-height: var(--pd-seo-play-height, calc(100dvh - var(--pd-seo-pad, 0px))) !important;
  height: auto !important;
  max-height: none !important;
  overflow: visible !important;
}

body.pd-game.pd-game-seo.pd-content-ready > .pd-game-article,
body.pd-game.pd-game-seo.pd-content-ready > .pd-site-footer {
  display: block;
  flex: 0 0 auto;
  width: 100%;
  max-width: none;
}

/* The banner reserve is padding on the body, so it shows up as a blank
   band under the footer. Pull the footer down over that band and paint it
   above the fixed banner (ads are 160). Menus stay above this. */
body.pd-game.pd-game-seo.pd-has-ads > .pd-site-footer {
  position: relative;
  z-index: 180;
  margin-bottom: calc(-1 * var(--pd-ad-bottom-reserve, 0px));
}

/* Side-rail padding insets the body so the board stays clear of the ads.
   The footer band still runs edge to edge. The columns stay on the same
   three-card measure as the homepage. */
@media (min-width: 769px) {
  body.pd-game.pd-game-seo.pd-content-ready.pd-has-ads > .pd-site-footer {
    box-sizing: border-box;
    flex: none;
    width: 100vw;
    max-width: 100vw;
  }
}

/* Fixed ad slots stay on the puzzle. Once the page moves, hide them so
   they do not cover the article. Visibility only â€” the reserve, and
   therefore the board height, stays put. */
body.pd-game-seo.pd-seo-scrolled .pd-ads {
  visibility: hidden;
  pointer-events: none;
}

.pd-game-article {
  margin-top: 100px;
  padding: 0 clamp(22px, 5vw, 48px) 8px;
  max-width: 100%;
  overflow-wrap: break-word;
  font-family: var(--pd-font-ui);
  color: var(--pd-colour-text);
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

.pd-game-article * {
  -webkit-user-select: text;
  user-select: text;
}

.pd-game-article-inner {
  width: 100%;
  max-width: 40rem;
  margin: 0 auto;
  padding-top: 24px;
  border-top: 1px solid color-mix(in srgb, var(--pd-colour-heading, #161613) 14%, transparent);
}

.pd-game-article h1 {
  margin: 0 0 16px;
  font-family: var(--pd-font-heading);
  font-size: clamp(2rem, 4.5vw, 2.65rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.02;
  color: var(--pd-colour-heading);
}

.pd-game-article .pd-game-dek {
  margin: 0 0 8px;
  font-size: clamp(1.12rem, 2.4vw, 1.28rem);
  font-weight: 500;
  line-height: 1.55;
  color: var(--pd-colour-text);
}

.pd-game-article h2 {
  margin: 40px 0 10px;
  font-family: var(--pd-font-heading);
  font-size: clamp(1.4rem, 2.8vw, 1.75rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--pd-colour-heading);
}

.pd-game-article h3 {
  margin: 22px 0 6px;
  font-family: var(--pd-font-heading);
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: var(--pd-colour-heading);
}

.pd-game-article p,
.pd-game-article li {
  font-size: clamp(1.05rem, 2.1vw, 1.15rem);
  font-weight: 500;
  line-height: 1.65;
}

.pd-game-article p {
  margin: 0 0 14px;
}

.pd-game-article ul {
  margin: 0 0 16px;
  padding-left: 1.2em;
}

.pd-game-article li + li {
  margin-top: 6px;
}

.pd-game-article a {
  color: var(--pd-colour-accent);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1.5px;
}

.pd-game-article a:hover {
  color: var(--pd-colour-accent-hover);
}

.pd-game-reading {
  margin-top: 36px;
  padding-top: 22px;
  border-top: 1px solid color-mix(in srgb, var(--pd-colour-heading, #161613) 12%, transparent);
}

.pd-game-reading ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.pd-game-reading li + li {
  margin-top: 8px;
}
