/*
 * layout.css - fitting every screen into the window, on every device.
 *
 * The rule the whole game follows: the GAME WINDOW NEVER SCROLLS. The page is
 * pinned to the viewport (no rubber-band, no address-bar drift), screens are
 * laid out to fit, and only an inner panel (a move list, a modal, a journal
 * page) may scroll inside its own box.
 *
 * Loaded after pap.css and touch.css.
 */

/* ---------------------------------------------------------- pinned page -- */

html, body { position: fixed; inset: 0; width: 100%; height: 100%; overflow: hidden; overscroll-behavior: none; }
#app { position: fixed; inset: 0; overflow: hidden; }
.pp-screen { overflow: hidden !important; overscroll-behavior: none; }

/* Inner panels that may scroll say so explicitly. */
.pp-overlay, .pp-book__page, .pp-match__left, .pp-match__right, .pp-moves { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }

/* ================================================================ match == */

/* ----------------------------------------- landscape tablets and phones -- */
@media (orientation: landscape) and (max-width: 1100px), (orientation: landscape) and (max-height: 620px) {
  .pp-match {
    --rail: clamp(180px, 26vw, 300px);
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: stretch; gap: 8px;
    padding: 6px max(8px, env(safe-area-inset-right)) max(6px, env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left));
  }
  .pp-match__board {
    align-self: center;
    --frame-w: min(calc(100vh - 12px), calc(100vw - 2 * var(--rail) - 40px));
    --frame-w: min(calc(100dvh - 12px), calc(100vw - 2 * var(--rail) - 40px));
  }
  .pp-lesson .pp-match__board {
    --frame-w: min(calc(100dvh - var(--hud-h, 56px) - 12px), calc(100vw - 2 * var(--rail) - 40px));
  }
  .pp-match__left, .pp-match__right { min-height: 0; max-width: none; gap: 6px; }
  .pp-match .pp-panel { padding: 6px 10px; flex: none; }
  .pp-match .pp-small { font-size: 15px; }
  .pp-match .pp-player { grid-template-columns: 36px 1fr; gap: 6px; }
  .pp-match .pp-player > img { width: 36px; height: 36px; }
  .pp-match .pp-player__name { font-size: 8px; }
  .pp-match .pp-player .pp-muted { display: none; }
  .pp-match .pp-player.is-turn { outline-offset: 1px; }
  .pp-hintbtn { min-height: 44px; font-size: 17px; }
  .pp-moves { max-height: none; font-size: 15px; }
}

/* ----------------------------------------- portrait phones and tablets -- */
@media (orientation: portrait) and (max-width: 1100px) {
  .pp-match {
    --opp-h: 50px; --me-h: 66px; --info-min: 120px; --gap: 6px;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: var(--opp-h) auto var(--me-h) minmax(0, 1fr);
    grid-template-areas: "opp opp" "board board" "me focus" "info info";
    align-items: stretch; gap: var(--gap);
    padding: max(6px, env(safe-area-inset-top)) 6px max(6px, env(safe-area-inset-bottom));
  }
  .pp-match__left { display: contents; }
  .pp-match__kind, .pp-match__note, .pp-match .pp-cost, .pp-match .pp-meter--focus { display: none; }
  .pp-match__opp { grid-area: opp; }
  .pp-match__me { grid-area: me; }
  .pp-match__focus { grid-area: focus; }
  .pp-match__board {
    grid-area: board;
    --frame-w: min(calc(100vw - 12px), calc(100vh - var(--opp-h) - var(--me-h) - var(--info-min) - 4 * var(--gap) - 12px));
    --frame-w: min(calc(100vw - 12px), calc(100dvh - var(--opp-h) - var(--me-h) - var(--info-min) - 4 * var(--gap) - 12px));
  }
  .pp-match__right { grid-area: info; max-width: none; min-height: 0; overflow-y: auto; gap: 6px; }

  .pp-match .pp-panel { padding: 4px 10px; flex: none; min-height: 0; }
  .pp-match__opp, .pp-match__me { overflow: hidden; }
  .pp-match .pp-player { grid-template-columns: 36px 1fr; gap: 8px; }
  .pp-match .pp-player > img { width: 36px; height: 36px; }
  .pp-match .pp-player__name { font-size: 9px; line-height: 1.3; }
  .pp-match .pp-player .pp-small { font-size: 15px; line-height: 1.15; }
  .pp-match .pp-player .pp-muted { display: none; }
  .pp-match .pp-player .pp-thinking { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); display: block; }
  .pp-match .pp-player { position: relative; }
  .pp-match .pp-player.is-turn { outline-offset: -3px; }
  .pp-match__focus { gap: 2px; justify-content: center; overflow: hidden; }
  .pp-match .pp-focus__row { font-size: 14px; line-height: 1.1; }
  .pp-match .pp-hintbtn { min-height: 38px; font-size: 16px; padding: 2px 6px; gap: 4px; }
  .pp-match .pp-hintbtn small { font-size: 11px; }
  .pp-moves { max-height: none; }

  /* Puzzles: the host on top, the board, then the puzzle panel fills the rest. */
  .pp-match--puzzle { grid-template-rows: var(--opp-h) auto minmax(0, 1fr); grid-template-areas: "opp opp" "board board" "focus focus"; }
  .pp-match--puzzle .pp-match__board {
    --frame-w: min(calc(100vw - 12px), calc(100vh - var(--opp-h) - 180px));
    --frame-w: min(calc(100vw - 12px), calc(100dvh - var(--opp-h) - 180px));
  }
  .pp-match--puzzle .pp-match__focus { overflow-y: auto; justify-content: flex-start; padding: 6px 10px; }
  .pp-match--puzzle .pp-match__right { display: none; }
}

/* ================================================================ title == */
.pp-title__stage { width: min(100vw, calc(100dvh * 1672 / 941)); }

/* =============================================================== create == */
/* Two pages, one panel each (js/ui/screens/create.js): who you are, then the
   home city. Both are in the DOM at once and one is hidden, so there is only
   ever ONE panel to fit - which is the whole reason the split exists. What
   scrolls inside it is the questions, or the city list; the buttons under
   them never do. */
.pp-create { display: flex; }
.pp-create__wrap {
  display: flex; flex-direction: column; min-height: 0; height: 100%;
  padding: max(10px, env(safe-area-inset-top)) max(12px, env(safe-area-inset-right)) max(10px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
}
.pp-create__logo { width: auto; height: clamp(36px, 11vh, 120px); max-width: 80vw; margin: 0 auto 2px; flex: none; }
.pp-create__sub { width: auto; height: clamp(14px, 4vh, 44px); max-width: 70vw; margin: 0 auto 10px; flex: none; }
.pp-create__step { flex: none; margin: 0 auto 6px; text-align: center; color: var(--gold); }
.pp-create__grid { flex: 1; min-height: 0; display: grid; grid-template-rows: minmax(0, 1fr); grid-template-columns: minmax(0, 1fr); }
/* Both pages occupy the same cell, so hiding one cannot move the other. */
.pp-create__page { grid-area: 1 / 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
.pp-create__page[hidden] { display: none; }
/* Three questions do not want the width six cities do. */
.pp-create__who { width: 100%; max-width: 520px; margin: 0 auto; }
/* Only the questions scroll. The action row stays put at any window height. */
.pp-create__ask { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: inherit; }
.pp-create__go { flex: none; margin-top: 8px; }
.pp-create__foot { flex: none; }
.pp-create__summary { margin: 8px 0 0; }
.pp-create__summary.is-ready { color: var(--ink); }
.pp-create__cities > .pp-h2, .pp-create__cities > .pp-small { flex: none; }
/* min-content, not auto. The grid's height is definite (flex: 1), and inside
   a definite-height grid an `auto` row gets compressed toward the space
   available instead of toward its card: six cities in 251px produced six
   34px rows holding 57px cards, and `overflow: hidden` on the card ate the
   club name. Sizing the rows to the card is what makes the panel's own
   overflow-y do the scrolling it was always there for. */
.pp-create__cities .pp-cities {
  flex: 1; min-height: 0; overflow-y: auto; padding: 4px; align-content: start;
  /* Three across, so all six sit in two rows and the page needs no scrolling
     on a desktop window. auto-fill made four columns and left the bottom two
     cities under the fold of a list that is only six long. */
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  max-width: 1100px; margin: 0 auto; width: 100%;
  grid-auto-rows: min-content;
}
@media (min-width: 821px) {
  .pp-create__cities .pp-cities { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* A letterbox crop, not the card's usual 16:9: at three across, a 16:9
     photo makes each card ~285px and the second row of six falls under the
     fold of a list that is only two rows long. */
  .pp-create__cities .pp-city > img { aspect-ratio: 2.5 / 1; }
}

@media (max-width: 820px), (max-height: 560px) {
  .pp-create__sub { display: none; }
  .pp-create .pp-h2 { font-size: 13px; margin: 2px 0 6px; }
  .pp-create .pp-panel { padding: 8px 10px; }
  .pp-avatar { padding: 4px; flex-direction: row; justify-content: center; }
  .pp-avatar canvas { width: 32px; height: 48px; }
  .pp-create .pp-input { padding: 6px 10px; font-size: 18px; }
  .pp-create__cities .pp-muted { display: none; }
  .pp-cities { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px; }
  .pp-create__cities .pp-cities { grid-template-columns: minmax(0, 1fr); }
  .pp-city { flex-direction: row; align-items: stretch; }
  .pp-city > img { width: 34%; aspect-ratio: auto; }
  .pp-city__body { padding: 4px 8px; font-size: 16px; line-height: 1.15; }
  .pp-city__body .pp-muted { display: none; }
  .pp-city__side { top: auto; bottom: 4px; left: 4px; right: auto; font-size: 11px; }
}
/* There used to be a portrait rule here that squeezed the name box in beside
   the avatars and hid its heading, so that all four questions could share one
   screen. Splitting the creator into two pages is what actually bought that
   space, and the squeeze cost more than it saved: it left the questions
   numbered 1, 3, 4. Page 1 now has room for all three, written out. */
/* Landscape phone: the logo is the first thing that can go. */
@media (orientation: landscape) and (max-height: 560px) {
  .pp-create__logo { height: 30px; margin-bottom: 6px; }
  .pp-create__step { display: none; }
  .pp-create__who .pp-small { font-size: 14px; }
}

/* =============================================================== ending == */
.pp-ending { display: flex; flex-direction: column; }
.pp-ending__scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.pp-credits { padding-bottom: 24px; }
.pp-ending__bar { flex: none; justify-content: center; padding: 10px 12px max(12px, env(safe-area-inset-bottom)); background: linear-gradient(transparent, #0d0806 30%); }
@media (max-height: 560px) { .pp-ending__hero { padding-top: 12px; } }

/* ======================================================== match polish == */
.pp-match__banner:has(.pp-opening-banner:empty) { display: none; }
@media (max-width: 1100px), (max-height: 620px) {
  .pp-hintbtn__ask { display: none; }
  .pp-match .pp-hintbtn { white-space: nowrap; }
}

/* ================================================================ scene == */
/* The label slides back inside a narrow stage; the arrow stays on its spot. */
.pp-hotspot { transform: translate(calc(-50% + var(--nudge, 0px)), calc(-100% + var(--nudge-y, 0px))); }
.pp-hotspot__arrow { position: relative; left: calc(-1 * var(--nudge, 0px)); }
/* An exit at the bottom of the art hangs under the feet, pointing out. */
.pp-hotspot.is-out { transform: translate(calc(-50% + var(--nudge, 0px)), var(--nudge-y, 0px)); }

/* ============================================================== journal == */
/* A column: HUD, tabs, then the page, which gets whatever height is left.
   Books size to that box (container units), not to a guessed 100vh - 90px. */
.pp-journal { display: flex; flex-direction: column; }
.pp-journal > .pp-hud { position: relative; flex: none; }
.pp-journal__tabs { position: static; flex: none; padding: 6px 8px; }
.pp-journal__body { position: relative; top: auto; bottom: auto; flex: 1; min-height: 0; overflow-y: auto; container-type: size; padding-bottom: max(8px, env(safe-area-inset-bottom)); }
.pp-journal__body > .pp-book { width: min(100cqw - 16px, (100cqh - 8px) * 1536 / 1024); margin: 4px auto; }
@media (max-width: 760px), (max-height: 520px) {
  .pp-journal__tabs { gap: 4px; padding: 4px; }
  .pp-journal__tabs .pp-btn--small { min-height: 32px; padding: 2px 8px; font-size: 15px; }
}
.pp-journal__list { display: flex; flex-direction: column; gap: 8px; padding: 8px 10px; max-width: 640px; margin: 0 auto; }
.pp-journal__shelf { color: var(--gold-hi); margin: 6px 0 0; }
.pp-openingcard { display: flex; flex-direction: column; gap: 4px; padding: 8px 10px; }
.pp-openingcard.is-equipped { outline: 3px solid var(--gold); }
.pp-openingcard__head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.pp-openingcard .pp-meter { height: 8px; }
.pp-passportcard { display: grid; grid-template-columns: 88px 1fr; gap: 10px; align-items: center; }
.pp-passportcard img { width: 88px; height: 88px; }

/* ============================================================= settings == */
/* The book fills what the about strip (version, Share) leaves below it. */
.pp-settings { --about-h: 44px; }
.pp-settings__wrap { position: absolute; inset: 0 0 calc(var(--about-h) + env(safe-area-inset-bottom)) 0; display: grid; place-items: center; }
.pp-book--settings { width: min(100vw - 24px, calc((100dvh - 24px - var(--about-h) - env(safe-area-inset-bottom)) * 1536 / 1024)); }
.pp-about {
  position: absolute; left: 0; right: 0; bottom: env(safe-area-inset-bottom); height: var(--about-h);
  display: flex; align-items: center; justify-content: center; gap: 12px; padding: 0 12px;
  color: var(--paper); font-size: 15px; white-space: nowrap;
}
.pp-about__name { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.pp-about__share { flex: none; }
@media (min-height: 700px) and (min-width: 701px) {
  .pp-settings { --about-h: 52px; }
  .pp-about { font-size: 18px; }
  .pp-about__share { min-height: 36px; font-size: 17px; }
}
@media (max-height: 420px) {
  .pp-settings { --about-h: 36px; }
  .pp-about { font-size: 13px; }
  .pp-about__share { min-height: 26px; padding: 1px 8px; font-size: 14px; }
}
@media (orientation: portrait) and (max-width: 700px) {
  /* No book art on a phone held upright: the two pages stack in one panel. */
  .pp-book--settings {
    width: calc(100vw - 16px); height: calc(100dvh - 8px - var(--about-h) - env(safe-area-inset-bottom)); aspect-ratio: auto; margin: 8px auto 0 !important;
    background: rgba(243, 227, 191, 0.98); border: var(--px) solid var(--wood-dark); border-radius: 8px;
    overflow-y: auto; overscroll-behavior: contain; container-type: normal;
  }
  .pp-book--settings .pp-book__page { position: static !important; width: auto !important; top: auto !important; font-size: 17px; padding: 8px 12px; overflow: visible; }
}

/* ======================================================== opening study == */
.pp-study { width: min(1000px, 100%); max-height: calc(100dvh - 32px); display: flex; flex-direction: column; gap: 6px; margin: auto; }
.pp-study__title .pp-h2 { margin: 0; }
.pp-study__body { flex: 1; min-height: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 12px; }
.pp-study__board { --frame-w: min(520px, calc(100dvh - 180px), 55vw); align-self: start; }
.pp-study__side { display: flex; flex-direction: column; gap: 6px; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding-right: 4px; }
.pp-study__note { min-height: 4.2em; padding: 8px 10px; background: #102238; color: #d8f4ff; border-radius: 6px; font-size: 17px; line-height: 1.25; }
.pp-study__nav { gap: 4px; align-items: center; }
.pp-study__nav .pp-btn--small { min-width: 40px; }
.pp-study__counter { min-width: 3.4em; text-align: center; font-weight: 700; }
.pp-study__moves { display: grid; grid-template-columns: 30px 1fr 1fr; gap: 2px 6px; font-size: 16px; }
.pp-study__moves .num { color: var(--ink-soft); text-align: right; align-self: center; }
.pp-study__move { font: inherit; text-align: left; padding: 1px 6px; border: 0; border-radius: 4px; background: transparent; color: var(--ink); cursor: pointer; }
.pp-study__move.is-current { background: var(--gold); font-weight: 700; }
.pp-study__locked { color: var(--ink-soft); opacity: 0.55; padding: 1px 6px; }
.pp-study__lines { display: flex; flex-direction: column; gap: 4px; }
.pp-study__line { font: inherit; font-size: 15px; text-align: left; padding: 4px 8px; border: 2px solid var(--paper-3); border-radius: 6px; background: var(--paper-2); color: var(--ink); cursor: pointer; }
.pp-study__line.is-active { border-color: var(--blue); background: #fff4d8; }
.pp-study__line.is-done b::after { content: ' done'; font-size: 0.8em; color: var(--green); }
@media (orientation: portrait) and (max-width: 820px), (max-height: 560px) {
  .pp-overlay:has(.pp-study) { padding: 6px; }
  .pp-study { max-height: calc(100dvh - 12px); }
}
@media (orientation: portrait) and (max-width: 820px) {
  .pp-study__body { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  .pp-study__board { --frame-w: min(calc(100vw - 40px), 46dvh); justify-self: center; }
  .pp-study__note { min-height: 3.6em; font-size: 15px; }
}
@media (orientation: landscape) and (max-height: 560px) {
  .pp-study__title .pp-small { display: none; }
  .pp-study__board { --frame-w: calc(100dvh - 90px); }
  .pp-study__note { min-height: 3em; font-size: 14px; }
}

/* ======================================================= practice room == */
.pp-practice__option {
  display: grid; grid-template-columns: 44px 1fr; gap: 10px; align-items: center; text-align: left;
  padding: 8px 10px; font: inherit; color: var(--ink); cursor: pointer;
  background: var(--paper-2); border: var(--px) solid var(--wood-dark); border-radius: 8px;
}
.pp-practice__option > span:last-child { display: flex; flex-direction: column; }
.pp-practice__option:active { filter: brightness(0.95); }
.pp-practice__option.is-new { outline: 3px solid var(--gold); }
.pp-practice__icon { line-height: 0; text-align: center; }
.pp-dots--many { flex-wrap: wrap; gap: 3px; }
.pp-dots--many .pp-dot { width: 10px; height: 10px; }
/* The side column scrolls as a whole; its parts must never shrink into each other. */
.pp-study__side > * { flex: none; }

/* ============================================================ safe areas == */
/* iPhone draws the page under the status bar and the home indicator
   (viewport-fit=cover): everything that touches an edge keeps clear of them. */
.pp-hud { padding-top: max(6px, env(safe-area-inset-top)); }
@media (max-width: 760px), (max-height: 520px) { .pp-hud { padding-top: max(4px, env(safe-area-inset-top)); } }
.pp-overlay {
  padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
}
.pp-toasts { top: max(64px, calc(env(safe-area-inset-top) + 64px)); }
.pp-ending__scroll { padding-top: env(safe-area-inset-top); }

/* =========================================================== loading ==== */
.pp-curtain > div { display: flex; flex-direction: column; align-items: center; width: min(520px, 86vw); }
.pp-curtain img { display: block; width: 100%; }

/* ================================================================== map == */
.pp-map__area { position: absolute; left: 0; right: 0; top: var(--hud-h, 56px); bottom: 0; overflow: hidden; }
.pp-map__area.is-pannable { touch-action: none; cursor: grab; }
.pp-map__area > .pp-map__stage { left: 0; width: auto; aspect-ratio: auto; transform: none; will-change: transform; }
.pp-map__card {
  max-height: calc(100vh - var(--hud-h, 56px) - 28px);
  max-height: calc(100dvh - var(--hud-h, 56px) - 28px);
  overflow-y: auto; overscroll-behavior: contain;
  right: max(14px, env(safe-area-inset-right)); bottom: max(14px, env(safe-area-inset-bottom));
}
.pp-map__default { display: none; }
.pp-map__legend { left: max(14px, env(safe-area-inset-left)); bottom: max(14px, env(safe-area-inset-bottom)); }

/* Short landscape (phones): a compact card, and the legend gives way to it. */
@media (orientation: landscape) and (max-height: 560px) {
  .pp-map__card { width: min(340px, 46vw); max-height: calc(100dvh - var(--hud-h, 56px) - 16px); bottom: max(8px, env(safe-area-inset-bottom)); }
  .pp-map__card .pp-panel { padding: 8px 12px; }
  .pp-map__card .pp-h2 { font-size: 13px; margin: 0 0 6px; }
  .pp-map__card .pp-small { font-size: 15px; gap: 2px; }
  .pp-map__card .pp-row { gap: 6px; margin-top: 6px !important; }
  .pp-map__card .pp-btn { min-height: 34px; padding: 2px 10px; font-size: 16px; }
  .pp-map__legend { display: none; }
}

/* Portrait: the map on top, and under it a panel only as tall as its words
   (map.js measures it into --sheet; the map ends where the panel starts). */
@media (orientation: portrait) and (max-width: 820px) {
  .pp-map__area { bottom: calc(var(--sheet, 110px) + env(safe-area-inset-bottom)); }
  .pp-map__legend { display: none; }
  .pp-map__card {
    left: max(8px, env(safe-area-inset-left)); right: max(8px, env(safe-area-inset-right)); width: auto;
    bottom: max(8px, env(safe-area-inset-bottom)); height: auto; max-height: 40dvh;
  }
  .pp-map__card > .pp-panel { padding: 8px 12px; }
  .pp-map__default { display: block; }
  .pp-map__default > * { margin: 0; }
  .pp-map__default > * + * { margin-top: 4px; }
  .pp-map__card .pp-h2 { font-size: 13px; }
  .pp-map__card .pp-small { font-size: 15px; line-height: 1.3; }
  .pp-map__card .pp-row { gap: 6px; }
  .pp-map__card .pp-btn { min-height: 40px; font-size: 17px; padding: 4px 12px; }
}

/* ================================================================ title == */
.pp-title__stage { container-type: size; }
/* The row of four: as large as the art allows, never wider than its share of the row. */
.pp-title__item { font-size: clamp(10px, min(3.9cqh, 1.7cqw), 40px); white-space: nowrap; overflow: hidden; }
.pp-title__continue-note { font-size: clamp(11px, 2.4cqh, 26px); }
.pp-title__footer { font-size: clamp(11px, 2.4cqh, 26px); }
.pp-title__logo, .pp-title__logo-sub { display: none; }

/* As wide as a phone on its side (2.17:1): the travel desk, its logo and four
   menu slots painted; the real buttons sit exactly over the slots, measured
   in percent of title-background-wide.png (1846x852). */
@media (min-aspect-ratio: 197/100) {
  .pp-title__stage { width: min(100vw, calc(100dvh * 1846 / 852)); aspect-ratio: 1846 / 852; background-image: url('../assets/ui/title-bg-wide.webp'); }
  .pp-title__menu { left: 38.03%; top: 51.53%; bottom: auto; width: 22.32%; height: 34.39%; transform: none; display: block; }
  .pp-title__item {
    position: absolute; left: 0; width: 100%; height: 22.87%;
    justify-content: flex-start; gap: 6%; padding: 0 0 0 6%; border-radius: 8px; box-shadow: none;
    font-size: clamp(10px, 3.9cqh, 40px);
  }
  .pp-title__item:nth-child(1) { top: 0; }
  .pp-title__item:nth-child(2) { top: 25.6%; }
  .pp-title__item:nth-child(3) { top: 50.85%; }
  .pp-title__item:nth-child(4) { top: 76.79%; }
  .pp-title__continue-note { left: 61.2%; top: 60%; bottom: auto; transform: none; padding: 1px 6px; font-size: clamp(10px, 2.8cqh, 26px); }
}

/* A window taller than the art: the portrait title art (no painted logo or
   menu) fills the screen. The logo sits over the wall map at the top and the
   real menu over the empty parchment in the middle of the desk. */
@media (max-aspect-ratio: 13/10) {
  .pp-title__stage {
    width: 100%; height: 100%; aspect-ratio: auto; container-type: normal; overflow: hidden;
    background: #2a1a10 url('../assets/ui/title-bg-portrait.webp') 50% 45% / cover no-repeat;
  }
  /* A soft shade behind the logo only, so it reads over the busy map. */
  .pp-title__stage::before {
    content: ''; position: absolute; left: 0; right: 0; top: 0; height: 36%; z-index: 0;
    background: linear-gradient(rgba(20, 12, 6, 0.55), rgba(20, 12, 6, 0));
  }
  .pp-title__stage > * { z-index: 1; }
  .pp-title__logo {
    display: block; position: absolute; left: 50%; transform: translateX(-50%);
    top: max(3.5dvh, calc(env(safe-area-inset-top) + 8px)); width: min(80vw, 440px);
    filter: drop-shadow(0 4px 0 rgba(0, 0, 0, 0.45));
  }
  .pp-title__logo-sub { display: block; position: absolute; left: 50%; transform: translateX(-50%); top: calc(max(3.5dvh, calc(env(safe-area-inset-top) + 8px)) + min(80vw, 440px) * 0.5); width: min(66vw, 360px); }
  .pp-title__menu {
    position: absolute; left: 50%; top: 40dvh; bottom: auto; transform: translateX(-50%);
    width: min(74vw, 340px); height: auto; display: flex; flex-direction: column; gap: 1.6dvh;
  }
  .pp-title__item {
    position: static; flex: none; justify-content: flex-start; width: 100%; height: auto; min-height: min(58px, 6.6dvh); padding: 0 20px; gap: 16px;
    font-size: min(22px, 2.7dvh); border-width: 3px; border-radius: 8px; box-shadow: 0 5px 0 rgba(0, 0, 0, 0.45);
  }
  .pp-title__continue-note {
    position: absolute; left: 50%; top: calc(40dvh + 4 * min(58px, 6.6dvh) + 3 * 1.6dvh + 14px); bottom: auto; transform: translateX(-50%); white-space: normal;
    width: min(86vw, 420px); font-size: 17px; text-align: center; padding: 4px 10px; border-radius: 6px; background: rgba(20, 12, 6, 0.6);
  }
  .pp-title__footer {
    right: auto; left: 50%; transform: translateX(-50%); bottom: max(10px, calc(env(safe-area-inset-bottom) + 6px));
    font-size: min(16px, 2.3dvh); gap: 12px; padding: 4px 6px 4px 4px; border-radius: 8px; background: rgba(20, 12, 6, 0.6);
  }
  .pp-title__share { min-height: max(34px, 2.3em); padding: 0 14px; border-width: 3px; border-radius: 6px; }
}

/* ======================================================== scene camera == */
.pp-scene__viewport.is-camera { place-items: start; overflow: hidden; }
.pp-scene__viewport.is-camera > .pp-scene__stage { will-change: transform; }
@media (orientation: portrait) and (max-width: 820px) {
  :root[data-touch="true"] .pp-scene__dock .pp-row { flex-wrap: nowrap; overflow-x: auto; overscroll-behavior: contain; padding-bottom: 2px; }
  :root[data-touch="true"] .pp-scene__dock .pp-btn--small { flex: none; }
}
/* Very short landscape (small phones): the dock column and the stick share the left gutter. */
@media (orientation: landscape) and (max-height: 400px) {
  :root[data-touch="true"] .pp-pad__stick { width: 104px; height: 104px; }
  :root[data-touch="true"] .pp-pad__base { width: 78px; height: 78px; }
  :root[data-touch="true"] .pp-pad__knob { width: 38px; height: 38px; }
  :root[data-touch="true"] .pp-scene__dock .pp-btn--small { min-height: 26px; font-size: 14px; }
  :root[data-touch="true"] .pp-scene__dock .pp-row { gap: 3px; }
}

/* ============================================================== arrival == */
/* The portrait loading screen on a window taller than wide: as tall as fits. */
@media (max-aspect-ratio: 13/10) {
  .pp-arrival img {
    width: auto; max-width: 92vw;
    height: min(calc(100dvh - 90px - env(safe-area-inset-top) - env(safe-area-inset-bottom)), calc(92vw * 1672 / 941));
    border-width: 4px;
  }
  .pp-arrival__tap { bottom: max(3dvh, calc(env(safe-area-inset-bottom) + 10px)); }
}
/* Short landscape: leave room under the card for the "tap to step off" line. */
@media (min-aspect-ratio: 13/10) and (max-height: 560px) {
  .pp-arrival img { width: auto; height: calc(100dvh - 60px - env(safe-area-inset-bottom)); max-width: 92vw; margin-bottom: 24px; }
  .pp-arrival__tap { bottom: max(6px, env(safe-area-inset-bottom)); }
}

/* ======================================================== depth layers == */
/* Cut-out objects in a layered scene: stacked with the characters by their ground line. */
.pp-prop { position: absolute; pointer-events: none; user-select: none; background-repeat: no-repeat; }

/* ======================================================= label stacking == */
/* The cut-out objects carry z-indexes up to ~1000. Give the actors layer its
   own stacking context so hotspot labels always float above the furniture. */
.pp-scene__actors { z-index: 1; isolation: isolate; }
.pp-scene__labels { z-index: 2; }

/* ======================================================= puzzle actions == */
/* Next / Hint / Retry / Leave stay on screen; only the text above them scrolls. */
.pp-puzzle__panel { display: flex; flex-direction: column; min-height: 0; overflow: hidden !important; }
.pp-puzzle__info { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 6px; }
.pp-puzzle__actions { flex: none; gap: 6px; flex-wrap: wrap; padding-top: 6px; border-top: 2px dashed var(--paper-3); }
.pp-puzzle__actions .pp-btn { min-height: 38px; }
@media (max-width: 820px), (max-height: 560px) {
  .pp-puzzle__info .pp-h2 { font-size: 13px; margin: 0; }
  .pp-puzzle__info .pp-h3 { font-size: 11px; }
  .pp-puzzle__info p { margin: 0; }
  .pp-puzzle__actions .pp-btn { min-height: 34px; padding: 2px 10px; font-size: 16px; }
}
/* The puzzle column itself never scrolls: the panel takes the space left under
   the host card, and inside it only the text does. */
.pp-match--puzzle .pp-match__left { overflow: hidden; }
.pp-match--puzzle .pp-puzzle__panel { flex: 1 1 auto !important; }
@media (orientation: landscape) and (max-height: 560px) {
  .pp-puzzle__actions { gap: 4px; }
  .pp-puzzle__actions .pp-btn { min-height: 30px; padding: 0 8px; font-size: 15px; }
}

/* ============================================================ abilities == */
/* Hint and Undo sit side by side in every layout, with distinct colours. */
.pp-abilities { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.pp-abilities .pp-btn { width: 100%; min-width: 0; flex-direction: column; gap: 0; line-height: 1.05; padding: 4px 6px; white-space: nowrap; }
.pp-abilities .pp-btn small { display: block; font-size: 12px; font-weight: 600; opacity: 0.9; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.pp-hintbtn { min-height: 54px; font-size: 19px; }
.pp-undobtn {
  min-height: 54px; font-size: 19px; color: #fff6dc;
  background: linear-gradient(#9b6ad6, #6a3fa8); border-color: #2d1a4a;
}
.pp-undobtn:disabled { filter: saturate(0.35) brightness(0.9); }
.pp-undobtn[data-state="ready"]:not(:disabled) { box-shadow: 0 0 0 2px #e2cbff inset; }
@media (max-width: 1100px), (max-height: 620px) {
  .pp-abilities .pp-btn { min-height: 44px; font-size: 16px; }
  .pp-abilities .pp-btn small { font-size: 11px; }
}
/* Portrait phones: the Focus cell is narrow, so the two buttons stack their text tightly. */
@media (orientation: portrait) and (max-width: 1100px) {
  .pp-match { --me-h: 74px; }
  .pp-match__focus { padding: 3px 6px !important; }
  .pp-match .pp-focus__row { font-size: 12px; }
  .pp-abilities { gap: 4px; }
  .pp-abilities .pp-btn { min-height: 44px; font-size: 15px; padding: 2px 3px; }
  .pp-abilities .pp-btn small { font-size: 10px; }
}

/* ------------------------------------------- practice tree and lessons -- */
/* The tree's own scroller keeps the page still; the wrap only has to stay
   clear of the rounded corners and the home bar. */
.pp-tree__wrap {
  padding-left: max(14px, env(safe-area-inset-left));
  padding-right: max(14px, env(safe-area-inset-right));
  padding-bottom: max(10px, env(safe-area-inset-bottom));
}

/* A phone held upright has no room for a rail beside the board: the board
   goes on top and the lesson panel underneath, as the match screen does. */
@media (orientation: portrait) and (max-width: 1100px) {
  .pp-lesson .pp-match--lesson {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "board" "panel";
    gap: 6px;
    padding: 6px max(6px, env(safe-area-inset-right)) max(6px, env(safe-area-inset-bottom)) max(6px, env(safe-area-inset-left));
  }
  .pp-lesson .pp-match--lesson .pp-match__left { display: flex; grid-area: panel; max-width: none; width: auto; justify-self: stretch; min-height: 0; }
  .pp-lesson .pp-match--lesson .pp-match__right { display: none; }
  .pp-lesson .pp-match--lesson .pp-match__board {
    grid-area: board;
    --frame-w: min(calc(100vw - 12px), calc(100dvh - var(--hud-h, 56px) - 250px));
  }
  .pp-lesson .pp-lesson__panel { max-height: none; }
}

/* ============================================================ phone HUD == */
/* A phone gives the status bar two rows at most, and a sideways phone one:
   the portrait carries the level as a badge (no name, no "Level"), the XP
   meter drops its word, and the next goal shares a row with the buttons,
   wrapping to two short lines instead of being cut off. */
.pp-hud__who { position: relative; }
.pp-hud__badge { display: none; }
@media (max-width: 600px), (max-height: 520px) {
  .pp-hud { column-gap: 6px; row-gap: 0; }
  .pp-hud__id, .pp-hud__xpword { display: none; }
  .pp-hud__who img { width: 30px; height: 30px; }
  .pp-hud__badge {
    display: grid; place-items: center; position: absolute; right: -7px; bottom: -5px;
    min-width: 15px; height: 14px; padding: 0 2px; border-radius: 7px;
    background: var(--gold); color: #2a1a10; border: 1.5px solid #2a1a10;
    font-family: var(--font-pixel); font-size: 7px; line-height: 1;
  }
  .pp-hud__lvl { width: 58px; margin-left: 4px; }
  .pp-hud__lvl .pp-small { justify-content: center; font-size: 12px; line-height: 1.1; }
  .pp-hud__stat { font-size: 15px; gap: 2px; }
  .pp-hud .pp-btn--small { min-height: 36px; min-width: 40px; padding: 2px 6px; }
  .pp-hud__next {
    flex: 1 1 0; order: 10; min-width: 0; margin: 0;
    font-size: 13px; line-height: 1.15; white-space: normal;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  }
  .pp-hud__next .pp-ico { width: 12px; height: 12px; vertical-align: -1px; }
  .pp-hud > .pp-btn { order: 11; }
}
/* Upright: stats on the first row (pushed right), goal + buttons on the second. */
@media (max-width: 600px) and (min-height: 521px) {
  .pp-hud__lvl { margin-right: auto; }
  .pp-hud > .pp-spacer { flex: 0 0 100%; height: 4px; order: 9; }
}
/* Sideways: one row; the goal takes whatever the stats and buttons leave. */
@media (max-height: 520px) {
  .pp-hud { padding-top: max(3px, env(safe-area-inset-top)); padding-bottom: 3px; }
  .pp-hud > .pp-spacer { display: none; }
  .pp-hud__next { margin-left: 6px; }
  .pp-hud .pp-btn--small { min-height: 34px; }
}
