:root {
  --bg: #0b0a10;
  --panel: #16141f;
  --panel2: #1f1c2b;
  --border: #3a3450;
  --text: #e6dfd0;
  --dim: #9a93a8;
  --gold: #e0b84a;
  --red: #c8403a;
  --green: #5ec06a;
  --blue: #5a8de0;
  --accent: #b08a3e;
  /* the portrait frames a class's mastery earns */
  --frame-bronze: #b0703c;
  --frame-silver: #c8ccd4;
  --frame-gold: #e8c050;
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);
  --sar: env(safe-area-inset-right, 0px);
  /* the design system: one sheet of colours, one type scale, one spacing scale.
     A screen is built from these; a value outside them is a picture, not the interface */
  --text-soft: #c8bfae;
  --text-mid: #d8cfbe;
  --press: #2b2740;
  --primary-bg: #4a3a1c;
  --primary-text: #f5e6c0;
  --edge-won: #7a6030;
  --sel-bg: #33291a;
  --card-edge: #3a3224;
  --card-bg: #15120e;
  --warn: #ffb040;
  --armed-bg: #6a3a12;
  --armed-text: #fff2d8;
  --bad-text: #f08a80;
  --good-text: #9ee08a;
  --alarm-bg: #6a2228;
  --danger-edge: #7a3030;
  /* the grades of what is found: fine, rare, and the legends (a relic is --gold) */
  --g-fine: #8fd88a;
  --g-rare: #86b0f0;
  --g-mythic: #e2bcff;
  --g-mythic-edge: #81629c;
  --g-legend: #ffa040;
  --g-legend-edge: #8a4a18;
  --g-fine-edge: #3c5a3a;
  --g-rare-edge: #34486a;
  --overlay-bg: #08070c;
  --frame-radius: 8px;
  --frame-sheen: inset 0 1px 0 rgba(232, 215, 180, 0.08);
  --t-2xs: 0.62rem;
  --t-xs: 0.7rem;
  --t-sm: 0.78rem;
  --t-md: 0.86rem;
  --t-lg: 0.94rem;
  --t-base: 1.0rem;
  --t-xl: 1.1rem;
  --t-2xl: 1.2rem;
  --t-3xl: 1.4rem;
  --t-4xl: 1.6rem;
  --t-5xl: 1.9rem;
  --s-2: 2px;
  --s-4: 4px;
  --s-6: 6px;
  --s-8: 8px;
  --s-10: 10px;
  --s-12: 12px;
  --s-14: 14px;
  --s-16: 16px;
  --s-20: 20px;
  --s-24: 24px;
  --s-28: 28px;
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { margin: 0; padding: 0; height: 100%; background: var(--bg); color: var(--text); font-family: Georgia, 'Times New Roman', serif; overscroll-behavior: none; }
body { touch-action: manipulation; -webkit-user-select: none; user-select: none; }
#app { height: 100%; height: 100dvh; width: 100%; overflow: hidden; position: relative; }
.screen { position: absolute; inset: 0; display: none; flex-direction: column; }
.screen.active { display: flex; }
.screen.scroll { overflow-y: auto; -webkit-overflow-scrolling: touch; touch-action: pan-y pinch-zoom; }
h1, h2, h3 { margin: 0.4em 0 0.3em; font-weight: normal; letter-spacing: 0.04em; }
h2 { color: var(--gold); font-size: var(--t-3xl); }
h3 { color: var(--gold); font-size: var(--t-base); margin-top: 1em; }
p { line-height: 1.45; margin: 0.4em 0; }
b { color: var(--gold); font-weight: normal; }
.dim { color: var(--dim); }
.small { font-size: var(--t-md); }
.row { display: flex; gap: var(--s-8); align-items: center; }
.row.spread { justify-content: space-between; margin-top: var(--s-16); }
button { font-family: inherit; font-size: var(--t-base); color: var(--text); background: var(--panel2); border: 1px solid var(--border); border-radius: 8px; padding: var(--s-10) var(--s-14); min-height: 44px; cursor: pointer; }
/* one set of button states for every button: pressed, focused from a keyboard,
   pointed at (where there is a pointer to point), and unavailable */
button:active { background: var(--press); }
button:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* there for a screen reader, not the eye */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* every stop a keyboard or a pad can reach shows where it is; a pad's ring
   (pad.js marks the page while one is steering) shows even where a browser
   would hide a ring it moved there itself */
:is(a, summary, select, input, textarea, [tabindex]):focus-visible,
body.pad :is(button, a, summary, select, input, textarea, [tabindex]):focus { outline: 2px solid var(--gold); outline-offset: 2px; }
body.pad .seg button:focus { outline-offset: -2px; }
@media (hover: hover) { button:not(:disabled):hover { border-color: var(--accent); } }
button:disabled { opacity: 0.4; cursor: default; }
/* hidden means hidden, whatever a layout rule says about display */
[hidden] { display: none !important; }
button.big { font-size: var(--t-xl); padding: var(--s-14) var(--s-16); width: 100%; }
button.primary { background: var(--primary-bg); border-color: var(--accent); color: var(--primary-text); }
button.ghost { background: transparent; }
button.danger { border-color: var(--danger-edge); color: #f0b0a8; }
button.small { padding: var(--s-6) var(--s-10); min-height: 44px; font-size: var(--t-lg); }
input, select { font-family: inherit; font-size: var(--t-base); color: var(--text); background: var(--panel); border: 1px solid var(--border); border-radius: 6px; padding: var(--s-8) var(--s-10); min-height: 40px; }
input { width: 100%; }
label.field { display: block; margin: var(--s-10) 0; }
label.field input { margin-top: var(--s-4); }
label.field .row { margin-top: var(--s-4); }
/* the dice beside the name and the seed: a thumb's width, not a fingertip's */
label.field .row input { flex: 1 1 auto; min-width: 0; }
label.field .row button.small { flex: 0 0 auto; min-width: 44px; min-height: 44px; font-size: var(--t-xl); }
canvas { image-rendering: pixelated; image-rendering: crisp-edges; }

/* Title */
#screen-title { overflow-y: auto; }
#screen-title > .title-inner { flex-shrink: 0; padding-bottom: var(--s-8); }
.release-info { position: relative; z-index: 1; flex-shrink: 0; padding: var(--s-6) var(--s-12) calc(var(--s-8) + var(--sab)); background: var(--bg); color: var(--text-soft); font-size: var(--t-sm); text-align: center; line-height: 1.4; }
/* the end screen shares the title's inner block but has no art to sit under */
#screen-end .title-inner { margin-top: auto; margin-bottom: auto; padding-top: calc(var(--s-16) + var(--sat)); }
/* a question, not a title: it sits in the middle of the screen */
#screen-confirm .title-inner { margin-top: auto; margin-bottom: auto; padding-top: calc(var(--s-16) + var(--sat)); }
#screen-end .end-stats { margin-top: var(--s-16); }
/* The art occupies a band at the top so the 16:10 scene is not cropped to a
   sliver on tall phones; the fade blends it into the menu below. */
.title-bg { position: absolute; top: 0; left: 0; right: 0; height: 64%; z-index: 0; }
/* The dungeon is lit for play, not for a poster: lift it so it reads behind the fade. */
#title-art { width: 100%; height: 100%; display: block; background: #050408; }
.title-vignette { position: absolute; inset: 0; background: radial-gradient(ellipse 82% 72% at 50% 40%, rgba(0,0,0,0) 0%, rgba(0,0,0,0.38) 66%, rgba(0,0,0,0.8) 100%); }
.title-fade { position: absolute; inset: 0; background: linear-gradient(to bottom, rgba(11,10,16,0.5) 0%, rgba(11,10,16,0.04) 30%, rgba(11,10,16,0.4) 68%, rgba(11,10,16,0.88) 90%, var(--bg) 100%); }
.title-inner { position: relative; z-index: 1; margin-top: auto; width: 100%; max-width: 440px; margin-left: auto; margin-right: auto; padding: 0 var(--s-20) calc(var(--s-24) + var(--sab)); text-align: center; }
.logo-block { margin-bottom: var(--s-20); }
.logo-rule { display: flex; align-items: center; gap: var(--s-10); color: var(--accent); margin-bottom: var(--s-10); }
.logo-rule::before, .logo-rule::after { content: ''; flex: 1; height: 1px; background: linear-gradient(to right, transparent, var(--accent), transparent); }
.logo-rule span { font-size: var(--t-sm); opacity: 0.8; }
.logo { font-size: clamp(2.1rem, 11.5vw, 3.2rem); letter-spacing: 0.09em; margin: 0; line-height: 1.05; font-weight: normal;
  text-shadow: 0 1px 0 #6b5220, 0 2px 0 #4a3714, 0 3px 0 #2e2109, 0 4px 6px rgba(0,0,0,0.8), 0 0 30px rgba(224,184,74,0.28);
  animation: torchglow 4.2s ease-in-out infinite; }
.logo .l1 { color: #f6e4b4; }
.logo .l2 { color: var(--gold); }
@keyframes torchglow {
  0%, 100% { text-shadow: 0 1px 0 #6b5220, 0 2px 0 #4a3714, 0 3px 0 #2e2109, 0 4px 6px rgba(0,0,0,0.8), 0 0 30px rgba(224,184,74,0.28); }
  45% { text-shadow: 0 1px 0 #6b5220, 0 2px 0 #4a3714, 0 3px 0 #2e2109, 0 4px 6px rgba(0,0,0,0.8), 0 0 42px rgba(255,200,90,0.45); }
  70% { text-shadow: 0 1px 0 #6b5220, 0 2px 0 #4a3714, 0 3px 0 #2e2109, 0 4px 6px rgba(0,0,0,0.8), 0 0 22px rgba(224,184,74,0.22); }
}
.tagline { color: #bdb2a0; margin: var(--s-10) 0 0; font-size: var(--t-lg); text-shadow: 0 1px 3px #000; text-wrap: balance; }   /* no word left alone on a narrow phone */
.menu { display: flex; flex-direction: column; gap: var(--s-8); }
.menu-row { display: flex; gap: var(--s-8); }
body.big-text #screen-title .menu-row { flex-wrap: wrap; }
body.big-text #screen-title .menu-row > * { flex: 1 1 140px; min-width: 0; }
/* the in-game menu in short groups: a heading each, the switches two to a row */
.menu-h { margin: var(--s-8) 0 -2px; font-size: var(--t-sm); font-weight: normal; letter-spacing: 0.08em; text-transform: uppercase; color: var(--dim); }
.menu-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-8); }
.menu .menu-grid .big { justify-content: center; padding: var(--s-10) var(--s-8); font-size: var(--t-lg); min-height: 48px; }
.menu-grid .big[hidden] { display: none; }
.menu-fold { margin-top: var(--s-8); display: flex; justify-content: space-between; align-items: center; padding: var(--s-10) var(--s-14); min-height: 48px; background: transparent; border: 1px dashed var(--border); color: var(--dim); font-size: var(--t-lg); }
.menu-fold[aria-expanded="true"] .fold-mark { display: inline-block; transform: rotate(90deg); }
.menu-tests { display: flex; flex-direction: column; gap: var(--s-8); }
.menu-tests[hidden] { display: none; }
.menu-row button { flex: 1; }
/* the pack's count and its Sort button, over the grid */
.inv-tools { display: flex; align-items: center; justify-content: space-between; margin: var(--s-6) 0 var(--s-4); }
.inv-tools button { min-height: 32px; padding: var(--s-4) var(--s-14); }
/* the run before this one, under the tagline */
.last-run { text-align: center; margin: var(--s-4) var(--s-12) 0; }
/* one thing to go down for next, under the last run's line and on the end screen */
.next-goal { text-align: center; margin: var(--s-4) var(--s-12) 0; color: var(--gold); }
#screen-end .next-goal { margin: var(--s-8) 0; font-size: var(--t-md); }
.beats { display: block; margin-top: var(--s-4); color: var(--text-mid); font-size: var(--t-sm); }
/* a hero from another phone, under the menu rather than beside the Weekly: wanted rarely */
.title-foot { text-align: center; margin: var(--s-6) 0 0; }
.linkish { background: none; border: 0; padding: var(--s-6) var(--s-10); min-height: 36px; color: var(--dim); font-size: var(--t-sm); text-decoration: underline; text-underline-offset: 3px; }
.linkish:hover, .linkish:focus-visible { color: var(--text); }
.confirm-what { text-align: center; margin: 0 0 var(--s-4); color: var(--gold); }
/* the prologue: the hero's face beside their past */
.pro-hero { display: flex; align-items: center; gap: var(--s-12); margin-top: 1.2em; }
.pro-hero h3 { margin: 0; }
.pro-face { width: 56px; height: 56px; flex: none; image-rendering: pixelated; border-radius: 8px; border: 1px solid var(--card-edge); background: var(--card-bg); }
.pro-face:not([src]), .pro-face[src=""] { display: none; }
/* the hero above a choice (the level-up, the path, the divided stair): the top of the phone is not black,
   and the dungeon shows dimly through the window, so what lies between the hero and the cards is the floor they stand on */
#ov-boons, #ov-fork, #ov-encounter { background: rgba(11, 10, 16, 0.84); }
.choice-head { display: flex; align-items: center; gap: var(--s-12); padding: var(--s-6) 0 var(--s-10); }
.choice-face { width: 64px; height: 64px; flex: none; image-rendering: pixelated; border-radius: 8px; border: 1px solid var(--card-edge); background: var(--card-bg); }
.choice-who { display: flex; flex-direction: column; gap: var(--s-2); min-width: 0; }
.choice-who b { color: var(--gold); font-weight: normal; font-size: var(--t-xl); }
.choice-who span { color: var(--dim); font-size: var(--t-md); }
/* no room for it held sideways or on a short screen: the cards come first */
@media (max-height: 560px), (orientation: landscape) and (max-height: 700px) { .choice-head { display: none; } }
/* the Hall's nearest goals, before the grid */
.trophy-near { margin: 0 0 var(--s-8); color: var(--dim); font-size: var(--t-md); line-height: 1.4; }
.trophy-near b { color: var(--gold); font-weight: normal; }
/* a find: the gold on the HUD flares as it grows */
@keyframes gold-flare { 0% { color: #fff8dc; text-shadow: 0 0 10px rgba(255, 214, 102, 0.9); transform: scale(1.18); } 100% { color: var(--gold); text-shadow: none; transform: none; } }
#hud-gold.flare { animation: gold-flare 650ms ease-out; display: inline-block; transform-origin: right center; }
body.calm #hud-gold.flare { animation: none; }
/* the testing tools' pickers: the list takes the room, the button stays a thumb's width */
.menu-row.test-row select { flex: 1; min-width: 0; }
.menu-row.test-row button { flex: 0 0 auto; min-width: 64px; }
.menu .big { display: flex; flex-direction: column; align-items: center; gap: var(--s-2); padding: var(--s-12) var(--s-16);
  background: linear-gradient(#232032, #17151f); border-color: #4a4463; box-shadow: 0 2px 0 #0d0c12, inset 0 1px 0 rgba(255,255,255,0.06); }
.menu .big b { font-weight: normal; font-size: var(--t-xl); letter-spacing: 0.03em; }
.menu .big small { font-size: var(--t-sm); color: var(--dim); font-weight: normal; }
.menu .big.primary { background: linear-gradient(#5a4622, #3a2c13); border-color: #a6823c; color: #f8ecca; box-shadow: 0 2px 0 #1a1408, inset 0 1px 0 rgba(255,220,150,0.18), 0 0 20px rgba(200,150,60,0.18); }
.menu .big.primary small { color: #cbb68a; }
.menu .big:active { transform: translateY(2px); box-shadow: none; }
.menu .ghost { background: rgba(14,13,20,0.7); border-color: #3a3450; font-size: var(--t-lg); padding: var(--s-10) var(--s-8); }
.foot { color: var(--dim); font-size: var(--t-md); margin-top: var(--s-16); }

/* Panels */
.panel { width: 100%; max-width: 520px; margin: 0 auto; padding: calc(var(--s-12) + var(--sat)) var(--s-16) calc(var(--s-24) + var(--sab)); }
.class-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-8); margin: var(--s-8) 0; }
.class-card { text-align: left; padding: var(--s-8) var(--s-10); min-height: 64px; display: flex; flex-direction: column; justify-content: flex-start; align-items: stretch; }
/* the face and the name side by side at the top, and what follows under both, at the card's full width */
.cc-head { display: flex; align-items: center; gap: var(--s-8); margin-bottom: var(--s-2); }
.cc-name { min-width: 0; }
.class-more { margin: var(--s-2) 0 var(--s-10); padding: var(--s-8) var(--s-10); border: 1px solid var(--card-edge); border-radius: 8px; background: var(--card-bg); color: var(--dim); line-height: 1.4; font-size: var(--t-lg); }
.class-more b { color: var(--gold); font-weight: normal; margin-right: var(--s-2); }
.class-more .key { display: block; margin-top: var(--s-4); }
.class-intro { display: flex; align-items: flex-start; gap: var(--s-12); flex-wrap: wrap; }
.class-intro > div { flex: 1 1 180px; min-width: 0; }
.class-intro h3 { margin: 0 0 var(--s-8); color: var(--gold); font-size: var(--t-xl); }
.class-backstory, .class-play { margin: 0; color: var(--text-soft); }
.class-play { margin-top: var(--s-12); }
.portrait-toggle { flex: 0 0 144px; max-width: 100%; padding: 0; border: 0; background: transparent; text-align: center; cursor: zoom-in; }
.portrait-toggle > span { display: block; padding: var(--s-6) 0; color: var(--text); font-size: var(--t-sm); }
.create-portrait { display: block; width: 100%; height: auto; aspect-ratio: 1; object-fit: contain; image-rendering: auto; border-radius: 8px; border: 1px solid var(--card-edge); }
.portrait-toggle.expanded { flex-basis: 100%; cursor: zoom-out; }
.portrait-toggle.expanded .create-portrait { max-width: 512px; margin: 0 auto; }
/* titles in a row line up: the cards used to centre their words, so a two-line blurb sat its title higher */
.class-card.sel { border-color: var(--gold); background: var(--sel-bg); }
.class-card b { display: block; font-size: var(--t-base); }
.class-card small { color: var(--dim); line-height: 1.3; display: block; }
.bg-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-8); margin: var(--s-8) 0 var(--s-4); }
.bg-card { text-align: left; padding: var(--s-8) var(--s-10); min-height: 58px; }
.bg-card.sel { border-color: var(--gold); background: var(--sel-bg); }
.bg-card b { display: block; font-weight: normal; font-size: var(--t-base); }
.bg-card small { color: var(--dim); line-height: 1.3; display: block; }
.perk-line { color: var(--green); font-size: var(--t-lg); min-height: 1.3em; margin: var(--s-2) 0 var(--s-8); }
.opts.start-extras { display: flex; flex-direction: column; gap: var(--s-6); margin: 0 0 var(--s-8); }
.start-extras .seg { margin: 0; }
.start-extras p { margin: 0; }
.start-extras .locked-line { font-style: italic; }
.vow-score { color: var(--gold); font-style: normal; font-size: var(--t-sm); }
.rung-pick { margin: var(--s-4) 0 var(--s-8); }
.rung-pick .seg { margin: 0 0 var(--s-6); }
.rung-pick .seg button { min-height: 40px; font-size: var(--t-md); }
.rung-rules { margin: 0 0 var(--s-4); padding-left: var(--s-16); font-size: var(--t-md); color: var(--text-soft); }
.rung-rules li { margin: var(--s-2) 0; }
.rung-pick p { margin: var(--s-2) 0; }
.trophy-grid .cell .rung-won { font-size: var(--t-2xs); margin-left: var(--s-2); }
/* the key art behind the prologue, darkened so the words stand clear of it */
#screen-prologue { background: linear-gradient(rgba(11, 10, 16, 0.84), rgba(11, 10, 16, 0.93) 45%, var(--bg)), url('../img/keyart-portrait.webp') center top / cover no-repeat, var(--bg); }
@media (orientation: landscape) { #screen-prologue { background: linear-gradient(rgba(11, 10, 16, 0.86), rgba(11, 10, 16, 0.93) 60%, var(--bg)), url('../img/keyart-landscape.webp') left center / cover no-repeat, var(--bg); } }
.story p { line-height: 1.6; margin: 0 0 0.9em; }
.story .motive { color: var(--gold); font-style: italic; }
.story h3 { margin-top: 1.2em; }
.cause { max-width: 460px; margin: 0 auto var(--s-14); color: #f0a49a; font-size: var(--t-base); line-height: 1.45; }
.cause b { color: #ff8a7a; }
.final-moments { max-width: 460px; margin: 0 auto var(--s-16); text-align: left; color: var(--dim); font-size: var(--t-md); }
.final-moments summary { cursor: pointer; padding: var(--s-6) 0; color: var(--dim); }
.final-moments div { padding: var(--s-6) var(--s-10); background: var(--panel); border: 1px solid var(--border); border-radius: 8px; }
.final-moments p { margin: 0 0 var(--s-4); line-height: 1.4; }
.hall-row .score { display: flex; flex-direction: column; align-items: flex-end; }
.hall-row .score small { color: var(--dim); font-size: var(--t-2xs); letter-spacing: 0.06em; }
.epilogue { max-width: 460px; margin: var(--s-14) auto var(--s-16); text-align: left; }
/* the run summary on the end screen: a few told lines, then pictures and names, numbers last */
.end-summary { max-width: 460px; margin: 0 auto var(--s-6); text-align: left; }
.end-lines { list-style: none; margin: 0 0 var(--s-4); padding: 0; }
.end-lines li { padding: var(--s-6) 0 var(--s-6) var(--s-16); border-bottom: 1px solid var(--border); line-height: 1.4; font-size: var(--t-lg); color: var(--text-mid); position: relative; }
.end-lines li::before { content: '\2726'; position: absolute; left: 0; top: 8px; font-size: var(--t-2xs); color: var(--accent); }
.end-lines li:last-child { border-bottom: 0; }
.end-none { color: var(--dim); font-style: italic; text-align: center; margin: var(--s-10) 0; }
.end-h { display: flex; align-items: center; gap: var(--s-10); margin: var(--s-14) 0 var(--s-8); color: var(--accent); font-size: var(--t-xs); letter-spacing: 0.14em; text-transform: uppercase; }
.end-h::before, .end-h::after { content: ''; flex: 1; height: 1px; background: linear-gradient(to right, transparent, var(--accent), transparent); }
/* six to a row on a phone, the count under each picture where it cannot hide a leg */
.end-kills { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-8) var(--s-6); }
.end-kills .kill { width: 50px; text-align: center; }
.end-kills .kill img { width: 50px; height: 50px; object-fit: contain; image-rendering: pixelated; display: block; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; box-sizing: border-box; padding: var(--s-2); }
.end-kills .kill span { display: block; margin-top: var(--s-2); font-family: monospace; font-size: var(--t-sm); color: var(--gold); }
.end-tags { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-6); }
.end-tags .tag { padding: var(--s-4) var(--s-10); border: 1px solid var(--border); border-radius: 999px; background: var(--panel); font-size: var(--t-md); color: var(--text); }
.end-tags .tag.path { color: var(--gold); border-color: var(--gold); }
.end-build { margin: 0 0 var(--s-8); text-align: center; font-size: var(--t-md); color: var(--gold); font-style: italic; }
.end-tags .tag.combo, .finds .tag.combo { color: var(--text-mid); border-style: dashed; }
.end-tags .tag.g-rare { color: var(--g-rare); border-color: var(--g-rare-edge); }
.end-tags .tag.g-relic { color: var(--gold); border-color: var(--edge-won); }
.end-tags .tag.g-legend { color: var(--g-legend); border-color: var(--g-legend-edge); }
/* this run's finds on the hero sheet, as the end screen shows them */
.finds { display: flex; flex-wrap: wrap; gap: var(--s-4); margin: var(--s-4) 0 var(--s-8); }
.finds .tag { padding: var(--s-2) var(--s-8); border: 1px solid var(--border); border-radius: 999px; background: var(--panel); font-size: var(--t-sm); }
.finds .tag.g-rare { border-color: var(--g-rare-edge); }
.finds .tag.g-relic { border-color: var(--edge-won); }
.finds .tag.g-legend { border-color: var(--g-legend-edge); }
.end-tags .tag.relic { color: var(--gold); border-color: var(--edge-won); box-shadow: inset 0 0 8px rgba(232, 180, 80, 0.18); }
.end-totals { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-6); margin-top: var(--s-16); text-align: center; }
.end-totals div { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: var(--s-6) var(--s-4) var(--s-6); }
.end-totals b { display: block; font-size: var(--t-2xl); font-family: monospace; }
.end-totals small { color: var(--dim); font-size: var(--t-xs); }
.epilogue p { color: var(--text-soft); line-height: 1.5; margin: 0 0 0.7em; font-size: var(--t-lg); }
.journal-entry { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: var(--s-10) var(--s-12); margin-bottom: var(--s-8); }
.journal-entry h3 { margin: 0 0 var(--s-4); font-size: var(--t-base); }
.journal-entry p { margin: 0; line-height: 1.5; color: var(--text-soft); font-size: var(--t-lg); }
.journal-entry .where { color: var(--dim); font-size: var(--t-sm); }
.journal-entry.missing { background: none; border-style: dashed; padding: var(--s-6) var(--s-12); }
.journal-entry.missing p { color: var(--dim); font-size: var(--t-sm); }
.pages-act { margin-bottom: var(--s-12); }
.act-head { margin: 0 0 var(--s-6); color: var(--gold); font-size: var(--t-sm); letter-spacing: 0.08em; text-transform: uppercase; }
.hall-pages li b { font-style: normal; color: var(--text); }
#ov-boons .ov-head { padding: var(--s-10) var(--s-14); }
#boon-title { font-size: var(--t-base); line-height: 1.3; }
.boon { display: block; width: 100%; text-align: left; padding: var(--s-12) var(--s-14); margin-bottom: var(--s-8); background: linear-gradient(#232032, #17151f); border-color: #4a4463; }
.boon.talent { border-color: var(--gold); background: linear-gradient(#2e2618, #1b1710); }
.boon.talent b { color: var(--gold); }
/* a rank of renown: past the top level, a paler gold than a talent's */
.boon.renown { border-color: #e8d8a0; background: linear-gradient(#2a2a22, #18170f); }
.boon.renown b { color: #f0e2b0; }
.boon b { display: block; font-weight: normal; font-size: var(--t-xl); color: var(--gold); }
.boon small { color: var(--dim); line-height: 1.35; }
/* the talent card held over from the last offer */
.boon .held-note { display: block; margin-top: var(--s-2); font-size: var(--t-xs); color: var(--gold); font-style: normal; }
/* what a road holds, under its card's words: the names the run's own plans give it */
.fork-choice .road-facts { display: block; margin-top: var(--s-4); font-size: var(--t-sm); color: var(--gold); }
/* a path: the bigger choice, once a run, so its card says everything it does */
.boon.path { border-color: var(--gold); background: linear-gradient(#2a2335, #15131c); box-shadow: inset 0 0 14px rgba(224, 184, 74, 0.12); }
.boon.path b, .path-sheet b { font-size: var(--t-2xl); color: var(--gold); display: block; }
.boon.path.armed { border-color: var(--warn); background: linear-gradient(#3a2a1c, #1c1510); box-shadow: 0 0 0 2px rgba(255, 176, 64, 0.35), inset 0 0 18px rgba(255, 176, 64, 0.18); }
/* the second tap it asks for, said on the card itself */
.path-confirm { display: block; margin-top: var(--s-8); padding: var(--s-6) var(--s-8); border-radius: 6px; background: var(--armed-bg); color: var(--armed-text); font-weight: bold; text-align: center; }
.path-flavour { display: block; font-style: italic; margin: var(--s-2) 0 var(--s-6); color: var(--dim); }
.path-effects { margin: 0; padding-left: 1.1em; color: var(--text-mid); font-size: var(--t-lg); line-height: 1.4; }
.path-warn { display: block; color: #f0a860; margin-top: var(--s-4); }
.path-effects li { margin: var(--s-2) 0; }
.path-sheet { padding: var(--s-4) 0 var(--s-8); border-bottom: 1px solid var(--border); }
.stats-box { display: flex; align-items: center; gap: var(--s-12); background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: var(--s-10); }
.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-4) var(--s-14); flex: 1; font-size: var(--t-lg); }
.stats span { color: var(--gold); float: right; }
.opts { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-8) var(--s-12); margin: var(--s-8) 0; }
.opts label { display: flex; flex-direction: column; gap: var(--s-4); font-size: var(--t-lg); }
.opts label.check { flex-direction: row; align-items: center; grid-column: 1 / -1; gap: var(--s-8); }
.opts input[type=checkbox] { width: 22px; height: 22px; min-height: 0; }

/* Game layout */
#screen-game { padding-top: var(--sat); }
.game-layout { display: flex; flex-direction: column; height: 100%; }
/* Portrait: the view takes the spare height first (up to square), the log
   what is left after that, and the controls only what the buttons need. The
   controls used to take all the slack, which on a modern phone left a quarter
   of the screen as padding around the buttons. */
.view-col { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.ctrl-col { display: flex; flex-direction: column; flex: 0 0 auto; min-height: 0; }
.hud { display: flex; align-items: center; gap: var(--s-8); padding: var(--s-4) var(--s-8); background: var(--panel); border-bottom: 1px solid var(--border); font-size: var(--t-md); }
/* name above class and level, so neither is cut off on a narrow phone */
.hud-name { flex: 0 0 auto; max-width: 32%; display: flex; flex-direction: column; line-height: 1.15; }
.hud-name span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.hud-bars { flex: 1 1 auto; display: flex; flex-direction: column; gap: var(--s-2); }
.bar { position: relative; height: calc(0.72rem + 4px); background: #0a0910; border: 1px solid #2c2838; border-radius: 3px; overflow: hidden; }
.bar .fill { position: absolute; inset: 0; width: 100%; transition: width 0.2s; }
.bar.hp .fill { background: linear-gradient(#e05a50, #8a2a24); }
.bar.sp .fill { background: linear-gradient(#6a9cf0, #2c4a90); }
.bar.food .fill { background: linear-gradient(#c8a050, #7a5a20); }
.bar span { position: absolute; inset: 0; font-size: var(--t-xs); line-height: calc(0.72rem + 2px); text-align: center; color: #fff; text-shadow: 0 0 2px #000, 0 0 2px #000; font-family: monospace; }
.hud-right { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; font-size: var(--t-sm); line-height: 1.2; }
#hud-gold { color: var(--gold); }
.compare { margin: var(--s-6) 0 0; font-size: var(--t-md); }
.compare.up { color: var(--green); }
.compare.down { color: #e08a80; }
.compare.mixed { color: var(--gold); }
#hud-compass { color: var(--dim); font-family: monospace; }
.view-wrap { position: relative; background: #000; border-bottom: 2px solid var(--border);
  flex: 1000 1 auto; min-height: calc(100vw * 0.625); max-height: calc(100vw * 1.125); }
/* the buffer height is matched to this box in script, so the fill is exact;
   contain only matters at the extremes where the buffer hits its limits */
#view { display: block; width: 100%; height: 100%; object-fit: contain; margin: 0 auto; touch-action: none; }
/* see-through, so what stands in the top corner still shows, and further
   still while a creature is under it (the script sets .faded) */
#minimap { position: absolute; top: 6px; right: 6px; width: 76px; height: 76px; border: 1px solid rgba(255,255,255,0.18); border-radius: 4px; background: rgba(0,0,0,0.25); image-rendering: auto; opacity: 0.7; transition: opacity 0.25s, top 0.2s; }
#minimap.faded { opacity: 0.16; }
@media (min-width: 600px) { #minimap { width: 90px; height: 90px; } }
.log-history div { padding: var(--s-4) 0; border-bottom: 1px solid #1c1a26; }
.log-history div.bad { color: var(--bad-text); }
.log-history div.good { color: var(--good-text); }
.log-history div.info { color: #9ab8f0; }
.hall { display: flex; flex-direction: column; gap: var(--s-6); margin-bottom: var(--s-16); }
#beasts-list { margin-bottom: var(--s-16); }
.hall-fallen { margin: 0 0 var(--s-10); padding: var(--s-8) var(--s-10); border-left: 3px solid var(--border); color: var(--dim); }
.hall-fallen b { color: var(--text); }
.hall-wick { margin: 0 0 var(--s-10); padding: var(--s-8) var(--s-10); border-left: 3px solid var(--gold); color: var(--dim); }
.hall-wick summary { cursor: pointer; color: var(--text); }
.hall-wick small { color: var(--dim); }
.hall-wick ol { margin: var(--s-8) 0 0; padding-left: var(--s-20); }
.hall-wick li { margin-bottom: var(--s-6); font-style: italic; }
.hall-row { display: flex; align-items: center; gap: var(--s-10); padding: var(--s-8) var(--s-10); background: var(--panel); border: 1px solid var(--border); border-radius: 8px; }
.hall-row .rank { color: var(--gold); font-size: var(--t-2xl); min-width: 28px; }
.hall-row .who { flex: 1; }
.hall-row .who small { display: block; color: var(--dim); }
.hall-row .score { color: var(--gold); font-family: monospace; font-size: var(--t-base); }
.hall-row.won { border-color: var(--gold); }
.hud-status { position: absolute; top: 6px; left: 8px; right: calc(76px + 14px); display: flex; flex-wrap: wrap; gap: var(--s-4) var(--s-6); pointer-events: none; }
/* the chips wrap in rows left of the map rather than running under it and off the screen */
@media (min-width: 600px) { .hud-status { right: calc(90px + 14px); } }
/* a boss's bar runs along the top of the view: the chips and tips go under it */
.view-wrap.boss-up .hud-status { top: calc(var(--bar-bottom, 0px) + 4px); }
.hud-status span { white-space: nowrap; flex: none; font-size: var(--t-sm); padding: var(--s-2) var(--s-6); border-radius: 4px; background: rgba(0,0,0,0.6); border: 1px solid rgba(255,255,255,0.2); }
.hud-status .bad { color: #f88; }
.hud-status .good { color: #8f8; }
/* the oldest line fades out at the top rather than being sliced through */
.log { -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 1.3em); mask-image: linear-gradient(to bottom, transparent 0, #000 1.3em); }
.log { flex: 1 1 auto; height: 5.2em; min-height: 5.2em; overflow: hidden; padding: var(--s-4) 68px var(--s-4) var(--s-8); font-size: var(--t-md); line-height: 1.38; background: #0e0d14; border-bottom: 1px solid var(--border); display: flex; flex-direction: column; justify-content: flex-end; }
/* on a narrow phone a long line wraps to three, and the newest two must still fit */
@media (max-width: 379px) { .log { height: 6.4em; min-height: 6.4em; } }
/* lines wrap rather than truncate: on a phone the ellipsis was eating the
   damage and the dice, which were the parts worth reading. They must not
   shrink either, or the flex column squashes a wrapped line back to one row
   and clips its second half inside its own box. */
.log div { flex-shrink: 0; overflow-wrap: anywhere; color: #cfc8ba; }
.log.long { justify-content: flex-start; -webkit-mask-image: linear-gradient(to top, transparent 0, #000 1.3em); mask-image: linear-gradient(to top, transparent 0, #000 1.3em); }
.log .roll, .log-history .roll { color: #948da3; font-size: 0.86em; white-space: nowrap; }
.log div.bad { color: var(--bad-text); }
/* what the bestiary learned: said, but quieter than the fight */
.log div.note { color: #8f879e; font-size: 0.9em; }
.log div.good { color: var(--good-text); }
.log div.info { color: #9ab8f0; }
.log div:last-child:not(.bad):not(.good):not(.info) { color: #fff; }
/* the newest line keeps its colour, and says it is newest by weight instead */
.log div:last-child { font-weight: bold; }
.controls { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: var(--s-10); padding: var(--s-12) var(--s-10) var(--s-8); }
/* The log is not a button: a thumb that strays up off the d-pad used to open
   the history. Its own small button sits in the corner furthest from the pad,
   and the log keeps a margin clear for it so no line runs under it. */
.log-more-anchor { position: relative; height: 0; z-index: 2; }
.log-more { z-index: 2; position: absolute; right: 4px; top: 4px; min-width: 56px; min-height: 44px; padding: 0 var(--s-10); font-size: var(--t-sm); color: #cfc8ba; background: rgba(20, 18, 30, 0.85); border: 1px solid var(--border); border-radius: 8px; }
/* and the top row of pads reaches a little up, so a press that lands just
   above an arrow still counts as that arrow instead of missing */
.ctl { position: relative; }
.dpad .ctl:nth-child(-n+3)::before, .actions .ctl:nth-child(-n+2)::before { content: ''; position: absolute; left: -3px; right: -3px; top: -12px; height: 12px; }
/* sized to the screen: roomier on a big phone, never cramped on a small one */
.dpad { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(2, 1fr); gap: var(--s-6); width: 52%; max-width: 250px; height: clamp(130px, 21vh, 170px); height: clamp(130px, 21dvh, 170px); }
.actions { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: var(--s-6); width: 44%; max-width: 220px; height: clamp(130px, 21vh, 170px); height: clamp(130px, 21dvh, 170px); }
.actions .attack { grid-row: 1 / 3; background: #4a2020; border-color: #8a3a34; font-size: var(--t-4xl); }
/* (the pad's and the zoom's glyphs are sized as pictures, off the type scale) */
.ctl { font-size: 1.5rem; padding: 0; min-height: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1; touch-action: none; }
.ctl small { font-size: var(--t-xs); color: var(--dim); margin-top: var(--s-2); letter-spacing: 0.05em; }
/* the controls' line icons (icon in uikit.js): one weight, the button's own colour */
.ico { display: inline-flex; line-height: 0; }
.ico .icon { width: 28px; height: 28px; }
.ctl { color: #e8e0d0; }
.ctl.attack .ico { color: #f4d2c8; }
.ctl.attack .ico .icon { width: 34px; height: 34px; }
.ctl.ctx .ico, .ctl.ctx small { color: var(--gold); }
.hud-quaff .ico .icon { width: 20px; height: 20px; }
.ctl.held { background: #3a3555; }
/* the Attack button fills from the bottom as the next blow readies */
.ctl.attack.cooling { background-image: linear-gradient(to top, rgba(255,120,90,0.28) calc(var(--ready, 1) * 100%), rgba(0,0,0,0.25) calc(var(--ready, 1) * 100%)); }
.ctl.attack.cooling small { opacity: 0.6; }
.ctl.attack small { color: #f4d2c8; }
.ctl.empty { opacity: 0.45; }
.bottombar { display: flex; gap: var(--s-4); padding: var(--s-6) var(--s-6) calc(var(--s-6) + var(--sab)); background: var(--panel); border-top: 1px solid var(--border); }
.bottombar button { flex: 1; padding: var(--s-8) 1px; font-size: var(--t-md); min-height: 44px; }

/* Overlays */
.overlay { position: absolute; inset: 0; background: var(--overlay-bg); display: none; flex-direction: column; z-index: 10; padding-top: var(--sat); }
.overlay.open { display: flex; }
/* Nothing comes up with a hard cut: a screen or an overlay fades in over a
   fifth of a second. Opacity only, so nothing moves under a finger, and none
   at all in a calm view or where the phone asks for less motion. */
@keyframes come-up { from { opacity: 0; } to { opacity: 1; } }
/* the title's opening, once a visit (ui.js, startOpening): the scene out of the
   dark, then the name a word at a time, then the rest; opacity only, so every
   button is where it will be and works from the first moment */
/* (quicker than it was: the menu is there to tap inside a second and a half, not two and a half) */
#screen-title.opening .title-bg { animation: come-up 1000ms ease-out both; }
#screen-title.opening .logo-rule { animation: come-up 500ms ease-out 300ms both; }
#screen-title.opening .logo .l1 { animation: come-up 600ms ease-out 400ms both; }
#screen-title.opening .logo .l2 { animation: come-up 600ms ease-out 650ms both; }
#screen-title.opening .tagline, #screen-title.opening .last-run, #screen-title.opening .next-goal { animation: come-up 500ms ease-out 900ms both; }
#screen-title.opening .menu, #screen-title.opening .first-card, #screen-title.opening .news { animation: come-up 500ms ease-out 1000ms both; }
/* a floor's name as the hero arrives (ui.js, showFloorCard): up, held, and gone, over the far end of the view */
.floor-card { position: absolute; left: var(--s-16); right: var(--s-16); top: 22%; z-index: 2; text-align: center; pointer-events: none; opacity: 0;
  color: var(--gold); text-shadow: 0 1px 3px #000, 0 0 12px rgba(0, 0, 0, 0.9); }
.floor-card small { display: block; font-size: var(--t-sm); letter-spacing: 0.2em; text-transform: uppercase; color: var(--text-mid); }
.floor-card b { display: block; font-weight: normal; font-size: var(--t-3xl); letter-spacing: 0.06em; margin-top: var(--s-2); }
.floor-card.show { animation: floor-card 2600ms ease-out forwards; }
@keyframes floor-card { 0% { opacity: 0; } 18% { opacity: 1; } 70% { opacity: 1; } 100% { opacity: 0; } }
body.calm .floor-card { display: none; }
/* the first-time card put away: it fades out, then the title fades up where it now stands (ui.js, firstTimeSeen) */
.first-card.closing { pointer-events: none; animation: go-down 160ms ease-in forwards; }
.title-inner.settling { animation: come-up 240ms ease-out; }
.screen.active { animation: come-up 200ms ease-out; }
.overlay.open { animation: come-up 170ms ease-out; }
/* and an overlay put away fades out, letting taps through to what is behind */
@keyframes go-down { from { opacity: 1; } to { opacity: 0; } }
.overlay.closing { display: flex; pointer-events: none; animation: go-down 130ms ease-in forwards; }
body.calm .screen.active, body.calm .overlay.open { animation: none; }
body.calm .overlay.closing { display: none; }
@media (prefers-reduced-motion: reduce) { .screen.active, .overlay.open { animation: none; } .overlay.closing { display: none; } }
.ov-head { display: flex; align-items: center; justify-content: space-between; padding: var(--s-6) var(--s-12); border-bottom: 1px solid var(--border); }
.ov-head h2 { margin: 0; margin-right: var(--s-10); }
.close { min-width: 44px; font-size: var(--t-2xl); }
.ov-body { flex: 1; overflow-y: auto; padding: var(--s-10) var(--s-12) calc(var(--s-12) + var(--sab)); touch-action: pan-y pinch-zoom; }
/* a heading that opens a panel sits under its bar, not a line below it */
.ov-body > h3:first-child { margin-top: var(--s-2); }
.ov-body.center { display: flex; flex-direction: column; align-items: center; }
.ov-body.menu { display: flex; flex-direction: column; gap: var(--s-10); max-width: 420px; margin: 0 auto; width: 100%; }
/* the in-game menu's How to Play is as large as its neighbours (the title's small ghost buttons are another thing) */
.ov-body.menu .big.ghost { font-size: var(--t-xl); padding: var(--s-14) var(--s-16); }
/* One neutral figure for every class. Its right hand is on the viewer's left.
   Real grid cells let long item names grow without covering another slot. */
.equipment-figure { position: relative; isolation: isolate; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: minmax(100px, auto) minmax(100px, auto) minmax(76px, auto); gap: var(--s-8) var(--s-12); padding-bottom: 64px; margin: 0 auto var(--s-10); max-width: 480px; }
.equipment-silhouette { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
.figure-body { fill: var(--panel); stroke: var(--accent); stroke-width: 1; }
.figure-ground { fill: var(--panel); opacity: 0.6; }
.figure-links { fill: var(--dim); stroke: var(--border); stroke-width: 1; }
.figure-links path { fill: none; }
.equipment-figure .equip { display: contents; }
.equipment-figure .slot { align-self: end; min-width: 0; min-height: 76px; overflow-wrap: anywhere; }
.equipment-figure [data-slot="weapon"] { grid-area: 2 / 1; }
.equipment-figure [data-slot="offhand"] { grid-area: 2 / 3; }
.equipment-figure [data-slot="armor"] { grid-area: 2 / 2; }
.equipment-figure [data-slot="shield"] { grid-area: 1 / 3; }
.equipment-figure [data-slot="ring"] { grid-area: 3 / 1; }
.equipment-figure [data-slot="ring2"] { grid-area: 3 / 3; }
.equipment-figure [data-slot="amulet"] { grid-area: 1 / 2; align-self: start; min-height: 52px; }
.equipment-figure [data-slot="cloak"] { grid-area: 1 / 1; }
/* At large text sizes the figure yields to a readable equipment list. */
body.big-text .equipment-figure { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: none; padding-bottom: 0; }
body.big-text .equipment-silhouette { display: none; }
body.big-text .equipment-figure .slot { grid-area: auto; align-self: stretch; min-height: 76px; }
.slot { background: var(--panel); border: 1px solid var(--border); border-radius: 6px; min-height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s-2); font-size: var(--t-xs); text-align: center; padding: var(--s-4); color: var(--dim); position: relative; font-family: inherit; width: 100%; }
button.slot { cursor: pointer; }
button.slot:focus-visible, .class-card:focus-visible, .bg-card:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.slot img { width: 32px; height: 32px; }
.slot.filled { color: var(--text); }
.slot.sel { border-color: var(--gold); background: #2a2418; }
.slot .qty { position: absolute; right: 4px; top: 2px; font-size: var(--t-xs); color: var(--gold); font-family: monospace; }
.slot .lbl { position: absolute; left: 4px; top: 2px; font-size: var(--t-2xs); color: var(--dim); letter-spacing: 0.05em; text-transform: uppercase; }
/* gear of unknown quality, and gear known to be cursed */
.slot .unk { position: absolute; right: 4px; top: 2px; font-size: var(--t-sm); color: #9ad; font-family: monospace; font-weight: bold; }
.slot.cursed { border-color: var(--danger-edge); color: #f0a0a0; }
/* named relics: gold lettering and a warm edge, so one stands out in a full pack */
.slot.relic { color: var(--gold); border-color: var(--edge-won); box-shadow: inset 0 0 8px rgba(232, 180, 80, 0.18); }
.relic { color: var(--gold); }
/* the grades: fine and rare in their colours, a legend brighter and warmer than a relic */
.g-fine { color: var(--g-fine); }
.g-rare { color: var(--g-rare); }
.g-relic { color: var(--gold); }
.g-legend { color: var(--g-legend); }
.slot.g-fine { color: var(--g-fine); border-color: var(--g-fine-edge); }
.slot.g-rare { color: var(--g-rare); border-color: var(--g-rare-edge); }
.slot.g-legend { color: var(--g-legend); border-color: var(--g-legend-edge); box-shadow: inset 0 0 10px rgba(255, 150, 60, 0.26); }
.grade-word { margin: 0 0 var(--s-4); font-size: var(--t-xs); letter-spacing: 0.08em; text-transform: uppercase; }
.relic-powers { margin: var(--s-6) 0; padding-left: var(--s-16); font-size: var(--t-sm); color: var(--text); }
.relic-powers li { margin: var(--s-2) 0; }
.relic-set { font-size: var(--t-sm); color: #c8b890; margin: var(--s-4) 0; }
.relic-set b { color: var(--gold); font-weight: normal; }
.relic-lore { font-style: italic; font-size: var(--t-sm); color: var(--dim); margin: var(--s-6) 0; }
.grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--s-6); }
.grid .slot { min-height: 54px; }
.floor-box { margin-top: var(--s-10); }
.floor-box h3 { margin: var(--s-4) 0; font-size: var(--t-lg); }
.floor-item { display: flex; align-items: center; gap: var(--s-8); padding: var(--s-6); border: 1px solid var(--border); border-radius: 6px; margin: var(--s-4) 0; background: var(--panel); }
.floor-item img { width: 28px; height: 28px; }
.floor-item span { flex: 1; }
.detail { margin-top: var(--s-12); background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: var(--s-10); display: none; }
.detail.open { display: block; }
/* The chosen treasure has room to be looked at, without another modal or a
   delay before its actions. Its grade is always written as well as coloured. */
.item-showcase { display: flex; align-items: center; gap: var(--s-12); margin-bottom: var(--s-8); }
.item-showcase > img { flex: 0 0 48px; width: 48px; height: 48px; object-fit: contain; image-rendering: pixelated; border: 1px solid var(--border); border-radius: var(--frame-radius); background: radial-gradient(ellipse, var(--panel2), var(--bg)); }
.item-showcase > div { min-width: 0; overflow-wrap: anywhere; }
.item-showcase .grade-word { margin-bottom: 0; }
.detail:is([data-grade="rare"], [data-grade="relic"], [data-grade="legend"], [data-grade="mythic"]) .item-showcase > img { flex-basis: 64px; width: 64px; height: 64px; border-color: currentColor; animation: come-up 240ms ease-out; }
.detail[data-grade="rare"] { border-color: var(--g-rare-edge); }
.detail[data-grade="relic"] { border-color: var(--edge-won); }
.detail[data-grade="legend"] { border-color: var(--g-legend-edge); }
/* in the pack the chosen item's panel keeps to the bottom of the screen, so
   Read or Drink is in reach however full the pack is and however small the phone */
#ov-inv .detail.open { position: sticky; bottom: 0; z-index: 2; max-height: 60vh; overflow-y: auto; box-shadow: 0 -10px 18px var(--overlay-bg); }
.detail h3 { margin: 0 0 var(--s-4); }
.detail .buttons { display: flex; flex-wrap: wrap; gap: var(--s-6); margin-top: var(--s-10); }
.detail .buttons button { flex: 1; min-width: 80px; }
#map-canvas { max-width: 100%; border: 1px solid var(--border); background: #05050a; image-rendering: auto; touch-action: none; }
/* the zoom buttons lie in the map's own corner, so they take none of the height the squares want */
.map-frame { position: relative; display: inline-block; max-width: 100%; line-height: 0; }
.map-zoom { position: absolute; right: 8px; bottom: 8px; display: flex; gap: var(--s-8); line-height: normal; }
.map-zoom button { min-width: 44px; min-height: 44px; font-size: 1.3rem; background: rgba(20, 18, 30, 0.88); }
.map-legend { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-4) var(--s-12); margin: var(--s-10) 0 var(--s-2); max-width: 460px; }
.map-legend .key { display: flex; align-items: center; gap: var(--s-4); font-size: var(--t-sm); color: var(--dim); }
.map-legend .key[hidden] { display: none; }
/* the line under the key kept tight: on a short phone the map's squares are sized to the height left */
#map-note { margin: var(--s-2) 0 0; }
.map-legend .key i { width: 11px; height: 11px; border-radius: 2px; border: 1px solid rgba(255,255,255,0.25); }
.map-legend .key[data-key="hound"] i { border-radius: 50%; }
.shop-gold { color: var(--gold); font-size: var(--t-lg); margin-left: auto; margin-right: var(--s-10); text-align: right; line-height: 1.25; min-width: 0; }
.shop-list { display: flex; flex-direction: column; gap: var(--s-6); margin-bottom: var(--s-4); }
.shop-row { display: flex; align-items: center; gap: var(--s-10); padding: var(--s-6) var(--s-8); background: var(--panel); border: 1px solid var(--border); border-radius: 8px; }
.shop-row img { width: 30px; height: 30px; image-rendering: pixelated; }
.shop-row .what { flex: 1; min-width: 0; }
.shop-row .what b { display: block; font-weight: normal; }
.shop-row .what small { color: var(--dim); }
.shop-row button { min-width: 86px; min-height: 44px; padding: var(--s-6) var(--s-8); }
.shop-row { cursor: pointer; }
/* a dear purchase asks twice, and so does a testing tool while the run still counts: the first tap turns the button to a warning */
.shop-row button.armed { background: var(--armed-bg); border-color: var(--warn); color: var(--armed-text); font-weight: bold; }
#ov-menu button.armed { background: var(--armed-bg); border-color: var(--warn); color: var(--armed-text); font-weight: bold; }
.shop-row button.afford { border-color: var(--accent); color: var(--primary-text); }
.shop-row button:disabled { opacity: 0.6; }   /* dimmed, but the price still easy to read */
.shop-empty { color: var(--dim); font-size: var(--t-lg); padding: var(--s-6) var(--s-2); }
.spell { display: flex; align-items: center; gap: var(--s-10); padding: var(--s-10); border: 1px solid var(--border); border-radius: 8px; margin-bottom: var(--s-8); background: var(--panel); width: 100%; text-align: left; }
.spell.locked { opacity: 0.45; }
.spell .cost { min-width: 52px; text-align: center; color: var(--blue); font-family: monospace; font-size: var(--t-xl); white-space: nowrap; }
.spell b { display: block; }
.spell small { color: var(--dim); display: block; line-height: 1.3; }
.sheet { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4) var(--s-16); max-width: 460px; margin: 0 auto; }
.sheet div { display: flex; justify-content: space-between; gap: var(--s-10); padding: var(--s-6) 0; border-bottom: 1px solid #221f2e; }
.sheet div span { color: var(--gold); text-align: right; }
.sheet .full { grid-column: 1 / -1; }
/* the hero at the top of the sheet: face, name and how far to the next level */
.sheet-top { display: flex; align-items: center; gap: var(--s-14); max-width: 460px; margin: 0 auto var(--s-4); }
.sheet-top .sheet-face { margin: 0; flex: none; }
.sheet-who { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-2); }
.sheet-who b { color: var(--gold); font-weight: normal; font-size: var(--t-2xl); }
.sheet-who span, .sheet-who small { color: var(--dim); }
.xp-bar { height: 8px; border-radius: 4px; background: #221f2e; overflow: hidden; }
.xp-bar i { display: block; height: 100%; background: linear-gradient(90deg, #8a6a2a, var(--gold)); }
#char-sheet .sheet-h { max-width: 460px; margin-left: auto; margin-right: auto; }
/* the six scores three to a row, each name over its number; the class's own marked */
.sheet.scores { grid-template-columns: repeat(3, 1fr); gap: var(--s-6) var(--s-10); }
.sheet.scores div { flex-direction: column; align-items: center; gap: var(--s-2); text-align: center; font-size: var(--t-md); color: var(--dim); }
.sheet.scores div span { text-align: center; font-size: var(--t-base); }
.sheet.scores div.key-stat { color: var(--gold); border-bottom-color: #6a5420; }
/* what the gear worn comes to, over the pack */
.inv-sum { display: flex; flex-wrap: wrap; gap: var(--s-4) var(--s-14); margin: var(--s-8) 0 0; font-size: var(--t-md); color: var(--dim); }
.inv-sum b { color: var(--gold); font-weight: normal; }
/* the history's chips: one kind of line at a time */
.log-kinds { display: flex; flex-wrap: wrap; gap: var(--s-6); margin: 0 0 var(--s-8); }
.log-kinds .chip { min-height: 36px; padding: var(--s-4) var(--s-14); border-radius: 18px; font-size: var(--t-md); }
.log-kinds .chip[aria-pressed="true"] { border-color: var(--gold); color: var(--gold); background: #2a2212; }
.end-stats { max-width: 320px; margin: 0 auto var(--s-20); grid-template-columns: 1fr 1fr; text-align: left; }

/* Landscape phones and wide screens */
@media (min-aspect-ratio: 5/4) and (min-width: 640px) {
  .game-layout { flex-direction: row; }
  .view-col { flex: 1 1 60%; max-width: none; justify-content: center; min-width: 0; }
  .view-wrap { flex: 1 1 auto; display: flex; align-items: center; justify-content: center; min-height: 0; }
  #view { max-height: none; max-width: 100%; width: 100%; height: 100%; object-fit: contain; aspect-ratio: auto; }
  .view-wrap { min-height: 0; max-height: none; }
  .ctrl-col { flex: 0 0 340px; border-left: 1px solid var(--border); justify-content: space-between; }
  /* fill the column rather than hugging the top corner */
  .controls { flex-direction: column; justify-content: center; gap: var(--s-16); flex: 1 1 auto; padding: var(--s-16); }
  /* Size the pads from the height there is, not the column's width: on a
     landscape phone the width-driven version was 550px tall in a 390px
     screen, and Cast sat below the edge where nobody could press it. */
  .controls { min-height: 0; }
  .dpad, .actions { width: auto; max-width: 100%; align-self: center; margin: 0 auto;
    height: min(200px, calc((100vh - 118px - var(--sat) - var(--sab)) / 2));
    height: min(200px, calc((100dvh - 118px - var(--sat) - var(--sab)) / 2)); aspect-ratio: 3 / 2; }
  .actions { aspect-ratio: 1; }
  .log { flex: 1 1 auto; height: auto; min-height: 7.4em; justify-content: flex-end; }
  .view-col { display: flex; flex-direction: column; }
}
@media (min-width: 900px) {
  .title-inner { max-width: 480px; }
}
/* Wide screens: the art fills the whole panel and the menu sits beside the logo */
@media (min-aspect-ratio: 6/5) {
  .title-bg { height: 100%; bottom: 0; }
  .title-fade { background: linear-gradient(to bottom, rgba(11,10,16,0.5) 0%, rgba(11,10,16,0.12) 30%, rgba(11,10,16,0.72) 78%, rgba(11,10,16,0.94) 100%); }
}
@media (max-height: 560px) and (min-aspect-ratio: 6/5) {
  /* the title's logo and menu side by side; the end and confirm screens,
     which share the class, keep their stacked column */
  #screen-title .title-inner { display: flex; align-items: center; gap: var(--s-28); max-width: 820px; text-align: left; margin-top: auto; margin-bottom: auto; padding-bottom: calc(var(--s-14) + var(--sab)); }
  .logo-block { flex: 1.1; margin-bottom: 0; }
  .menu { flex: 1; }
  .logo-rule::before { display: none; }
  .title-fade { background: linear-gradient(to right, rgba(11,10,16,0.3) 0%, rgba(11,10,16,0.55) 45%, rgba(11,10,16,0.88) 100%); }
}

/* the Use button lights up when it has something specific to do */
.ctl.ctx { border-color: var(--gold); color: var(--gold); }
.ctl.ctx small { color: var(--gold); }
/* Rest with foes near, or no rest left on the floor: quieter, and says why */
.bottombar button.unavail { color: var(--dim); border-style: dashed; background: var(--panel); }
.bottombar button small { display: block; font-size: var(--t-2xs); line-height: 1.1; color: var(--dim); }
/* a caster's healing draught, a tap away beside the life bar */
.hud-quaff { flex: 0 0 auto; position: relative; min-width: 52px; height: 44px; min-height: 44px; padding: var(--s-2) var(--s-6); line-height: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s-2);
  color: #f8e6e0; background: #3a1c22; border-color: #a0484a; border-radius: 8px; }
.hud-quaff:active { background: #5a2830; }
/* held fast, no drinking: the button greys and says so */
.hud-quaff.held { opacity: 0.5; filter: grayscale(0.7); }
/* nearly dead with a draught to hand: the button beats; held still, it simply burns bright */
.hud-quaff.urgent { border-color: #ff6a5a; animation: quaff-beat 0.6s ease-in-out infinite alternate; }
@keyframes quaff-beat { from { box-shadow: 0 0 0 0 rgba(255, 90, 70, 0.2); background: #3a1c22; } to { box-shadow: 0 0 10px 3px rgba(255, 90, 70, 0.75); background: var(--alarm-bg); } }
@media (prefers-reduced-motion: reduce) { .hud-quaff.urgent { animation: none; background: var(--alarm-bg); box-shadow: 0 0 8px 2px rgba(255, 90, 70, 0.6); } }
body.calm .hud-quaff.urgent { animation: none; background: var(--alarm-bg); box-shadow: 0 0 8px 2px rgba(255, 90, 70, 0.6); }
/* what it does, and how many are carried: "Drink ×2" */
.hud-quaff small { font-size: var(--t-xs); color: #ffd8c8; white-space: nowrap; }
/* the title's Continue only while there is a run to continue */
#btn-continue[hidden] { display: none; }
/* the Daily button over its switch: the day's dungeon for any hero, or for a Ranger or a Druid */
.daily-cell { flex: 1; display: flex; flex-direction: column; gap: var(--s-4); min-width: 0; }
.daily-cell #btn-daily { flex: 1; }
.daily-cell small[hidden] { display: none; }
.seg.daily-kind { margin: 0; border-radius: 8px; }
.seg.daily-kind button { min-height: 34px; font-size: var(--t-xs); padding: var(--s-2) var(--s-2); white-space: nowrap; }
/* Quick Start stands as tall as the Daily and its switch: its words in its middle, not at its top */
.menu-row > #btn-quick { justify-content: center; }

/* encounters */
.svc-fold { margin-top: var(--s-6); grid-column: 1 / -1; }
.svc-fold summary { cursor: pointer; color: var(--dim); padding: var(--s-8) var(--s-4); min-height: 36px; }
.svc-fold .shop-row { margin-top: var(--s-6); }
.enc-art { text-align: center; margin: var(--s-4) 0 var(--s-8); }
.enc-art img { width: 112px; height: 112px; image-rendering: pixelated; }
.enc-text { max-width: 520px; margin: 0 auto var(--s-14); line-height: 1.5; color: var(--text-mid); }
#enc-choices { max-width: 520px; margin: 0 auto; }
/* a choice out of reach looks it (the level-up guard keeps .boon:disabled at full strength) */
.boon.enc-choice:disabled { opacity: 0.5; border-style: dashed; cursor: not-allowed; }
.enc-pass { color: var(--green); font-weight: normal; }
.enc-fail { color: var(--bad-text); font-weight: normal; }
.enc-lines { margin: 0 0 var(--s-14); padding-left: var(--s-20); color: var(--gold); line-height: 1.6; }
#enc-choices > .primary { width: 100%; }

/* character creation: what each class leans on, and what each past grants */
.class-card .key, .bg-card .key { display: block; font-style: normal; font-size: var(--t-sm); color: var(--gold); margin-top: var(--s-4); }
.stats .key-stat { color: #f2e2b8; font-weight: bold; }
/* a stat never breaks across two lines, star and all */
#c-stats > div { white-space: nowrap; }
.stats .bg-boost span { color: var(--good-text); }
/* a spell that could not be cast says why at the top of the list */
.spell-why { color: #f0a090; background: #2a1414; border: 1px solid #5a2a24; border-radius: 6px; padding: var(--s-6) var(--s-8); margin: 0 0 var(--s-8); font-size: var(--t-md); }
/* the spell the Cast button will throw */
.spell.ready { border-color: var(--gold); }
.spell .on-cast { display: block; font-style: normal; font-size: var(--t-xs); color: var(--gold); }

/* narrow phones: two stat columns, so a score and its value stay on one line */
@media (max-width: 380px) {
  .stats { grid-template-columns: repeat(2, 1fr); }
}
/* a one-time tip over the log, below the view: gone on its own, or at a tap
   on it. It used to lie along the top of the view, where it covered whatever
   flew there; now it keeps off the fight altogether, and off the newest line
   of the log (placeTip in ui.js sets where) */
/* over the view while the way in plays; taps go through it to the view */
.prelude-skip { position: absolute; right: 8px; top: 8px; padding: var(--s-4) var(--s-12); border-radius: 12px; font-size: var(--t-md);
  color: rgba(232, 224, 204, 0.85); background: rgba(0, 0, 0, 0.5); pointer-events: none; }
.prelude-skip[hidden] { display: none; }
.tip { position: absolute; left: 6px; right: 76px; bottom: 6px; overflow: hidden; padding: var(--s-6) var(--s-28) var(--s-6) var(--s-10); border-radius: 8px;
  background: #17141f; border: 1px solid var(--accent); color: #f2e6c8; font-size: var(--t-md); line-height: 1.3;
  pointer-events: none; opacity: 0; transform: translateY(4px); transition: opacity 0.2s, transform 0.2s; z-index: 3; }
.tip.show { opacity: 1; transform: none; pointer-events: auto; }
.tip.show::after { content: '\2715'; position: absolute; right: 10px; top: 7px; color: var(--dim); }
.tip b { color: var(--gold); }
/* the tip hangs over the log's older lines: they are hidden while it does, or
   their edges showed above and below it, half struck through by its border */
.view-col:has(#tip.show) .log div:not(:last-child) { visibility: hidden; }
/* what lies underfoot, at the foot of the view */
.feet { position: absolute; left: 50%; bottom: 6px; transform: translateX(-50%); z-index: 2; display: flex; align-items: center; gap: var(--s-6);
  min-height: 44px; padding: var(--s-4) var(--s-10); background: rgba(12, 10, 18, 0.72); border: 1px solid var(--border); border-radius: 10px; }
.feet[hidden] { display: none; }
.feet-icons { display: flex; gap: var(--s-2); align-items: center; }
.feet-icons img { width: 28px; height: 28px; image-rendering: pixelated; }
.feet-icons em { font-style: normal; font-size: var(--t-sm); color: var(--dim); margin-left: var(--s-2); }
.feet small { font-size: var(--t-sm); color: #f2e6c8; }
/* the scroll worth reading now, at the left end of the log under the view,
   in reach of the left thumb: in the view's corner it sat over the shield or
   the focus held there. The log's lines keep clear of it while it shows. */
.quick-scroll { position: absolute; left: 6px; top: calc(100% + 8px); width: 56px; height: 56px; min-height: 56px; padding: var(--s-2) 0 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  background: rgba(20, 16, 28, 0.82); border: 2px solid var(--qs, var(--gold)); border-radius: 12px; box-shadow: 0 0 10px var(--qs, var(--gold)); }
.quick-scroll img { width: 30px; height: 30px; image-rendering: pixelated; }
.quick-scroll small { font-size: var(--t-xs); line-height: 1; color: #f2e6c8; }
.quick-scroll:active { transform: scale(0.94); }
.view-col:has(#quick-scroll:not([hidden])) .log { padding-left: 70px; }
/* equipped slots carry a label in the corner: keep the picture below it */
#equip .slot, #equip-jewels .slot { padding-top: calc(0.6rem + var(--s-8)); }


/* the list of monster tricks in the help */
ul.tricks { margin: 0.4em 0 0.8em; padding-left: 1.2em; }
ul.tricks li { margin-bottom: 0.35em; line-height: 1.4; }

/* journal tabs */
.tabs { display: flex; gap: var(--s-6); margin-bottom: var(--s-10); }
.tabs .tab { flex: 1; padding: var(--s-8); border-radius: 8px; border: 1px solid var(--border); background: var(--panel); color: var(--dim); font: inherit; }
.tabs .tab.on { color: var(--gold); border-color: var(--gold); }
.beast-el { color: var(--warn); font-size: 0.9em; }
/* the help's tabs stay in reach while a page scrolls under them */
.help-tabs { position: sticky; top: var(--sat, 0px); z-index: 1; background: var(--bg); padding: var(--s-6) 0; margin: 0 0 var(--s-6); gap: var(--s-4); }
.help-tabs .tab { padding: var(--s-8) 1px; min-height: 44px; min-width: 0; font-size: clamp(0.78rem, 3.6vw, 1rem); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* the bestiary */
.beast { display: flex; gap: var(--s-12); align-items: flex-start; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: var(--s-10) var(--s-12); margin-bottom: var(--s-8); }
.beast img { flex: 0 0 64px; width: 64px; height: 64px; object-fit: contain; image-rendering: pixelated; }
.beast.unmet img { filter: brightness(0) invert(1); opacity: 0.2; }
.beast h3 { margin: 0 0 var(--s-4); font-size: var(--t-base); }
.beast h3.named { color: #f0c860; }
.beast p { margin: var(--s-4) 0 0; line-height: 1.45; color: var(--text-soft); font-size: var(--t-lg); }
.beast .beast-stats { color: var(--text); font-size: var(--t-md); }
.beast > div { flex: 1; min-width: 0; }
.beast .trick b { color: #c890ff; }
.beast .answer b { color: #8fdc8f; }
.beast .locked { color: var(--dim); font-style: italic; }
.beast .where { color: var(--dim); font-size: var(--t-sm); }

/* the level-up screen: what the level gave, then the choice */
.boon-head { color: var(--gold); margin: var(--s-4) 0 var(--s-2); font-size: var(--t-lg); }
.boon:disabled { opacity: 1; }
/* a line fills along the card while it arms, so the pause reads as on purpose */
.boon { position: relative; overflow: hidden; }
/* a choice just offered is dimmed until it will take a tap, so a first tap that
   does nothing is seen to be early rather than lost */
.boon.arming { opacity: 0.6; }
.boon.arming::after { content: ''; position: absolute; left: 0; bottom: 0; height: 2px; width: 100%; background: var(--gold); transform-origin: left; animation: boon-arm 0.7s linear forwards; }
@keyframes boon-arm { from { transform: scaleX(0); } to { transform: scaleX(1); } }
/* talents on the Hero sheet: one to a line, name then what it does */
.sheet-h { margin: var(--s-14) 0 var(--s-6); font-size: var(--t-base); color: var(--gold); }
.talent-list { list-style: none; margin: 0; padding: 0; }
.talent-list li { padding: var(--s-6) 0; border-bottom: 1px solid var(--border); line-height: 1.4; }
.talent-list b { display: block; color: var(--gold); }
.talent-list span { color: var(--text-soft); font-size: var(--t-lg); }
/* creation stats: two to a row, so a starred score never breaks its line */
#c-stats { grid-template-columns: repeat(2, 1fr); }

/* creation: difficulty as three joined buttons near the top, one line under it */
.seg { display: flex; margin: var(--s-6) 0 var(--s-4); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.seg button { flex: 1; border: 0; border-radius: 0; border-left: 1px solid var(--border); background: var(--panel); color: #b0a8bc; min-height: 44px; font-size: var(--t-base); }
.seg button:first-child { border-left: 0; }
.seg button.on { background: var(--primary-bg); color: var(--primary-text); box-shadow: inset 0 -3px 0 var(--gold); }
.seg button:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }
.diff-note { color: var(--text-soft); font-size: var(--t-md); margin: var(--s-2) 0 var(--s-6); min-height: 1.3em; }
/* Back and Descend stay on screen however far down the form you are */
#screen-create .panel { padding-bottom: 0; }
/* a card ringed by a pad or Tab is scrolled clear of the pinned foot, not under it */
#screen-create { scroll-padding-bottom: calc(var(--s-16) * 6 + var(--sab)); }
.row.spread.create-foot { position: sticky; bottom: 0; z-index: 2; margin: var(--s-16) -16px 0; padding: var(--s-10) var(--s-16) calc(var(--s-10) + var(--sab));
  background: var(--bg); border-top: 1px solid var(--border); }
.create-foot .big { width: auto; flex: 1; }
/* the hero chosen so far, over Back and Descend: the cards that say it can be far above */
.row.spread.create-foot { flex-wrap: wrap; }
.create-sum { flex-basis: 100%; margin: 0 0 var(--s-8); font-size: var(--t-md); color: var(--text-soft); text-align: center; }
/* the game in a minute, for someone new */
.first-card { margin: 0 0 var(--s-10); padding: var(--s-8) var(--s-12); border: 1px solid var(--accent); border-radius: 10px; background: rgba(22, 20, 31, 0.92); text-align: left; }
.first-card .first-head { margin: 0 0 var(--s-2); font-size: var(--t-base); text-align: center; }
.first-card ul { margin: 0 0 var(--s-6); padding-left: 1em; }
.first-card li { margin: 0 0 var(--s-2); line-height: 1.3; font-size: var(--t-sm); }
.first-btns { gap: var(--s-8); }
.first-btns button { flex: 1; font-size: var(--t-lg); padding: var(--s-6) var(--s-10); }
/* opaque: the form scrolling under a see-through Back read through it */
.create-foot .ghost { flex: 0 0 auto; min-width: 88px; background: var(--bg); }
/* checkboxes drawn to match the dark theme, with a whole-row tap target */
.opts label.check { min-height: 44px; cursor: pointer; line-height: 1.3; }
.opts input[type=checkbox] { -webkit-appearance: none; appearance: none; flex: 0 0 auto; width: 24px; height: 24px; margin: 0; padding: 0;
  border: 1.5px solid #6a6288; border-radius: 6px; background: var(--panel); display: inline-grid; place-content: center; cursor: pointer; }
.opts input[type=checkbox]::after { content: ''; width: 12px; height: 7px; border-left: 3px solid #1a1408; border-bottom: 3px solid #1a1408; transform: translateY(-2px) rotate(-45deg); opacity: 0; }
.opts input[type=checkbox]:checked { background: var(--gold); border-color: var(--gold); }
.opts input[type=checkbox]:checked::after { opacity: 1; }
.opts input[type=checkbox]:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* the title's Quick Start and Daily Delve, side by side, each with a line under it */
.menu .ghost.two { display: flex; flex-direction: column; align-items: center; gap: var(--s-2); padding: var(--s-8) var(--s-6); }
.menu .ghost.two b { font-weight: normal; font-size: var(--t-base); }
.menu .ghost.two small { font-size: var(--t-xs); color: #b0a8bc; line-height: 1.25; }
#btn-daily.done b, #btn-daily-earned.done b { color: var(--text-soft); }

/* how a run is kept, said before the first stair */
.pro-again { margin: 0 0 var(--s-12); }
.pro-again summary { color: var(--gold); cursor: pointer; padding: var(--s-8) 0; min-height: 28px; }
.pro-rules { color: var(--text-soft); font-size: var(--t-lg); border-left: 2px solid var(--accent); padding-left: var(--s-10); }
.share-line { color: #e6dfd0; font-family: monospace; font-size: var(--t-md); background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: var(--s-8) var(--s-10); margin: 0; -webkit-user-select: text; user-select: text; overflow-wrap: anywhere; }
.hall-row .daily-mark { font-style: normal; font-size: var(--t-xs); color: #1a1408; background: var(--gold); border-radius: 999px; padding: 1px var(--s-6); margin-left: var(--s-4); white-space: nowrap; }
.hall-row.daily { border-color: var(--edge-won); }


/* trophies at the top of the Hall: a class to a row, a difficulty to a column */
.trophies { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: var(--s-8) var(--s-10) var(--s-10); margin: var(--s-4) 0 var(--s-8); }
.trophy-head { display: flex; justify-content: space-between; align-items: baseline; color: var(--gold); font-size: var(--t-lg); margin-bottom: var(--s-6); }
.trophy-head #trophy-count { color: var(--dim); font-size: var(--t-sm); }
.trophy-grid { display: grid; grid-template-columns: minmax(0, 1.2fr) repeat(3, minmax(0, 1fr)); gap: var(--s-4); align-items: center; }
.trophy-grid .th { color: var(--dim); font-size: var(--t-xs); text-align: center; letter-spacing: 0.04em; }
.trophy-grid .tcls { font-size: var(--t-md); color: var(--text-soft); }
.trophy-grid .cell, .trophy-grid .stagecell { min-height: 36px; border: 1px solid var(--border); border-radius: 6px; background: #121019; display: grid; place-content: center; color: var(--gold); font-size: var(--t-base); }
.trophy-grid .cell.won, .trophy-grid .stagecell.won { border-color: var(--edge-won); background: var(--sel-bg); box-shadow: inset 0 0 8px rgba(232, 180, 80, 0.25); }
/* the mastery cell shows its star dim until it is won: blank, the narrow column had no name */
.trophy-grid .cell.mastery:not(.won) { color: #4a4458; }
.trophy-grid.paths { grid-template-columns: minmax(0, 1.2fr) repeat(2, minmax(0, 1.5fr)) minmax(0, 0.5fr); }
.trophy-grid.vows { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.trophy-grid.stages { grid-template-columns: minmax(0, 1fr) repeat(5, minmax(0, 1fr)); }
/* a long name wraps onto a second line on the narrowest phones rather than losing its end */
.trophy-grid .cell.named, .trophy-grid .stagecell { font-size: var(--t-sm); line-height: 1.15; color: #b8b0c4; padding: var(--s-2) var(--s-4); text-align: center; overflow-wrap: anywhere; }
.trophy-grid .cell.named.won { color: var(--gold); }
/* a vow not yet open is dimmer and dashed, not faded: faded, its name fell below a readable contrast (axe) */
.trophy-grid .cell.shut { color: var(--dim); border-style: dashed; }
/* what the wins have opened: not trophies, so drawn plainer, lit once open */
.trophy-grid .unlock { min-height: 36px; border: 1px dashed var(--border); border-radius: 6px; display: grid; place-content: center; font-size: var(--t-sm); line-height: 1.15; color: var(--dim); padding: var(--s-2) var(--s-4); text-align: center; overflow-wrap: anywhere; }
.trophy-grid .unlock.open { border-style: solid; border-color: var(--edge-won); color: var(--gold); }
.trophy-grid .cell { cursor: pointer; }
.trophy-grid .cell.picked, .trophy-grid .unlock.picked { outline: 2px solid var(--gold); outline-offset: 1px; }
.trophy-note { color: var(--text-soft); font-size: var(--t-md); margin: var(--s-8) var(--s-2) 0; min-height: 2.6em; }
.trophy-sub { color: var(--dim); font-size: var(--t-sm); letter-spacing: 0.04em; margin: var(--s-10) 0 var(--s-4); }
.trophy-sub small { font-size: var(--t-xs); }
.vow-list .check span b { color: var(--gold); font-weight: normal; }
.codex-btn { width: 100%; display: flex; justify-content: space-between; align-items: baseline; gap: var(--s-8); margin-bottom: var(--s-4); }
.codex-btn b { font-weight: normal; }
.codex-btn small { color: var(--dim); font-size: var(--t-sm); }
/* the relic codex: found relics in full, the rest as dim rows */
.relic-row { display: flex; gap: var(--s-12); align-items: flex-start; background: var(--panel); border: 1px solid var(--edge-won); border-radius: 8px; padding: var(--s-10) var(--s-12); margin-bottom: var(--s-8); }
.relic-row img { flex: 0 0 48px; width: 48px; height: 48px; object-fit: contain; image-rendering: pixelated; }
.relic-row > div { flex: 1; min-width: 0; }
.relic-row h3 { margin: 0 0 var(--s-2); font-size: var(--t-base); }
.relic-row .codex-kind { margin: 0; color: var(--dim); font-size: var(--t-sm); }
.relic-row.unfound { border-color: var(--border); background: #111018; padding: var(--s-6) var(--s-12); align-items: center; }
.relic-row.unfound h3 { color: var(--dim); font-style: italic; font-size: var(--t-lg); }
/* a combination found: its mark, and how often this run has made it */
.relic-q.combo-mark { color: var(--gold); border-style: solid; border-color: var(--edge-won); }
.combo-now { margin: var(--s-2) 0 0; font-size: var(--t-xs); color: var(--good-text); }
.combos-about { margin: 0 0 var(--s-8); }
.relic-q { flex: 0 0 48px; height: 32px; display: grid; place-content: center; color: var(--dim); border: 1px dashed var(--border); border-radius: 6px; }
/* a background still to be earned: dim, and says how */
.bg-card.locked, .bg-card.locked:disabled { opacity: 1; border-style: dashed; background: #111018; cursor: not-allowed; }
.bg-card.locked b { color: #b39a5c; }
.bg-card .key.lock { color: var(--text-soft); }
/* a class won on Hard wears its title */
.class-title { display: block; font-style: normal; color: var(--gold); font-size: var(--t-sm); letter-spacing: 0.04em; }
.tcls .class-title { display: inline; font-size: var(--t-sm); }
.class-card .ease { display: block; font-style: normal; color: var(--text-mid); font-size: var(--t-sm); margin: var(--s-2) 0 var(--s-2); }
.class-card .key.goal { color: var(--text-soft); }
.first-hero { display: inline-block; align-self: flex-start; font-style: normal; font-size: var(--t-xs); color: #16120a; background: var(--gold); border-radius: 4px; padding: 1px var(--s-6); margin: var(--s-2) 0; }
.trophy-line { color: var(--gold); font-size: var(--t-base); margin: var(--s-4) 0 var(--s-8); }

/* Phones held sideways. Height is what runs short, so the view, its bars and
   the log take the left and nearly all the width, and every control goes in
   one column on the right: the d-pad and the three actions as a single 3x3
   pad, the bar below it in two rows. Tablets and desktops keep the layout
   above; this only asks for a short screen. */
@media (orientation: landscape) and (max-height: 500px) {
  /* the end's title took two fifths of a short screen, and the cause and the
     buttons were below the fold */
  #screen-end .logo { font-size: var(--t-5xl); }
  /* a notch or a rounded corner sits on one side or the other now */
  #screen-game { padding-left: var(--sal); padding-right: var(--sar); }
  /* The view had the bars above it and the log below, and a control column a
     third of the screen wide beside it: 525 by 265 on an 851 by 393 phone.
     Now the bars go to the top of a narrower control column, and the view
     takes the whole height above the log: the view's column dissolves into
     the grid, and the controls' column sits in its right-hand cell. */
  .game-layout { display: grid; grid-template-columns: minmax(0, 1fr) clamp(212px, 27vw, 252px); grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas: "view hud" "view ctrl" "log ctrl"; }
  .view-col { display: contents; }
  .view-wrap { grid-area: view; min-height: 0; max-height: none; }
  /* four lines, the oldest fading: sideways a line seldom wraps */
  .log { grid-area: log; flex: none; height: calc(4 * 1.3em + 8px); min-height: 0; font-size: var(--t-sm); line-height: 1.3; }
  .log-more-anchor { grid-area: log; align-self: start; }
  .ctrl-col { grid-area: ctrl; min-width: 0; min-height: 0; border-left: 1px solid var(--border); justify-content: flex-end; }
  /* the bars on one line with the quick drink, name and floor above them */
  .hud { grid-area: hud; min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "name right" "bars quaff";
    gap: var(--s-2) var(--s-6); padding: var(--s-2) var(--s-6) var(--s-4); border-left: 1px solid var(--border); font-size: var(--t-sm); }
  .hud-name { grid-area: name; max-width: none; min-width: 0; flex-direction: row; gap: var(--s-4); align-items: baseline; overflow: hidden; }
  .hud-name span { min-width: 0; }
  .hud-bars { grid-area: bars; align-self: center; }
  .bar { height: calc(0.66rem + 3px); }
  .bar span { font-size: var(--t-xs); line-height: calc(0.66rem + 1px); }
  .hud-quaff { grid-area: quaff; }
  .hud-right { grid-area: right; flex-direction: row; gap: var(--s-6); font-size: var(--t-xs); align-self: baseline; white-space: nowrap; }
  .controls { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: 1fr; grid-template-rows: 2fr 1fr; place-content: stretch; gap: var(--s-6); padding: var(--s-6) var(--s-6) var(--s-4); }
  .dpad, .actions { width: auto; max-width: none; height: auto; aspect-ratio: auto; margin: 0; align-self: stretch; }
  .actions { grid-template-columns: repeat(3, 1fr); grid-template-rows: 1fr; }
  .actions .attack { grid-row: auto; font-size: 1.5rem; }   /* a glyph, sized as a picture */
  /* the pad's top row reaching up would land on the d-pad's bottom row here */
  .actions .ctl::before { content: none; }
  .bottombar { flex-wrap: wrap; padding: var(--s-6) var(--s-6) calc(var(--s-6) + var(--sab)); }
  .bottombar { gap: var(--s-4); padding: var(--s-4) var(--s-6) calc(var(--s-4) + var(--sab)); }
  .bottombar button { flex: 1 1 22%; min-width: 44px; padding: var(--s-4) 1px; font-size: var(--t-sm); }

  /* sideways the log is short too: a tip is small print over it */
  .tip { font-size: var(--t-xs); line-height: 1.22; padding: var(--s-2) var(--s-24) var(--s-2) var(--s-6); border-radius: 6px; background: #17141f; }
  .tip.show::after { top: 3px; right: 8px; }
  /* what lies underfoot sits in the log's corner, beside its button, rather
     than over the feet of whatever stands in front of you; the log's lines
     keep clear of it while it is there */
  .feet { left: auto; right: 66px; bottom: auto; top: calc(100% + 6px); transform: none; flex-direction: column; gap: 1px; min-height: 44px; min-width: 56px; padding: var(--s-2) var(--s-8) var(--s-2); }
  .feet-icons img { width: 24px; height: 24px; }
  .feet small { font-size: var(--t-xs); line-height: 1; }
  .view-col:has(#feet:not([hidden])) .log { padding-right: 172px; }
  .quick-scroll { width: 52px; height: 52px; min-height: 52px; top: calc(100% + 10px); }
  .quick-scroll img { width: 26px; height: 26px; }
  .view-col:has(#quick-scroll:not([hidden])) .log { padding-left: 64px; }

  /* overlays: a slimmer head, and what was stacked put side by side */
  .overlay { padding-left: var(--sal); padding-right: var(--sar); }
  .ov-head { padding: 1px var(--s-12); }
  .ov-head h2 { font-size: var(--t-2xl); }
  /* sideways, the groups' switches three to a row, so more of the menu is on the screen at once */
  .ov-body.menu { max-width: 760px; gap: var(--s-8); }
  .ov-body.menu .menu-grid { grid-template-columns: repeat(3, 1fr); gap: var(--s-8); }
  .ov-body.menu .big { justify-content: center; }
  /* the picture beside the words, so the choices start on the first screen */
  .enc-art { float: left; margin: 0 var(--s-14) var(--s-6) 0; }
  .enc-art img { width: 84px; height: 84px; }
  .enc-text { max-width: none; }
  /* two choices to a row, so the last one is not cut off below the fold */
  #enc-choices { clear: both; display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-6) var(--s-8); max-width: none; }
  #enc-choices > * { margin: 0; }
  #enc-choices > .primary, #enc-choices > .enc-lines, #enc-choices > p { grid-column: 1 / -1; }
  /* the trader's wares two to a row: one wide column showed four at a time */
  .shop-list { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-6) var(--s-8); }

  /* the create form uses the width it has: four classes and four backgrounds
     to a row, the dungeon's settings side by side, so it is two screens
     tall instead of four */
  #screen-create { padding-left: var(--sal); padding-right: var(--sar); }
  #screen-create .panel { max-width: 900px; padding-top: calc(var(--s-6) + var(--sat)); }
  #screen-create h2 { margin: var(--s-4) 0 var(--s-6); }
  #screen-create h3 { margin: var(--s-10) 0 var(--s-2); }
  #screen-create .class-grid, #screen-create .bg-grid { grid-template-columns: repeat(4, 1fr); }
  #screen-create .class-card, #screen-create .bg-card { padding: var(--s-6) var(--s-8); }
  /* the six classes in one row, each a face, a name and its line */
  #screen-create .class-grid { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
  #screen-create .class-face { width: 34px; height: 34px; }
  /* (narrow cards: the badge keeps to its column and wraps there; on one line it ran a pixel or two over the card's edge) */
  #screen-create .first-hero { font-size: var(--t-xs); line-height: 1.15; padding: 1px var(--s-4); max-width: 100%; box-sizing: border-box; }
  /* the difficulty and the name side by side, so the classes come higher up the screen */
  #screen-create .create-top { display: grid; grid-template-columns: 1.3fr 1fr; column-gap: var(--s-14); align-items: start; }
  #screen-create .create-top label.field { margin: var(--s-2) 0 0; }
  #screen-create .diff-note { margin: var(--s-2) 0; }
  #screen-create .class-more { margin-bottom: var(--s-4); padding: var(--s-6) var(--s-8); }
  #screen-create .stats { grid-template-columns: repeat(6, 1fr); }
  /* six to a row, each name sits over its own number, not beside the next one's */
  #screen-create .stats > div { text-align: center; }
  #screen-create .stats span { float: none; display: block; }
  #screen-create .opts { grid-template-columns: repeat(4, 1fr); }
  #screen-create .opts label.check { grid-column: span 2; }
  #screen-create .opts label.check:last-child { grid-column: 1 / -1; }
  /* the chosen item's panel beside the pack rather than over half of it */
  #ov-inv .ov-body:has(> .detail.open) { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr); column-gap: var(--s-12); align-content: start; }
  #ov-inv .ov-body:has(> .detail.open) > :not(.detail) { grid-column: 1; }
  #ov-inv .detail.open { grid-column: 2; grid-row: 1 / span 3; align-self: start; top: 0; bottom: auto; margin-top: 0; box-shadow: none;
    max-height: calc(100vh - 72px - var(--sat) - var(--sab)); max-height: calc(100dvh - 72px - var(--sat) - var(--sab)); }
}

/* Self-Taught: a score for each point */
.spread-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-6); margin: var(--s-8) 0; }
.spread-grid .boon { text-align: center; }
.spread-grid .boon.key b { color: var(--gold); }
.spread-grid .boon { position: relative; }
/* where the points have gone so far, and scores Self-Taught has given all it may */
.spread-grid .boon.picked { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold) inset; }
.spread-grid .boon .picked { position: absolute; top: 3px; right: 5px; font-style: normal; font-size: var(--t-sm); color: var(--gold); }
.spread-grid .boon.full { opacity: 0.45; }
.spread-hint { margin: 0 0 var(--s-4); }

/* point buy: a score's own steps beneath it */
.stat-mode { margin: var(--s-8) 0 var(--s-6); }
.stats.buying > div { display: flex; flex-direction: column; gap: var(--s-4); }
.stats.buying span { float: none; }
.buy-row { display: flex; gap: var(--s-4); }
.buy-step { min-width: 44px; min-height: 44px; padding: 0; font-size: var(--t-xl); }
.points-left { margin: var(--s-4) 0 0; }
.spread-grid .boon.raises small { color: var(--good-text); }

/* On a phone held upright a choice's cards sit at the foot of the screen, where
   the thumb already is; a level's few lines about them go down with them, so
   they are read just above what they explain rather than across an empty
   band; an encounter's picture and words stay at the top. (An automatic top
   margin rather than justify-content, so a list too long for the screen still
   scrolls from its start.) */
@media (orientation: portrait) and (max-width: 600px) {
  #boon-list, #ov-encounter .ov-body, #ov-fork .ov-body { display: flex; flex-direction: column; }
  #boon-list > :first-child, #enc-choices, #fork-choices { margin-top: auto; }
  /* the hero's head stays at the top; what follows it is pushed to the foot */
  #boon-list > .choice-head { margin-top: 0; }
  #boon-list > .choice-head + * { margin-top: auto; }
  #enc-choices, #fork-choices { width: 100%; }
  #boon-list > *, #ov-encounter .ov-body > *, #ov-fork .ov-body > * { flex-shrink: 0; }
  /* the choices sit low, so the picture above them takes some of the room a tall phone leaves */
  .enc-art img { width: clamp(112px, 26vh, 232px); height: clamp(112px, 26vh, 232px); }
}

/* Left-handed controls: the pad and the blows change sides, Attack keeps to the
   inside edge where the thumb rests, and sideways the whole panel moves left. */
.lefty .controls { flex-direction: row-reverse; }
.lefty .log-more { right: auto; left: 4px; }   /* kept clear of the pad, which has moved right */
.lefty .log { padding-left: 68px; padding-right: var(--s-8); }   /* the text keeps clear of the Log button, which moved with it */
.lefty .actions { direction: rtl; }   /* mirrors the grid in every layout */
.lefty .actions > * { direction: ltr; }
@media (min-aspect-ratio: 5/4) and (min-width: 640px) {
  .lefty .game-layout { flex-direction: row-reverse; }
  .lefty .ctrl-col { border-left: 0; border-right: 1px solid var(--border); }
  .lefty .controls { flex-direction: column; }
}
/* Held sideways, the two paths stand side by side: one under the other, the
   second was below the fold, and pushed further down when the first was armed. */
@media (orientation: landscape) and (max-height: 500px) {
  #boon-list.paths { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--s-8); align-items: start; }
  #boon-list.paths > :not(.boon) { grid-column: 1 / -1; }
  /* the confirm bar has its room kept at the foot of every card, so arming
     one does not grow it and move both under the thumb before the second tap */
  #boon-list.paths .boon.path { padding-bottom: 52px; }
  #boon-list.paths .path-confirm { position: absolute; left: 14px; right: 14px; bottom: 10px; margin: 0; }
}

@media (orientation: landscape) and (max-height: 500px) {
  .lefty .game-layout { grid-template-columns: clamp(212px, 27vw, 252px) minmax(0, 1fr); grid-template-areas: "hud view" "ctrl view" "ctrl log"; }
  .lefty .ctrl-col, .lefty .hud { border-left: 0; border-right: 1px solid var(--border); }
}

/* A save code: long, unbroken, and meant to be copied whole, not read. */
.code-box { width: 100%; font: 0.75rem/1.3 ui-monospace, Menlo, Consolas, monospace; color: var(--text); background: var(--panel); border: 1px solid var(--border); border-radius: 6px; padding: var(--s-8); resize: vertical; word-break: break-all; margin: var(--s-8) 0; }
.code-why { color: var(--bad-text); min-height: 1.4em; }

/* In the Bestiary a met creature's picture enlarges on a tap. */
.beast img.beast-art { cursor: zoom-in; transition: width 0.15s, height 0.15s, flex-basis 0.15s; }
.beast img.beast-art.zoom { flex-basis: 160px; width: 160px; height: 160px; cursor: zoom-out; }

/* What's new, for a returning player: a slim note over the art, clear of the menu. */
.news { position: absolute; z-index: 2; top: calc(10px + var(--sat)); left: 12px; right: 12px; max-width: 460px; margin: 0 auto; display: flex; gap: var(--s-6); align-items: flex-start; background: rgba(18, 16, 26, 0.9); border: 1px solid var(--accent); border-radius: 8px; padding: var(--s-8) var(--s-4) var(--s-8) var(--s-12); font-size: var(--t-md); }
.news p { margin: 0; flex: 1; line-height: 1.35; padding-top: var(--s-2); }
.news .close { background: transparent; border: 0; padding: 0; min-height: 36px; min-width: 40px; }
.game-fact { flex-direction: column; padding: var(--s-12); }
.game-fact button { align-self: flex-end; min-height: 44px; background: var(--primary-bg); border-color: var(--accent); color: var(--primary-text); }
@media (max-height: 560px) and (min-aspect-ratio: 6/5) { .news { right: auto; max-width: 44%; } }
/* On a narrow screen a picture looked at close takes the card's whole width, above the words */
@media (max-width: 480px) {
  .beast { flex-wrap: wrap; }
  .beast img.beast-art.zoom { flex-basis: 100%; width: 100%; height: 200px; }
    }

/* The victory's news, a line each. */
#end-trophy .end-news { display: block; }
#end-trophy .end-news + .end-news { margin-top: var(--s-4); }

/* a figure and its word kept together: "prices 18%" / "higher" read as two things */
.nowrap { white-space: nowrap; }

/* the heroes' faces: on the class cards, the hero sheet and the end of a run */
.class-face { flex: none; width: 44px; height: 44px; image-rendering: pixelated; border-radius: 6px; border: 1px solid var(--card-edge); background: var(--card-bg); }
.class-face.frame-bronze, .create-portrait.frame-bronze, .end-face.frame-bronze { border: 2px solid var(--frame-bronze); }
.class-face.frame-silver, .create-portrait.frame-silver, .end-face.frame-silver { border: 2px solid var(--frame-silver); }
.class-face.frame-gold, .create-portrait.frame-gold, .end-face.frame-gold { border: 2px solid var(--frame-gold); box-shadow: 0 0 6px rgba(232, 192, 80, 0.45); }
.stage-line { display: block; margin-top: var(--s-4); }
.sheet-face { display: block; width: 72px; height: 72px; margin: 0 auto var(--s-8); image-rendering: pixelated; border-radius: 8px; border: 1px solid var(--card-edge); background: var(--card-bg); }
.end-face { display: block; width: 88px; height: 88px; margin: var(--s-6) auto var(--s-4); image-rendering: pixelated; border-radius: 8px; border: 2px solid #c9a24a; background: var(--card-bg); }
.end-face.fallen { filter: grayscale(0.85) brightness(0.75); border-color: #6a5a4a; }

/* The two largest text sizes (Menu > Text size: Larger, Double). Everything is
   sized from the root, so it all grows; here the dungeon's own bars are laid
   out afresh so nothing is cut short or pushed off the screen: the hero's
   name above the bars, which then run the full width with their numbers; the
   buttons along the bottom on two rows if they must; a tip that scrolls
   rather than losing its end. */
body.big-text .hud { flex-wrap: wrap; row-gap: var(--s-2); }
body.big-text .hud-name { flex: 1 1 auto; max-width: none; flex-direction: row; flex-wrap: wrap; gap: 0 var(--s-6); }
body.big-text .hud-bars { order: 3; flex: 1 1 100%; }
body.big-text .bar { height: calc(0.9rem + 4px); }
body.big-text .bar span { line-height: calc(0.9rem + 2px); }
/* the view gives up some of its height (never less than a wide strip) and the
   log keeps two lines, the rest a tap on Log away at the same size */
body.big-text .view-wrap { min-height: calc(100vw * 0.4); }
body.big-text .log { height: 2.9em; min-height: 2.9em; padding-right: 92px; }
body.big-text .logo { font-size: clamp(1.5rem, 8vw, 2.4rem); letter-spacing: 0.06em; }
body.big-text .daily-kind button { font-size: var(--t-2xs); padding-left: var(--s-4); padding-right: var(--s-4); white-space: normal; line-height: 1.1; }
.pro-class { display: block; color: var(--dim); }
body.big-text .slot { font-size: var(--t-2xs); }
body.big-text .slot .lbl { font-size: 0.55rem; letter-spacing: 0; }
body.big-text .sheet.scores { grid-template-columns: 1fr 1fr; }
body.big-text .sheet { grid-template-columns: 1fr; }
body.big-text .hud-right { flex-direction: row; gap: var(--s-6); }
body.big-text .bottombar { flex-wrap: wrap; }
body.big-text .bottombar button { flex: 1 1 auto; padding: var(--s-6) var(--s-6); }
body.big-text .tip { overflow-y: auto; touch-action: pan-y; overscroll-behavior: contain; }

/* Held sideways with the largest text, a narrow side column cannot hold the
   bars, the controls and the buttons: the bars run along the top, the
   buttons along the foot, and the column keeps the pad and the actions. */
@media (orientation: landscape) and (max-height: 500px) {
  body.big-text .game-layout { grid-template-rows: auto minmax(0, 1fr) auto auto; grid-template-areas: "hud hud" "view ctrl" "log ctrl" "bar bar"; }
  body.big-text.lefty .game-layout { grid-template-columns: clamp(212px, 27vw, 252px) minmax(0, 1fr); grid-template-areas: "hud hud" "ctrl view" "ctrl log" "bar bar"; }
  body.big-text .hud { border-left: 0; border-bottom: 1px solid var(--border); }
  body.big-text .hud-bars { flex-direction: row; gap: var(--s-6); }
  body.big-text .hud-bars .bar { flex: 1 1 0; min-width: 0; }
  body.big-text .view-wrap { min-height: 0; }   /* (the upright floor under the view is for a phone held upright) */
  body.big-text .ctrl-col { display: contents; }
  body.big-text .controls { grid-area: ctrl; min-height: 0; border-left: 1px solid var(--border); }
  body.big-text.lefty .controls { border-left: 0; border-right: 1px solid var(--border); }
  body.big-text .bottombar { grid-area: bar; border-top: 1px solid var(--border); }
  body.big-text .bottombar button { flex: 1 1 auto; min-width: 0; }
}

/* Calm view (Menu, and on by itself where the phone asks for less motion)
   stills the page as well as the view: no fades, pulses, slides or sweeps.
   Nothing waits on an animation's end (the overlays close on a timer), and a
   choice's guard still keeps its time: only its bar no longer sweeps. */
body.calm *, body.calm *::before, body.calm *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }

/* One-handed (Menu > Controls), held upright: every control a fight needs under
   one thumb. The actions, with the quick drink brought down from the top of the
   screen, make a row over the pad, and the two stand together on the thumb's
   side, a little narrower than the screen. Held sideways the game is played
   with both hands already, and keeps its usual layout. */
@media (orientation: portrait) {
  body.onehand .controls { flex-direction: column; align-items: flex-end; gap: var(--s-6); padding-top: var(--s-8); }
  body.onehand.lefty .controls { flex-direction: column; align-items: flex-start; }
  body.onehand .dpad, body.onehand .actions { width: 74%; max-width: 320px; }
  body.onehand .dpad { height: clamp(120px, 17vh, 150px); height: clamp(120px, 17dvh, 150px); }
  body.onehand .actions { order: -1; height: 56px; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); grid-auto-flow: column; grid-template-rows: 1fr; }
  body.onehand .actions .attack { grid-row: auto; font-size: var(--t-xl); }
  body.onehand .actions .hud-quaff { height: auto; min-height: 0; min-width: 0; }
}


/* The docked map. Hidden on a phone, where the corner map serves; on a wide
   screen (a tablet held sideways, a Steam Deck, a desktop window) the floor
   about the hero stands at the head of the control column, as large as the
   column allows, and the corner map makes way for it. The pads draw in a
   little to give it room. */
.dock { display: none; }
#dock-map { display: block; image-rendering: pixelated; cursor: pointer; border: 1px solid var(--border); border-radius: 6px; background: #05050a; }
@media (min-aspect-ratio: 5/4) and (min-width: 960px) and (min-height: 600px) {
  .dock { display: flex; flex: 1 1 auto; min-height: 120px; align-items: center; justify-content: center; padding: var(--s-12) var(--s-16) 0; container-type: size; }
  #dock-map { width: min(100cqw, 100cqh); height: min(100cqw, 100cqh); }
  #minimap { display: none; }
  .hud-status { right: var(--s-8); }
  .controls { flex: 0 0 auto; gap: var(--s-12); padding: var(--s-12) var(--s-16); }
  .dpad, .actions { height: min(170px, calc((100vh - 420px) / 2)); height: min(170px, calc((100dvh - 420px) / 2)); }
  .ctrl-col { justify-content: flex-start; flex-basis: clamp(340px, 26vw, 440px); }
}
/* A tablet held upright has the room for a larger corner map. */
@media (orientation: portrait) and (min-width: 700px) and (min-height: 900px) {
  #minimap { width: 150px; height: 150px; image-rendering: pixelated; }
  .hud-status { right: calc(150px + 14px); }
}

/* the start with a relic once found, at the last stage of a class's mastery (createextras.js) */
.relic-line { display: flex; flex-direction: column; gap: var(--s-4); margin-top: var(--s-6); }
.relic-line select { width: 100%; }
/* the Hall's filters: a class or the shared runs, wrapping on a narrow phone */
.seg.hall-filter { flex-wrap: wrap; margin: 0 0 var(--s-8); }
.seg.hall-filter button { flex: 1 0 auto; min-height: 40px; font-size: var(--t-sm); padding: var(--s-2) var(--s-8); border-top: 1px solid var(--border); margin-top: -1px; }

/* The storyteller stays in reach while the dungeon is quiet. */
.voice-controls { flex-wrap: wrap; margin-block: var(--s-8); }
.voice-controls label, .voice-volume { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-4); }
.voice-controls input, .voice-volume input { max-width: 100%; }
.discovery-voice { position: absolute; z-index: 8; bottom: var(--s-8); left: var(--s-8); right: var(--s-8); padding: var(--s-8); background: var(--bg); border: 1px solid var(--border); font-size: var(--t-sm); max-height: calc(100% - var(--s-16)); overflow-y: auto; }
.discovery-voice p { margin: 0 0 var(--s-4); max-height: 4.5em; overflow-y: auto; }
.discovery-voice button { padding: var(--s-4); font-size: inherit; min-width: 44px; }

/* Painted faces keep their brushwork at every size; the dungeon stays crisp. */
.class-face, .pro-face, .choice-face, .sheet-face, .end-face { image-rendering: auto; object-fit: cover; }

/* A keeper's first words wait for the hero; no timer takes the page away. */
#ov-boss { background: var(--bg); }
.boss-reveal { display: flex; flex-direction: column; align-items: center; gap: var(--s-16); }
.boss-reveal > img { width: min(100%, 280px); height: auto; aspect-ratio: 1; flex-shrink: 0; border: 1px solid var(--accent); border-radius: 8px; }
.boss-reveal > p { max-width: 36em; margin: 0; color: var(--text); line-height: 1.5; }
.boss-reveal > button { width: 100%; max-width: 360px; flex-shrink: 0; }
.boss-portrait, .beast img.bestiary-portrait { image-rendering: auto; object-fit: cover; }
.beast img.bestiary-portrait { flex-basis: 96px; width: 96px; height: 96px; border: 1px solid var(--accent); border-radius: 6px; }
.beast.unmet img.bestiary-portrait { filter: grayscale(1) brightness(0.15) blur(5px); opacity: 0.35; }
.beast img.bestiary-portrait.zoom { flex-basis: 256px; width: 256px; height: 256px; }
@media (max-width: 480px) {
  .beast img.bestiary-portrait.zoom { flex-basis: 100%; width: 100%; height: auto; aspect-ratio: 1; }
}
@media (max-height: 560px) and (min-aspect-ratio: 6/5) {
  .boss-reveal { display: grid; grid-template-columns: min(36%, 240px) 1fr; align-content: start; }
  .boss-reveal > img { grid-row: span 2; width: 100%; }
}

/* A recording has its own rules and storage in this framed view. */
.run-replay { width: min(960px, calc(100vw - var(--s-16))); max-width: none; height: calc(100dvh - var(--s-24)); max-height: none; padding: var(--s-12); background: var(--bg); color: var(--text); border: 1px solid var(--accent); border-radius: 8px; }
.run-replay::backdrop { background: rgba(0,0,0,0.8); }
.run-replay[open] { display: flex; flex-direction: column; gap: var(--s-8); }
.run-replay h2 { margin: 0; }
.run-replay iframe { width: 100%; flex: 1; min-height: 0; border: 0; }
.replay-page { overflow-y: auto; }
.replay-player { padding: var(--s-8); max-width: 900px; margin: auto; }
#replay-view { display: block; width: 100%; max-height: 65dvh; object-fit: contain; image-rendering: pixelated; }

.run-replay > .row, .replay-player > .row { flex-wrap: wrap; }
.run-replay h2 { min-width: 0; overflow-wrap: anywhere; }

/* The catches on optional treasure: four named marks, never colour alone. */
.puzzle-clue { padding: var(--s-12); border: 1px solid var(--border); color: var(--primary-text); background: var(--card-bg); }
.puzzle-marks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-8); }
.puzzle-marks button { min-height: 48px; }
.puzzle-marks small { display: block; }
.puzzle-marks [aria-pressed="true"] { border-color: var(--gold); background: var(--sel-bg); }
#puzzle-controls { display: grid; gap: var(--s-8); }
#puzzle-feedback { color: var(--gold); }

/* Keep each hero's puzzle choice and the stair in reach while the story scrolls. */
.pro-start { position: sticky; bottom: 0; z-index: 2; padding: var(--s-10) 0 calc(var(--s-10) + var(--sab)); background: var(--bg); border-top: 1px solid var(--border); }
.pro-start .opts { grid-template-columns: 1fr; }
@media (max-height: 600px) { .pro-start { position: static; } }

/* The catch lifts once. No flash or motion is needed to read the reward. */
.puzzle-unlock { position: relative; width: 64px; height: 48px; margin: var(--s-12) auto; }
.puzzle-unlock[hidden] { display: none; }
.puzzle-box, .puzzle-lid { position: absolute; left: 0; width: 64px; border: 2px solid var(--gold); border-radius: 4px; background: var(--card-bg); }
.puzzle-box { bottom: 0; height: 28px; box-shadow: 0 0 16px rgba(232, 180, 80, 0.2); }
.puzzle-lid { top: 0; height: 16px; transform: translateY(-4px) rotate(-8deg); transform-origin: left bottom; }
.puzzle-unlock.opening .puzzle-lid { animation: cache-open 550ms ease-out; }
.puzzle-reward { text-align: left; padding: var(--s-12); }
.puzzle-reward b, .puzzle-reward small { display: block; }
.puzzle-reward small { margin-top: var(--s-4); color: var(--dim); }
@keyframes cache-open { from { transform: translateY(16px) rotate(0); } to { transform: translateY(-4px) rotate(-8deg); } }
body.calm .puzzle-unlock.opening .puzzle-lid { animation: none; }
@media (prefers-reduced-motion: reduce) { .puzzle-unlock.opening .puzzle-lid { animation: none; } }

/* Shared frames and selected states across the pack, creature book and hero
   screens. Mastery metals and treasure colours still belong to their owners. */
:is(.class-card, .bg-card, .slot, .beast, .relic-row, .detail) { border-radius: var(--frame-radius); box-shadow: var(--frame-sheen); }
:is(.class-card.sel, .bg-card.sel, .slot.sel) { border-color: var(--gold); background: var(--sel-bg); box-shadow: var(--frame-sheen), inset 0 -3px 0 var(--gold); }
:is(.create-portrait, .class-face, .sheet-face, .end-face, .beast img.bestiary-portrait) { border-radius: var(--frame-radius); background-color: var(--panel); }
:is(.ov-head, .sheet-top) { background-image: linear-gradient(100deg, rgba(224, 184, 74, 0.07), transparent 70%); }
body.calm .item-showcase > img { animation: none !important; }
@media (prefers-reduced-motion: reduce) { .item-showcase > img { animation: none !important; } }

.g-mythic { color: var(--g-mythic); }
.slot.g-mythic { color: var(--g-mythic); border-color: var(--g-mythic-edge); box-shadow: inset 0 0 10px rgba(200,150,240,.25); }
.detail[data-grade="mythic"], .finds .tag.g-mythic, .end-tags .tag.g-mythic { border-color: var(--g-mythic-edge); }

.end-tags .tag.g-mythic { color: var(--g-mythic); }

/* A find is revealed in the pack the player already opened, clear of combat. */
.detail:is([data-grade="legend"], [data-grade="mythic"]) .item-showcase {
  padding: var(--s-12); border: 1px solid currentColor; border-radius: var(--frame-radius);
  background: radial-gradient(ellipse at 20% 50%, rgba(224,184,74,.12), transparent 75%);
}
.detail[data-grade="mythic"] .item-showcase { background: radial-gradient(ellipse at 20% 50%, rgba(200,150,240,.14), transparent 75%); }
.detail:is([data-grade="legend"], [data-grade="mythic"]) .item-showcase > img { flex-basis: 96px; width: 96px; height: 96px; }
.treasure-new { font-size: var(--t-sm); color: var(--text); margin-bottom: var(--s-4); }
.detail.treasure-reveal .item-showcase > img { animation: treasure-unveil 650ms ease-out; }
@keyframes treasure-unveil { from { opacity: .25; transform: scale(.82); } to { opacity: 1; transform: scale(1); } }

.offline-status { position: relative; z-index: 1; flex-shrink: 0; margin: 0; padding: var(--s-4) var(--s-12); background: var(--bg); color: var(--text-soft); font-size: var(--t-sm); line-height: 1.4; text-align: center; overflow-wrap: anywhere; }

/* Collections remain reachable on narrow phones and with enlarged text. */
#screen-title .menu-row:has(#btn-companions) { flex-wrap: wrap; }
#screen-title .menu-row:has(#btn-companions) > button { flex: 1 1 40%; min-width: 0; }
#ov-journal .tabs { flex-wrap: wrap; }
#ov-journal .tabs .tab { flex: 1 1 auto; }

/* Paintings are confined to discovered codex rows and selected item details. */
.relic-row img.relic-portrait, .detail .item-showcase > img.relic-portrait {
  flex: 0 0 96px; width: 96px; height: 96px; image-rendering: auto;
  object-fit: contain; border-radius: 8px; cursor: zoom-in;
}
.relic-portrait:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.relic-row:has(img.zoom), .item-showcase:has(img.zoom) { flex-direction: column; align-items: flex-start; }
.relic-row:has(img.zoom) > div, .item-showcase:has(img.zoom) > div { width: 100%; }
.relic-row img.relic-portrait.zoom, .detail .item-showcase > img.relic-portrait.zoom {
  flex: none; width: min(100%, 320px); height: auto; max-width: 100%; cursor: zoom-out;
}
