/* Daily Dungeon components (CLAUDE.md §7). Every rule is ported from docs/design/play-screen.html and
   docs/design/share-card.html with the same values; states, motion and responsive rules extend them with
   the same tokens. No raw colors here: tokens.css only. */

/* ---------- Base (the two rules the mockups set on body/a) ---------- */
body { margin: 0; background: var(--ground); }
a { color: var(--accent); }
a:hover { color: var(--accent-hover); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* DECISIONS #367: an element only a script focuses (a screen's heading, a dialog's panel, a line of text; focusTemporarily
   in dom.js) draws no ring: a page opened from a link counts as keyboard use, and the ring flashed over the headline. */
[tabindex="-1"]:focus-visible { outline: none; }
button { cursor: pointer; }
[hidden] { display: none !important; } /* author display rules (flex) must not resurrect hidden elements */

/* JetBrains Mono line boxes pinned per size (see tokens.css): every mono element the mockups set to
   line-height normal, grouped by font size. */
.micro, .stat__label, .tile__label, .echo__label, .recap__verdict-label, .recap__tile-label,
.wall__count, .dc-table th { line-height: var(--lh-mono-11); }
.brand__meta, .meter__label, .chip, .chip-practice, .label, .kit__calling, .run__sub, .showrunner__label,
.turn__label, .tags, .run__prompt, .recap__countdown, .form-error, .archive-row__meta { line-height: var(--lh-mono-12); }
.pill, .btn-ghost, .dice, .friend, .input-mono, .toast, .dc-table { line-height: var(--lh-mono-13); }
.meter__count, .recap__subline, .btn-outline { line-height: var(--lh-mono-14); }
.stat__value { line-height: var(--lh-mono-16); }
.tile__value { line-height: var(--lh-mono-18); }
.recap__tile-value { line-height: var(--lh-mono-20); }
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.noscript { margin: 0; padding: 24px; color: var(--text); font-family: var(--font-body); font-size: 18px; }

/* ---------- Page shell ---------- */
.page { min-height: 100vh; box-sizing: border-box; padding: var(--pad-page); background: var(--ground); color: var(--text); font-family: var(--font-body); }
.container { max-width: 1392px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--gap-col); }

/* ---------- Header ---------- */
.header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px; padding: 14px 20px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); }
.brand { display: flex; align-items: center; gap: 14px; }
.brand__logo { display: block; flex: none; width: 40px; height: 40px; }   /* the Keyhole Die mark, web/brand/dd-mark.svg (DECISIONS #231) */
.brand__text { display: flex; flex-direction: column; gap: 2px; }
.brand__name { font-family: var(--font-display); font-size: 24px; letter-spacing: 1px; color: var(--accent); }
.brand__meta { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.meters { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.meter { display: flex; align-items: center; gap: 12px; }
.meter__label { font-family: var(--font-mono); font-size: 12px; color: var(--muted); letter-spacing: 1px; }
.pips { display: flex; gap: 6px; }
.pip { width: 28px; height: 10px; border-radius: 3px; background: var(--line); box-sizing: border-box; }
.pip--success { background: var(--good); }
.pip--fail { background: transparent; border: 2px solid var(--accent); }
.pip--auto { background: var(--muted); }
.pip--current { background: var(--text); }
.pip--unused { background: var(--line); }
.pip--hp { background: var(--text); }
.pip--hp-lost { background: var(--line); }
.meter__count { font-family: var(--font-mono); font-size: 14px; font-weight: 600; }
.header__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.pill { padding: 8px 12px; border-radius: var(--r-tile); background: var(--raised); font-family: var(--font-mono); font-size: 13px; }
.pill--streak strong { color: var(--accent); }
.btn-ghost { padding: 8px 12px; border-radius: var(--r-tile); border: 1px solid var(--line); background: transparent; font-family: var(--font-mono); font-size: 13px; text-decoration: none; color: var(--text); }
/* DECISIONS #340: a link styled as a ghost button centres its words and keeps the phone's 44 px minimum as its whole
   height, as a <button> does (border-box): as a block it had put them at the top of the 44 px with the padding on top,
   62 px in all (the profile's ADMIN Open, the pages' nav). */
a.btn-ghost { display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; }
.btn-ghost:hover { border-color: var(--muted); }
a.btn-ghost:hover { color: var(--text); }   /* an anchor styled as a ghost button (the profile's Admin link, M6) keeps the button look */
.chip-practice { padding: 5px 10px; border-radius: var(--r-pill); border: 1px solid var(--accent); color: var(--accent); font-family: var(--font-mono); font-size: 12px; letter-spacing: 1px; }

/* ---------- Columns (§7.5) ---------- */
.columns { display: flex; flex-wrap: wrap; gap: var(--gap-col); align-items: flex-start; }
.col-room { flex: 1 1 400px; min-width: 0; display: flex; flex-direction: column; gap: var(--gap-card); }
.col-run { flex: 2 1 520px; min-width: 0; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); display: flex; flex-direction: column; }
.col-aside { flex: 1 1 260px; min-width: 0; display: flex; flex-direction: column; gap: var(--gap-card); }

/* ---------- Cards ---------- */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); }
.card--pad { padding: var(--pad-card); display: flex; flex-direction: column; }
.label { font-family: var(--font-mono); font-size: 12px; letter-spacing: 1px; color: var(--muted); }

/* Scene */
.scene-card { overflow: hidden; }
.scene { position: relative; }
.scene > svg { display: block; width: 100%; height: auto; }
/* The room's drawn changes (DECISIONS #262): layers in the scene's own frame, each shape with a soft amber glow */
/* The keeper's chips stay on one row inside the picture's top band, which a Stage-Lit scene keeps clear (DECISIONS
   #309): a long name or mood is cut with an ellipsis. The row itself takes no pointer events (the tips hit-test
   the picture under it); the chips do. */
.scene__chips { position: absolute; top: 14px; left: 14px; right: 14px; display: flex; flex-wrap: nowrap; gap: 8px; pointer-events: none; }
.scene__chips .chip { pointer-events: auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
/* A chip cut with an ellipsis opens on a tap to show its whole text (DECISIONS #322): the row wraps and the open chip
   takes the width its text needs, over the picture while it is open */
.scene__chips .chip--cut { cursor: pointer; }
.scene__chips--open { flex-wrap: wrap; }
.scene__chips .chip--open { flex: 0 1 auto; max-width: 100%; white-space: normal; overflow: visible; text-overflow: clip; }
/* Things in the picture named on hover or tap (DECISIONS #269): a faint ring around the thing and a small tip */
.scene--hit { cursor: pointer; }
.scene__ring { position: absolute; z-index: 2; pointer-events: none; box-sizing: border-box; border: 1px dashed var(--text-soft); border-radius: 6px; opacity: 0.6; }
.scene__tip { position: absolute; z-index: 3; pointer-events: none; display: flex; flex-direction: column; gap: 2px; box-sizing: border-box; max-width: min(260px, 72%); padding: 6px 10px; background: var(--ground-glass); border: 1px solid var(--line); border-radius: var(--r-chip); font-family: var(--font-body); font-size: 15px; font-weight: 600; line-height: 1.3; color: var(--text); }
.scene__tip-flavor { font-weight: 400; font-size: 13px; line-height: 1.35; color: var(--text-soft); }
.scene__tip-note, .scene__tip-count { font-family: var(--font-mono); font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.chip { padding: 5px 10px; border-radius: var(--r-pill); background: var(--ground-glass); border: 1px solid var(--line); font-family: var(--font-mono); font-size: 12px; }
.chip--danger { border-color: var(--accent); color: var(--accent); }
.scene-card__body { padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 6px; }
.chip--holiday, .chip--changed { align-self: flex-start; margin-bottom: 4px; background: var(--raised); color: var(--text-soft); text-transform: uppercase; letter-spacing: 1px; }   /* DECISIONS #250; the room changed, #262 */
.room-title { margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 22px; letter-spacing: 0.5px; }
.room-tagline { margin: 0; font-style: italic; font-size: 16px; line-height: 1.45; color: var(--text-soft); }

/* Objective */
.objective { gap: 8px; }
.objective__text { font-size: 18px; font-weight: 600; line-height: 1.35; }
.objective__hint { font-size: 15px; line-height: 1.45; color: var(--text-soft); }

/* Kit (a <details> so it can collapse on phones) */
.kit { padding: var(--pad-card); }
.kit__head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; list-style: none; cursor: default; }
.kit__head::-webkit-details-marker { display: none; }
.kit__head:focus-visible { outline-offset: 4px; }
.kit__calling { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.kit__toggle { display: none; }
.kit__body { display: flex; flex-direction: column; gap: 12px; padding-top: 12px; }
.item { display: flex; align-items: center; gap: 12px; }
/* Lost rows: the mockup fades the whole row to .55, which leaves the 14 px flavor (--muted) at 3.1:1 on
   --surface (axe serious; AA needs 4.5:1). The icon and the struck-through name keep the mockup's fade
   (the name still reads 5.0:1); the flavor fades only to .8, which is 5.1:1 (M4 Frontend decision). */
.item--lost .item__icon, .item--lost .item__name { opacity: 0.55; }
.item--lost .item__flavor { opacity: 0.8; }
.item__icon { width: 40px; height: 40px; flex: none; border-radius: var(--r-tile); background: var(--raised); display: flex; align-items: center; justify-content: center; color: var(--text); }
.icon { display: inline-flex; width: 22px; height: 22px; }
.icon svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; display: block; }
.item__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.item__name { font-weight: 600; font-size: 16px; }
.item--lost .item__name { text-decoration: line-through; }
.item__flavor { font-size: 14px; color: var(--muted); }
.stats { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; padding-top: 4px; }
.stat { background: var(--raised); border-radius: var(--r-stat); padding: 8px 4px; text-align: center; font-family: var(--font-mono); }
.stat--top { border: 1px solid var(--accent); }
.stat__label { font-size: 11px; color: var(--muted); }
.stat__value { font-size: 16px; font-weight: 600; }
.stat--top .stat__value { color: var(--accent); }

/* ---------- The Run ---------- */
.run__head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 8px; padding: 16px 22px; border-bottom: 1px solid var(--line); }
/* The title and the run clock (DECISIONS #230). Centred on the title's 23 px line, and no taller than it, so
   the head keeps the mockup's height; the group's baseline is still the title's for .run__head. */
.run__heading { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.run__title { margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 18px; letter-spacing: 0.5px; }
.run__clock { display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px; border: 1px solid var(--line); border-radius: var(--r-pill); font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); color: var(--text); font-variant-numeric: tabular-nums; }
.run__clock-icon { flex: none; fill: none; stroke: var(--good); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.run__clock--paused { color: var(--muted); }
.run__clock--paused .run__clock-icon { stroke: var(--muted); }
.run__sub { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.run__log { padding: 20px 22px; display: flex; flex-direction: column; gap: 22px; }
.showrunner { display: flex; flex-direction: column; gap: 6px; }
.showrunner--later { padding-top: 18px; border-top: 1px dashed var(--line); }
.showrunner__label { font-family: var(--font-mono); font-size: 12px; letter-spacing: 1px; color: var(--good); }
.showrunner__text { margin: 0; font-size: 18px; line-height: 1.5; font-style: italic; }
.turn { display: flex; flex-direction: column; gap: 10px; padding-top: 18px; border-top: 1px dashed var(--line); }
.turn__label { font-family: var(--font-mono); font-size: 12px; letter-spacing: 1px; color: var(--muted); }
.turn__result { display: flex; flex-direction: column; gap: 10px; }
.bubble { margin: 0; font-size: 17px; line-height: 1.45; padding: 10px 14px; background: var(--raised); border-radius: var(--r-tile); overflow-wrap: anywhere; }
.dice { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; font-family: var(--font-mono); font-size: 13px; }
.check { padding: 5px 10px; border-radius: var(--r-chip); border: 1px solid var(--line); }
.d20 { display: inline-block; min-width: 28px; text-align: center; padding: 2px 6px; border-radius: var(--r-chip); background: var(--text); color: var(--ground); }
/* Two dice on an edge (M6, DECISIONS #223 item 10): the kept die renders as the single die always did; the
   other is dimmed to a raised tile in --muted (5.1:1 on --raised). A one-die roll has neither class. */
.d20--dropped { background: var(--raised); color: var(--muted); box-shadow: inset 0 0 0 1px var(--line); }
.edge { padding: 5px 8px; border-radius: var(--r-chip); border: 1px solid var(--line); font-size: 11px; letter-spacing: 1px; color: var(--muted); line-height: var(--lh-mono-11); }
.badge { padding: 5px 10px; border-radius: var(--r-chip); background: var(--good); color: var(--on-good); font-weight: 600; }
.badge--fail { padding: 4px 10px; background: transparent; border: 2px solid var(--accent); color: var(--accent); }
.narration { margin: 0; font-size: 17px; line-height: 1.55; color: var(--text-narr); overflow-wrap: anywhere; white-space: pre-line; }
.tags { display: flex; flex-wrap: wrap; gap: 8px; font-family: var(--font-mono); font-size: 12px; }
.tag { padding: 4px 9px; border-radius: var(--r-chip); background: var(--raised); }
.tag--danger { color: var(--accent); }
.considering { margin: 0; font-size: 17px; line-height: 1.55; font-style: italic; color: var(--muted); }
.dots span { display: inline-block; animation: dot-pulse 1.6s infinite ease-in-out; }
.dots span:nth-child(2) { animation-delay: 0.27s; }
.dots span:nth-child(3) { animation-delay: 0.54s; }
.turn__error { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.run__input, .run__confirm { margin-top: auto; padding: 18px 22px 22px; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 10px; }
.run__prompt { font-family: var(--font-mono); font-size: 12px; letter-spacing: 1px; color: var(--accent); }
.textarea { width: 100%; box-sizing: border-box; resize: vertical; padding: 14px 16px; border-radius: var(--r-control); border: 2px solid var(--accent); background: var(--ground); color: var(--text); font-family: var(--font-body); font-size: 17px; line-height: 1.45; }
.textarea:disabled { border-color: var(--line); color: var(--text-soft); }
.run__foot { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; }
/* DECISIONS #254: the 280-character limit shows near the end; at the limit it says so, in amber. */
.run__count { margin-left: auto; font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.run__count--full { color: var(--accent); }
.hint { font-size: 14px; color: var(--muted); }
.btn-primary { min-height: 48px; padding: 0 22px; border: none; border-radius: var(--r-control); background: var(--accent); color: var(--ground); font-family: var(--font-display); font-size: 16px; letter-spacing: 0.5px; }
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary:disabled { opacity: 0.5; cursor: default; }
/* The account page's forms (DECISIONS #304): the primary action at a third of the size, beside Cancel; on a phone it keeps
   the 44 px touch target. */
.btn-primary--small { min-height: 34px; padding: 0 12px; border-radius: var(--r-tile); font-size: 12px; letter-spacing: 0.5px; }
@media (max-width: 759px) { .btn-primary--small { min-height: 44px; padding: 0 16px; font-size: 14px; } }
/* DECISIONS #294: the room closed by the daily player cap; the line under the button appears on hover, focus or tap */
.btn-primary.is-closed { opacity: 0.5; cursor: not-allowed; }
.arrival__closed { margin: 0; font-size: 14px; color: var(--accent); }
.run__ended { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; }
/* Leave the room (M6, DECISIONS #223 item 4): a compact ghost button at the right end of the prompt row while
   the run is ACTIVE. Above 760 px it is absolutely positioned, so the row keeps the label's 14 px line box and
   nothing below it moves (the pinned play-screen baseline); on phones it joins the row and grows to 44 px. */
.run__prompt-row { position: relative; display: flex; align-items: center; min-height: var(--lh-mono-12); }
.run__leave { position: absolute; right: 0; top: 50%; transform: translateY(-50%); padding: 4px 10px; font-size: 12px; line-height: var(--lh-mono-12); }
/* The inline confirmation that replaces the input block until Leave or Stay (.run__confirm shares .run__input's box). */
.run__confirm-text { margin: 0; font-size: 16px; line-height: 1.45; color: var(--text); }
.run__confirm-text:focus-visible { outline-offset: 4px; }
.run__confirm-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }

/* ---------- Aside panels ---------- */
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); padding: var(--pad-card); display: flex; flex-direction: column; gap: 14px; }
.panel--today { gap: 12px; }
.panel--friends { gap: 10px; }
.panel__head { display: flex; flex-direction: column; gap: 4px; }
.panel__title { margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 16px; letter-spacing: 0.5px; }
/* DECISIONS #241: the Leaderboard link rides on the panel's title row, so the panel keeps its height. */
.panel__titlebar { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.panel__link { padding: 0; border: 0; background: none; font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); cursor: pointer; }
.panel__link:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }

/* ---------- The footer and the donate dialog (DECISIONS #248) ---------- */
.site-footer { max-width: 1392px; margin: 0 auto; padding: 8px var(--pad-page) 28px; box-sizing: border-box; display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.site-footer__motto { margin: 0; font-family: var(--font-body); font-style: italic; font-size: 15px; line-height: 1.4; color: var(--text-soft); }
.site-footer__line, .site-footer__links, .site-footer__give { margin: 0; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 4px 10px; font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); letter-spacing: 0.5px; color: var(--muted); }   /* the links: DECISIONS #332 */
.site-footer__donate-wrap { display: inline-flex; align-items: center; gap: 10px; }
.site-footer__donate-wrap[hidden] { display: none; }
.site-footer a, .site-footer__donate { color: var(--muted); text-decoration: none; }
/* DECISIONS #332: with a third line of links under the mail link, every footer target keeps the 24 px minimum (WCAG 2.5.8) */
.site-footer a, .site-footer__donate { display: inline-flex; align-items: center; min-height: 24px; }
.site-footer a:hover, .site-footer__donate:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.site-footer__donate { display: inline-flex; align-items: center; gap: 6px; padding: 0; border: 0; background: none; font: inherit; letter-spacing: inherit; cursor: pointer; }
.site-footer__donate .icon, .site-footer__donate .icon svg { width: 14px; height: 14px; }
.donate-modal { max-width: 440px; }
.donate { display: flex; flex-direction: column; gap: 12px; }
.donate__line { margin: 0; font-style: italic; font-size: 17px; line-height: 1.45; color: var(--text-soft); }
.donate__amounts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; padding: 0; border: 0; }
.donate__amounts legend { padding: 0; margin-bottom: 6px; }
.donate__choice { display: inline-flex; align-items: center; gap: 8px; }
.donate__chip { display: inline-flex; align-items: center; justify-content: center; min-width: 64px; min-height: 44px; padding: 0 16px; box-sizing: border-box; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--raised); color: var(--text); font-family: var(--font-mono); font-size: 15px; cursor: pointer; }
.donate__chip:hover { border-color: var(--text-soft); }
.donate__choice input:checked + .donate__chip { border-color: var(--good); color: var(--good); }
.donate__choice input:focus-visible + .donate__chip { outline: 2px solid var(--accent); outline-offset: 2px; }
.donate__other { display: inline-flex; align-items: center; gap: 4px; }
.donate__currency { font-family: var(--font-mono); font-size: 15px; color: var(--muted); }
.donate__other-input { width: 96px; font-family: var(--font-mono); }
.donate__rule { margin: 0; color: var(--muted); }
.donate .form-error { margin: 0; }
.donate .form-error:empty { display: none; }
.donate__actions { display: flex; }
.donate__note { margin: 0; font-family: var(--font-mono); font-size: 11px; line-height: 1.5; letter-spacing: 0.5px; color: var(--muted); }

/* ---------- The leaderboard (DECISIONS #241) ---------- */
.leaderboard__meta { margin: 0; }
.leaderboard__panel { display: flex; flex-direction: column; gap: 10px; }
.leaderboard__list { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; }
.leaderboard__list--you { padding-top: 10px; border-top: 1px dashed var(--line); }
.leaderboard__row { display: grid; grid-template-columns: 3.4em minmax(0, 1fr) auto; align-items: center; gap: 4px 12px; min-height: 44px; padding: 8px 14px; box-sizing: border-box; border-radius: var(--r-tile); background: var(--raised); }
.leaderboard__row--mine { outline: 2px solid var(--good); outline-offset: -2px; }
.leaderboard__rank { font-family: var(--font-mono); font-size: 14px; font-weight: 600; color: var(--muted); }
.leaderboard__who { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; min-width: 0; }
.leaderboard__name { font-family: var(--font-body); font-size: 16px; font-weight: 600; overflow-wrap: anywhere; }
.leaderboard__detail { font-family: var(--font-mono); font-size: 13px; color: var(--text-soft); }
.leaderboard__score { font-family: var(--font-display); font-size: 18px; }
.howto__score { display: flex; flex-direction: column; gap: 8px; }
.howto__score p { margin: 0; }
.howto__criteria { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 4px; }
.echo { display: flex; flex-direction: column; gap: 4px; padding: 12px; background: var(--raised); border-radius: var(--r-tile); }
.echo__label { font-family: var(--font-mono); font-size: 11px; color: var(--muted); }
.echo__text { font-size: 15px; line-height: 1.4; overflow-wrap: anywhere; }
.echo__text--quote { font-style: italic; }
.echo__pending { font-style: normal; color: var(--muted); }
.echo--empty .echo__text { color: var(--muted); font-style: italic; }
/* DECISIONS #254: whose scratch, as an inset outline (no layout shift) beside the label's "· you" / "· friend":
   yours in teal (the player, as on the leaderboard), a friend's in the dungeon's yellow-orange. */
.echo--mine { box-shadow: inset 0 0 0 2px var(--good); }
.echo--friend { box-shadow: inset 0 0 0 2px var(--accent); }
.tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; font-family: var(--font-mono); }
.tile { background: var(--raised); border-radius: var(--r-stat); padding: 10px; }
.tile__label { font-size: 11px; color: var(--muted); }
.tile__value { font-size: 18px; font-weight: 600; }
.today__line { font-size: 14px; line-height: 1.45; color: var(--text-soft); }
.micro { font-family: var(--font-mono); font-size: 11px; color: var(--muted); }
.friend, .request { display: flex; justify-content: space-between; gap: 8px; font-family: var(--font-mono); font-size: 13px; }
.status--good { color: var(--good); }
.status--bad { color: var(--accent); }
.status--muted { color: var(--muted); }
/* The friends in a box of their own (DECISIONS #287): the same 10 px between rows as the panel, and past eight rows
   (friends.js SCROLL_FROM) it scrolls instead of growing, a region a keyboard can reach. */
.friends__list { display: flex; flex-direction: column; gap: 10px; flex: none; }
.friends__list--scroll { max-height: 300px; overflow-y: auto; padding-right: 4px; }
.friends__me { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 8px; padding-top: 6px; border-top: 1px dashed var(--line); font-family: var(--font-mono); font-size: 13px; }
.friends__me .btn-ghost { padding: 4px 10px; font-size: 12px; }
.friends__form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.input-mono { padding: 8px 10px; border-radius: var(--r-stat); border: 1px solid var(--line); background: var(--ground); color: var(--text); font-family: var(--font-mono); font-size: 13px; min-width: 0; flex: 1 1 120px; }
.input-mono:focus { border-color: var(--accent); outline: none; }
.form-error { font-family: var(--font-mono); font-size: 12px; color: var(--accent); }

/* ---------- Arrival (§7.2.1) ---------- */
.arrival { display: flex; flex-wrap: wrap; gap: var(--gap-col); align-items: flex-start; }
.arrival__room { flex: 1 1 400px; min-width: 0; display: flex; flex-direction: column; gap: var(--gap-card); }
.arrival__enter { flex: 1 1 400px; min-width: 0; padding: 22px; gap: 18px; }
.arrival__enter .btn-primary { align-self: flex-start; min-height: 52px; font-size: 17px; }

/* ---------- Recap (share-card.html) ---------- */
/* The overlay hangs off <body>, outside .page, so it sets the page's text colour and face itself: before M6 the
   submitted wall scratch (in the wall card, a sibling of .recap, which sets its own) inherited the UA black Times
   (DECISIONS #223 item 1); the scratch is now an .echo card with the label, as in the Echoes panel. */
.recap-overlay { position: fixed; inset: 0; z-index: 50; overflow: auto; background: var(--scrim); display: flex; flex-direction: column; color: var(--text); font-family: var(--font-body); }
.recap-stack { display: flex; flex-direction: column; gap: var(--gap-col); margin: auto; }
.recap { width: 390px; box-sizing: border-box; padding: 28px 24px; background: var(--ground); color: var(--text); font-family: var(--font-body); display: flex; flex-direction: column; gap: 20px; }
/* The mark beside the two title lines (DECISIONS #231): 48 px, no taller than the lines, so nothing below moves. */
.recap__brand { display: flex; align-items: center; gap: 12px; }
/* DECISIONS #252: a shared run's card names its player above everything else, in the player's teal. */
.recap__shared { display: flex; flex-direction: column; gap: 4px; padding: 12px 16px; border: 1px solid var(--good); border-radius: var(--r-tile); }
.recap__shared-label { font-family: var(--font-mono); font-size: 12px; letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.recap__shared-name { font-family: var(--font-display); font-size: 22px; letter-spacing: 0.5px; line-height: 1.2; color: var(--good); overflow-wrap: anywhere; }
.recap__logo { display: block; flex: none; width: 48px; height: 48px; }
.recap__brand-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.recap__name { font-family: var(--font-display); font-size: 18px; letter-spacing: 1px; color: var(--accent); }
.recap__room { font-size: 17px; font-style: italic; color: var(--text-soft); }
/* Centred since DECISIONS #287 (the user's choice, from the phone's result screen): the headline and the subline over the
   turns as tiles, in place of the mockup's left-aligned headline and squares. */
/* DECISIONS #324: the block reads left to right since the keeper's medallion (centred before, DECISIONS #287). */
.recap__result { display: flex; flex-direction: column; align-items: stretch; text-align: left; gap: 0; padding: 22px 20px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-recap); }
.recap__headline { font-family: var(--font-display); font-size: 46px; line-height: 1; }
.recap__headline--ESCAPED { color: var(--good); }
.recap__headline--DIED { color: var(--accent); }
.recap__headline--TRAPPED { color: var(--text); }
.recap__headline--LEFT { color: var(--text); }   /* M6 (DECISIONS #223 item 4): like TRAPPED */
.recap__subline { font-family: var(--font-mono); font-size: 14px; color: var(--text-soft); padding-top: 8px; }
/* DECISIONS #324: the keeper's medallion (components/medallion.js) beside the headline and the subline, the keeper's
   name and the state the run left them in under them. The hexagon's rim is the dungeon's amber; the cut of the scene
   keeps the scene's own colours. */
.recap__top { display: flex; align-items: center; gap: 14px; min-width: 0; }
.recap__title { display: flex; flex-direction: column; justify-content: center; min-width: 0; }
.recap__title .recap__subline { padding-top: 6px; }
.recap__keeper { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding-top: 14px; font-family: var(--font-mono); font-size: 13px; color: var(--text); }
.recap__keeper-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.recap__keeper-state { flex: none; color: var(--muted); }
.medallion { display: block; flex: none; width: 88px; height: 92px; }
.medallion__svg { display: block; width: 100%; height: 100%; }
.medallion__bg { fill: var(--surface); }
.medallion__rim { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linejoin: round; }
/* The turns as tiles (DECISIONS #287, the handoff's result screen): T1 over the stat with a check or a cross, a teal
   inset outline for a success, an amber one for a fail, AUTO for a turn that needed no roll, an en dash for a turn not
   played; a LEFT run's unplayed tiles are black, like the share text's ⬛. The phone's Result tab uses the same. */
.dd-recap { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; width: 100%; box-sizing: border-box; padding-top: 18px; }
.dd-rt { padding: 9px 2px; border-radius: 10px; background: var(--raised); text-align: center; font-family: var(--font-mono); font-size: 10px; font-weight: 500; line-height: 1; color: var(--muted); }
.dd-rt b { display: block; margin-top: 5px; font-size: 11.5px; font-weight: 600; line-height: 1; color: var(--muted); white-space: nowrap; }
.dd-rt.is-ok { box-shadow: inset 0 0 0 1.5px var(--good); }
.dd-rt.is-ok b { color: var(--good); }
.dd-rt.is-fail { box-shadow: inset 0 0 0 1.5px var(--accent); }
.dd-rt.is-fail b { color: var(--accent); }
.recap--LEFT .dd-rt.is-unused { background: var(--ground); }
/* In the card the tiles stand as tall as the mockup's squares and their labels (63 px), so nothing below them moves. */
.recap .dd-rt { display: flex; flex-direction: column; justify-content: center; box-sizing: border-box; min-height: 63px; }
.recap__verdict { display: flex; flex-direction: column; gap: 8px; padding: 18px 20px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-recap); }
.recap__verdict-label { font-family: var(--font-mono); font-size: 11px; letter-spacing: 1px; color: var(--good); }
.recap__verdict-text { margin: 0; font-size: 18px; line-height: 1.45; font-style: italic; }
.recap__verdict-text--pending { color: var(--muted); }
.recap__tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; font-family: var(--font-mono); }
.recap__tiles--practice { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.recap__tile { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-control); padding: 12px 10px; }
.recap__tile-label { font-size: 11px; color: var(--muted); }
.recap__tile-value { font-size: 20px; font-weight: 600; }
.recap__tile-value--style, .recap__tile-value--score { color: var(--accent); }
/* DECISIONS #241: RANK opens the leaderboard; the chevron is drawn here so the value reads as the number. */
.recap__tile--link { display: block; width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer; }
.recap__tile--link > span { display: block; }
.recap__tile--link .recap__tile-value::after { content: ' ›'; color: var(--muted); }
.recap__tile--link:hover { border-color: var(--accent); }
.recap__actions { margin-top: auto; display: flex; flex-direction: column; gap: 10px; }
.btn-share, .btn-again { min-height: 52px; border: none; border-radius: var(--r-card); background: var(--accent); color: var(--ground); font-family: var(--font-display); font-size: 17px; letter-spacing: 0.5px; }
.btn-share:hover, .btn-again:hover { background: var(--accent-hover); }
.btn-again { width: 100%; }
.btn-again:disabled { opacity: 0.5; cursor: default; }
.recap__again { display: flex; flex-direction: column; }  /* no gap: the empty alert span costs nothing */
.recap__error:not(:empty) { padding-top: 6px; text-align: center; }
.btn-outline { min-height: 48px; border: 1px solid var(--line); border-radius: var(--r-card); background: transparent; color: var(--text); font-family: var(--font-mono); font-size: 14px; }
.btn-outline:hover { border-color: var(--muted); }
/* The recap's Return in Share result's size and type (Bungee 17, its caps, 52 px), outlined so Share stays the one
   primary action (DECISIONS #231). */
.btn-outline.recap__return { min-height: 52px; font-family: var(--font-display); font-size: 17px; letter-spacing: 0.5px; line-height: normal; }
.recap__countdown { text-align: center; font-family: var(--font-mono); font-size: 12px; color: var(--muted); padding-top: 4px; }
/* DECISIONS #254: the wall inside the card, the first of the actions (above Share result). */
.wall { display: flex; flex-direction: column; gap: 8px; }
.wall__open { width: 100%; min-height: 44px; }
.wall__panel { display: flex; flex-direction: column; gap: 6px; }
.wall__foot { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.wall__foot .hint { font-size: 13px; }
/* DECISIONS #320: How was today's room?, above the wall. The question in Spectral italic, two square thumb buttons
   (the chosen one in its colour: teal up, amber down), the note box in mono, the private line with the lock, Done;
   settled, the chosen thumb as a mark beside the Showrunner's line. */
.feedback { display: flex; flex-direction: column; gap: 10px; }
.feedback__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.feedback__ask { margin: 0; font-size: 17px; font-style: italic; color: var(--text); line-height: 1.3; }
.feedback__optional { margin-left: 8px; font-family: var(--font-mono); font-size: 12px; font-style: normal; color: var(--muted); }
.feedback__thumbs { display: flex; flex: none; gap: 8px; }
.feedback__thumb { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; padding: 0; border: 1px solid var(--line); border-radius: var(--r-tile); background: transparent; color: var(--muted); cursor: pointer; }
.feedback__thumb:hover { border-color: var(--muted); color: var(--text); }
.feedback__thumb.is-on, .feedback__thumb.is-on:hover { border-color: var(--good); color: var(--good); }
.feedback__thumb--down.is-on, .feedback__thumb--down.is-on:hover { border-color: var(--accent); color: var(--accent); }
.feedback__panel { display: flex; flex-direction: column; gap: 8px; }
.feedback__note { display: block; width: 100%; min-height: 104px; box-sizing: border-box; padding: 12px; resize: none; border-radius: var(--r-tile); border: 1px solid var(--line); background: var(--ground); color: var(--text); font-family: var(--font-mono); font-size: 15px; line-height: 1.45; }
.feedback__note::placeholder { color: var(--muted); opacity: 1; }
.feedback__note:focus { border-color: var(--accent); outline: none; }
@media (max-width: 759px) { .feedback__note { font-size: 16px; } }   /* no zoom on focus (iOS) */
.feedback__foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.feedback__private { display: inline-flex; align-items: flex-start; gap: 6px; font-family: var(--font-mono); font-size: 12px; line-height: 1.4; color: var(--muted); }
.feedback__private .icon, .feedback__private .icon svg { width: 14px; height: 14px; flex: none; }
.feedback__private .icon { margin-top: 1px; }
.feedback__done { flex: none; min-width: 72px; min-height: 44px; }
.feedback__row--noted { justify-content: flex-start; }
.feedback__mark { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 40px; height: 40px; border: 1px solid var(--good); border-radius: var(--r-tile); color: var(--good); }
.feedback__mark--down { border-color: var(--accent); color: var(--accent); }
.feedback__noted { margin: 0; font-size: 16px; font-style: italic; line-height: 1.35; color: var(--text); }
.feedback__noted:focus-visible { outline-offset: 4px; }
/* DECISIONS #241: "How your run was scored", a card under the recap. Collapsed by default (DECISIONS #269): the
   title row is a toggle, SHOW / HIDE at its right in the kit toggle's micro style. */
.score-card { width: 390px; box-sizing: border-box; padding: 18px 20px; gap: 12px; }
.score-card--collapsed { gap: 0; }
.score-card__head { margin: 0; font-weight: 400; }
.score-card__toggle { display: flex; width: 100%; justify-content: space-between; align-items: baseline; gap: 12px; padding: 0; border: 0; background: none; color: inherit; font: inherit; letter-spacing: inherit; text-align: left; cursor: pointer; }
.score-card__toggle:hover { color: var(--text); }
.score-card__title { text-transform: uppercase; }
.score-card__state { flex: none; font-family: var(--font-mono); font-size: 11px; letter-spacing: 1px; color: var(--muted); }
.score-card__body { display: flex; flex-direction: column; gap: 10px; }
.score-card__parts { display: flex; flex-direction: column; gap: 10px; margin: 0; padding: 0; list-style: none; }
.score-card__row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.score-card__name { font-family: var(--font-body); font-size: 16px; font-weight: 600; }
.score-card__points { font-family: var(--font-mono); font-size: 13px; color: var(--muted); }
.score-card__play { padding-top: 10px; border-top: 1px dashed var(--line); }
.score-card__play-points { font-family: var(--font-mono); font-size: 13px; color: var(--muted); }
.score-card__why { margin: 2px 0 0; font-size: 15px; color: var(--text-soft); line-height: 1.4; }
.score-card__total { padding-top: 10px; border-top: 1px dashed var(--line); }
.score-card__style { font-family: var(--font-mono); font-size: 18px; font-weight: 600; color: var(--accent); }
.score-card__score { font-family: var(--font-display); font-size: 20px; }
.score-card__formula { margin: 0; font-family: var(--font-mono); font-size: 13px; color: var(--text-soft); }
.score-card__rank { margin: 0; }
.wall__form { display: flex; flex-wrap: wrap; gap: 8px; }
.wall__input { flex: 1 1 180px; min-width: 0; box-sizing: border-box; padding: 10px 12px; border-radius: var(--r-tile); border: 1px solid var(--line); background: var(--ground); color: var(--text); font-family: var(--font-body); font-size: 16px; }
.wall__input:focus { border-color: var(--accent); outline: none; }
.wall__count { font-family: var(--font-mono); font-size: 11px; color: var(--muted); }

/* ---------- Modals, toasts, loading ---------- */
.modal-overlay { position: fixed; inset: 0; z-index: 60; overflow: auto; background: var(--scrim); display: flex; flex-direction: column; padding: 24px; box-sizing: border-box; }
.modal { margin: auto; width: 100%; max-width: 640px; box-sizing: border-box; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); padding: 20px 22px; display: flex; flex-direction: column; gap: 14px; color: var(--text); font-family: var(--font-body); }
.modal__head { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.modal__head--bare { justify-content: flex-end; }   /* the profiles: Close alone (DECISIONS #260) */
.modal__title { margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 18px; letter-spacing: 0.5px; }
.howto__steps { margin: 0; padding-left: 22px; font-size: 16px; line-height: 1.5; display: flex; flex-direction: column; gap: 6px; }
.howto__example { display: flex; flex-direction: column; gap: 10px; padding: 12px 14px; background: var(--raised); border-radius: var(--r-tile); }
.dc-table { width: 100%; border-collapse: collapse; font-family: var(--font-mono); font-size: 13px; }
.dc-table th, .dc-table td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line); }
.dc-table th { font-size: 11px; letter-spacing: 1px; color: var(--muted); font-weight: 400; }
.dc-table td.num { font-weight: 600; }
.archive-list { display: flex; flex-direction: column; gap: 8px; margin: 0; padding: 0; list-style: none; }
.archive-row { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 8px 12px; min-height: 44px; padding: 10px 14px; box-sizing: border-box; border-radius: var(--r-tile); background: var(--raised); color: var(--text); font-family: var(--font-body); font-size: 16px; }
.archive-row__text { flex: 1 1 200px; min-width: 0; display: flex; flex-direction: column; }  /* margins, not gap: the empty alert span costs nothing */
.archive-row__meta { margin-top: 2px; font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.archive-row__error:not(:empty) { margin-top: 4px; }
/* A profile row that opens the run's end screen (DECISIONS #287): the row itself is the button. */
.archive-row.profile-row--link { width: 100%; border: 0; font: inherit; font-size: 16px; cursor: pointer; text-align: left; }
.archive-row.profile-row--link:hover { background: var(--line); }
.archive-row__action { flex: none; margin-left: auto; }
.toast-stack { position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%); z-index: 70; display: flex; flex-direction: column; gap: 8px; pointer-events: none; }
.toast { padding: 10px 14px; background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-tile); color: var(--text); font-family: var(--font-mono); font-size: 13px; animation: fade-in var(--dur-fade) ease-out; }
/* DECISIONS #367: a shared result on the clipboard, confirmed in the middle of the screen, where it is seen: a card
   with the success teal's check and edge, over the screen and the recap card, gone after a moment (toast.js notice). */
.toast-center { position: fixed; inset: 0; z-index: 65; display: grid; place-items: center; padding: 16px; pointer-events: none; }
.toast-card { display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 220px; padding: 18px 28px 20px;
  border: 2px solid var(--good); border-radius: var(--r-card); background: var(--raised); text-align: center;
  box-shadow: 0 12px 40px color-mix(in srgb, var(--ground) 70%, transparent); animation: pop var(--dur-pop) ease-out; }
.toast-card.is-leaving { opacity: 0; transition: opacity var(--dur-fade) ease-in; }
.toast-card__icon { display: flex; color: var(--good); }
.toast-card__title { font-family: var(--font-display); font-size: 22px; line-height: 1.1; color: var(--text); }
.toast-card__text { font-family: var(--font-body); font-size: 16px; line-height: 1.4; color: var(--text-soft); }
.skeleton { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); position: relative; overflow: hidden; min-height: 120px; }
.skeleton--header { min-height: 70px; }
.skeleton::after { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, var(--raised), transparent); transform: translateX(-100%); animation: shimmer 1.4s infinite; }
.notice { gap: 12px; align-items: flex-start; }
.notice__text { font-size: 18px; }

/* ---------- Accounts (M5, DECISIONS #217): the auth modal, the profile, the friends rows ---------- */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); }
.tab { padding: 10px 14px; margin-bottom: -1px; border: none; border-bottom: 2px solid transparent; background: transparent; color: var(--muted); font-family: var(--font-mono); font-size: 13px; line-height: var(--lh-mono-13); letter-spacing: 0.5px; }
.tab:hover { color: var(--text); }
.tab--selected { color: var(--accent); border-bottom-color: var(--accent); }
.auth__panel, .auth__form, .profile__form { display: flex; flex-direction: column; gap: 12px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field__label { font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.field__rule { font-size: 13px; }
.input { width: 100%; min-height: 44px; box-sizing: border-box; padding: 10px 12px; border-radius: var(--r-tile); border: 1px solid var(--line); background: var(--ground); color: var(--text); font-family: var(--font-body); font-size: 16px; line-height: 1.45; color-scheme: dark; }   /* a dark field: the browser's own parts follow, so Edge's show-password eye (::-ms-reveal) is light, not black */
.input:focus { border-color: var(--accent); outline: none; }
.input:-webkit-autofill { -webkit-box-shadow: 0 0 0 1000px var(--ground) inset; -webkit-text-fill-color: var(--text); caret-color: var(--text); }
.auth__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.auth__note { margin: 0; line-height: 1.45; }
.auth__lead { margin: 0; font-size: 16px; line-height: 1.45; color: var(--text-soft); }   /* why the dialog opened (DECISIONS #252) */
.auth .form-error:not(:empty), .profile .form-error:not(:empty) { line-height: 1.4; }
.modal.profile { max-width: 760px; gap: 18px; }
.profile__body { display: flex; flex-direction: column; gap: 18px; }
.profile__id { display: flex; flex-direction: column; gap: 8px; }
.profile__who { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.profile__handle { margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 22px; letter-spacing: 0.5px; overflow-wrap: anywhere; }
.profile__kind { letter-spacing: 1px; }
.profile__signup { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 10px; padding: 12px 14px; background: var(--raised); border-radius: var(--r-tile); }
.profile__signup-text { color: var(--text-soft); font-size: 15px; }
.profile__section { display: flex; flex-direction: column; gap: 10px; }
h3.label { margin: 0; font-weight: 400; text-transform: uppercase; }  /* mixed-case DOM text for readers, the mockup's uppercase look */
.profile__tiles { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
.profile-row__result { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin-left: auto; font-family: var(--font-mono); font-size: 13px; line-height: var(--lh-mono-13); color: var(--text-soft); }
.profile__friends, .profile__requests { display: flex; flex-direction: column; gap: 10px; }
/* DECISIONS #260: a friend request by name, under the friends */
.profile__ask { display: flex; flex-direction: column; gap: 6px; padding-top: 10px; border-top: 1px dashed var(--line); }
.profile__ask-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.profile__ask-row .input-mono { max-width: 260px; }
.profile__friends-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.profile__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.profile__pw, .profile__delete { padding: 14px; background: var(--raised); border-radius: var(--r-tile); }
.profile__delete-text { margin: 0; font-size: 15px; line-height: 1.45; color: var(--text-soft); }
/* DECISIONS #263: Remove friend on a friend's profile, its "Are you sure?" in the Delete account box's style */
.profile__friend-actions { display: flex; flex-direction: column; gap: 12px; }
.profile__delete-text:focus-visible { outline-offset: 4px; }
.friend--account, .request { align-items: center; }
.friend__right { display: flex; align-items: center; gap: 10px; }
.request .btn-ghost { padding: 4px 10px; font-size: 12px; }
/* DECISIONS #254: friend requests (Accept, Decline; yours: waiting, Cancel) and the Friends list's Show more. */
.request { flex-wrap: wrap; }
.request__handle { overflow-wrap: anywhere; }
.request .friend__right { flex-wrap: wrap; justify-content: flex-end; }
.friends__more { align-self: flex-start; padding: 4px 10px; font-size: 12px; }
/* DECISIONS #239: a friend's handle opens their profile, in the row's own mono text (the mockup's look). */
.friend__name { padding: 0; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.friend__name:hover { text-decoration: underline; text-underline-offset: 3px; }
.friends__guest { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.friends__guest-text { line-height: 1.45; }
.btn-danger { border-color: var(--accent); color: var(--accent); }
.btn-danger:hover { border-color: var(--accent-hover); color: var(--accent-hover); }

/* ---------- Motion (§7.3) ---------- */
.pop { animation: pop var(--dur-pop) ease-out; }
.fade-in { animation: fade-in var(--dur-fade) ease-out; }
.flash { animation: flash var(--dur-flash) ease-out; }
@keyframes pop { from { transform: scale(0.9); } to { transform: scale(1); } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes flash { 0% { outline: 2px solid var(--accent); outline-offset: 2px; } 100% { outline: 2px solid transparent; outline-offset: 2px; } }
@keyframes dot-pulse { 0%, 100% { opacity: 0.2; } 50% { opacity: 1; } }
@keyframes shimmer { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------- Responsive (§7.5) ---------- */
@media (min-width: 1180px) {
  .columns { flex-wrap: nowrap; }
}
@media (min-width: 760px) and (max-width: 1179px) {
  .columns { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: start; }
  .col-aside { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); align-items: start; }
}
@media (max-width: 759px) {
  .page { padding: 16px; }
  .header { padding: 12px 14px; }
  .columns { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
  .col-room, .col-aside { display: contents; }
  .col-run { flex: 0 0 auto; }
  .scene-card { order: 1; }
  .objective { order: 2; }
  .col-run { order: 3; }
  .kit { order: 4; }
  .panel--wall { order: 5; }
  .panel--remembers { order: 6; }
  .panel--today { order: 7; }
  .panel--requests, .panel--friends { order: 8; }   /* requests first: page order (DECISIONS #254) */
  .kit__head { cursor: pointer; }
  .kit__toggle { display: inline-flex; margin-left: auto; color: var(--muted); font-family: var(--font-mono); font-size: 11px; letter-spacing: 1px; }
  .run__head, .run__log, .run__input, .run__confirm { padding-left: 16px; padding-right: 16px; }
  .run__prompt-row { justify-content: space-between; gap: 10px; }
  .run__leave { position: static; transform: none; }
  .run__input, .run__confirm { position: sticky; bottom: 0; z-index: 5; background: var(--surface); border-radius: 0 0 var(--r-card) var(--r-card); }
  .recap-overlay { background: var(--ground); }
  .recap-stack { margin: 0; width: 100%; }
  .recap { width: 100%; min-height: 100vh; min-height: 100dvh; }
  .score-card { width: auto; margin: 0 16px 16px; }
  .modal-overlay { padding: 12px; }
  /* DECISIONS #340: a footer on a phone reads as the phone shell's lines (#338): the motto, then rows 28 px tall at a
     28 px pitch with their separators, each link's hit box its row (over WCAG 2.5.8's 24 px), the donate link a row
     of its own; one item to a 44 px row before, 281 px for the pages' five. */
  .site-footer { padding: 2px 16px 20px; gap: 0; }
  .site-footer__motto { padding-bottom: 4px; font-size: 16px; }
  .site-footer__line, .site-footer__links, .site-footer__give { gap: 0 7px; letter-spacing: 0; }
  .site-footer a, .site-footer__donate { min-height: 28px; }
  .site-footer__donate-wrap { flex-basis: 100%; justify-content: center; }
  .site-footer__donate-wrap .site-footer__sep { display: none; }
  /* Touch targets: raise the small controls to 44 px (.btn-outline and .btn-primary are already 48+). */
  .btn-ghost, .archive-row, .friends__me .btn-ghost, .tab, .friend__name, .panel__link,
  .request .btn-ghost, .friends__more, .score-card__toggle { min-height: 44px; }
  .chip, .check, .tag { min-height: 0; }
}
@media (min-width: 760px) {
  .recap-overlay { padding: 24px; box-sizing: border-box; }
  .recap { border: 1px solid var(--line); border-radius: var(--r-recap); min-height: min(844px, calc(100vh - 48px)); }
  .recap-stack { align-items: center; }
}
@media (pointer: coarse) {
  .btn-ghost, .archive-row, .tab, .friend__name, .panel__link, .request .btn-ghost, .friends__more, .score-card__toggle { min-height: 44px; }
  /* A 44 px Leave the room cannot float over the 14 px prompt row: on a touch tablet it joins the row. */
  .run__prompt-row { justify-content: space-between; gap: 10px; }
  .run__leave { position: static; transform: none; }
}

/* ---------- The reveal camera and the phone's turn box (DECISIONS #273) ---------- */
/* While a turn reveals the camera (web/js/components/camera.js) owns the page's scroll: the browser's scroll
   anchoring, which on a phone picked the kit panel below The Run as its anchor and dragged the page down with every
   typed line, is off for that long. */
html.is-revealing, html.is-revealing body { overflow-anchor: none; }
@media (max-width: 759px) {
  /* The input block sticks to the bottom of the screen (above): every row it does not need is a row of the Dungeon
     Master's answer in view above it. Two rows of sentence that grow with the text up to five (run.js `fit`), the
     hint beside Roll for it instead of above it, tighter padding: about 230 px instead of 313. */
  .run__input, .run__confirm { padding: 14px 16px calc(16px + env(safe-area-inset-bottom, 0px)); }   /* the box clears a home indicator (viewport-fit=cover, DECISIONS #285) */
  .textarea { height: calc(2 * 1.45em + 32px); resize: none; }   /* two lines plus the padding and the 2 px borders */
  .run__foot { flex-wrap: nowrap; }
  .run__foot .hint { flex: 1 1 auto; min-width: 0; }
  .run__foot .btn-primary { flex: none; }
}

/* ---------- The chat's end holds (DECISIONS #275, #277) ---------- */
@media (max-width: 759px) {
  /* The card is at least a screen tall, so an opening chat shows its box at the bottom and the chat's end is a place
     the page can rest on. The stop itself is the hold in web/js/components/hold.js (#277): a downward swipe whose
     momentum would carry the page past the chat's end is halted there, and only another swipe moves on. No scroll
     snap any more (#275's rules): its magnet pulled the page back to the box after any short drag past it. */
  .col-run { min-height: 100vh; min-height: 100dvh; }
}

/* ---------- The profile page (DECISIONS #301): the account as a page on the desktop, a tab on the phone ---------- */
/* The user's two style guides, ported with the tokens: the header with the avatar tile, the three stat tiles, YOUR
   DUNGEONS (the strip), RECORD, LAST TEN ROOMS, FRIENDS and the ACCOUNT rows. Below 760 px phone.css restyles it for
   the shell's tab. The teal avatar is the player's colour (the mockup's amber is the keeper's). */
.profile-page { max-width: 1100px; margin: 0 auto; }
.profile-page:focus { outline: none; }
.profile { display: flex; flex-direction: column; gap: 20px; padding: 22px 24px 26px; box-sizing: border-box; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); color: var(--text); font-family: var(--font-body); }
.profile__loading { margin: 0; }
.profile__head { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; padding-bottom: 18px; border-bottom: 1px solid var(--line); }
.profile__avatar { flex: none; display: flex; align-items: center; justify-content: center; width: 64px; height: 64px; border-radius: 14px; background: var(--good); color: var(--on-good); font-family: var(--font-display); font-size: 28px; line-height: 1; }
.profile__avatar--friend { background: var(--raised); color: var(--text); }
.profile__id { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.profile__kind { letter-spacing: 1px; }
.profile__handle { margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 28px; letter-spacing: 0.5px; line-height: 1.1; overflow-wrap: anywhere; }
.profile__since { font-size: 15px; color: var(--text-soft); }
.profile__return { margin-left: auto; align-self: flex-start; display: inline-flex; align-items: center; gap: 10px; }
.profile__kbd { padding: 2px 6px; border: 1px solid var(--line); border-radius: var(--r-chip); font-family: var(--font-mono); font-size: 11px; line-height: var(--lh-mono-11); color: var(--muted); }
.profile__signup { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 10px; padding: 12px 14px; background: var(--raised); border-radius: var(--r-tile); }
.profile__signup-text { color: var(--text-soft); font-size: 15px; }
.profile__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; align-items: start; }
.profile__main, .profile__side { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.profile__section { display: flex; flex-direction: column; gap: 10px; }
.profile__section-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 4px 12px; }
.profile__section-meta { font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); color: var(--muted); }
.profile__box { display: flex; flex-direction: column; gap: 12px; padding: 14px 16px; background: var(--raised); border-radius: var(--r-tile); }
h4.label { margin: 0; font-weight: 400; text-transform: uppercase; }
@media (min-width: 900px) {
  .profile__grid { grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr); }
  .profile__grid--single { grid-template-columns: minmax(0, 1fr); }
}

/* The three stat tiles */
.profile__stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 14px 16px; background: var(--raised); border-radius: var(--r-tile); }
.profile__stat { display: flex; flex-direction: column; gap: 6px; min-width: 0; padding: 0 16px; border-left: 1px solid var(--line); }
.profile__stat:first-child { padding-left: 0; border-left: 0; }
.profile__stat-label { font-family: var(--font-mono); font-size: 11px; line-height: var(--lh-mono-11); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.profile__stat-value { font-family: var(--font-display); font-size: 34px; line-height: 1; overflow-wrap: anywhere; }
.profile__stat-value small { font-family: var(--font-mono); font-size: 13px; color: var(--muted); }
.profile__stat--streak .profile__stat-value { color: var(--accent); }
.profile__stat--rate .profile__stat-value { color: var(--good); }
.profile__stat-sub { font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); color: var(--text-soft); }
.profile__stat-sub em { font-style: normal; color: var(--good); }
.profile__stat-sub i { font-family: var(--font-body); font-size: 14px; }

/* YOUR DUNGEONS: the strip of tiles (the last seven rooms and tomorrow) and the chosen room's line */
.profile__next em { font-style: normal; color: var(--accent); }
.profile__strip { display: flex; flex-wrap: wrap; gap: 8px; }
.dg { display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; box-sizing: border-box; min-width: 58px; height: 58px; padding: 0 6px; border: 2px solid var(--line); border-radius: 10px; background: transparent; color: var(--text); font-family: var(--font-display); font-size: 17px; line-height: 1; }
button.dg { cursor: pointer; }
button.dg:hover { border-color: var(--text-soft); }
.dg__day { font-family: var(--font-mono); font-size: 9px; line-height: 1; letter-spacing: 1px; color: var(--muted); }
.dg__day--short { display: none; }
.dg--escaped { background: var(--good); border-color: var(--good); color: var(--on-good); }
.dg--escaped .dg__day { color: var(--on-good); }
.dg--died { background: var(--accent); border-color: var(--accent); color: var(--ground); }
.dg--died .dg__day { color: var(--ground); }
.dg--trapped { border-color: var(--text-soft); }
.dg--left { border-color: var(--muted); }
.dg--none { border-style: dashed; color: var(--muted); }
.dg--active { border-style: dashed; border-color: var(--good); color: var(--good); }
.dg--next { border-style: dashed; border-color: var(--accent); color: var(--accent); }
.dg.is-today .dg__day { color: var(--accent); }
.dg--escaped.is-today .dg__day, .dg--died.is-today .dg__day { color: inherit; }
.dg[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--text); }
.dg--small { min-width: 40px; height: 40px; padding: 0; border-width: 1.5px; border-radius: 8px; font-size: 14px; }
.profile__dg-line { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 12px; padding: 12px 14px; background: var(--raised); border-radius: var(--r-tile); }
.profile__dg-title { font-weight: 600; font-size: 17px; line-height: 1.3; }
.profile__dg-text { font-family: var(--font-mono); font-size: 13px; line-height: var(--lh-mono-13); color: var(--text-soft); }
.profile__dg-meta { grid-column: 2; grid-row: 1 / 3; align-self: center; font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); color: var(--muted); text-align: right; }
.profile__dg-line--next .profile__dg-countdown, .profile__dg-line--active .profile__dg-text { color: var(--good); }

/* RECORD: the stacked bar, its legend, WHEN YOU ESCAPE */
.profile__bar { display: flex; gap: 2px; height: 10px; border-radius: 5px; overflow: hidden; background: var(--line); }
.profile__bar-seg { display: block; height: 100%; }
.profile__bar--escaped { background: var(--good); }
.profile__bar--trapped { background: var(--text-soft); }
.profile__bar--died { background: var(--accent); }
.profile__bar--left { background: var(--muted); }
.profile__legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 0; padding: 0; list-style: none; font-family: var(--font-mono); font-size: 13px; line-height: var(--lh-mono-13); }
.profile__legend-item { display: inline-flex; align-items: center; gap: 8px; }
.profile__legend-dot { flex: none; width: 10px; height: 10px; border-radius: 50%; }
.profile__legend-count { font-weight: 600; }
.profile__escape { display: flex; flex-direction: column; gap: 10px; padding-top: 12px; border-top: 1px solid var(--line); }
.profile__escape-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.profile__escape-value { font-family: var(--font-mono); font-size: 22px; font-weight: 600; line-height: 1.1; }
.profile__escape-label { margin-top: 4px; font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); color: var(--muted); }

/* LAST TEN ROOMS: a row per room, a grid of four columns (the phone stacks them, phone.css) */
.profile__cols, .profile__cols-meta { display: none; }
@media (min-width: 760px) {
  .profile__cols { display: grid; grid-template-columns: minmax(0, 1.6fr) auto minmax(120px, 1fr) auto; gap: 12px; padding: 0 14px; font-family: var(--font-mono); font-size: 11px; line-height: var(--lh-mono-11); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
}
.profile__col--score { text-align: right; }
@media (min-width: 760px) {
  .archive-row.profile-row { display: grid; grid-template-columns: minmax(0, 1.6fr) auto minmax(120px, 1fr) auto; align-items: center; gap: 12px; }
}
.archive-row.profile-row { align-items: center; }   /* below 760 px without the shell (?phone=classic): the wrapping row */
.profile-row__who { display: flex; align-items: center; gap: 12px; min-width: 0; }
.profile-row__num { flex: none; }
/* DECISIONS #343: the keeper's medallion beside a room's name in a row that lists rooms (an <img> cut on the server,
   GET /medallion/{n}.svg): the profile's last ten rooms, the in-app past rooms; /rooms has its own size (pages.css). */
.room-medallion { display: block; flex: none; width: 36px; height: 36px; }
.profile-row__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.profile-row__title { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; font-weight: 600; font-size: 16px; }
.chip-today { padding: 2px 7px; border-radius: var(--r-chip); background: var(--accent); color: var(--ground); font-family: var(--font-mono); font-size: 10px; line-height: 14px; letter-spacing: 1px; }
.profile-row__turns { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); color: var(--muted); }
.profile-row__dots { display: inline-flex; gap: 3px; }
.profile-row__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); }
.profile-row__dot.is-on { background: var(--text-soft); }
.profile-row__dot.is-escaped { background: var(--good); }
.profile-row__dot.is-died { background: var(--accent); }
.profile-row__dot.is-left { background: var(--muted); }
.profile-row__result { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 4px; margin-left: 0; font-family: var(--font-mono); font-size: 13px; line-height: var(--lh-mono-13); color: var(--text-soft); }
.profile-row__score { display: inline-flex; justify-content: flex-end; align-items: center; gap: 6px; font-family: var(--font-display); font-size: 16px; text-align: right; }
.profile-row__crown { width: 14px; height: 14px; color: var(--accent); }
.profile-row__verdict { display: flex; flex-direction: column; gap: 6px; margin: 6px 0 2px 52px; padding: 12px 14px; background: var(--ground); border: 1px solid var(--line); border-radius: var(--r-tile); }
.profile-row__verdict-text { margin: 0; font-style: italic; font-size: 16px; line-height: 1.45; color: var(--text-soft); }

/* FRIENDS: the rows with the handle's initial, WANTS TO BE FRIENDS, ADD A FRIEND, the link */
.profile__friends { display: flex; flex-direction: column; }
.profile__friends .friend { padding: 8px 0; border-bottom: 1px solid var(--line); }
.friend__who { display: inline-flex; align-items: center; gap: 10px; min-width: 0; }
.friend__avatar { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 8px; background: var(--raised); color: var(--text); font-family: var(--font-display); font-size: 12px; line-height: 1; }
.profile__requests { display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.profile__requests-rows { display: flex; flex-direction: column; gap: 8px; }
.profile__ask .label { text-transform: uppercase; }
.profile__friends-foot { flex-direction: column; align-items: stretch; gap: 8px; }
.profile__copy { width: 100%; text-align: center; }
.profile__link-hint { line-height: 1.45; }
.profile__brought { line-height: 1.45; color: var(--text-soft); }

/* ACCOUNT: the rows (HANDLE, PASSWORD, ADMIN for an admin, SESSION), each form opening under its row; the Delete card */
.profile__rows { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: var(--r-tile); overflow: hidden; }
.profile__row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 14px; padding: 12px 14px; background: var(--raised); border-top: 1px solid var(--line); }
.profile__row:first-child { border-top: 0; }
.profile__row-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.profile__row-label { font-family: var(--font-mono); font-size: 11px; line-height: var(--lh-mono-11); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.profile__row-label--admin { color: var(--accent); }
.profile__row-value { font-family: var(--font-mono); font-size: 14px; line-height: var(--lh-mono-14); overflow-wrap: anywhere; }
.profile__row-action { display: inline-flex; align-items: center; gap: 10px; margin-left: auto; }
.profile__row-note { font-family: var(--font-mono); font-size: 12px; }
.profile__row-form { flex-basis: 100%; }
.profile__row-form.friends__form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.profile__row-form.profile__pw { background: var(--ground); }
.profile__delete-card { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 14px; padding: 14px; border: 1px solid var(--accent); border-radius: var(--r-tile); }
.profile__delete-head { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.profile__delete-title { font-family: var(--font-mono); font-size: 13px; line-height: var(--lh-mono-13); font-weight: 600; color: var(--accent); }

/* DECISIONS #360: a tile's third line (a run's place under RANK, a guest's way to keep the STREAK); a guest's STREAK
   is a button like RANK, with a class of its own so RANK's stays one button */
.recap__tile--save { display: block; width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer; }
.recap__tile--save > span { display: block; }
.recap__tile--save .recap__tile-value::after { content: ' ›'; color: var(--muted); }
.recap__tile-note { display: block; margin-top: 2px; font-size: 11px; line-height: var(--lh-mono-12); color: var(--muted); }
.recap__tile--save .recap__tile-note { color: var(--accent); }
.recap__tile--save:hover { border-color: var(--accent); }
/* DECISIONS #360: a guest's own result says what a guest loses when the next dungeon opens, with the way to keep it;
   in the Leave question's amber, its edge and its tint (phone.css .dd-confirm; DECISIONS #367) */
.guest-save { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; padding: var(--pad-card);
  border: 1px solid var(--accent); border-radius: var(--r-control); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.guest-save__text, .welcome__text, .auth__pitch { margin: 0; font-family: var(--font-body); font-size: 15px; line-height: 1.4;
  color: var(--text-soft); }
.guest-save .guest-save__text { color: var(--text); }
/* DECISIONS #361: a guest the nightly purge had cleared, welcomed back (the arrival's Enter card, the phone's Briefing) */
.welcome { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; padding: var(--pad-card);
  border: 1px solid var(--good); border-radius: var(--r-control); background: var(--raised); }
.welcome__title { margin: 0; font-family: var(--font-mono); font-size: 12px; font-weight: 600; letter-spacing: 1px;
  line-height: var(--lh-mono-12); text-transform: uppercase; color: var(--good); }
/* DECISIONS #383: the share loop. The dare a shared link set (the arrival's Enter card, the phone's Briefing) and where
   a friend link landed, in the welcome's teal frame; the dare settled under the result's headline (teal beaten, amber
   standing, the words saying which); what the run's own link did, under Share result; the rival line in Today so far. */
.dare, .invite { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding: var(--pad-card);
  border: 1px solid var(--good); border-radius: var(--r-control); background: var(--raised); }
.dare__label { margin: 0; font-family: var(--font-mono); font-size: 12px; font-weight: 600; letter-spacing: 1px;
  line-height: var(--lh-mono-12); text-transform: uppercase; color: var(--good); }
.invite__title { margin: 0; font-family: var(--font-mono); font-size: 13px; font-weight: 600; line-height: var(--lh-mono-13);
  color: var(--good); overflow-wrap: anywhere; }
.dare__text, .invite__text { margin: 0; font-family: var(--font-body); font-size: 15px; line-height: 1.4; color: var(--text); }
.invite__state { margin: 0; font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); color: var(--muted); }
.recap__dare { margin: 8px 0 0; font-family: var(--font-mono); font-size: 13px; line-height: var(--lh-mono-13); color: var(--text-soft); }
.recap__dare--beat { color: var(--good); }
.recap__dare--stands { color: var(--accent); }
.recap__receipt { margin: 0; font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); color: var(--muted);
  text-align: center; }
.today__rival { font-family: var(--font-mono); font-size: 13px; color: var(--text); }
/* DECISIONS #385: the rewards. The Showrunner's greeting in the dare and the shout-out under the intro, in their italic;
   the encore, a hint while locked and the welcome's teal frame once a link has opened it; the shields in the Showrunner's
   teal; the Herald's chip beside a handle and its ring round the profile's tile (teal: --brass is scene art only); the
   friends' head-to-head and the finished run one tap from the row. */
.dare__greeting { margin: 0; font-family: var(--font-body); font-size: 15px; font-style: italic; line-height: 1.4; color: var(--text-soft); }
.showrunner__shout { margin: 0; font-size: 18px; line-height: 1.5; font-style: italic; overflow-wrap: anywhere; }
.encore { display: flex; flex-direction: column; gap: 8px; }
.encore--open { padding: var(--pad-card); border: 1px solid var(--good); border-radius: var(--r-control); background: var(--raised); }
.encore__text { margin: 0; font-family: var(--font-body); font-size: 14px; line-height: 1.4; color: var(--text-soft); }
.encore--open .encore__text { font-size: 15px; color: var(--text); }
.encore__play { width: 100%; border-color: var(--good); color: var(--good); }
.encore__play:hover { border-color: var(--text); color: var(--text); }
.recap__shield { margin: 0; font-family: var(--font-mono); font-size: 12px; line-height: var(--lh-mono-12); color: var(--good); text-align: center; }
.recap__darefriend { display: flex; flex-direction: column; }
/* A word that explains itself (DECISIONS #387, components/tip.js): a button in the text's own style, a dotted underline
   saying so, and the small tip it opens, in the look of the picture's over a solid ground. */
.tip-word { position: relative; padding: 0; border: 0; background: none; color: inherit; font: inherit; letter-spacing: inherit;
  cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
@media (hover: hover) { .tip-word:hover { color: var(--text); } }
.word-tip { position: fixed; z-index: 80; box-sizing: border-box; max-width: min(260px, calc(100vw - 24px)); padding: 6px 10px;
  background: var(--raised); border: 1px solid var(--dd-line-2); border-radius: var(--r-chip); box-shadow: var(--dd-shadow);
  font-family: var(--font-body); font-size: 14px; line-height: 1.35; color: var(--text-soft); cursor: default; }
.chip-herald { display: inline-block; margin-left: 6px; padding: 0 5px; border: 1px solid var(--good); border-radius: var(--r-chip);
  text-decoration: none;
  color: var(--good); font-family: var(--font-mono); font-size: 11px; font-weight: 400; font-style: normal; letter-spacing: 0.5px;
  line-height: 1.4; text-transform: uppercase; white-space: nowrap; }
.profile__avatar--herald { box-shadow: 0 0 0 2px var(--ground), 0 0 0 4px var(--good); }
.profile__herald { line-height: 1.45; color: var(--text-soft); }
/* The Ratings (DECISIONS #390, #393, components/feeding.js; the code keeps its first name, feeding): one quiet row. A needle dial
   in place of a bar, amber as the ratings climb and teal at prime time, with who is watching in words, so colour is never alone.
   A needle that moves while the page is open swings over with a small overshoot; reduced motion stops that with every other
   animation. */
.feeding { display: grid; gap: 5px; }
.feeding[hidden] { display: none; }
.feeding__head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 10px; }
.feeding__label { font-family: var(--font-mono); font-size: 11px; color: var(--muted); text-align: left; }
.feeding__gauge { display: inline-flex; align-items: center; gap: 8px; flex: none; }
.feeding__dial { display: block; width: 46px; height: 27px; overflow: visible; fill: none; stroke-linecap: round; }
.feeding__arc, .feeding__reach { stroke-width: 2.4; }
.feeding__arc { stroke: var(--dd-line-2); }
.feeding__reach { stroke: transparent; stroke-dasharray: 5 5; transition: stroke-dashoffset 1.4s ease, stroke 1.6s ease; }
.feeding__reach.is-lit { stroke: var(--accent); }
.feeding--full .feeding__reach.is-lit { stroke: var(--good); }
.feeding__tick { stroke: var(--dd-line-2); stroke-width: 1.2; }
.feeding__needle { stroke: var(--text); stroke-width: 1.7; transform-box: view-box; transform-origin: 23px 24px;
  transition: transform 1.4s cubic-bezier(0.34, 1.56, 0.64, 1); }
.feeding__hub { fill: var(--text); stroke: none; }
.feeding__word { font-family: var(--font-mono); font-size: 11px; letter-spacing: 1px; text-transform: uppercase; white-space: nowrap; color: var(--accent); }
.feeding--full .feeding__word { color: var(--good); }
.feeding__line { margin: 0; }
.chip.chip--fed { padding: 5px 10px; background: var(--raised); border: 1px solid var(--line); font-family: var(--font-mono); font-size: 12px;
  color: var(--good); text-decoration: none; }
.dice__fed { color: var(--good); }
/* What a share sends (DECISIONS #391): two plain radio buttons right above Share result, the chosen one in teal with a tick,
   and a line saying what goes out. */
.share-choice { display: grid; gap: 6px; margin: 0; padding: 0; border: 0; min-width: 0; }
.share-choice__options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
.share-choice__option { display: flex; position: relative; cursor: pointer; }
.share-choice__chip { display: flex; flex: 1; align-items: center; justify-content: center; gap: 6px; min-height: 44px; padding: 0 8px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: var(--r-control); font-family: var(--font-mono); font-size: 13px; line-height: 1.2; text-align: center; color: var(--text-soft); }
.share-choice__option:hover .share-choice__chip { border-color: var(--text-soft); }
.share-choice__option input:checked + .share-choice__chip { border-color: var(--good); color: var(--good); }
.share-choice__option input:checked + .share-choice__chip::before { content: '✓'; }
.share-choice__option input:focus-visible + .share-choice__chip { outline: 2px solid var(--accent); outline-offset: 2px; }
.share-choice__hint { margin: 0; font-size: 14px; line-height: 1.35; color: var(--text-soft); text-align: center; }
.friends__played { white-space: nowrap; }
.friend__status { padding: 0; border: 0; background: none; font: inherit; text-align: right; cursor: pointer; }
.friend__status:hover { text-decoration: underline; text-underline-offset: 3px; }
.friend__id { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 1px; min-width: 0; }
.friend__duel { color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* §7.5, DECISIONS #387: a small word's hit box reaches past it over what is no control, on a touch screen. Under a
   friend's handle it stays out of the handle's 44 px above, 24 px in all, and a scrolling list's last one adds
   nothing to scroll. */
@media (pointer: coarse) {
  .tip-word::after { content: ''; position: absolute; inset: -14px -8px; }
  .friend__duel::after { inset: -2px -8px -7px; }
  .friends__list--scroll .friend:last-child .friend__duel::after { bottom: 0; }
  .dd-pill .tip-word::after { inset: -10px -6px; }
}
