/* Registered so the place colors fade from one to the next. */
@property --bg { syntax: '<color>'; inherits: true; initial-value: #1a1b26; }
@property --panel { syntax: '<color>'; inherits: true; initial-value: #16161e; }
@property --accent { syntax: '<color>'; inherits: true; initial-value: #9d7cd8; }
@property --accent-dim { syntax: '<color>'; inherits: true; initial-value: #695591; }

:root {
  /* The main screen's buttons (over the map, the menu's, the exits'
     middle, the HUD) take the place's colour: a tint of it on the panel. */
  --button: color-mix(in srgb, var(--accent) 24%, var(--panel));
  --button-hover: color-mix(in srgb, var(--accent) 38%, var(--panel));
  --button-line: color-mix(in srgb, var(--accent) 70%, var(--line));
  /* What's over the map (legend, about, log in): glass, not a tile's
     colour: by day white (the panel's grey over
     the map's pastels read as dirt), by night the panel; the street
     label's halo the same (mapview.js). */
  --scrim: light-dark(rgb(255 255 255 / 75%), color-mix(in srgb, var(--panel) 75%, transparent));
  /* Stardust, wherever it's said (the HUD, the bag, the shop): one colour,
     the rainbow's gold. */
  --stardust: var(--hl6);
  /* Faces: prose (Outfit; numbers that line up, stardust's, in its
     even-width digits), titles and the HUD's number (Fredoka). The dev
     menu's font tries others (body[data-font], below: Plex Mono among
     them). */
  --font-mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;
  --font-text: "Outfit", system-ui, sans-serif;
  --font-title: "Fredoka", "Outfit", system-ui, sans-serif;
  /* Tokyo Night until app.js applies the chosen theme (see themes.js).
     --accent and --accent-dim are the color of the place you're in, and
     --bg and --panel are tinted toward it. */
  --bg: #1a1b26;
  --panel: #16161e;
  --text: #c0caf5;
  --muted: #737aa2;
  --accent: #9d7cd8;
  --accent-dim: #695591;
  --line: #3b4261;
  --back: #7dcfff;
  --error: #f7768e;
  --good: #9ece6a;
  --warn: #e0af68;
  --risk: #ff9e64;
  /* The scheme's rainbow (themes.js RAINBOW: theme.js sets them). */
  --rb-red: #f7768e; --rb-orange: #ff9e64; --rb-yellow: #e0af68; --rb-green: #9ece6a; --rb-blue: #7aa2f7; --rb-purple: #bb9af7;
  color-scheme: dark;
  transition: --bg 0.4s, --panel 0.4s, --accent 0.4s, --accent-dim 0.4s;
}

* { box-sizing: border-box; scrollbar-color: var(--line) transparent; }

/* The page never zooms or moves as a whole: no double-tap zoom (tapping
   the compass fast zoomed in), no pinch, no pulling it past its edges (a
   drag on the map took the whole screen along). Only panes with more in
   them than shows (the log, the menu's tabs, a dialog's list) scroll, and
   stop at their own ends. */
* { touch-action: pan-x pan-y; }
html, body { overflow: hidden; overscroll-behavior: none; }
* { overscroll-behavior: contain; }
/* A field's text at 16px on a touch screen: smaller, a phone zooms in to it. */
@media (pointer: coarse) { input, select, textarea { font-size: 16px; } }
/* Tapping and holding is play, not the phone's own business: no text
   selection, no copy/look-up callout, no tap flash. Fields still select. */
body {
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
input, textarea { user-select: text; -webkit-user-select: text; -webkit-touch-callout: default; }
body {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.6 var(--font-text);
}

/* What sits over the map's four corners (the pill, account and dev, the
   legend's chip and help's): one look, a scrim rectangle with a hairline,
   its text at 12 px, no underline (the box says it's a button); each
   taller to a finger than it looks (44 px, ::after). One plate a corner:
   account and dev side by side in one, a line between, as the pill's light
   and theme are. */
.corner, .pill, .map-links .map-chip {
  background: var(--scrim); border: 1px solid var(--line); border-radius: 1px; font-size: 12px; color: var(--text); text-decoration: none; }
.corner .header-button { background: none; border: 0; border-radius: 0; font-size: 12px; color: var(--text); text-decoration: none; }
.corner .header-button:not([hidden]) ~ .header-button { border-left: 1px solid var(--line); }
.corner:not(:has(.header-button:not([hidden]))) { display: none; }
.corner .header-button, .map-links .map-chip { position: relative; min-height: 26px; padding: 4px 10px; }
.corner .header-button::after, .map-links .map-chip::after, .pill > button::after {
  content: ""; position: absolute; inset: -9px 0; }
.corner .header-button:hover, .map-links .map-chip:hover { background: var(--button-hover); color: var(--text); }
/* A guest's "guest": the profile's icon after it. */
.corner-icon { width: 14px; height: 14px; margin-left: 5px; vertical-align: -3px; fill: currentColor; }
/* Light or dark, in the pill (upper left), after the light. */
.theme-toggle { display: grid; place-items: center; padding: 0 10px 0 8px; color: var(--muted); background: none;
  border: 0; border-left: 1px solid var(--line); cursor: pointer; }
.theme-toggle:hover { color: var(--text); }
.theme-toggle .icon { width: 15px; height: 15px; }
/* Its menu: auto, light, dark, under it. */
.theme-menu { position: absolute; top: calc(100% + 4px); left: 0; display: flex; flex-direction: column; min-width: 7.5em;
  background: var(--panel); border: 1px solid var(--line); box-shadow: 0 4px 14px rgb(0 0 0 / 25%); z-index: 3; }
.theme-menu[hidden] { display: none; }
.theme-menu button { display: flex; align-items: center; gap: 8px; padding: 7px 10px; font: inherit; color: var(--text);
  background: none; border: 0; cursor: pointer; text-align: left; }
.theme-menu button:hover { background: var(--button-hover); }
.theme-menu button[aria-checked="true"] { color: var(--accent); }
.theme-menu .icon { width: 16px; height: 16px; flex: none; }
/* (In the tutorial, light or dark alone.) */
body.tutorial #net { display: none; }
body.tutorial .theme-toggle { border-left: 0; padding: 4px 10px; }
.corner {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  display: flex;
  align-items: stretch;
}

.muted { color: var(--muted); }
.header-button {
  padding: 2px 10px;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 1px;
  font: inherit;
  cursor: pointer;
}
.header-button:hover { border-color: var(--accent); }
/* What does something (buy): filled, a tint of the place's colour, as the
   menu's buttons; outlined is for what's on or off (a toggle, pressed: the
   accent). */
.header-button.act { background: var(--button); border-color: var(--button-line); }
.header-button.act:hover { background: var(--button-hover); }
a.header-button { text-decoration: none; }
.header-button[hidden] { display: none; }

/* The page fills the window, the map edge to edge. Narrow screens: map on
   top, then the log (which scrolls) and the compass. Wide screens: log and
   compass on the left, map on the right. */
main {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 33%) minmax(0, 1fr);
  flex: 1 1 auto;
  min-height: 0;
}
.map-pane { grid-column: 1; grid-row: 1; border-bottom: 1px solid var(--line); } /* (placed: the toast shares its cell) */
.play-pane { grid-column: 1; grid-row: 2; padding: 12px 16px; }
/* The menu or the chat open (narrow screens): the map smaller, they more of it. */
@media (max-width: 899px) { body:is(.menu-open, .chat-open) main { grid-template-rows: minmax(0, 20%) minmax(0, 1fr); } }

@media (min-width: 900px) {
  main {
    grid-template-columns: minmax(360px, 40%) minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
  }
  .play-pane { grid-column: 1; grid-row: 1; padding: 16px 24px 16px 16px; }
  .map-pane { grid-column: 2; grid-row: 1; border-bottom: 0; border-left: 1px solid var(--line); }
}

.map-pane {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
/* The map and what's laid on it. On a desktop (the map on the right), laid
   out at half the pane's width and height and blown up twice: drawn as a
   phone-sized map is, a quarter of the pixels, its cells, roads, names
   and counts all twice the size (a 2560-wide map has fine-grained roads,
   whispered names, and takes hundreds of ms a step to render without a
   GPU). */
.map-layers {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
@media (min-width: 900px) {
  .map-layers { position: absolute; left: 0; top: 0; width: 50%; height: 50%; transform: scale(2); transform-origin: 0 0; }
}
/* Progress pill over the top of the map while map data loads. */
.map-loading {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 999px;
  font: 13px var(--font-text);
  pointer-events: none;
}
.map-loading[hidden] { display: none; }
.map-loading.middle { top: 50%; transform: translate(-50%, -50%); }
.map-loading .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse 1s ease-in-out infinite alternate;
}
@keyframes pulse { from { opacity: 0.25; } to { opacity: 1; } }
/* Your cell: its outline (the map leaves it to this: it moves with you,
   unrepainted). While the map is busy (loading, finding you), a point of
   light with a fading tail runs around its edge. view.js sizes the box over
   the map's outline of the cell and sets the shapes they're cut to (--rim,
   --ring). */
.here-tile {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
  transform: translate(-50%, -50%); /* (app.js moves it: a translate first) */
  will-change: transform;
}
.here-tile[hidden] { display: none; }
/* An altar nobody holds, over the map: its hex in the flowing rainbow, as
   shimmering text (still, with reduced motion). */
.lit-tiles { position: absolute; overflow: hidden; pointer-events: none; }
.lit-tiles[hidden], .lit-tile[hidden] { display: none; }
.lit-tile { position: absolute; left: 0; top: 0; clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%); }
.lit-tile, .lit-swatch { /* (the legend's swatch for one: the same) */
  background: linear-gradient(100deg, var(--rb-red), var(--rb-orange), var(--rb-yellow), var(--rb-green),
    var(--rb-blue), var(--rb-purple), var(--rb-red), var(--rb-orange), var(--rb-yellow), var(--rb-green),
    var(--rb-blue), var(--rb-purple), var(--rb-red)) 0 50% / 200% 100%;
  animation: shimmer-flow 2s linear infinite;
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) { .lit-tile, .lit-swatch { animation: none; } }
.here-tile .spin, .here-tile .rim, .here-tile .aim { position: absolute; inset: 0; }
/* The edge a held exit goes through (view.js aimHere). */
.here-tile .aim { background: var(--accent); }
.here-tile .aim[hidden] { display: none; }
/* Each cut to its shape, which stays put; what moves is inside it. */
.here-tile .rim { background: var(--text); clip-path: var(--rim); }
.here-tile .spin { display: none; clip-path: var(--ring); }
.here-tile .spin::before {
  content: "";
  position: absolute;
  inset: 0;
  background: conic-gradient(from 10deg, transparent 0deg 240deg, rgba(255, 255, 255, 0.15) 290deg,
    #fff 340deg, rgba(255, 255, 255, 0.5) 352deg, transparent 360deg);
  animation: spin 2.4s linear infinite;
}
.here-tile.busy .spin { display: block; }
@keyframes spin { to { transform: rotate(1turn); } }
/* Walking: how sure the position is, upper left of the map, in a pill
   with light or dark. */
.pill {
  position: absolute;
  left: 12px;
  top: 12px;
  z-index: 4; /* (its menus over the map's chips: the legend's) */
  display: flex;
  align-items: stretch;
}
.pill > button { position: relative; }
.chip {
  min-height: 26px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px 4px 10px;
  border: 0;
  border-radius: 1px 0 0 1px;
  background: none;
  color: var(--muted);
  font: 12px var(--font-text);
  cursor: pointer;
}
.chip #gps-text[hidden] { display: none; }
.chip .light {
  width: 11px; /* (beside the light-or-dark icon) */
  height: 11px;
  border-radius: 50%;
  background: var(--good);
}
.chip.warn .light { background: var(--warn); }
/* At risk: orange, mixed toward red by --heat (how near a limit). */
.chip.risk .light, .whatsup-list dt.risk .light { background: color-mix(in oklab, var(--risk), var(--error) var(--heat, 0%)); }
.chip.bad .light { background: var(--error); }
.whatsup-list { display: grid; grid-template-columns: auto 1fr; gap: 10px 14px; margin: 0; max-width: 340px; }
.whatsup-list dt { display: flex; align-items: center; gap: 8px; color: var(--muted); }
.whatsup-list dt .light { width: 8px; height: 8px; border-radius: 50%; background: var(--good); flex: none; }
.whatsup-list dt.warn .light { background: var(--warn); }
.whatsup-list dt.bad .light { background: var(--error); }
.whatsup-list dt.none .light { background: var(--line); }
.whatsup-list dd { margin: 0; }
.whatsup-list dt { white-space: nowrap; }
.whatsup-list .switch { display: flex; align-items: flex-start; justify-content: flex-start; gap: 10px; color: var(--text); cursor: pointer; }
.whatsup-list .switch input { width: 18px; height: 18px; margin: 2px 0 0; flex: none; accent-color: var(--accent); }
#map {
  display: block;
  touch-action: none; /* (taps only: a drag here moves nothing) */
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  background: var(--panel);
  cursor: pointer;
}

/* The map's lower left: the legend's chip; the legend opens above it, in
   place. The lower right: about. */
.map-links { position: absolute; left: max(10px, env(safe-area-inset-left, 0px)); bottom: 10px; z-index: 3; /* (an open legend over the dungeon's bar) */
  display: flex; flex-direction: column; align-items: flex-start; gap: 9px; max-height: calc(100% - 20px); }
.map-links .map-chip[aria-expanded="true"] { background: var(--button-hover); }
.map-links .legend { display: grid; grid-template-columns: repeat(2, auto); gap: 2px 12px; padding: 6px 8px; font-size: 10px;
  background: var(--panel); border: 1px solid var(--line); color: var(--text); overflow-y: auto; min-height: 0; }
.map-links .legend[hidden] { display: none; }
.map-links-right { left: auto; right: max(10px, env(safe-area-inset-right, 0px)); align-items: flex-end; }
.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  padding: 6px 12px;
  font: 12px var(--font-text);
  color: var(--muted);
}
.legend i {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 4px;
  vertical-align: -1px;
  outline: 1px solid var(--line);
}

.play-pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

/* A standing notice above the log (offline, and the like). */
.dev-num { display: inline-flex; gap: 6px; align-items: center; }
.dev-num input { width: 5em; font: inherit; }

.notice {
  margin: 0 0 10px;
  padding: 6px 10px;
  font-size: 13px;
}
/* What the page tells you, to catch your eye: a tint of the scheme's
   colour behind it and a bar of the colour itself before it. Green, what
   helps (the game's guide, a guest's nudge to log in, a callout: the
   message of the day, a game's word); blue, the sky (a room's weather and
   time of day); purple, a trip (trips.js); yellow, how things stand (the notice above the log:
   offline, a new version); red, what went wrong. */
.notice, .log .guide, .log .nudge, .log .callout, .log .ambient:not(.event-line), .log .entry.error {
  --callout: var(--good);
  background: color-mix(in srgb, var(--callout) 16%, var(--bg));
  border-left: 4px solid var(--callout);
  border-radius: 0 6px 6px 0;
  color: var(--text);
}
.notice { --callout: var(--warn); }
.log .ambient:not(.event-line) { --callout: var(--rb-blue); }
.log .callout.trip { --callout: var(--rb-purple); } /* (taken somewhere: trips.js) */
.log .entry.error { --callout: var(--error); }
/* (button.notice's display, below, is no stronger than this.) */
.notice[hidden], button.notice[hidden] { display: none; }
/* A notice you tap (to update; a guest's log in): a button, and looks it. */
button.notice {
  display: block;
  width: 100%;
  border-top: 0;
  border-right: 0;
  border-bottom: 0;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}

/* A toast (what an act with news says), gone in a moment: on the seam
   between the map and the log (narrow screens: centred on that line, over
   the map's margin and the oldest of the log, not the cells round you;
   wide, the map's bottom). Filled in the place's accent, as the menu's
   button is, its text cut out in the page's ground;
   a no (too big, too fast, log in first) and an error red. */
.toast {
  grid-row: 1;
  grid-column: 1;
  align-self: end;
  justify-self: center;
  position: relative;
  z-index: 5; /* over the map's chips, buttons and your cell's light */
  transform: translateY(50%);
  width: max-content;
  max-width: calc(100% - 32px);
  padding: 8px 14px;
  border: 0;
  border-radius: 1px;
  background: var(--accent-tile, var(--accent));
  color: var(--bg);
  font-size: 14px;
  transition: opacity 0.3s;
}
@media (min-width: 900px) { .toast { grid-column: 2; transform: translateY(-12px); } }
.toast.no, .toast.error { background: var(--error); } /* (a no, or a nudge: the bad news red too) */
/* In a dungeon, over the bottom middle of the map, above the chips in its
   corners (legend, about): the way out (a game's look may add how a run
   stands). A toast goes above it. */
.map-bar {
  position: absolute;
  bottom: 44px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  gap: 8px;
  align-items: stretch;
  width: max-content;
  max-width: calc(100% - 16px);
}
.map-bar[hidden], .map-bar [hidden] { display: none; }
.map-bar > * {
  padding: 8px 14px;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 1px;
  box-shadow: 0 4px 16px rgb(0 0 0 / 0.3);
  font: 14px var(--font-text);
}
.map-bar button { border-color: var(--accent); cursor: pointer; }
.map-bar button:hover { filter: brightness(1.15); }
.toast.leaving { opacity: 0; }
.toast[hidden] { display: none; }

/* The log or the chat (chat.js): a pair of tabs over them, logged in. */
.log-tabs { display: flex; gap: 16px; margin: 0 0 10px; border-bottom: 1px solid var(--line); }
.log-tabs[hidden] { display: none; }
.log-tab {
  position: relative;
  margin-bottom: -1px;
  padding: 4px 2px 6px;
  background: none;
  color: var(--muted);
  border: 0;
  border-bottom: 2px solid transparent;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.log-tab.on { color: var(--text); border-bottom-color: var(--accent); }
.log-tab:hover { color: var(--text); }
.log-tab .unread-dot { display: none; position: absolute; top: 4px; right: -7px; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.log-tab.unread .unread-dot { display: block; }
.chat { display: none; flex: 1 1 auto; min-height: 0; flex-direction: column; }
body.chat-open .chat { display: flex; }
body.chat-open #log { display: none; }
.chat-list { flex: 1 1 auto; }
/* Quiet (no one's said anything): what's in the list on top, the rest
   the empty state's. */
.chat-list:has(+ .empty-state:not([hidden])) { flex: none; }
.chat > .empty-state { flex: 1 1 auto; justify-content: center; }
/* A view with next to nothing in it (the chat, the bag early on): an
   icon, a line, and what would fill it. */
.empty-state { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px; padding: 24px 16px; }
.empty-state[hidden] { display: none; }
.empty-state p { margin: 0; max-width: 32ch; }
.empty-state .empty-icon { width: 44px; height: 44px; fill: currentColor; opacity: 0.35; margin-bottom: 4px; }
.empty-state .empty-title { font-weight: 600; }
/* The room's things under what's said (room.js): two lines at most, the
   rest "…" till you've rolled up what you can. */
.chat .chat-here { flex: none; padding: 8px 0 0; border-top: 1px solid var(--line);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.chat .chat-here:empty { display: none; }
.chat-here p { margin: 0; }
.chat-list .chat-msg { margin: 0 0 6px; overflow-wrap: anywhere; }
.chat-list .chat-name { font-weight: 600; }
.chat-list .mine .chat-name { color: var(--accent); }
.chat-list .chat-said { cursor: pointer; }
.chat-list .mine .chat-said { cursor: auto; }
.chat-list .chat-time { color: var(--muted); font-size: 11px; }
.chat-list .chat-note { margin: 0 0 8px; }
.chat-list .chat-note.error { color: var(--error); }
.chat-form { display: flex; gap: 8px; padding-top: 8px; }
.chat-form input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 6px 8px;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 1px;
  font: inherit;
  font-size: 16px; /* (under 16 px, iOS zooms in on it) */
}
.chat-form input:focus-visible { outline: 1px solid var(--accent); }
.chat-form button:disabled { opacity: 0.4; cursor: default; }

/* The log: read top to bottom, newest at the bottom, like a MUD. */
.log {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-right: 8px;
  font-size: 14px;
}
/* Four colors: text, muted, and the place's accent and dim accent. Each
   room entry carries the accent of where it was; older entries fade. */
.log .entry { margin: 0 0 16px; transition: color 0.4s; }
/* Rooms before: all in the dim text colour, not faded (faded, their words
   read at 1.7-2.6:1; the dim colour is at least 4.5:1 on every ground:
   themes.js readable). A present's chip keeps its own, and what the page
   told you (the guide, a nudge, a callout, the sky, an error) all of its
   colours: the text's on its tint, as when it was said. */
.log .entry.past:not(.guide, .nudge, .callout, .error),
.log .entry.past:not(.guide, .nudge, .callout, .error) :not(.ambient:not(.event-line), .ambient:not(.event-line) *) { color: var(--muted); }
.log .entry.past .thing.present .thing-name { color: var(--bg); }
.log .entry.placeholder .thing { pointer-events: none; } /* until the engine is ready */
.log .room-title { color: var(--text); font-size: 16px; font-weight: 600; }
/* A game's tutorial (its look's tutorial hook): in the log's place, the rest of the page
   (the menu, the exits, the map) out of the way till you step out. */
#tutorial[hidden] { display: none; }
body.tutorial #log, body.tutorial #facts, body.tutorial .compass-row, body.tutorial #notice,
body.tutorial #join, body.tutorial #reload { display: none; }
body.tutorial .map-pane > :not(#tutorial-map):not(.pill) { visibility: hidden; }
.tutorial-map { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.tutorial-map[hidden] { display: none; }
/* The tutorial's exits row, bottom (what's in it: the game's look). */
.tutorial-exits { display: flex; justify-content: space-between; align-items: center; padding: 8px 0 max(10px, env(safe-area-inset-bottom)); }
.tutorial-exits[hidden] { display: none; }
/* Take me somewhere (trips.js): filled in the accent (.act); take me home
   beside it, plain. */
.play-controls { display: flex; flex-direction: column; gap: 12px; }
.trips { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.trips[hidden] { display: none; }
.log .room-area { color: var(--accent-dim); font-size: 13px; }
.log p { margin: 4px 0 0; }
.log .ambient { color: var(--muted); font-style: italic; }
.log .ambient:not(.event-line) { color: var(--text); margin-top: 8px; padding: 6px 12px; } /* (a box: above) */
.log .pois { color: var(--muted); font-weight: normal; }
.poi-open { font: inherit; color: var(--muted); background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline dotted; text-underline-offset: 3px; white-space: nowrap; }
.poi-open:hover { color: var(--accent); }
/* A dev's debug (the room's facts, lines, places after a room's name): always there,
   shown by the dev menu's one toggle (app.js), the ones before too. */
body:not(.show-debug) .log .debug, body:not(.show-debug) .pois, body:not(.show-debug) #facts { display: none; }
.pois-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; max-height: 60vh; overflow-y: auto; }
.pois-list li { line-height: 1.4; }
.poi-cat { color: var(--muted); font-size: 0.9em; }
.log .arrival { margin: 0 0 14px; color: var(--muted); font-style: italic; } /* (a paragraph before the room's title) */
.hl-name { color: var(--accent); }

/* Coloring words by where they came from (for writing text): each word list
   gets one of six colors, names their own; hover shows the list. */
body.sources .hl { color: var(--hl); }
body.sources .hl-name { color: var(--hl-name); }
.log .note { color: var(--muted); font-size: 13px; }
.log .note.nudge { color: var(--text); } /* (a callout: above) */
/* A guest's nudge to make an account: its way in a link, in the accent. */
.log .nudge .link-button { font-size: inherit; color: var(--accent); }
.log .act { font-size: 14px; }
/* The game's guide (guide.js): a line said once, in the text's colour, a
   rule of the accent before it; its links open a menu tab. */
.log .guide, .log .nudge, .log .callout, .log .entry.error { padding: 8px 12px; font-size: 14px; } /* (the text's size: what it says matters as much) */
.log .callout p { margin: 0; }
.log .callout p + p { margin-top: 8px; }
.guide-link { font: inherit; color: var(--accent); background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px; }

/* Shimmer: text that should catch your eye (the first thing to roll up, a
   first present). Its letters are a window on a rainbow (the scheme's)
   flowing through them, each letter its own colour, glowing; still, with
   reduced motion. (Two rainbows across twice its width, slid one width:
   seamless.) */
.shimmer {
  --shimmer-bg: linear-gradient(100deg, var(--rb-red), var(--rb-orange), var(--rb-yellow), var(--rb-green),
    var(--rb-blue), var(--rb-purple), var(--rb-red), var(--rb-orange), var(--rb-yellow), var(--rb-green),
    var(--rb-blue), var(--rb-purple), var(--rb-red)) 0 50% / 200% 100%; /* (a rule that sets its own background puts this back) */
  background: var(--shimmer-bg);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  animation: shimmer-flow 2s linear infinite, glow 1.6s ease-in-out infinite alternate;
}
@keyframes shimmer-flow { to { background-position: 100% 50%; } }
@keyframes glow {
  from { filter: drop-shadow(0 0 1px color-mix(in srgb, var(--rb-yellow) 60%, transparent)); }
  to { filter: drop-shadow(0 0 6px var(--rb-purple)); }
}
@media (prefers-reduced-motion: reduce) {
  .shimmer { animation: none; filter: drop-shadow(0 0 3px var(--rb-purple)); }
}
/* (Not in the rooms before: just the one you're in.) */
.log .entry.past .shimmer { animation: none; filter: none; background: none; color: inherit; -webkit-text-fill-color: currentColor; }
/* Desktop: read from farther away, in a wider column. 16 px keeps about 50
   characters to a line at the narrowest (40% of a 1280 px window). */
@media (min-width: 900px) {
  .log, .log .act { font-size: 16px; }
  .log .room-title { font-size: 18px; }
  .log .room-area { font-size: 14px; }
  .log .note { font-size: 14px; }
  .log .guide, .log .nudge, .log .callout { font-size: 16px; }
}

/* Things you can do something with: tap the line; the thing's name is
   marked. Not in old entries (that room is gone). */
.thing[data-thing] { cursor: pointer; }
.thing-name { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
/* A chip of its colour behind it: what you can tap reads as such in any
   cell's colours (a shimmer's letters are its background: none there). */
.thing-name:not(.shimmer) { background: color-mix(in srgb, var(--accent) 14%, transparent); border-radius: 3px;
  padding: 0 0.15em; -webkit-box-decoration-break: clone; box-decoration-break: clone; }
/* Too big to roll yet: the muted text color, not faded (readable: 4:1 or
   more, where opacity gave 2:1). */
/* Too big, for now: dim, bigger and bold, no
   underline (the underline says what you can roll up; a tap still says it's
   too big). */
.thing.too-big .thing-name { color: var(--muted); text-decoration: none; font-size: 1.1em; font-weight: 700; background: none; padding: 0; }
.log .entry.past .thing-name { color: inherit; text-decoration: none; font-size: inherit; font-weight: inherit; }
.log .entry.past .thing:not(.present) .thing-name { background: none; padding: 0; }
.log .entry.past .thing[data-thing] { cursor: auto; }
/* Moving fast (walk.js): the room's things wait, in the dim text. */
body.fast .log .entry:not(.past) .thing-name { color: var(--muted); text-decoration: none; }
body.fast .log .entry:not(.past) .thing:not(.present) .thing-name { background: none; padding: 0; }
body.fast .log .entry:not(.past) .thing .thing-name.shimmer { animation: none; filter: none; background: none; -webkit-text-fill-color: currentColor; }
.held p { margin: 0 0 10px; }

/* The action sheet: the thing's name, a row per verb, and cancel, at the
   bottom of the screen. */
.sheet {
  width: min(440px, calc(100% - 24px));
  max-width: none;
  margin: auto auto max(12px, env(safe-area-inset-bottom));
  padding: 0;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 1px;
}
.sheet::backdrop { background: rgba(0, 0, 0, 0.45); }
.sheet-title { padding: 12px 16px; background: var(--muted); color: var(--panel); font-weight: 600; text-align: center; }
.sheet-list button, .sheet-list a, .sheet-cancel {
  display: block;
  width: 100%;
  min-height: 48px;
  background: none;
  color: var(--accent);
  border: 0;
  border-bottom: 1px solid var(--line);
  font: inherit;
  font-size: 16px;
  cursor: pointer;
}
.sheet-list button:hover, .sheet-list button:focus-visible, .sheet-list a:hover, .sheet-list a:focus-visible { background: var(--bg); outline: none; }
/* (A row that's a link: as a button looks, its label in the middle.) */
.sheet-list a { display: flex; align-items: center; justify-content: center; box-sizing: border-box; text-decoration: none; }
.sheet-cancel { color: var(--muted); border-bottom: 0; }
.sheet u { text-underline-offset: 3px; }
/* The underlined letters are keys: none on a phone. */
@media (hover: none) and (pointer: coarse) { .sheet u { text-decoration: none; } }

/* Off the bottom edge (and the phone's home bar), above the log's end:
   three columns, the menu dead center. The row is at least as tall as the
   exits (88 px), or walking, 48, and taller for a
   HUD that is; the menu's close button (below) lands where the ☰ is. */
.compass-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  grid-template-rows: minmax(48px, auto); /* (taller for a HUD of more lines: never over the log) */
  align-items: center;
  column-gap: 12px;
  padding: 8px 0 var(--row-foot);
  border-top: 1px solid var(--line); /* (a hairline between the log and the HUD) */
}
body.keys .compass-row { grid-template-rows: minmax(88px, auto); }
/* The row's foot (the phone's home bar, else a little), and how far the ☰
   sits above it: by keys, centred on the exits' two rows (their bottom the
   row's: .compass), as the HUD's last line is (a game's look: --menu-lift).
   The ☰ as far up however tall the HUD makes the row: its close button
   (.menu-foot) as high. */
body { --row-foot: max(6px, env(safe-area-inset-bottom)); --menu-lift: calc((48px - 40px) / 2); }
body.keys { --menu-lift: calc((2 * 40px + 3px - 40px) / 2); }
body.keys .compass { align-self: end; }
#menu-open { grid-column: 2; grid-row: 1; align-self: end; margin-bottom: var(--menu-lift); }
.compass { grid-column: 3; grid-row: 1; justify-self: end; }
.compass[hidden] { display: none; }
/* The exits (compass.js): arrows, nw n ne over sw s se, each a whole 44 px
   square to tap (a finger's: the arrow's smaller), the arrow in the colour
   of the cell that way; on a desktop, its key in the corner. */
.compass { user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent; touch-action: none; }
/* The exits as tiles, 3 px apart, as the map's cells nearly touch: each
   whole 44 px square the neighbour cell as a tile (--swatch: its hue, at one
   lightness and chroma for all six: themes.js tile), the arrow cut out of
   it in the page's ground. */
.exit-words { display: grid; grid-template-columns: repeat(3, 40px); grid-auto-rows: 40px; gap: 3px; justify-content: end; }
.exit-word { position: relative; display: grid; place-items: center; width: 40px; height: 40px; padding: 0;
  font: inherit; color: var(--bg); border: 0; border-radius: 1px; cursor: pointer;
  background: var(--swatch, var(--accent-tile, var(--accent))); }
.exit-icon { width: 26px; height: 26px; }
.exit-box { display: none; }
.exit-arrow { fill: currentColor; stroke: currentColor; stroke-width: 10px; stroke-linejoin: round; }
/* Held: pressed in (a step brighter, a step smaller). */
.exit-word.held { filter: brightness(1.15); transform: scale(0.94); }
/* (The tutorial's, blocked: an outline, the arrow in it, dim.) */
.exit-word:disabled { color: var(--muted); background: none; box-shadow: inset 0 0 0 1.5px currentColor; opacity: 0.5; cursor: default; }
.exit-key { position: absolute; top: 3px; right: 3px; font-size: 10px; line-height: 1; color: var(--bg); opacity: 0.7; }
@media (pointer: coarse) { .exit-key { display: none; } }
.menu-button {
  width: 48px;
  height: 40px;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 1px;
  font: 20px/1 var(--font-text);
  cursor: pointer;
}

/* Every dialog one width (else their edges jump from one to the next). */
.settings {
  width: min(30rem, calc(100vw - 32px));
  padding: 0;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 1px;
}
.settings::backdrop { background: rgba(0, 0, 0, 0.45); }
/* A dialog's content box holds the focus as it opens (dom.js quietDialogs): no ring on it. */
.quiet-focus:focus { outline: none; }
/* The menu takes the log's place (the map stays in view); it uses the
   dialogs' look for its controls, without their box. Its tabs stay put and
   only the body scrolls. */
body.menu-open .play-pane > :not(#menu) { display: none; }
.menu-pane {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
.menu-pane[hidden] { display: none; }
.menu-pane.settings { min-width: 0; background: none; border: 0; border-radius: 0; }
.menu-head { display: flex; align-items: stretch; gap: 4px; border-top: 1px solid var(--line); }
.menu-tabs { display: flex; flex: 1 1 auto; }
/* Tabs, under the panel: an icon each (its name the tooltip), the chosen
   one's stretch of the hairline over them lit (the panel has room above
   it, so it cuts through nothing). */
.menu-tab {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: -1px;
  padding: 10px 0 10px;
  background: none;
  color: var(--muted);
  border: 0;
  border-top: 2px solid transparent;
  font: inherit;
  cursor: pointer;
}
/* The tabs in the place's colour, as what's in their panels (one colour, not a
   rainbow), the chosen one full. */
.tab-label { font-size: 11px; line-height: 1; margin-top: 3px; }
.menu-tab { color: color-mix(in srgb, var(--accent) 45%, var(--muted)); }
.menu-tab.on { color: var(--accent); border-top-color: var(--accent); }
.menu-tab:hover { color: var(--accent); }
.tab-icon { width: 24px; height: 24px; fill: currentColor; }
.menu-foot {
  display: flex;
  justify-content: center;
  padding: 8px 0 calc(var(--row-foot) + var(--menu-lift));
}
/* The menu's buttons (☰ and its close): a square with equal room around the
   icon, filled in the place's accent as a tile (its hue, as the ball's to
   its left and the exits' are theirs), the icon cut
   out in the page's ground. */
#menu-open, #menu-close {
  width: 40px;
  background: var(--accent-tile, var(--accent));
  color: var(--bg);
  border-color: transparent;
}
/* By keys: the exits 40 px squares (the tile and what a finger hits one
   box), 3 px apart, their arrows 26 px; the ☰ a square as big, dead centre
   (not beside the exits), its middle on their two
   rows; its close the same size, centred under the menu. */
body.keys #menu-open, body.keys #menu-close { width: 40px; height: 40px; }
#menu-open:hover, #menu-open:focus-visible, #menu-close:hover, #menu-close:focus-visible {
  filter: brightness(1.12);
}
.pref[hidden] { display: none; }
/* Icons drawn as SVG, so they sit dead center whatever the font (text
   glyphs like ☰ and ✕ come from fallback fonts with their own metrics). */
.icon {
  display: block;
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: square;
}
.menu-button { display: flex; align-items: center; justify-content: center; padding: 0; }
.menu-foot .icon { width: 20px; height: 20px; }
.menu-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 12px 0 20px; /* (its last line clear of the tabs) */
}
.prefs { display: flex; flex-direction: column; gap: 14px; }
.pref { display: flex; justify-content: space-between; align-items: center; gap: 16px; color: var(--muted); }
/* Side-by-side choices (radio buttons drawn as one bar). */
/* The real radio buttons stay in the bar, tiny and invisible (wider, they
   pushed the page sideways). */
.segmented { position: relative; display: inline-flex; border: 1px solid var(--line); border-radius: 1px; overflow: hidden; }
.settings .segmented label { display: block; cursor: pointer; }
.settings .segmented input { position: absolute; width: 1px; height: 1px; margin: 0; padding: 0; opacity: 0; pointer-events: none; }
.segmented span { display: block; padding: 3px 12px; color: var(--muted); }
.segmented label + label span { border-left: 1px solid var(--line); }
.segmented input:checked + span { background: var(--accent); color: var(--bg); }
.segmented input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: -2px; }
.segmented input:disabled + span { opacity: 0.4; cursor: not-allowed; }
.settings-form { display: flex; flex-direction: column; gap: 12px; padding: 16px; }
/* A dialog's head: bigger, in the accent, ruled off from what it says. */
.settings-head { display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding-bottom: 10px; border-bottom: 1px solid var(--line); color: var(--accent); font-size: 17px; font-weight: 600; }
.settings-head .header-button { font-size: 14px; font-weight: normal; }
/* A dialog's close: just an x in the corner, no box. */
.close-x { display: grid; place-items: center; width: 32px; height: 32px; margin: -6px -8px -6px 0; padding: 0;
  background: none; border: 0; color: var(--muted); cursor: pointer; }
.close-x:hover, .close-x:focus-visible { color: var(--accent); }
.close-x .icon { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.settings label { display: flex; justify-content: space-between; align-items: center; gap: 16px; color: var(--muted); }
.settings label.check { justify-content: flex-start; gap: 8px; }
.settings select, .settings-buttons button {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 1px;
  font: inherit;
  padding: 2px 6px;
}
/* A dialog's choices: going back at the left edge, going ahead at the right,
   in the accent (.primary). A lone button sits at the right. */
.settings-buttons { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; }
.settings-buttons > :first-child:not(:last-child) { margin-right: auto; }
/* (The dev menu's are tools, not a choice.) */
#dev .settings-buttons > :first-child { margin-right: 0; }
.settings-buttons button { padding: 8px 16px; }
/* Two choices (merge, wear, team, location...): halves of the row, or when
   they don't fit side by side, one above the other, each the full width
   (not one left and one right, a row apart). */
.settings-buttons:has(> button:nth-child(2):last-child) > button { flex: 1 1 auto; margin: 0; white-space: nowrap; }
.settings .primary, .settings-buttons .primary {
  background: var(--accent);
  color: var(--bg);
  border-color: var(--accent);
  font-weight: 600;
}
.settings .primary:hover { filter: brightness(1.1); }
/* What can't be undone (delete your account, join a team, give half your
   ball): red. */
.settings .danger { background: var(--error); color: var(--bg); border-color: var(--error); font-weight: 600; }
.settings .danger:disabled { opacity: 0.35; cursor: default; }
.account-form button.primary { padding: 8px 16px; }
.dev-info { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; font-size: 13px; }
.dev-maps { display: flex; gap: 8px; }
.settings input:not([type=checkbox]) {
  width: 14em;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 1px;
  font: inherit;
  padding: 2px 6px;
}
.settings input:focus-visible { outline: 1px solid var(--accent); }

/* Account: log in / new account share one form, under tabs as the
   boards' are; the dialog keeps one width (messages wrap in it). About,
   with help: its two tabs, the same, in the title's place. */
.acct-head.tabbed, .about-head.tabbed { position: relative; padding-bottom: 0; }
.acct-head .acct-tabs, .about-head .about-tabs { flex: 1 1 auto; border-bottom: 0; }
.about-head .about-tabs { margin-bottom: 0; }
.acct-head .board-tab, .about-head .board-tab { font-size: 15px; font-weight: normal; }
/* (Over the tabs' corner, not beside them: they take the whole width.) */
.acct-head.tabbed .close-x, .about-head.tabbed .close-x { position: absolute; top: 50%; right: 0; margin: 0 -8px 0 0; transform: translateY(-50%); }
.prefs[hidden], .held[hidden], .boards[hidden] { display: none; }
.boards { display: flex; flex-direction: column; gap: 10px; }
/* Your area's or the world's: tabs, as the menu's are (words here). */
.board-tabs { display: flex; border-bottom: 1px solid var(--line); }
.board-tab { flex: 1 1 0; margin-bottom: -1px; padding: 6px 0 8px; font: inherit; color: var(--muted); background: none;
  border: 0; border-bottom: 2px solid transparent; cursor: pointer; }
.board-tab.on { color: var(--text); border-bottom-color: var(--accent); }
.board-tab:hover { color: var(--text); }
/* Today, then what's behind it: a line each, the open one's list under it. */
.board-period { display: grid; gap: 6px; }
.board-when { justify-self: start; font: inherit; color: var(--muted); background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline dotted; text-underline-offset: 3px; }
.board-when:hover, .board-when:focus-visible { color: var(--text); }
.board-period.open .board-when { color: var(--accent); font-weight: 600; text-decoration: none; }
.board-body { display: grid; gap: 6px; margin-bottom: 8px; }
.board-note { margin: 0; color: var(--muted); font-size: 13px; }
/* About's tabs (about | help), and the help: sections under a heading (a
   rule above, in the text's colour: not a topic's), a title and its line each. */
.about-tabs { margin-bottom: 12px; }
.about[hidden], .about-tabs[hidden] { display: none; }
#about-help h3 { font-size: 17px; color: var(--text); margin-top: 8px; padding-top: 12px; border-top: 1px solid var(--line); }
.help { margin: 0; display: grid; gap: 4px; }
.help dt { font-weight: 700; color: var(--accent); margin-top: 10px; }
.help dt:first-child { margin-top: 0; }
.help dd { margin: 0; }
.board-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.board-list li { display: grid; grid-template-columns: 2.5em 1fr auto; gap: 8px; align-items: baseline; }
.board-rank { color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
.board-score { font-variant-numeric: tabular-nums; }
.board-you { color: var(--accent); }
.board-name { font: inherit; color: inherit; background: none; border: 0; padding: 0; text-align: left; cursor: pointer; }
.board-name:hover, .board-name:focus-visible { text-decoration: underline; }
.board-name.board-unknown { color: var(--muted); font-style: italic; cursor: default; text-decoration: none; }
.board-name.board-npc { color: var(--muted); }
.profile { display: grid; gap: 8px; }
#menu [data-panel][hidden] { display: none; } /* (a panel's own display mustn't show it on other tabs) */
.profile-row { display: grid; grid-template-columns: 8em 1fr; gap: 8px; align-items: baseline; }
.profile-head { margin: 8px 0 0; font-size: 13px; font-weight: normal; color: var(--muted); }
.profile-section { margin: 14px 0 2px; padding-bottom: 6px; border-bottom: 1px solid var(--line); font-size: 15px;
  font-weight: 600; color: var(--accent); }
.profile-foot { margin-top: 18px; display: flex; gap: 16px; align-items: center; justify-content: space-between; }
/* A guest's: what being one means, and the way to log in, under it. */
.guest-head { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.guest-head p { margin: 0; }
.profile > * { min-width: 0; } /* (grid items: shrink to the panel, never wider) */
.pick { font: inherit; color: inherit; background: none; border: 0; padding: 0; text-align: left; cursor: pointer; }
.pick[aria-pressed="true"]::after { content: " · wearing"; color: var(--muted); }
@media (max-width: 480px) { .profile-row { grid-template-columns: 8.5em 1fr; } }
.board-gap { color: var(--muted); padding-left: 2.5em; }
.account-form { display: flex; flex-direction: column; gap: 12px; }
.account-form button[type=submit] { align-self: flex-start; }
.acct-msg { margin: 0; min-height: 1.4em; font-size: 12px; color: var(--muted); }
.acct-msg.good { color: var(--accent); }
.acct-msg.bad { color: var(--error); }
.acct-msg.again { animation: shake 0.35s; }
@keyframes shake { 20%, 60% { transform: translateX(-4px); } 40%, 80% { transform: translateX(4px); } }
@media (prefers-reduced-motion: reduce) { .acct-msg.again { animation: pulse 0.35s; } }
#account-user p { margin: 0 0 8px; }
.acct-who { font-size: 20px; font-weight: 600; color: var(--text); }
.acct-other { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.acct-other[hidden], .account-form[hidden], .acct-tabs[hidden] { display: none; }
.acct-other .acct-msg:empty { display: none; }
/* Apple's: our own, as Apple's guidelines draw it (black, its logo, the
   system font), the size of Google's beside it; both centered (Google's is
   400 px at most, narrower than a dialog). */
.apple-button { position: relative; display: flex; align-items: center; justify-content: center; width: 100%;
  max-width: 400px; height: 40px; margin: 0 auto; padding: 0 0 0 39px; color: #fff; background: #000; border: 0; border-radius: 4px;
  font: 400 14px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  letter-spacing: 0.25px; cursor: pointer; }
.apple-button[hidden] { display: none; }
.apple-button:hover { background: #1a1a1a; }
.apple-button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* (The logo where Google's G is, at the left end; the words centered in the rest, as Google's are.) */
.apple-button svg { position: absolute; top: 50%; left: 11px; width: 18px; height: 18px; transform: translateY(-55%); fill: currentColor; }
.acct-provider { display: flex; justify-content: center; min-height: 44px; color-scheme: light; } /* (else a dark page paints Google's frame white behind it) */
.acct-or { margin: 0; font-size: 12px; }
.acct-pick-note { margin: 0; }
.acct-ways-head { margin: 14px 0 6px; font-size: 13px; }
.acct-ways { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.acct-connect { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.acct-connect[hidden] { display: none; }
.acct-user-foot { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-top: 16px; }
.acct-user-foot .link-button { align-self: center; }
.acct-connect .acct-ways-head { margin-bottom: 0; }
.acct-ways li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.acct-ways .muted { min-width: 0; overflow-wrap: anywhere; }
.link-button { align-self: flex-start; font: inherit; font-size: 13px; color: var(--muted); background: none; border: 0;
  padding: 0; cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.link-button:hover { color: var(--accent); }
.about { display: flex; flex-direction: column; gap: 10px; max-height: 65vh; overflow-y: auto; line-height: 1.5; }
.about p, .about ul { margin: 0; }
.about h3 { margin: 6px 0 0; font-size: 14px; color: var(--accent); }
.about ul { padding-left: 1.2em; display: grid; gap: 6px; font-size: 13px; color: var(--muted); }
.about a { color: var(--text); }
.settings-buttons button { cursor: pointer; }

#facts {
  max-height: 30vh;
  overflow-y: auto;
  margin: 10px 0 0;
  background: var(--panel);
  border: 1px solid var(--line);
  padding: 8px;
  font-size: 12px;
  white-space: pre-wrap;
}
.error { color: var(--error); }

/* The page's scripts didn't start (index.html): a notice over the bottom,
   and a button that reloads it fresh. (Plain colours to fall back on: the
   theme may not be set, with no scripts.) */
#boot-stuck {
  position: fixed;
  inset: auto 0 0;
  z-index: 40;
  display: grid;
  gap: 12px;
  background: var(--panel, #2a2633);
  color: var(--text, #ece6ff);
  padding: 16px max(16px, env(safe-area-inset-right, 0px)) max(16px, env(safe-area-inset-bottom, 0px))
    max(16px, env(safe-area-inset-left, 0px));
  border-top: 2px solid var(--accent, #b07cff);
}
#boot-stuck p { margin: 0; }
#boot-stuck button { justify-self: start; font: inherit; padding: 8px 14px; min-height: 44px; cursor: pointer; }

/* The welcome (welcome.js): a device's first visit, over the whole page
   while the game loads behind it. */
.welcome {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  overflow-y: auto;
  background: var(--bg);
  color: var(--text);
  padding: max(24px, env(safe-area-inset-top, 0px)) max(20px, env(safe-area-inset-right, 0px))
    max(24px, env(safe-area-inset-bottom, 0px)) max(20px, env(safe-area-inset-left, 0px));
  transition: opacity 0.25s ease;
}
.welcomed .welcome { display: none; }
/* The game under it isn't painted until it closes (laid out, so the map
   still measures): nothing of it shows through, and the welcome is what a
   first visit sees first. */
html:not(.welcomed):not(.playing) main { visibility: hidden; }
.welcome.leaving { opacity: 0; pointer-events: none; }
.welcome-card { width: 100%; max-width: 30rem; display: grid; gap: 18px; }
.welcome-title { margin: 0; font-size: 28px; font-weight: 600; color: var(--accent); text-wrap: balance; }
.welcome-text { margin: 0; line-height: 1.55; }
.welcome-buttons { display: grid; gap: 10px; margin-top: 6px; }
.welcome-buttons button { padding: 12px 16px; font-size: 16px; }
.welcome .primary { background: var(--accent); color: var(--bg); border-color: var(--accent); font-weight: 600; }
.welcome .primary:hover { filter: brightness(1.1); }
.welcome-note { margin: 0; font-size: 13px; line-height: 1.5; }

/* Phones: the legend and coordinates cost too much room. */
@media (max-width: 600px) {
}

/* The others to try (dev menu: font): the mono, and other pairings. */
body[data-font="plex"] { --font-text: var(--font-mono); --font-title: var(--font-mono); }
body[data-font="montserrat-comfortaa"] { --font-text: "Montserrat", system-ui, sans-serif; --font-title: "Comfortaa", "Montserrat", system-ui, sans-serif; }
body[data-font="quicksand"] { --font-text: "Quicksand", system-ui, sans-serif; --font-title: var(--font-text); }
body[data-font="montserrat"] { --font-text: "Montserrat", system-ui, sans-serif; --font-title: var(--font-text); }
.log .room-title, .welcome-title, .settings-head { font-family: var(--font-title); }
