/* The page's one stylesheet: every HTML overlay drawn over the WebGL world (the canvas itself is lit by the page script).
   It stays a single file so the first frame waits on one request. Its parts run in cascade order, each building on the
   ones above it:
     base           tokens, page shell, stage and the shared primitives (.px, .frame, .sr, .ic, the pixel button, focus rings)
     HUD            name chip, Rooms lit counter, Go to menu, hint, guide button, toast
     story card     the card's chrome and its card-only blocks
     story content  what a story renders in both the card and the plain view
     plain view     the plain view and the no-WebGL fallbacks
     media          every viewport and preference override, last so each one wins */

/* ======================================================================================================================
   Base: design tokens, the page shell, the WebGL stage and the shared primitives every overlay is built from (pixel type,
   framed panels, the pixel button, visually hidden text, focus rings).
   ====================================================================================================================== */

:root {
  /* palette (the night studio) */
  --night: #0f0d18;
  --panel: #17131f;
  --edge: #3b3354;
  --ink: #efe6d8;
  --mute: #b3a8c4;
  --lantern: #ffc15e;
  --orb: #8fdcff;

  /* type: Pixelify Sans for labels and headings, Atkinson Hyperlegible for reading. Both are web fonts loaded without
     blocking, so every stack ends in a system face */
  --font-pixel: 'Pixelify Sans', system-ui, sans-serif;
  --font-read: 'Atkinson Hyperlegible', system-ui, sans-serif;
  /* small print (the line of detail under a route, help or exhibit button) skips the system-ui step: without the web
     font it falls back straight to the browser's sans-serif */
  --font-note: 'Atkinson Hyperlegible', sans-serif;

  /* the pixel button: lantern face, near-black ink, brown contour, lit lip on top, shaded strip below */
  --btn-face: #d98a26;
  --btn-face-hover: #e69a32;
  --btn-face-open: #f0a840;
  --btn-ink: #1c1206;
  --btn-contour: #4a2406;
  --btn-lip: #f5bd66;
  --btn-shade: #94520e;
}

* {
  box-sizing: border-box;
}
html,
body {
  margin: 0;
  height: 100%;
  background: var(--night);
  color: var(--ink);
  overflow: hidden;
  font-family: var(--font-read);
}
/* iPhone: no grey tap rectangle, no double-tap zoom on buttons (pinch zoom stays), no text selection or loupe from a still press on the world,
   and a card scrolled to its end does not drag the page */
html {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
#panel,
#plain {
  overscroll-behavior: contain;
}

/* ---- the stage: one pixelated canvas under every overlay, the world's own input surface ---- */
#stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
  cursor: crosshair;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
#gl {
  position: absolute;
  left: 0;
  top: 0;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

/* ---- shared primitives ---- */
.px {
  font-family: var(--font-pixel);
}
/* a framed panel: black outline, a 2px inner rim and a hard drop shadow */
.frame {
  background: var(--panel);
  border: 2px solid #000;
  box-shadow:
    inset 0 0 0 2px var(--edge),
    0 4px 0 #000;
}
/* visually hidden but still read by screen readers: the live region, and the name chip's tagline once the chip goes mini */
.sr,
#hud-name.mini p {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* 14px pixel-art icons (rooms and exhibits), drawn from the world's own sprites */
.ic {
  width: 14px;
  height: 14px;
  image-rendering: pixelated;
  flex: none;
}

/* ---- the pixel button ----
   User-picked style B1, "text-safe dither": lantern orange, near-black ink, a notched 2px brown pixel contour (the four offset
   shadows leave the corner pixels open) over a hard black drop, a dithered light lip in the top padding and a checker-plus-solid
   shade strip in the bottom padding, so the shading never sits behind the label */
.btn {
  position: relative;
  font: 600 15px/1 var(--font-pixel);
  color: var(--btn-ink);
  background: var(--btn-face);
  border: 0;
  text-decoration: none;
  padding: 9px 12px 10px;
  cursor: pointer;
  --btn-outline:
    0 -2px 0 var(--btn-contour), 0 2px 0 var(--btn-contour), -2px 0 0 var(--btn-contour), 2px 0 0 var(--btn-contour);
  box-shadow:
    var(--btn-outline),
    0 5px 0 #000,
    -2px 3px 0 #000,
    2px 3px 0 #000;
}
.btn::before,
.btn::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  pointer-events: none;
}
.btn::before {
  top: 0;
  height: 4px;
  background:
    linear-gradient(var(--btn-lip), var(--btn-lip)) top/100% 2px no-repeat,
    repeating-conic-gradient(var(--btn-lip) 0 25%, transparent 0 50%) 0 0/4px 4px;
}
.btn::after {
  bottom: 0;
  height: 6px;
  background:
    linear-gradient(var(--btn-shade), var(--btn-shade)) bottom/100% 2px no-repeat,
    repeating-conic-gradient(var(--btn-shade) 0 25%, transparent 0 50%) 0 0/4px 4px;
}
.btn:hover {
  background: var(--btn-face-hover);
}
/* pressed: the button drops onto its shadow */
.btn:active {
  transform: translateY(2px);
  box-shadow:
    var(--btn-outline),
    0 3px 0 #000;
}
.btn small {
  color: var(--btn-contour);
}
.btn .ic {
  background: var(--btn-ink);
  padding: 2px;
  box-sizing: content-box;
}

/* ---- focus rings: white around buttons, lantern around links and rows inside a story ---- */
.btn:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 3px;
}
#panel button:not(.btn):focus-visible,
#plain a:not(.btn):focus-visible {
  outline: 2px solid var(--lantern);
  outline-offset: 2px;
}

/* ======================================================================================================================
   HUD: everything that floats over the world outside the story card. The name chip (top left), the right-hand bar with the
   "Rooms lit" counter and the Go to / Plain view buttons, the Go to menu, the controls hint, the Open guide button and the toast.
   The chips start transparent and are faded in by the page script once the world is up.
   ====================================================================================================================== */

/* ---- name chip ---- */
#hud-name {
  position: fixed;
  left: max(16px, env(safe-area-inset-left));
  top: max(16px, env(safe-area-inset-top));
  padding: 10px 14px 12px;
  max-width: min(360px, calc(100vw - 32px));
  opacity: 0;
  transition: opacity 0.6s;
}
#hud-name h1 {
  margin: 0;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 700;
  color: var(--lantern);
  transition: font-size 0.3s;
}
#hud-name p {
  margin: 4px 0 0;
  font-size: 15px;
  line-height: 1.4;
  color: var(--ink);
  transition: opacity 0.3s;
}
/* mini: once the visitor starts exploring, the chip shrinks to the name (the tagline goes screen-reader only, see .sr) */
#hud-name.mini {
  padding: 7px 12px 8px;
}
#hud-name.mini h1 {
  font-size: 17px;
}

/* ---- right-hand bar: Rooms lit, Go to, Plain view ---- */
#hud-right {
  position: fixed;
  right: max(16px, env(safe-area-inset-right));
  top: 16px;
  z-index: 31;
  display: flex;
  gap: 8px;
  align-items: flex-start;
  opacity: 0;
  transition: opacity 0.6s;
}
/* a Tab before the HUD fades in must not land on an invisible control */
#hud-name:focus-within,
#hud-right:focus-within {
  opacity: 1;
  transition: none;
}
/* Go to stays lit while its menu is open; hovering it still reads as hover */
#menubtn[aria-expanded='true'] {
  background: var(--btn-face-open);
}
#menubtn:hover {
  background: var(--btn-face-hover);
}

/* ---- Rooms lit counter ---- */
#lit {
  font: 600 15px/1 var(--font-pixel);
  padding: 9px 12px 10px;
  color: var(--mute);
}
#lit b {
  color: var(--lantern);
  display: inline-block;
}
/* the count reads in the reading face, like every number on the site (see story.css) */
#lit .n {
  font-family: var(--font-read);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* a room ignites: the count pops (compositor transform) and the frame rim flashes; the fourth shimmers longer. The page script
   drops .pop when the rim animation ends, so the next room can pop again */
#lit.pop b {
  animation: lit-count-pop 0.42s steps(3);
}
#lit.pop {
  animation: lit-rim-flash 0.5s steps(2);
}
#lit.pop.all b {
  animation: lit-count-pop 0.42s steps(6) 2;
}
#lit.pop.all {
  animation: lit-rim-flash 1s steps(4);
}
@keyframes lit-count-pop {
  0% {
    transform: none;
    color: #fff3c4;
  }
  50% {
    transform: scale(1.35);
    color: #fff3c4;
  }
  to {
    transform: none;
    color: var(--lantern);
  }
}
/* the reduced-motion pop: the same flash of colour, no scaling (applied in media.css) */
@keyframes lit-count-glow {
  0%,
  50% {
    color: #fff3c4;
  }
  to {
    color: var(--lantern);
  }
}
@keyframes lit-rim-flash {
  0%,
  60% {
    border-color: var(--lantern);
  }
  to {
    border-color: #000;
  }
}

/* ---- Go to menu: a column of room buttons under the bar ---- */
#menu {
  position: fixed;
  right: max(16px, env(safe-area-inset-right));
  top: 64px;
  padding: 8px;
  display: none;
  flex-direction: column;
  gap: 6px;
  min-width: 190px;
  z-index: 30;
}
#menu.open {
  display: flex;
}
#menu button {
  text-align: left;
}

/* ---- controls hint, bottom centre; the page script fades it out after the first key or press ---- */
#hint {
  position: fixed;
  left: 50%;
  bottom: 16px;
  transform: translateX(-50%);
  padding: 8px 12px 9px;
  font: 400 14px/1.3 var(--font-pixel);
  color: var(--mute);
  width: max-content;
  max-width: calc(100vw - 32px);
  text-align: center;
  opacity: 0;
  transition: opacity 0.6s;
  pointer-events: none;
}
#hint kbd {
  font: inherit;
  color: var(--ink);
  padding: 0 4px;
  border: 1px solid var(--edge);
}

/* ---- Open guide: shown once the card is closed, and brings it back ---- */
#guide {
  position: fixed;
  right: max(16px, env(safe-area-inset-right));
  top: 72px;
  display: none;
}
#guide.show {
  display: block;
}

/* ---- toast ----
   It lives low, in the open world left of the card: top-centre is where each room's back wall lands after a teleport.
   .hi is the high slot, used when the low one would cover a cabinet screen, a live hologram, the HUD or the card */
#toast {
  position: fixed;
  left: calc((100vw - 412px) / 2);
  bottom: calc(64px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  max-width: calc(100vw - 440px);
  width: max-content;
  text-align: center;
  padding: 9px 14px 10px;
  font: 600 15px var(--font-pixel);
  display: none;
  z-index: 12;
}
#toast.show {
  display: block;
  animation: toast-rise 0.18s steps(3) both;
}
#toast.hi {
  top: 84px;
  bottom: auto;
}
@keyframes toast-rise {
  from {
    transform: translateX(-50%) translateY(12px);
    opacity: 0;
  }
  to {
    transform: translateX(-50%);
    opacity: 1;
  }
}

/* ======================================================================================================================
   The story card (#panel): the framed card on the right that opens over the world for a room or an exhibit. It owns the card's
   position and open/close transition, its Back / Read more buttons, its title and prose, and the card-only blocks the page
   script writes into #pbody (a room's exhibit list, the hub's routes, the footer of next steps). The story content it shares
   with the plain view is styled in the story content part below; the phone bottom sheet is in the media part.
   ====================================================================================================================== */

#panel {
  position: fixed;
  z-index: 10;
  right: max(16px, env(safe-area-inset-right));
  top: 72px;
  width: min(380px, calc(100vw - 32px));
  max-height: calc(100vh - 150px);
  overflow: auto;
  padding: 16px 18px 18px;
  opacity: 0;
  visibility: hidden;
  transform: translateX(14px);
  /* closing: fade and slide out, then drop out of the tab order */
  transition:
    opacity 0.25s,
    transform 0.25s,
    visibility 0s 0.25s;
}
#panel.open {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition:
    opacity 0.25s,
    transform 0.25s;
}

/* ---- navigation: Back, and Read more (phone only, it expands the bottom sheet) ---- */
#close {
  display: inline-block;
  margin: 0 0 10px;
}
#more {
  display: none;
  margin: 0 0 10px 6px;
}
/* the card's navigation buttons: 14px Pixelify (13px went soft) with room to hit */
#close,
#more,
#panel .foot .btn,
#panel .also .btn {
  font-size: 14px;
  padding: 8px 12px 9px;
}

/* ---- title and prose ---- */
#panel h2 {
  margin: 0 0 8px;
  font: 700 22px/1.15 var(--font-pixel);
  color: var(--lantern);
}
/* when a new card replaces the one that held focus, focus lands on its title; it is not a control, so no ring */
#ptitle:focus {
  outline: none;
}
#panel p,
#panel li {
  font-size: 16px;
  line-height: 1.55;
  margin: 0 0 10px;
  max-width: 62ch;
}
#panel ul {
  padding-left: 18px;
  margin: 0 0 10px;
}
/* the section a scorecard row jumps to is marked for a moment in its exhibit's colour (the page script sets --hl) */
#panel h3.hl {
  border-left: 3px solid var(--hl);
  padding-left: 7px;
  margin-left: -10px;
}

/* ---- a room card's exhibit list: icon, title, and "Read" once seen ---- */
#panel .items {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 10px 0 0;
}
#panel .items .btn {
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
  font-size: 14px;
  line-height: 1.3;
}
#panel .items .btn span {
  flex: 1;
}
#panel .items small {
  font: 400 12px var(--font-note);
}

/* ---- the hub's routes: one button per kind of visitor, each with a line saying where it goes ---- */
#panel .routes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 8px;
  margin-top: 6px;
}
#panel .routes .btn {
  text-align: left;
  line-height: 1.3;
}
/* each route's line of detail is styled with the help buttons' (story content, below) */

/* ---- footer: Next exhibit and Get in touch ---- */
#panel .foot {
  font-size: 13px;
  color: var(--mute);
  margin: 12px 0 0;
}
#panel .foot .btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
#panel .acts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 8px;
}

/* ======================================================================================================================
   Story content: the blocks inside a story's HTML, which renders twice, in the card (#panel) and in the plain view (#plain).
   The plain view turns the card's buttons into links and its h3 section headings into h4, so most rules name both forms.
   Covers section headings, the scorecard (stat rows with their bars), in-text links, draft placeholders, the contact list and
   the cross-links at the end of a story.
   ====================================================================================================================== */

/* section headings inside a story */
#panel h3,
#plain .wrap h4 {
  font: 600 16px/1.3 var(--font-pixel);
  color: var(--orb);
  margin: 14px 0 4px;
}

/* ---- scorecard: a label, a number and a bar per row ---- */
:is(#panel, #plain) .stat {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
  border-bottom: 1px dashed var(--edge);
  padding: 7px 0;
}
#panel .stat {
  font-size: 15px;
}
:is(#panel, #plain) .bar {
  grid-column: 1/-1;
  display: block;
  height: 4px;
  background: var(--edge);
}
/* the bar's fill: the page script sets its width from data-w. The card's bars start full and step to their value; the
   plain view's are set at once, with no fill animation */
:is(#panel, #plain) .bar em {
  display: block;
  height: 100%;
  background: var(--lantern);
}
#panel .bar em {
  width: 100%;
  transition: width 0.9s steps(9) 0.2s;
}
#panel .stat b {
  font-size: 18px;
  white-space: nowrap;
}
/* scorecard rows are buttons (links in the plain view): each number opens the story behind it, scrolled to its section */
:is(#panel, #plain) .stat[data-a],
#plain a.stat {
  grid-template-columns: 1fr auto auto;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-bottom: 1px dashed var(--edge);
  color: inherit;
  font-family: inherit;
  cursor: pointer;
  margin: 0;
  text-decoration: none;
}
/* the › that marks a row as a link */
.stat .go {
  font: 700 17px/1 var(--font-read);
  color: var(--mute);
  align-self: center;
  font-style: normal;
}
.stat[data-a]:hover .go,
.stat[data-a]:focus-visible .go,
#plain a.stat:hover .go {
  color: var(--lantern);
}
.stat[data-a]:hover span {
  color: #fff;
}
/* numbers read in the reading face: Pixelify closes 2 into 8 and turns 5 into S at 18px */
:is(#panel, #plain) .stat b {
  color: var(--lantern);
  font-family: var(--font-read);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---- links ---- */
#panel a:not(.btn),
#plain a:not(.btn) {
  color: var(--lantern);
}

/* ---- draft placeholders: [text still to write], shown only with ?draft (the page script drops them otherwise) ---- */
.ph {
  background: #3b2f14;
  color: #ffd98a;
  padding: 0 4px;
}
html:not(.draft) .ph {
  display: none;
}

/* ---- link buttons and the contact list ---- */
:is(#panel, #plain) a.btn,
:is(#panel, #plain) .contact .btn {
  display: inline-block;
  font-size: 14px;
  line-height: 1.3;
}
/* contact: the live link is a real button; placeholder rows read as pending (dimmed), not as broken links */
:is(#panel, #plain) .contact .btn {
  overflow-wrap: anywhere;
}
:is(#panel, #plain) .contact li:has(.btn[href]) {
  list-style: none;
  margin-left: -18px;
}
.contact .pending {
  opacity: 0.55;
  font-weight: 400;
}
.contact .pending .ph {
  font-weight: 400;
}

/* ---- the mailbox's "Or see what I can help with": full-width buttons into the stadium, each with a line of detail ---- */
#panel .help {
  margin: 4px 0 12px;
}
#panel .help h3 {
  margin-top: 4px;
}
:is(#panel, #plain) .help .btn {
  display: block;
  width: 100%;
  text-align: left;
  line-height: 1.3;
  margin: 0 0 6px;
  font-size: 14px;
}
/* the line of detail under each help button, and under each of the hub's routes in the card */
:is(#panel .routes, #panel .help, #plain .help) small {
  display: block;
  font: 400 13px var(--font-note);
  margin-top: 3px;
}

/* ---- cross-links to other rooms at the end of a story ---- */
:is(#panel, #plain) .also {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* ======================================================================================================================
   Plain view (#plain): every story as one scrolling, readable page over the world, opened from the HUD or used as the whole page
   when WebGL2 is missing. Also the no-WebGL fallbacks: the reason line at the top of the plain view, and the #nogl overlay the
   page script shows when the GL context is lost.
   ====================================================================================================================== */

#plain {
  position: fixed;
  inset: 0;
  z-index: 40;
  overflow: auto;
  background: var(--night);
  display: none;
  padding: 32px 20px 64px;
}
#plain.open {
  display: block;
}
#plain .wrap {
  max-width: 680px;
  margin: 0 auto;
}

/* ---- header: GitHub on the left, Contact and Back to the game on the right ---- */
#plain .top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 24px;
}
#plain .top div {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* ---- type ---- */
#plain h1 {
  font: 700 40px/1.05 var(--font-pixel);
  color: var(--lantern);
  margin: 0 0 8px;
}
#plain h2 {
  font: 700 24px/1.2 var(--font-pixel);
  margin: 36px 0 10px;
}
#plain h3 {
  font: 600 18px/1.3 var(--font-pixel);
  margin: 18px 0 6px;
  color: var(--lantern);
}
#plain p,
#plain li {
  font-size: 17px;
  line-height: 1.6;
  max-width: 66ch;
}

/* ---- section nav, and in-page jumps that land clear of the top edge ---- */
#plain .pnav {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin: 18px 0 8px;
  font: 600 15px var(--font-pixel);
}
#plain section,
#plain h3,
#plain h4 {
  scroll-margin-top: 16px;
}
/* the last section is at least a screen tall, so the Contact jump scrolls it to the top */
#p-mail {
  min-height: calc(100vh - 80px);
}

/* ---- no WebGL2: the plain view is the page, so its way back to the game (and the HUD's way in) go ---- */
html.nogl #backbtn,
html.nogl #plainbtn {
  display: none;
}
/* the reason, as a line at the top of the plain view (it takes its size from #plain p) */
.nogl-line {
  margin: 0 0 18px;
  padding: 8px 12px 9px;
  border-left: 3px solid var(--lantern);
  background: var(--panel);
  color: var(--mute);
}
/* the GL context was lost: a dimmed full-screen notice that reloads on tap (shown and focused by the page script) */
#nogl {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 35;
  place-items: center;
  padding: 24px;
  text-align: center;
  background: rgba(15, 13, 24, 0.82);
  font-size: 18px;
}
#nogl:focus {
  outline: none;
}

/* ======================================================================================================================
   Media: every viewport and user-preference override, last in the sheet so each one wins over the parts above.
   Phones turn the card into a bottom sheet and move the HUD bar to the bottom edge; short and narrow screens tighten spacing;
   forced colours swap the pixel shading for system colours; reduced motion keeps state changes but drops their movement.
   ====================================================================================================================== */

/* ---- phones: the card becomes a bottom sheet with a peek height (30% of the screen) and a full height (70%) ----
   safe areas (viewport-fit=cover): keep HUD, card and menu clear of notches and the home indicator */
@media (max-width: 640px) {
  #hud-name {
    left: max(10px, env(safe-area-inset-left));
    top: max(10px, env(safe-area-inset-top));
    padding: 8px 10px 9px;
  }
  #hud-name h1 {
    font-size: 19px;
  }
  #hud-name p {
    font-size: 13px;
  }
  #hud-right {
    right: max(10px, env(safe-area-inset-right));
    top: auto;
    bottom: calc(10px + env(safe-area-inset-bottom));
  }
  /* one row above the HUD (where the sheet was), so 'Open guide' never sits under the Rooms lit chip */
  #guide {
    top: auto;
    bottom: calc(58px + env(safe-area-inset-bottom));
    left: max(10px, env(safe-area-inset-left));
    right: auto;
  }
  #menu {
    right: max(10px, env(safe-area-inset-right));
    top: auto;
    bottom: calc(58px + env(safe-area-inset-bottom));
  }
  /* the keyboard hint is replaced by the touch hint, just above the peeking sheet */
  #hint {
    display: none;
  }
  #hint.touch {
    display: block;
    bottom: calc(30vh + 66px + env(safe-area-inset-bottom));
    white-space: normal;
    max-width: calc(100vw - 40px);
    font-size: 13px;
  }
  /* vh first as the fallback for browsers without dvh */
  #panel {
    left: max(10px, env(safe-area-inset-left));
    right: max(10px, env(safe-area-inset-right));
    top: auto;
    bottom: calc(58px + env(safe-area-inset-bottom));
    width: auto;
    max-height: 30vh;
    max-height: 30dvh;
    transform: translateY(14px);
  }
  #panel.full {
    max-height: 70vh;
    max-height: 70dvh;
  }
  #more {
    display: inline-block;
    margin-left: 8px;
  }
  #close,
  #more,
  #panel .foot .btn,
  #panel .also .btn {
    min-height: 36px;
  }
  /* peek order: the routes first (2x2), then a 2-line intro, so the choices are visible without scrolling */
  #pbody {
    display: flex;
    flex-direction: column;
  }
  #panel .routes {
    order: -1;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin: 0 0 10px;
  }
  #panel .routes .btn {
    font-size: 14px;
    padding: 8px 9px 9px;
  }
  #panel .routes small {
    display: none;
  }
  #panel.room:not(.full) #pbody > p:first-child {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  /* peek order: numbers and item buttons before prose (the scorecard's lead line moves under its stats) */
  #pbody > p.lead {
    order: 1;
  }
  #pbody > p.foot {
    order: 2;
  }
  #panel .items {
    order: -1;
    margin: 0 0 8px;
  }
  #panel .stat {
    padding: 4px 0;
    gap: 2px 10px;
    font-size: 14px;
    line-height: 1.35;
  }
  /* phone: just above the sheet (or above the full sheet); .hi is the high slot under the name chip */
  #toast.hi {
    top: calc(max(10px, env(safe-area-inset-top)) + 52px);
    bottom: auto;
  }
  #toast {
    left: 50%;
    max-width: calc(100vw - 32px);
    bottom: calc(30vh + 66px + env(safe-area-inset-bottom));
    bottom: calc(30dvh + 66px + env(safe-area-inset-bottom));
  }
  body:has(#panel.full.open) #toast {
    bottom: calc(70vh + 66px + env(safe-area-inset-bottom));
    bottom: calc(70dvh + 66px + env(safe-area-inset-bottom));
  }
  body:has(#panel.full.open) #toast.hi {
    bottom: auto;
  }
}

/* ---- short phones: a 1-line intro and tighter card chrome ---- */
@media (max-width: 640px) and (max-height: 700px) {
  #panel.room:not(.full) #pbody > p:first-child {
    -webkit-line-clamp: 1;
  }
  #close,
  #more {
    margin-bottom: 6px;
    padding: 5px 9px 6px;
  }
  #panel h2 {
    font-size: 20px;
    margin-bottom: 6px;
  }
  #panel .items .btn {
    padding: 6px 10px 7px;
  }
}

/* ---- short screens (landscape phones): no hint, and the card may use nearly the full height ---- */
@media (max-height: 500px) {
  #hint,
  #hint.touch {
    display: none;
  }
  #panel {
    top: 60px;
    max-height: calc(100vh - 72px);
  }
}
/* short landscape: the toast sits in the open world left of the card, not over its Back button */
@media (max-height: 500px) and (min-width: 641px) {
  #toast {
    left: calc((100vw - 396px) / 2);
    bottom: calc(14px + env(safe-area-inset-bottom));
  }
}

/* ---- narrow phones: "Rooms lit 2 of 4" plus the two buttons stay on one row ---- */
@media (max-width: 360px) {
  #hud-right {
    gap: 6px;
  }
  #hud-right .btn,
  #lit {
    padding: 8px 8px 9px;
    font-size: 13px;
  }
}

/* ---- forced colours: system button borders instead of the drawn shading, and bars that stay visible ---- */
@media (forced-colors: active) {
  .btn {
    border: 2px solid ButtonText;
  }
  .btn::before,
  .btn::after {
    display: none;
  }
  .btn:focus-visible {
    outline-color: Highlight;
  }
  :is(#panel, #plain) .bar {
    outline: 1px solid CanvasText;
  }
  :is(#panel, #plain) .bar em {
    forced-color-adjust: none;
    background: Highlight;
  }
}

/* ---- reduced motion ---- */
@media (prefers-reduced-motion: reduce) {
  /* the Rooms lit count flashes its colour without scaling */
  #lit.pop b,
  #lit.pop.all b {
    animation-name: lit-count-glow;
  }
  #panel .bar em {
    transition: none;
  }
  #toast.show {
    animation: none;
  }
  #panel,
  #panel.open {
    transition: none;
    transform: none;
  }
}
