/* ============================================================================
   PERIODIC PILE-UP — STYLES
   EnjoyChemistry · enjoychemistry.com

   Depends on base.css and layout.css for shared tokens. Nothing here
   redeclares a system variable; every colour below is either a --ppu-* token
   of its own or derived from base.css.

   All selectors are prefixed .ppu- or #ppu- so nothing here can reach another
   page. This is a game stage, so it is a NAMED EXCEPTION to the 1060px
   container cap — the stage is viewport-relative rather than a magic number,
   because the height goals are measured in atoms and need real vertical room.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Self-hosted DM Sans. No Google Fonts CDN: the chemistry glyph coverage we
   need (subscripts, superscripts, arrows, the minus sign) gets dropped by the
   CDN's subsetting. Falls back to the system stack if the file is absent.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'DM Sans Local';
  src: url('../fonts/DMSans-Variable.woff2') format('woff2-variations');
  font-weight: 300 700;
  font-display: swap;
}


/* ==========================================================================
   BUTTONS

   .btn-primary, .btn-link and .btn-outline-sm are NOT in base.css — every app
   in the suite declares its own copy, and that duplication is the established
   convention. Omitting them here is why these buttons first rendered as raw
   unstyled <button> elements. Definitions match gas-laws.css verbatim so the
   suite stays consistent. (.btn-icon and .btn-random DO live in base.css.)
   ========================================================================== */

.btn-primary { background: var(--primary); color: white; border: none; border-radius: var(--radius-sm); padding: 0.5rem 1.1rem; cursor: pointer; font-size: 0.85rem; font-weight: 600; font-family: var(--font); transition: all var(--transition); white-space: nowrap; box-shadow: var(--shadow-primary); }
.btn-primary:hover { background: var(--primary-hover); transform: translateY(-1px); }
.btn-primary:active { transform: scale(.97); }
.btn-link { background: none; border: none; cursor: pointer; font-family: var(--font); font-size: 0.84rem; font-weight: 600; color: var(--primary); padding: 0.4rem 0.8rem; border-radius: var(--radius-sm); transition: all var(--transition); }
.btn-link:hover { background: var(--primary-light); }
.btn-outline-sm { background: var(--surface); border: 1px solid var(--border); color: var(--text-muted); border-radius: var(--radius-sm); padding: 0.4rem 0.8rem; cursor: pointer; font-size: 0.8rem; font-weight: 600; display: inline-flex; align-items: center; gap: 0.4rem; transition: all var(--transition); font-family: var(--font); }
.btn-outline-sm:hover { color: var(--primary); border-color: var(--primary); }

/* Reduced motion: the lift and press are decorative. */
@media (prefers-reduced-motion: reduce) {
  .btn-primary:hover, .btn-primary:active { transform: none; }
}

/* ==========================================================================
   1. STAGE TOKENS

   The canvas cannot read CSS variables, so pile-up-app.js copies these into a
   cache at resize and re-reads them when CoreUI changes data-theme or
   data-scheme. Renaming a token here means renaming it in PALETTE_KEYS.

   Element tile colours are deliberately NOT here. They are category colours
   (alkali red, nonmetal green) and stay constant across all five schemes, so
   the colour-to-family mapping students learn never shifts under them.
   ========================================================================== */

#ppu-stage {
  /* Light mode: a cool paper surface, so tiles read as objects on a table. */
  --ppu-stage-bg: #eef1f6;
  --ppu-grid: rgba(17, 24, 39, 0.06);
  --ppu-platform: #9aa7b8;
  --ppu-platform-shade: #7c8899;

  --ppu-goal-line: rgba(217, 95, 2, 0.45);
  --ppu-goal-text: #b34e02;
  --ppu-aim-line: rgba(17, 24, 39, 0.28);

  /* Force indicators — see section 2 for why these hues, not the tile greens
     and reds they used to borrow. */
  --ppu-force-attract: #0f9d58;
  --ppu-force-repel: #d81b60;
  --ppu-force-glyph: #ffffff;
  --ppu-force-halo: rgba(255, 255, 255, 0.85);

  --ppu-particle: #e8873a;
  --ppu-chip-bg: rgba(255, 255, 255, 0.94);
  --ppu-chip-border: rgba(17, 24, 39, 0.22);
  --ppu-chip-text: #111827;
  --ppu-tile-text: #ffffff;
  --ppu-compound-ring: rgba(255, 255, 255, 0.92);
  --ppu-noble-ring: rgba(255, 255, 255, 0.6);
  --ppu-glow: rgba(255, 190, 90, 0.95);

  --ppu-font: 'DM Sans Local', 'DM Sans', system-ui, -apple-system, sans-serif;
}

[data-theme="dark"] #ppu-stage {
  --ppu-stage-bg: #0e141a;
  --ppu-grid: rgba(255, 255, 255, 0.05);
  --ppu-platform: #3a4c5e;
  --ppu-platform-shade: #1d2833;

  --ppu-goal-line: rgba(240, 140, 74, 0.5);
  --ppu-goal-text: #f08c4a;
  --ppu-aim-line: rgba(255, 255, 255, 0.26);

  --ppu-force-attract: #35d07f;
  --ppu-force-repel: #ff5c8a;
  --ppu-force-glyph: #0e141a;
  --ppu-force-halo: rgba(14, 20, 26, 0.85);

  --ppu-particle: #ffd9a8;
  --ppu-chip-bg: rgba(12, 17, 22, 0.9);
  --ppu-chip-border: rgba(255, 255, 255, 0.28);
  --ppu-chip-text: #eef4fa;
  --ppu-tile-text: #ffffff;
  --ppu-compound-ring: rgba(255, 255, 255, 0.6);
  --ppu-noble-ring: rgba(255, 255, 255, 0.42);
  --ppu-glow: rgba(255, 214, 150, 0.9);
}

/* ==========================================================================
   2. PAGE FRAME

   CoreUI prepends #core-header and appends #core-footer to <body>, so the
   game sits between them. Making body a flex column lets the stage claim
   whatever vertical space is left without hard-coding chrome heights.
   ========================================================================== */

/* height, not min-height. With min-height the page height is max(100dvh,
   content) — and #ppu-canvas at height:100% resolves against an INDEFINITE
   height, falls back to its intrinsic size, which is the height ATTRIBUTE that
   resize() writes from the measured stage. That closes a feedback loop where
   board height chases board width. A definite height plus an absolutely
   positioned canvas breaks it: the canvas can never contribute layout height. */
body.ppu-page {
  display: flex;
  flex-direction: column;
  height: 100vh;            /* fallback first */
  height: 100dvh;
  max-height: 100dvh;
  overflow: hidden;
}
body.ppu-page > #core-header,
body.ppu-page > #core-footer { flex: 0 0 auto; }

.ppu-shell {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;                /* lets the stage actually shrink */
  padding: 0 clamp(0px, 1.5vw, 18px);
  gap: 8px;
}

/* ---- HUD, inside the CoreUI header ------------------------------------- */
.ppu-hud {
  display: flex;
  align-items: baseline;
  gap: clamp(10px, 2vw, 26px);
  flex-wrap: wrap;
}
.ppu-stat { display: flex; flex-direction: column; gap: 1px; }
.ppu-stat-label {
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-light);
}
.ppu-stat-value { font-size: 1.15rem; font-weight: 700; line-height: 1.1; }
.ppu-stat-value.is-quiet { font-size: 0.95rem; color: var(--text-muted); }
.ppu-stat-note { font-size: 0.62rem; color: var(--primary); font-weight: 600; }


/* ---- Play area: stage + drawer ----------------------------------------- */
.ppu-play {
  flex: 1 1 auto;
  display: flex;
  gap: 10px;
  min-height: 0;
}

#ppu-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  /* Hard ceiling. If the page-height rule above ever fails to apply — a load
     order problem, a cascade conflict, an unsupported unit — the stage would
     otherwise grow without bound and take the canvas past its maximum size
     with it. These caps mean the worst case is a wrong-looking board, not a
     dead one. `contain` also stops descendants from feeding size back up. */
  max-height: 100dvh;
  max-width: 100vw;
  contain: layout paint;
  background: var(--ppu-stage-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  font-family: var(--ppu-font);
  touch-action: none;           /* the canvas handles its own gestures */
}
#ppu-canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  /* Absolute positioning already keeps the canvas out of the flow; these stop
     its intrinsic (attribute) size from ever showing through if it does. */
  max-width: 100%;
  max-height: 100%;
}

/* ==========================================================================
   3. DRAWER
   ========================================================================== */

#ppu-drawer {
  flex: 0 0 300px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow-y: auto;
}
.ppu-panel { padding: 12px 14px; border-bottom: 1px solid var(--border-light); }
.ppu-panel:last-child { border-bottom: 0; }
.ppu-panel-title {
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-light);
  margin-bottom: 8px;
}

/* ---- Next element ------------------------------------------------------ */
.ppu-next { display: flex; align-items: center; gap: 12px; }
.ppu-tile-face {
  position: relative;
  flex: 0 0 auto;
  width: 62px; height: 62px;
  border-radius: 11px;
  display: flex; align-items: center; justify-content: center;
  color: #fff;
  box-shadow: var(--shadow);
}
.ppu-tile-sym { font-size: 1.6rem; font-weight: 700; line-height: 1; }
.ppu-tile-num {
  position: absolute; left: 7px; bottom: 5px;
  font-size: 0.62rem; font-weight: 600; opacity: 0.92;
}
.ppu-tile-chg {
  position: absolute; right: 7px; top: 4px;
  font-size: 0.66rem; font-weight: 600; opacity: 0.95;
}
.ppu-tile-star { font-weight: 700; }
.ppu-next-text { min-width: 0; }
.ppu-next-name { font-size: 0.98rem; font-weight: 700; line-height: 1.25; }
.ppu-next-cat { font-size: 0.74rem; color: var(--text-muted); }
.ppu-next-radius { font-size: 0.68rem; color: var(--text-light); }
#ppu-next-note {
  font-size: 0.7rem;
  line-height: 1.55;
  color: var(--text-muted);
  margin-top: 8px;
}
#ppu-next-note:empty { display: none; }

/* ---- Charge legend ----------------------------------------------------- */
.ppu-legend { display: flex; flex-direction: column; gap: 7px; }
.ppu-legend-row {
  display: flex; align-items: center; gap: 9px;
  font-size: 0.74rem; color: var(--text-muted);
}
.ppu-legend-mark {
  flex: 0 0 auto; width: 18px; height: 18px; border-radius: 5px;
}
.ppu-legend-mark.is-attract {
  border: 2px solid var(--ppu-force-attract);
  background: color-mix(in srgb, var(--ppu-force-attract) 16%, transparent);
}
.ppu-legend-mark.is-repel {
  border: 2px dashed var(--ppu-force-repel);
}

/* ---- Meters ------------------------------------------------------------ */
.ppu-meter {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 0.74rem; color: var(--text-muted);
  padding: 3px 0;
}
.ppu-meter-value { font-weight: 700; color: var(--text); }
#ppu-lives { display: flex; gap: 5px; }
.ppu-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--border);
  transition: background var(--transition);
}
.ppu-dot.is-on { background: var(--primary); }

/* ---- Chemistry log ---------------------------------------------------- */
#ppu-log {
  display: flex; flex-direction: column; gap: 7px;
  max-height: 300px; overflow-y: auto;
}
.ppu-log-item {
  border-left: 3px solid var(--primary);
  padding: 5px 0 5px 9px;
}
.ppu-log-title { font-size: 0.78rem; font-weight: 700; }
.ppu-log-detail {
  font-size: 0.7rem; line-height: 1.5; color: var(--text-muted); margin-top: 2px;
}
.ppu-log-empty { font-size: 0.72rem; color: var(--text-light); line-height: 1.55; }

/* ==========================================================================
   4. TOASTS
   ========================================================================== */

/* Anchored in the dead band UNDER the platform rather than over the drop zone.
   The platform spans h-101 to h-79, so there are about 79px of clear space
   below it — enough for two single-line toasts and no more. Hence the terse
   one-line format; the chemistry log holds the full record. */
#ppu-toasts {
  position: absolute; bottom: 10px; left: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 6px; align-items: center;
  pointer-events: none; z-index: 6; width: min(460px, 92%);
}
.ppu-toast {
  display: flex; align-items: baseline; gap: 8px;
  max-width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: var(--shadow-lg);
  padding: 5px 14px;
  animation: ppuToastIn 0.22s ease-out;
}
.ppu-toast-title {
  font-size: 0.78rem; font-weight: 700; white-space: nowrap;
}
.ppu-toast-sub {
  font-size: 0.7rem; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@keyframes ppuToastIn {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   5. QUIZ
   ========================================================================== */

/* A LIGHT scrim with an opaque card, not a full-bleed wash. The board has to
   stay visible behind it — a tile takes about 1.5s to settle and the student
   needs to watch that happen. A near-opaque overlay erases the gameplay. */
#ppu-quiz {
  position: absolute; inset: 0; z-index: 8;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 16px; overflow: auto;
  background: color-mix(in srgb, var(--ppu-stage-bg) 62%, transparent);
}
#ppu-quiz[hidden] { display: none; }

.ppu-quiz-card {
  width: 100%; max-width: 620px; margin: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 20px;
}
.ppu-quiz-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 10px;
}
.ppu-quiz-eyebrow {
  font-size: 0.6rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-light);
}
#ppu-quiz-streak { font-size: 0.68rem; font-weight: 600; color: var(--primary); }
#ppu-quiz-streak:empty { display: none; }
#ppu-quiz-prompt {
  font-size: clamp(1rem, 2.4vw, 1.3rem);
  font-weight: 700; line-height: 1.25; color: var(--text);
}
#ppu-quiz-sub {
  font-size: 0.76rem; color: var(--text-muted);
  margin-top: 6px; line-height: 1.5;
}
#ppu-quiz-sub:empty { display: none; }

/* Two by two, matching the reference build. The card is what groups the
   options, so they carry no numbering of their own. */
#ppu-quiz-options {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 16px;
}
.ppu-opt {
  position: relative;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 88px;
  background: var(--bg);
  border: 2px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 8px;
  cursor: pointer;
  font-family: inherit;
  transition: border-color var(--transition), transform var(--transition);
}
.ppu-opt:hover:not(:disabled) { border-color: var(--primary); transform: translateY(-2px); }
.ppu-opt:focus-visible { outline: 3px solid var(--primary); outline-offset: 2px; }
.ppu-opt:disabled { cursor: default; opacity: 0.75; }
.ppu-opt.is-wrong { border-color: var(--ppu-force-repel); }
.ppu-opt-tile {
  position: relative;
  width: 54px; height: 54px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  color: #fff;
}
.ppu-opt-main { font-size: 1.35rem; font-weight: 700; line-height: 1; }
.ppu-opt-num { position: absolute; left: 6px; bottom: 4px; font-size: 0.58rem; font-weight: 600; }
.ppu-opt-chg { position: absolute; right: 6px; top: 3px; font-size: 0.6rem; font-weight: 600; }

#ppu-quiz-explain {
  margin-top: 16px;
  background: var(--bg);
  border-left: 3px solid var(--ppu-force-repel);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: 14px 16px;
  animation: ppuSlideUp 0.2s ease-out;
}
#ppu-quiz-explain[hidden] { display: none; }
#ppu-quiz-explain-title { font-size: 0.94rem; font-weight: 700; margin-bottom: 5px; }
#ppu-quiz-explain-text { font-size: 0.82rem; line-height: 1.6; color: var(--text-muted); }
#ppu-quiz-picked {
  font-size: 0.74rem; color: var(--text-light); margin-top: 6px; font-style: italic;
}
#ppu-quiz-picked:empty { display: none; }
#ppu-quiz-continue { margin-top: 11px; }
@keyframes ppuSlideUp {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   6. OVERLAY (start, paused, run complete)
   ========================================================================== */

#ppu-overlay {
  position: absolute; inset: 0; z-index: 10;
  display: flex; align-items: center; justify-content: center; padding: 20px;
  background: color-mix(in srgb, var(--ppu-stage-bg) 92%, transparent);
  backdrop-filter: blur(4px);
}
#ppu-overlay[hidden] { display: none; }
#ppu-overlay-body {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 26px 28px;
  max-width: 27rem; width: 100%;
  text-align: center;
}
.ppu-ov-title { font-size: 1.4rem; font-weight: 700; margin-bottom: 9px; }
.ppu-ov-lede {
  font-size: 0.84rem; line-height: 1.65; color: var(--text-muted); margin-bottom: 16px;
}
.ppu-ov-foot {
  font-size: 0.72rem; color: var(--text-light);
  line-height: 1.55; margin-top: 12px;
}
.ppu-ov-actions {
  display: flex; gap: 9px; justify-content: center; flex-wrap: wrap;
}
.ppu-ov-stats {
  display: flex; flex-direction: column; gap: 6px;
  text-align: left; margin: 4px 0 16px;
}
/* Label above value, never beside it. Discoverer strings run from 12
   characters ("Henry Cavendish") to 117 for tennessine, which credits three
   laboratories. A side-by-side row cannot survive that spread: the label wraps
   to two lines while the value squeezes into half the width. Stacking is
   immune to length, so no card can break no matter who gets the credit. */
.ppu-ov-stats > div {
  display: flex; flex-direction: column; gap: 1px;
  padding: 6px 0; border-bottom: 1px solid var(--border-light);
}
.ppu-ov-stats dt {
  font-size: 0.6rem; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-light);
}
.ppu-ov-stats dd {
  font-size: 0.86rem; font-weight: 600; line-height: 1.45;
  overflow-wrap: break-word;
}

/* The run-complete summary is short paired values, so it keeps a two-column
   read. Scoped to that screen only. */
.ppu-ov-stats.is-tally > div {
  flex-direction: row; justify-content: space-between; align-items: baseline; gap: 12px;
}
.ppu-ov-stats.is-tally dt {
  font-size: 0.76rem; text-transform: none; letter-spacing: 0;
  color: var(--text-muted); font-weight: 400;
}
.ppu-ov-stats.is-tally dd { font-size: 0.9rem; font-weight: 700; }

/* layout.css gives .footer a 52px top margin plus 28px of inner padding, which
   is right for a scrolling document page and pure dead space on a full-height
   game — roughly 84px stolen from the board. Overridden here only, via a
   page-scoped selector; the shared rule is untouched. */
body.ppu-page .footer { margin-top: 0; }
body.ppu-page .footer-inner { padding: 10px 0; gap: 8px; }

/* ---- Settings view ----------------------------------------------------- */
#ppu-overlay-body { text-align: center; }
.ppu-set-group { text-align: left; margin: 14px 0 0; }
.ppu-set-label {
  font-size: 0.6rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-light); margin-bottom: 4px;
}
.ppu-set-note {
  font-size: 0.7rem; color: var(--text-muted); line-height: 1.5; margin-bottom: 8px;
}
.ppu-set-choices { display: flex; gap: 7px; }
.ppu-set-choice {
  flex: 1 1 0; display: flex; flex-direction: column; gap: 2px;
  background: var(--bg); border: 2px solid var(--border);
  border-radius: var(--radius-sm); padding: 8px 6px;
  font-family: var(--font); font-size: 0.78rem; font-weight: 600;
  color: var(--text); cursor: pointer; transition: all var(--transition);
}
.ppu-set-choice:hover { border-color: var(--primary); }
.ppu-set-choice.is-on { border-color: var(--primary); color: var(--primary); }
.ppu-set-hint { font-size: 0.62rem; font-weight: 500; color: var(--text-light); }
.ppu-set-row {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: 12px; background: none; border: 0; border-radius: var(--radius-sm);
  padding: 7px 8px; font-family: var(--font); font-size: 0.78rem;
  color: var(--text); text-align: left; cursor: pointer;
}
.ppu-set-row:hover { background: var(--bg); }
.ppu-set-row:focus-visible { outline: 3px solid var(--primary); outline-offset: 2px; }
.ppu-switch {
  flex: 0 0 auto; width: 34px; height: 19px; border-radius: 999px;
  background: var(--border); position: relative; transition: background var(--transition);
}
.ppu-switch::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 15px; height: 15px; border-radius: 50%; background: var(--surface);
  box-shadow: var(--shadow); transition: transform var(--transition);
}
.ppu-switch.is-on { background: var(--primary); }
.ppu-switch.is-on::after { transform: translateX(15px); }
#ppu-overlay-body { max-height: calc(100dvh - 180px); overflow-y: auto; }

/* ---- Award card and save code ------------------------------------------ */
.ppu-ov-eyebrow {
  font-size: 0.62rem; font-weight: 600; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--primary); margin-bottom: 10px;
}
.ppu-award-tile {
  width: 92px; height: 92px; margin: 0 auto 12px;
  border-radius: 16px; position: relative;
  display: flex; align-items: center; justify-content: center;
  color: #fff; box-shadow: var(--shadow-lg);
}
.ppu-award-sym { font-size: 2.4rem; font-weight: 700; line-height: 1; }
.ppu-award-z { position: absolute; left: 10px; bottom: 7px; font-size: 0.72rem; font-weight: 600; }
.ppu-award-note {
  font-size: 0.84rem; line-height: 1.6; color: var(--text-muted);
  margin-bottom: 14px;
}
.ppu-badge {
  display: block; margin: 6px 0;
  font-size: 0.7rem; font-weight: 600; line-height: 1.45;
  padding: 6px 10px; border-radius: var(--radius-sm);
  background: var(--bg); color: var(--text-muted);
  border-left: 3px solid var(--border);
}
.ppu-badge.is-mendeleev { border-left-color: var(--primary); color: var(--primary); }
.ppu-badge.is-predicted { border-left-color: var(--ppu-force-repel); }

.ppu-code-panel {
  margin: 14px 0; padding: 12px 14px;
  background: var(--bg); border: 1px solid var(--border-light);
  border-radius: var(--radius); text-align: center;
}
.ppu-code-label {
  font-size: 0.6rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-light);
}
.ppu-code {
  font-size: 1.7rem; font-weight: 700; letter-spacing: 0.16em;
  font-variant-numeric: tabular-nums; margin: 4px 0 6px;
}
.ppu-code-hint { font-size: 0.68rem; color: var(--text-muted); line-height: 1.5; }
.ppu-code-hint.is-warning { color: var(--ppu-force-repel); font-weight: 600; }
.ppu-code-entry {
  display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap;
}
.ppu-code-entry > span { font-size: 0.74rem; color: var(--text-muted); }
.ppu-code-entry input {
  flex: 1 1 120px; min-width: 0;
  padding: 7px 10px; font-family: var(--font);
  font-size: 0.92rem; font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase;
  background: var(--surface); color: var(--text);
  border: 2px solid var(--border); border-radius: var(--radius-sm);
}
.ppu-code-entry input:focus-visible { outline: 3px solid var(--primary); outline-offset: 1px; }
.ppu-code-error {
  font-size: 0.7rem; color: var(--ppu-force-repel); margin-top: 5px; line-height: 1.45;
}
.ppu-code-error:empty { display: none; }

/* ==========================================================================
   7. CONTROL BAR
   ========================================================================== */

.ppu-controls {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 9px;
  padding: 8px 4px 12px;
  flex-wrap: wrap;
}
#ppu-hint {
  flex: 1 1 auto;
  font-size: 0.68rem; color: var(--text-light); line-height: 1.4;
}
/* Nudge controls use .btn-icon from base.css — the canonical small square
   icon button. No app-specific button shape. */
.ppu-pad { display: flex; gap: 7px; }

/* ==========================================================================
   8. SCREEN-READER SUPPORT

   The canvas is aria-hidden: a pile of rotating rigid bodies has no useful
   text equivalent frame by frame. #ppu-live announces the events that matter
   and #ppu-status carries the board state, so the chemistry stays available
   even though the aiming does not.
   ========================================================================== */

.ppu-sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   9. RESPONSIVE

   Below 900px the drawer slides in over the stage, so the play area keeps as
   much height as possible. Tile size follows the stage, so the shorter the
   viewport the smaller the tiles — the height goals stay reachable either way.
   ========================================================================== */

#ppu-backdrop {
  position: fixed; inset: var(--ppu-header-h, 0px) 0 0 0; z-index: 20;
  background: rgba(0, 0, 0, 0.45);
  border: 0;
}
#ppu-backdrop[hidden] { display: none; }
#ppu-drawer-toggle { display: none; }

@media (max-width: 900px) {
  /* layout.css gives .header position:sticky with z-index:50, so an off-canvas
     drawer at top:0 gets painted over and its first panel is unreachable.
     --ppu-header-h is measured in resize() rather than hard-coded, because the
     header re-wraps and also grows with the font-scale control. */
  #ppu-drawer {
    position: fixed; top: var(--ppu-header-h, 0px); right: 0; bottom: 0;
    z-index: 21;
    flex: 0 0 300px;
    width: min(300px, 86vw);
    border-radius: 0;
    transform: translateX(100%);
    transition: transform var(--transition);
  }
  #ppu-drawer.is-open { transform: translateX(0); }
  #ppu-drawer-toggle { display: inline-flex; }
  .ppu-hud { gap: 12px; }
  .ppu-stat-value { font-size: 0.95rem; }
  .ppu-stat-note { display: none; }
}

@media (max-width: 560px) {
  .ppu-shell { padding: 0 6px; }
  #ppu-hint { display: none; }
  .ppu-controls { padding: 6px 2px 9px; }
  .ppu-opt-tile { width: 46px; height: 46px; }
  .ppu-opt-main { font-size: 1.15rem; }
  .ppu-opt { min-height: 72px; }
  .ppu-quiz-card { padding: 16px; }
}

/* Reduced motion: honour the OS setting as well as the in-game toggle. */
@media (prefers-reduced-motion: reduce) {
  .ppu-toast, #ppu-quiz-explain { animation: none; }
  .ppu-opt:hover:not(:disabled) { transform: none; }
  #ppu-drawer { transition: none; }
}

/* Print: a game board is not a worksheet. Send the log, not the canvas. */
@media print {
  #ppu-stage, .ppu-controls, #ppu-toasts, #ppu-backdrop { display: none !important; }
  #ppu-drawer {
    position: static; transform: none; flex: 1 1 auto;
    border: 0; max-height: none;
  }
  #ppu-log { max-height: none; }
}
