/* The page's components: one look for every screen, dialog and overlay around the game, ink and
   ember (www/DESIGN.md). Every colour is a token of palette.css, which is generated from
   games/shinobi-society/data/ui/palette.json; a tint is a color-mix() of a token, named once under
   Tokens. kit.html shows each component in its states. A screen (index.html) lays them out and
   adds no look of its own. */

/* ---- Face: Lora for every word on the page, titles and text alike (fonts/) ------------------- */
@font-face { font-family: "Lora"; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url(fonts/lora.woff2) format("woff2"); }
@font-face { font-family: "Lora"; font-style: italic; font-weight: 400 700; font-display: swap;
  src: url(fonts/lora-italic.woff2) format("woff2"); }

/* ---- Tokens: the tints of the palette, the faces, the grain and the spring -------------------- */
:root {
  /* The one face: titles, text, labels and asides differ by size, weight and case, not by family. */
  --face: "Lora", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  /* A release that overshoots a little and settles: a press springing back. */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  /* A motion that sets off fast and settles slowly: a page, a bar or a mark arriving. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  /* Paper fibres, laid over the lacquer. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .93 0 0 0 0 .89 0 0 0 0 .83 0 0 0 .07 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  /* A sheet's brush edge, as a mask: one stroke swelling from a fine start to a flicked end. Vector,
     so it stays smooth at any size; stretched along its length only. --brush-v runs down, --brush-h
     across. */
  --brush-v: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 400' preserveAspectRatio='none'%3E%3Cpath d='M5.2 0C6.6 22 8.6 52 9.2 96C9.8 150 8.8 214 9.4 268C9.8 318 8.4 362 6 400C5 380 2.2 344 1.2 292C.3 236 1.1 176 .7 118C.4 70 2.8 26 5.2 0Z'/%3E%3C/svg%3E");
  --brush-h: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 10' preserveAspectRatio='none'%3E%3Cpath d='M0 5.2C22 6.6 52 8.6 96 9.2C150 9.8 214 8.8 268 9.4C318 9.8 362 8.4 400 6C380 5 344 2.2 292 1.2C236 .3 176 1.1 118 .7C70 .4 26 2.8 0 5.2Z'/%3E%3C/svg%3E");
  /* Washi on the page (.washi): its cloud (the paper's thicker and thinner patches), its fibres
     laid along the sheet, and its specks, laid over `washi`; the paper's own picture, as the
     HUD's sheet is (scripts/washi-art.py). */
  --washi-cloud: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cfilter id='c' x='0' y='0' width='1' height='1'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.011' numOctaves='3' seed='5' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .52 0 0 0 0 .42 0 0 0 0 .28 0 0 0 .62 -.2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23c)'/%3E%3C/svg%3E");
  --washi-fibre: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='f' x='0' y='0' width='1' height='1'%3E%3CfeTurbulence type='turbulence' baseFrequency='.02 .2' numOctaves='2' seed='9' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 .99 0 0 0 0 .95 0 0 0 -9 .42'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
  --washi-speck: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='s' x='0' y='0' width='1' height='1'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.7' numOctaves='2' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .45 0 0 0 0 .36 0 0 0 0 .24 0 0 0 3.4 -2.82'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23s)'/%3E%3C/svg%3E");
  /* Sumi on washi, faint: a wash of ink (the ground of a step, the gutter's shade); what is yours
     washed in gold, and harm and risk in vermilion, as ink on the paper. */
  --sumi-wash: color-mix(in srgb, var(--sumi) 7%, transparent);
  --sumi-shade: color-mix(in srgb, var(--sumi) 22%, transparent);
  --gold-ink-wash: color-mix(in srgb, var(--gold-ink) 20%, transparent);
  --vermilion-ink-wash: color-mix(in srgb, var(--vermilion-ink) 22%, transparent);
  /* The accent as ink on washi, faint: the ground of what is picked on paper (a ledger's line, a
     switch that is on); the ring of a field on paper holding focus. */
  --accent-on-paper-wash: color-mix(in srgb, var(--accent-on-paper) 12%, transparent);
  --accent-on-paper-ring: color-mix(in srgb, var(--accent-on-paper) 24%, transparent);
  /* Paper over lacquer: the lift of what the pointer is over; a neutral pick, an empty slot. */
  --paper-wash: color-mix(in srgb, var(--paper) 5%, transparent);
  --paper-fill: color-mix(in srgb, var(--paper) 12%, transparent);
  /* The accent: the ground of what is picked, its rim, a focus ring round a well, the shadow of a
     stroke; the sheen that sweeps a call to action. */
  --accent-wash: color-mix(in srgb, var(--accent) 12%, transparent);
  --accent-rim: color-mix(in srgb, var(--accent-hi) 55%, transparent);
  --accent-ring: color-mix(in srgb, var(--accent) 26%, transparent);
  --accent-shadow: color-mix(in srgb, var(--accent) 35%, transparent);
  --sheen: color-mix(in srgb, var(--paper-bright) 38%, transparent);
  /* Ink on the accent, faint: the track a busy call to action's spinner turns on. */
  --on-accent-faint: color-mix(in srgb, var(--on-accent) 30%, transparent);
  /* The night the M menu sinks the world into: thick at its edges and under its bar, thin in its
     middle; the haze of ember glowing up from below it. */
  --night-thick: color-mix(in srgb, var(--ink) 92%, transparent);
  --night: color-mix(in srgb, var(--ink) 80%, transparent);
  --night-thin: color-mix(in srgb, var(--ink) 30%, transparent);
  --ember-haze: color-mix(in srgb, var(--accent) 15%, transparent);
  /* A problem: vermilion words and mark, its faint ground, the ring of a well that has one. */
  --danger: var(--vermilion);
  --danger-bg: color-mix(in srgb, var(--vermilion) 10%, transparent);
  --danger-ring: color-mix(in srgb, var(--vermilion) 24%, transparent);
}

/* ---- Base --------------------------------------------------------------------------------------- */
html { color-scheme: dark; }
body { margin: 0; background: var(--ink); color: var(--paper); font: 15px/1.45 var(--face); -webkit-font-smoothing: antialiased; }
*, *::before, *::after { box-sizing: border-box; }
:where(*) { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
/* The runes and brush filters (index.html's sprite) live in an SVG no one sees. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.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; }
svg.rune { flex: none; width: 1.2em; height: 1.2em; }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
/* "/ cap" after a figure. */
.of { font-style: normal; color: var(--faint); }

/* ---- Signals: the rarity inks, which colour a scroll's name and picture and nothing else -------- */
.r-common { color: var(--paper); }
.r-uncommon { color: var(--jade-hi); }
.r-rare { color: var(--azure); }
.r-epic { color: var(--violet); }
.r-legendary { color: var(--gold); }
/* A skill's group (`skills::group`), as the marks it colours read it: Setup jade, Mobility azure,
   Surge techniques and Chakra Surge gold, a Weapon steel. */
.g-setup { color: var(--jade-hi); }
.g-weapon { color: var(--paper-bright); }
.g-mobility { color: var(--azure); }
.g-surge { color: var(--gold); }
.g-action { color: var(--paper); }

/* ---- Marks: the society's shuriken (#logo), the seal --------------------------------------------- */
svg.logo { flex: none; width: 46px; height: 46px; --logo-lit: var(--accent-hi); --logo-shade: var(--accent);
  filter: drop-shadow(0 6px 14px var(--accent-glow)); }
/* A rune stamped in ember ink, its edge worn. */
.seal { flex: none; position: relative; width: 44px; height: 44px; display: grid; place-items: center; color: var(--on-accent); }
.seal::before { content: ""; position: absolute; inset: 0; rotate: -4deg; filter: url(#ink-rough) drop-shadow(0 6px 8px var(--accent-glow));
  background: linear-gradient(155deg, var(--accent-lit) 0%, var(--accent) 85%); }
.seal svg { position: relative; width: 26px; height: 26px; rotate: -4deg; }

/* ---- Lacquer, the one material: a frame is a sheet (a dialog, a menu, a card, a strip); a pop is
   a small one over the page (a tooltip, a mark's card). Both carry the ember brush edge. --------- */
.frame, .pop { position: relative; color: var(--paper); border: 1px solid var(--line); border-radius: 2px;
  background: var(--grain), linear-gradient(180deg, var(--lacquer), var(--lacquer-deep)); }
.frame { box-shadow: 0 30px 80px var(--shadow-soft); }
.pop { z-index: 2; padding: 12px 16px 13px 19px; border-color: var(--line-strong); border-radius: 3px; text-align: left;
  font: 400 15px/1.35 var(--face); box-shadow: 0 18px 44px var(--shadow);
  background: var(--grain), linear-gradient(180deg, var(--plate-lit), var(--lacquer-deep)); }
/* A pop's title, the italic line under it, and its lines. */
.pop > b { display: block; font: 600 17px/1.25 var(--face); color: var(--paper-bright); }
.pop > small { display: block; font-size: 13.5px; font-style: italic; color: var(--muted); }
.pop > span { display: block; }
/* The edge: one vertical brush stroke of the accent down the left. */
:is(.frame, .pop)::before { content: ""; position: absolute; left: 0; top: clamp(10px, 12%, 22px); bottom: clamp(10px, 12%, 22px);
  width: 4px; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, transparent, var(--accent) 12%, var(--accent-hi) 50%, var(--accent) 88%, transparent);
  mask: var(--brush-v) 0 0 / 100% 100% no-repeat; }
@keyframes pop-in { from { opacity: 0; translate: 0 var(--from, 0); } }

/* ---- Washi (.washi): paper with words in sumi, as the HUD's sheets are; on the page, the book's
   pages (below, "The book"). What the page's components say on it takes the paper's inks: words
   sumi, quieter words sumi-soft and sumi-faint, rules sumi-line, a signal or a rarity its -ink,
   ember accent-on-paper (below, "On paper"). */
.washi { color: var(--sumi); background: var(--washi-speck), var(--washi-fibre), var(--washi-cloud), var(--washi); }
/* A sheet of the HUD's washi (.washi.washi-sheet): the HUD's own picture of it (`--washi-sheet`, put on
   the page by src/panels/hud.rs from data/ui/icons/washi-sheet.svg), drawn in nine parts round
   the words, its deckled edge and its shadow; without it, the page's washi inside a clear edge. */
.washi-sheet { border: 16px solid transparent; background-clip: padding-box;
  border-image: var(--washi-sheet) 16 fill / 16px / 0 repeat; }
.washi .caps, .washi .muted { color: var(--sumi-faint); }
.washi .figure b { color: var(--sumi); }
.washi .figure span { color: var(--sumi-faint); }
.washi .note { color: var(--sumi-soft); }
.washi .note::before { background: var(--accent-on-paper); }
.washi .problem { color: var(--vermilion-ink); background: none; border-left-color: var(--vermilion-ink); }
.washi .problem::before { background: var(--vermilion-ink); }
.washi .rows dt { color: var(--sumi-soft); }
.washi .rows dd i { color: var(--sumi-faint); }
.washi .rows dd.bad { color: var(--vermilion-ink); }
.washi .r-common { color: var(--sumi-soft); }
.washi .r-uncommon { color: var(--jade-ink); }
.washi .r-rare { color: var(--azure-ink); }
.washi .r-epic { color: var(--violet-ink); }
.washi .r-legendary { color: var(--gold-ink); }

/* ---- A skill on a card (.skill-card.setup | .weapon | .surge | .mobility | .action; src/panels/skill_card.rs): its
   name after its icon, how it works drawn from above in its group's ink (svg.aim: what it reaches
   .area, where it goes .mark, how far it may go .edge, you .you), its tags, what it does on hit, its
   harm and its counter, and on the roster its figures. A pop holding one takes its group's ink for
   its edge. ------------------------------------------------------------------------------------- */
.skill-card { display: flex; flex-direction: column; gap: 8px; color: var(--jade); font-variant-numeric: tabular-nums; }
.skill-card.surge { color: var(--gold); }
.skill-card.mobility { color: var(--azure); }
.skill-card.action { color: var(--paper); }
.skill-card.weapon { color: var(--paper-muted); }
.pop:has(> .skill-card.setup) { --accent: var(--jade); --accent-hi: var(--jade-hi); }
.pop:has(> .skill-card.weapon) { --accent: var(--paper-muted); --accent-hi: var(--paper-bright); }
.pop:has(> .skill-card.surge) { --accent: var(--gold); --accent-hi: var(--gold-hi); }
.pop:has(> .skill-card.mobility) { --accent: var(--azure); --accent-hi: var(--azure-hi); }
.skill-name { display: flex; align-items: center; gap: 8px; font: 600 17px/1.25 var(--face); color: var(--paper-bright); }
.skill-name img { flex: none; width: 22px; height: 22px; }
.skill-body { display: flex; align-items: flex-start; gap: 14px; }
.skill-card .aim { flex: none; width: 54px; height: 54px; overflow: hidden;
  fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.skill-card .aim .area { fill: color-mix(in srgb, currentColor 24%, transparent); }
.skill-card .aim .edge { stroke-dasharray: 2.4 3.2; stroke-width: 1.4; opacity: 0.75; }
.skill-card .aim .mark { fill: currentColor; stroke: none; }
.skill-card .aim .you { fill: var(--paper-bright); stroke: var(--ink); stroke-width: 1; }
.skill-lines { display: flex; flex-direction: column; gap: 4px; min-width: 0; font-size: 14px; color: var(--paper); }
.skill-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 2px; }
.skill-tags i { padding: 1px 6px; border: 1px solid var(--line-strong); border-radius: 2px;
  font: 600 11px/1.35 var(--face); font-style: normal; letter-spacing: 0.1em; text-transform: uppercase; color: var(--paper-muted); }
.skill-line { display: flex; align-items: baseline; gap: 10px; }
.skill-line > small { flex: none; width: 56px; font-size: 12.5px; color: var(--muted); }
.skill-line > span { display: flex; flex-wrap: wrap; gap: 2px 10px; }
.skill-line > span > span { display: inline-flex; align-items: center; gap: 4px; }
.skill-line img { width: 15px; height: 15px; }
.skill-line em { font-style: normal; font-size: 12px; color: var(--paper-muted); }
.skill-line b { font-weight: 600; color: var(--paper-bright); }
.skill-line b.high { color: var(--vermilion-hi); }
.skill-figures { display: grid; grid-template-columns: auto auto auto auto; align-items: baseline; column-gap: 12px; row-gap: 1px;
  padding-top: 7px; border-top: 1px solid var(--line); }
.skill-figures small { font-size: 12.5px; color: var(--muted); }
.skill-figures b { font: 600 14px/1.3 var(--face); color: var(--paper-bright); text-align: right; white-space: nowrap; }

/* ---- The call to action (.cta): a brush stroke, not a box, one a view. A rune leads its words;
   a spinner takes the rune's place while it is busy (aria-busy). Hover lifts it, brightens and
   stretches the stroke and sweeps a sheen across it; a press squashes it; release springs it back,
   and boot.js throws an ink burst (.burst) from where it was pressed. ---------------------------- */
.cta { position: relative; isolation: isolate; display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  height: 44px; padding: 0 30px 0 calc(30px + 0.24em); border: 0; background: none; cursor: pointer; white-space: nowrap;
  font: 700 14px/1 var(--face); letter-spacing: 0.24em; text-transform: uppercase; color: var(--on-accent);
  text-shadow: 0 1px 0 var(--accent-glow); -webkit-tap-highlight-color: transparent;
  transition: translate 0.4s var(--ease-spring), scale 0.4s var(--ease-spring); }
.cta.large { height: 52px; padding: 0 34px 0 calc(34px + 0.26em); font-size: 15px; letter-spacing: 0.26em; }
.cta::before { content: ""; position: absolute; inset: 3px -6px; z-index: -1;
  background: linear-gradient(90deg, var(--accent-deep), var(--accent) 24%, var(--accent-lit) 50%, var(--accent) 76%, var(--accent-deep));
  filter: url(#ink-brush) drop-shadow(0 8px 16px var(--accent-shadow));
  transition: scale 0.4s var(--ease-spring), filter 0.2s, opacity 0.15s; }
.cta::after { content: ""; position: absolute; inset: 3px -6px; z-index: -1; pointer-events: none; filter: url(#ink-brush);
  background: linear-gradient(105deg, transparent 35%, var(--sheen) 50%, transparent 65%) -150% 0 / 250% 100% no-repeat; }
.cta:hover:not(:disabled) { translate: 0 -1px; }
.cta:hover:not(:disabled)::before { scale: 1.03 1.06;
  filter: url(#ink-brush) brightness(1.08) drop-shadow(0 10px 22px var(--accent-glow)); }
.cta:hover:not(:disabled)::after { background-position: 150% 0; transition: background-position 0.7s ease-out; }
.cta:active:not(:disabled) { translate: 0 2px; scale: 0.97; transition-duration: 0.07s; }
.cta:active:not(:disabled)::before { scale: 0.99 0.94;
  filter: url(#ink-brush) brightness(0.86) drop-shadow(0 3px 6px var(--accent-shadow)); transition-duration: 0.07s; }
.cta:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 5px; }
.cta:disabled { cursor: not-allowed; opacity: 0.45; }
.cta:disabled::before { scale: none; filter: url(#ink-brush) grayscale(0.7); }
.cta .rune { width: 17px; height: 17px; margin-left: -0.24em; opacity: 0.92; }
.cta .label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.cta .spinner { display: none; flex: none; width: 16px; height: 16px; margin-left: -0.24em; border-radius: 50%;
  border: 2px solid var(--on-accent-faint); border-top-color: var(--on-accent);
  animation: spin 0.7s linear infinite; }
.cta[aria-busy=true] { cursor: progress; }
.cta[aria-busy=true] .rune { display: none; }
.cta[aria-busy=true] .spinner { display: inline-block; }
@keyframes spin { to { rotate: 360deg; } }
/* The ink burst a press throws: a ring and six diamonds flung out (boot.js adds it, then removes it
   once played). */
.burst { position: absolute; z-index: 1; width: 10px; height: 10px; margin: -5px 0 0 -5px; pointer-events: none; }
.burst::before { content: ""; position: absolute; inset: 0; border: 2px solid var(--accent-hi); border-radius: 50%;
  animation: burst-ring 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) forwards; }
.burst i { position: absolute; left: 3px; top: 3px; width: 4px; height: 4px; background: var(--accent-hi);
  transform: rotate(var(--a)) translateY(0) rotate(45deg); animation: burst-shard 0.45s cubic-bezier(0.2, 0.7, 0.3, 1) forwards; }
@keyframes burst-ring { from { transform: scale(0.4); opacity: 0.9; } to { transform: scale(7); opacity: 0; } }
@keyframes burst-shard { to { transform: rotate(var(--a)) translateY(-26px) rotate(45deg) scale(0.3); opacity: 0; } }

/* ---- The word button (.btn): small capitals that act. Hover draws its underline in from the left;
   a press dips it; the one that is on (.on) keeps the underline. .quiet rests muted (a way back, a
   reset); .danger is for what cannot be taken back. ----------------------------------------------- */
.btn { position: relative; padding: 6px 0 6px 0.2em; border: 0; background: none; cursor: pointer; white-space: nowrap;
  font: 600 13px/1.2 var(--face); letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent-hi);
  -webkit-tap-highlight-color: transparent;
  transition: color 0.15s, translate 0.3s var(--ease-spring), scale 0.3s var(--ease-spring); }
.btn::after { content: ""; position: absolute; left: 0.2em; right: 0.2em; bottom: 2px; height: 1px; background: currentColor;
  scale: 0 1; transform-origin: left; transition: scale 0.25s ease-out; pointer-events: none; }
.btn.quiet { color: var(--muted); }
.btn.danger { color: var(--danger); }
.btn.on { color: var(--paper); }
.btn.on::after { scale: 1; background: var(--accent-hi); }
.btn:hover:not(:disabled) { color: var(--paper); }
.btn.danger:hover:not(:disabled) { color: var(--vermilion-hi); }
.btn:hover:not(:disabled)::after { scale: 1; }
.btn:active:not(:disabled) { translate: 0 1px; scale: 0.95; transition-duration: 0.15s, 0.06s, 0.06s; }
.btn:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 3px; }
.btn:disabled { cursor: not-allowed; color: var(--faint); }
/* A count beside its words. */
.btn .n { margin-left: 7px; color: var(--paper); letter-spacing: 0; }

/* ---- Close (.close): a quiet icon button, a paper cross that lights in the accent ---------------- */
.close { position: relative; flex: none; width: 36px; height: 36px; padding: 0; border: 0; border-radius: 2px; background: none;
  color: var(--paper-muted); cursor: pointer; -webkit-tap-highlight-color: transparent; }
.close::before, .close::after { content: ""; position: absolute; left: 50%; top: 50%; width: 18px; height: 1.5px;
  margin: -0.75px 0 0 -9px; border-radius: 1px; background: currentColor; rotate: 45deg; }
.close::after { rotate: -45deg; }
.close:is(:hover, :focus-visible) { color: var(--accent-hi); background: var(--paper-wash); }
.close:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 2px; }

/* ---- Small capitals for labels and legends; key caps ---------------------------------------------- */
.caps, .field > label, legend { font: 600 11.5px/1.3 var(--face); letter-spacing: 0.24em; text-transform: uppercase; color: var(--muted); }
kbd { display: inline-block; min-width: 1.6em; padding: 0 5px; border: 1px solid var(--line-strong); border-bottom-width: 2px;
  border-radius: 2px; font: 600 13px/1.45 var(--face); font-style: normal; letter-spacing: 0; text-transform: none;
  text-align: center; color: var(--paper); background: var(--paper-wash); }

/* ---- A field (.field > label + .input): a label in small capitals over a well of ink, a quiet
   icon leading the words (.lead) and, for a password, an eye to show it (.reveal). Focus rings the
   well in the accent and lights the icon; a problem (aria-invalid) edges it in vermilion. The one
   box of the page: a place to type has to look like one. .compact is a single line's well. ------ */
.field { display: flex; flex-direction: column; gap: 8px; }
.field > label { padding-left: 1px; }
.field .hint { margin: 6px 0 0; font-size: 13.5px; font-style: italic; color: var(--faint); }
.field:has(.problem:not(:empty)) .hint { display: none; }
.input { position: relative; display: flex; align-items: center; }
.input > .lead { position: absolute; left: 14px; width: 18px; height: 18px; color: var(--faint); pointer-events: none;
  transition: color 0.15s; }
.input input { width: 100%; height: 48px; margin: 0; padding: 0 14px; font: 500 16.5px var(--face);
  color: var(--paper); caret-color: var(--accent-hi); background: var(--well); border: 1px solid var(--line-strong);
  border-radius: 6px; outline: none; box-shadow: inset 0 1px 3px var(--shadow-soft);
  transition: border-color 0.15s, box-shadow 0.15s, background-color 0.15s; }
.input.compact input { height: 34px; padding: 0 10px; font-size: 14px; border-radius: 3px; }
.input > .lead ~ input { padding-left: 42px; }
.input input::placeholder { color: var(--faint); font-weight: 400; opacity: 1; }
.input input:hover { border-color: var(--line-bright); }
.input input:focus-visible { border-color: var(--accent-hi); box-shadow: inset 0 1px 3px var(--shadow-soft), 0 0 0 3px var(--accent-ring); }
.input:has(input:focus-visible) > .lead { color: var(--accent-hi); }
.input input[aria-invalid=true] { border-color: var(--danger); }
.input input[aria-invalid=true]:focus-visible { box-shadow: inset 0 1px 3px var(--shadow-soft), 0 0 0 3px var(--danger-ring); }
.input input:disabled { cursor: not-allowed; }
/* Autofill keeps the well's colours: the browser's own fill waits out a very long transition. */
.input input:-webkit-autofill { -webkit-text-fill-color: var(--paper); caret-color: var(--accent-hi);
  transition: background-color 9999s 0s, border-color 0.15s, box-shadow 0.15s; }
.input:has(.reveal) input { padding-right: 50px; }
.input .reveal { position: absolute; right: 6px; width: 36px; height: 36px; display: grid; place-items: center; padding: 0;
  border: 0; border-radius: 4px; background: transparent; color: var(--muted); cursor: pointer;
  transition: color 0.15s, background-color 0.15s, scale 0.3s var(--ease-spring); }
.input .reveal svg { width: 20px; height: 20px; }
.input .reveal:hover { color: var(--paper); background: var(--paper-wash); }
.input .reveal:active { scale: 0.86; transition-duration: 0.15s, 0.15s, 0.06s; }
.input .reveal:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 0; }
.input .reveal[aria-pressed=true] { color: var(--accent-hi); }
.input .reveal .hide, .input .reveal[aria-pressed=true] .show { display: none; }
.input .reveal[aria-pressed=true] .hide { display: block; }

/* ---- Tabs (.tabs > button[aria-selected]): words over a rule, the one shown underlined with a
   brush stroke; for views. ------------------------------------------------------------------------ */
.tabs { display: flex; gap: 26px; border-bottom: 1px solid var(--line); }
.tabs > button { position: relative; padding: 2px 0 10px; border: 0; background: none; cursor: pointer;
  font: 600 18px/1.2 var(--face); color: var(--muted); }
.tabs > button:hover, .tabs > button[aria-selected=true] { color: var(--paper); }
.tabs > button[aria-selected=true]::after { content: ""; position: absolute; left: -3px; right: -3px; bottom: -2px; height: 3px;
  background: var(--accent-hi); box-shadow: 0 0 10px var(--accent-glow); filter: url(#ink-brush); }
.tabs > button:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 2px; }

/* ---- The segmented well (.segmented): a dark slot of a few choices. A tab shown in it is lit
   neutral (aria-selected); a value picked in it, in the accent (aria-checked, or a checked radio
   in a label), because the accent marks a value you set. ----------------------------------------- */
.segmented { display: flex; gap: 2px; padding: 3px; border-radius: 4px; background: var(--well);
  box-shadow: inset 0 1px 2px var(--shadow-soft); }
.segmented > :is(button, label) { position: relative; flex: 1; min-width: 0; display: grid; place-items: center; padding: 7px 4px;
  border: 0; border-radius: 2px; background: none; color: var(--muted); font: 500 15px/1.3 var(--face); text-align: center;
  cursor: pointer; }
.segmented > label > input { position: absolute; opacity: 0; pointer-events: none; }
.segmented > :is(button, label):hover { color: var(--paper); background: var(--paper-wash); }
.segmented > button:focus-visible, .segmented > label:has(input:focus-visible) { outline: 1px solid var(--accent-hi); outline-offset: -1px; }
.segmented > [aria-selected=true] { color: var(--paper); background: var(--paper-fill); box-shadow: 0 1px 2px var(--shadow-soft); }
.segmented > :is([aria-checked=true], label:has(input:checked)) { color: var(--paper); background: var(--accent-deep);
  box-shadow: 0 0 12px var(--accent-glow); }

/* ---- A setting (.row): its name on the left, its control on the right (a slider and its value,
   or a switch); the row under the pointer or holding focus is washed, tying the two together. ---- */
.row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 14px; min-height: 40px;
  padding: 0 10px; border-radius: 3px; font-size: 16px; color: var(--paper); cursor: pointer;
  transition: background-color 0.15s, opacity 0.15s; }
.row:has(input[type=range]) { grid-template-columns: minmax(0, 1fr) 170px 52px; }
.row:hover, .row:has(:focus-visible) { background: var(--paper-wash); }
.row:has(input:disabled) { opacity: 0.4; cursor: default; background: none; }
.row small { display: block; color: var(--faint); font-size: 13px; }
.row label { cursor: inherit; }
.row output { justify-self: end; color: var(--accent-hi); font-size: 15px; font-variant-numeric: tabular-nums; }
/* Narrow: a slider drops under its name and value. */
@media (max-width: 520px) {
  .row:has(input[type=range]) { grid-template-columns: minmax(0, 1fr) auto; row-gap: 0; padding-block: 6px; }
  .row input[type=range] { grid-column: 1 / -1; grid-row: 2; }
}

/* ---- A slider (input[type=range]): a hairline filled in the accent up to a diamond; the page sets
   the fill as --fill. A switch (input[role=switch]): a slot with a diamond that crosses over and
   lights when on. -------------------------------------------------------------------------------- */
input[type=range] { --fill: 0%; -webkit-appearance: none; appearance: none; display: block; width: 100%; height: 22px; margin: 0;
  background: transparent; cursor: pointer; }
input[type=range]::-webkit-slider-runnable-track { height: 2px;
  background: linear-gradient(90deg, var(--accent-hi) var(--fill), var(--line-strong) var(--fill)); }
input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 13px; height: 13px; margin-top: -5.5px;
  background: var(--ink); border: 2px solid var(--accent-hi); rotate: 45deg; box-shadow: 0 0 12px var(--accent-glow); }
input[type=range]::-moz-range-track { height: 2px; background: var(--line-strong); }
input[type=range]::-moz-range-progress { height: 2px; background: var(--accent-hi); }
input[type=range]::-moz-range-thumb { width: 10px; height: 10px; border-radius: 0; background: var(--ink);
  border: 2px solid var(--accent-hi); rotate: 45deg; box-shadow: 0 0 12px var(--accent-glow); }
input[type=range]:disabled { pointer-events: none; }
input[role=switch] { -webkit-appearance: none; appearance: none; position: relative; flex: none; width: 40px; height: 20px; margin: 0;
  border-radius: 2px; background: var(--paper-fill); cursor: pointer; transition: background-color 0.15s, box-shadow 0.15s; }
input[role=switch]::after { content: ""; position: absolute; top: 5px; left: 6px; width: 10px; height: 10px; rotate: 45deg;
  background: var(--muted); transition: translate 0.2s var(--ease-spring), background-color 0.15s; }
input[role=switch]:checked { background: var(--accent-deep); box-shadow: 0 0 10px var(--accent-glow); }
input[role=switch]:checked::after { translate: 18px 0; background: var(--paper); }
:is(input[type=range], input[role=switch]):focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 4px; }

/* ---- Show uncollected (.show-all > input[role=switch] + span): the one switch over a collection. */
.show-all { display: inline-flex; align-items: center; gap: 10px; font-size: 15px; color: var(--muted); cursor: pointer; user-select: none;
  &:hover { color: var(--paper); } }

/* ---- A chip (.chip, aria-pressed): small capitals in a thin box, a filter that is on or off ----- */
.chip { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px 6px 12px; border: 1px solid var(--line);
  border-radius: 2px; background: transparent; font: 600 11.5px/1.2 var(--face); letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--muted); cursor: pointer; }
.chip:hover { color: var(--paper); border-color: var(--line-strong); }
.chip[aria-pressed=true] { color: var(--paper); border-color: var(--accent-rim); background: var(--accent-wash); }
.chip:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 2px; }

/* ---- What a body says: rows (a name and its value), keys (a key, then what it does), figures (the
   few numbers that matter), a meter (experience, in gold), a note (a state worth saying) and a
   problem (something wrong, the only red). ------------------------------------------------------- */
.rows { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 9px 24px; margin: 0; align-items: baseline; }
.rows dt { min-width: 0; }
.rows dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.rows dd i { font-style: normal; color: var(--faint); }
/* A value that needs a look (a slow round trip, a low frame rate): the problem's ink. */
.rows dd.bad { color: var(--danger); }
.keys { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 9px 14px; margin: 0; align-items: baseline; }
.keys dt { justify-self: end; white-space: nowrap; }
.keys dd { margin: 0; min-width: 0; }
/* What a key does, said more quietly under it. */
.keys dd small { display: block; font: italic 400 13px/1.3 var(--face); color: var(--muted); }
.keys .or { margin: 0 3px; font-size: 13px; color: var(--faint); }
.figures { display: flex; flex-wrap: wrap; gap: 20px 64px; }
.figure b { display: block; font: 300 42px/1 var(--face); font-variant-numeric: tabular-nums; color: var(--paper); }
.figure b .of { display: inline; margin: 0; font-size: 24px; }
.figure span { display: block; margin-top: 8px; font-size: 14.5px; color: var(--muted); }
.meter { position: relative; height: 2px; background: var(--line-strong); }
.meter i { position: absolute; left: 0; top: 0; bottom: 0;
  background: var(--gold); }
.note, .problem, [data-state=error] .message { position: relative; margin: 0; padding-left: 18px; font-size: 15px; color: var(--muted); }
.note::before, .problem::before, [data-state=error] .message::before { content: ""; position: absolute; left: 1px; top: 0.6em; width: 7px; height: 7px;
  rotate: 45deg; background: var(--muted); }
.note b { color: var(--paper); font-weight: 600; }
.problem, [data-state=error] .message { padding: 8px 12px 8px 28px; text-align: left; color: var(--danger); background: var(--danger-bg);
  border-left: 2px solid var(--danger); }
.problem::before, [data-state=error] .message::before { left: 12px; top: calc(8px + 0.725em - 3.5px); background: var(--danger); }
.note:empty, .problem:empty { display: none; }
/* A form's status line (.message): quiet words, or its screen's problem when it is in error. */
.message { margin: 0; font-size: 15px; color: var(--muted); }
.message:empty { display: none; }

/* ---- Actions and entries: a view's one call to action and its words; a list of things to act on,
   each what it is in a line with its button at the right. ---------------------------------------- */
.actions { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 26px; }
.entry { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 5px 0; }
.entry > :first-child { min-width: 0; }
.entry b { font-weight: 600; }
.entry small { display: block; color: var(--muted); font-size: 14px; }
.entry > .muted { max-width: 35%; text-align: right; font-size: 14px; }
.entry > .actions, .entry > .btn { flex: none; }

/* ---- A dialog (.overlay > .dialog.frame): the world steps back (dimmed, blurred) behind one sheet
   of lacquer. Its header is the title, the tabs when there are any and the close; then a body
   that scrolls. A .dialog.large fills the view less a margin. ------------------------------------- */
.overlay { position: fixed; inset: 0; z-index: 5; display: grid; place-items: center; padding: 24px 30px;
  background: radial-gradient(90% 80% at 50% 45%, var(--scrim), var(--veil));
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); font: 16px/1.45 var(--face); color: var(--paper); }
.overlay[hidden] { display: none; }
/* Unclassed buttons take the dialog's type; :where keeps this below the components. */
:where(.overlay) button { font: inherit; color: inherit; }
.dialog { display: flex; flex-direction: column; width: min(780px, 100%); max-height: calc(100% - 28px); min-height: 0; }
.dialog.large { width: min(1480px, 100%); height: calc(100% - 28px); }
.dialog > header { flex: none; display: flex; align-items: flex-end; gap: 26px; padding: 22px 18px 0 30px;
  border-bottom: 1px solid var(--line); }
.dialog > header .title { flex: none; min-width: 0; padding-bottom: 14px; }
.dialog > header h1 { margin: 0; font: 700 28px/1.05 var(--face); letter-spacing: 0.01em; color: var(--paper-bright);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dialog > header .tabs { align-self: stretch; align-items: flex-end; margin: 0 0 -1px; border: 0; }
.dialog > header .tabs > button { padding-bottom: 14px; }
.dialog > header .tabs > button[aria-selected=true]::after { bottom: 0; }
.dialog > header .close { align-self: center; margin: 0 0 4px auto; }
.dialog .body { flex: 1; min-height: 0; overflow-y: auto; padding: 24px 30px 30px; }
.dialog .body > * + * { margin-top: 28px; }
.dialog h3 { margin: 0 0 12px; font: 700 19px/1.2 var(--face); color: var(--paper); }
.dialog p { margin: 0; }
.dialog .cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 30px 56px; }
.dialog .cols > section + section { margin-top: 0; }
@media (max-width: 640px) {
  .overlay { padding: 10px; }
  .dialog > header { padding: 18px 12px 0 22px; gap: 16px; }
  .dialog > header h1 { font-size: 23px; }
  .dialog .body { padding: 18px 18px 22px 22px; }
}


/* ---- The M menu (#village.overlay.menu > .menu-scene + .menu-sheet > .dialog.menu-page): the
   whole screen, no sheet of lacquer. The world sinks into ink behind it: the overlay blurs and
   darkens it, and the scene (dialogs/menu_scene.rs) lays the night over it, a mist of paper-ink
   mountains along its foot, embers drifting up and an ensō that paints itself as the menu opens.
   The bar (.menu-bar): the society's mark, the tabs (.menu-tabs: a rune over tracked capitals)
   between a step back and a step on (.menu-step), and the close beside its key; on the bar's rule
   under the tab shown, an ember brush stroke and diamond (.menu-cursor). Then the tab's title over a
   brush flourish, and its body straight on the dark. The sheet plays its way in when the menu
   opens (data-enter=open on the root) and turns its page for another tab (data-enter=turn, the
   cursor gliding from the tab at --from to the one at --at); a redraw within a tab plays nothing. - */
.overlay.menu:not([hidden]) { display: block; }
.overlay.menu { padding: 0; background: none;
  --tab-w: clamp(84px, 7.6vw, 128px); --bar-h: clamp(76px, 12vh, 124px); --gutter: clamp(24px, 6.5vw, 112px); --page-w: 1560px;
  backdrop-filter: blur(12px) saturate(0.8) brightness(0.72); -webkit-backdrop-filter: blur(12px) saturate(0.8) brightness(0.72);
  animation: menu-sink 0.9s var(--ease-out) both; }
.menu-scene { position: absolute; inset: 0; overflow: hidden; pointer-events: none;
  background: linear-gradient(180deg, var(--ink), var(--night) calc(var(--bar-h) - 8px), var(--night-thin) 32%, transparent 46%),
    linear-gradient(0deg, var(--night-thick), transparent 46%),
    radial-gradient(120% 100% at 50% 52%, var(--night-thin) 30%, var(--night-thick)); }
.menu-scene .glow { position: absolute; left: 50%; bottom: -30vh; width: 94vw; height: 58vh; translate: -50% 0; border-radius: 50%;
  background: radial-gradient(closest-side, var(--ember-haze), transparent); animation: menu-fade 0.8s ease-out both; }
.menu-scene .mist { position: absolute; left: -80px; right: -80px; bottom: 0; height: 42vh;
  animation: menu-fade 0.8s ease-out both, menu-drift 38s ease-in-out infinite alternate; }
.menu-scene .mist svg { display: block; width: 100%; height: 100%; }
.menu-scene .mist path { fill: var(--paper); }
.menu-scene .mist .far { opacity: 0.035; }
.menu-scene .mist .mid { opacity: 0.05; }
.menu-scene .mist .near { opacity: 0.075; }
.menu-scene mask { mask-type: alpha; }
/* An ember: a spark of the accent rising, swaying and dying out, over and over (menu_scene.rs sets
   each one's place, pace, height and drift). */
.menu-scene .embers i { position: absolute; bottom: -10px; width: 3px; height: 3px; rotate: 45deg; background: var(--accent-hi);
  box-shadow: 0 0 6px 1px var(--accent-glow), 0 0 14px 3px var(--accent-glow); opacity: 0;
  animation: menu-ember var(--d) linear var(--w) infinite; }
.menu-scene .enso { position: absolute; right: -10vw; top: 7vh; width: min(96vh, 56vw); aspect-ratio: 1; opacity: 0.085; color: var(--paper); }
.menu-scene .enso .hairs path { fill: none; stroke: currentColor; stroke-linecap: round; }
.menu-scene .enso .draw { fill: none; stroke: currentColor; stroke-width: 90; stroke-dasharray: 1;
  animation: menu-draw 1.8s cubic-bezier(0.5, 0, 0.2, 1) 0.25s both; }
.menu-sheet { position: absolute; inset: 0; }
.dialog.menu-page { width: 100%; height: 100%; max-height: none; }
/* The bar: the mark, the tabs and the close, over a rule that fades out at either end. */
.menu-page > .menu-bar { position: relative; flex: none; display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: end; gap: 20px; height: var(--bar-h); padding: 0 clamp(20px, 3.4vw, 56px); border: 0; }
.menu-page > .menu-bar::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--line-strong) 22%, var(--line-strong) 78%, transparent); }
.menu-mark { align-self: center; display: flex; align-items: center; gap: 14px; min-width: 0; }
.menu-mark svg.logo { width: 34px; height: 34px; filter: drop-shadow(0 4px 12px var(--accent-glow)); }
.menu-mark span { font: 600 12px/1 var(--face); letter-spacing: 0.34em; text-transform: uppercase; color: var(--paper-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.menu-nav { display: flex; align-items: flex-end; }
.menu-step { align-self: center; position: relative; flex: none; width: 34px; height: 34px; margin: 0 clamp(2px, 1.4vw, 22px); padding: 0;
  border: 0; border-radius: 2px; background: none; color: var(--faint); cursor: pointer; }
.menu-step::before { content: ""; position: absolute; left: 50%; top: 50%; width: 9px; height: 9px; margin: -4.5px 0 0 -2.5px;
  border: solid currentColor; border-width: 0 0 1.5px 1.5px; rotate: 45deg; }
.menu-step.on::before { margin-left: -6.5px; rotate: -135deg; }
.menu-step:hover { color: var(--paper); }
.menu-step:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 2px; }
.menu-tabs { position: relative; display: flex; }
.menu-tabs > [role=tab] { position: relative; width: var(--tab-w); height: calc(var(--bar-h) - 26px); display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end; gap: 12px; padding: 0 0 18px; border: 0; background: none; color: var(--muted); cursor: pointer; }
.menu-tabs .rune { width: 26px; height: 26px; color: var(--faint); transition: color 0.25s, filter 0.25s, translate 0.35s var(--ease-spring); }
.menu-tabs span { font: 600 12.5px/1 var(--face); letter-spacing: 0.28em; text-transform: uppercase; padding-left: 0.28em; white-space: nowrap; }
.menu-tabs > [role=tab]:hover { color: var(--paper); }
.menu-tabs > [role=tab]:hover .rune { color: var(--paper-muted); translate: 0 -2px; }
.menu-tabs > [aria-selected=true] { color: var(--paper-bright); }
.menu-tabs > [aria-selected=true] .rune { color: var(--accent-hi); filter: drop-shadow(0 0 10px var(--accent-glow)); translate: 0 -3px; }
.menu-tabs > [role=tab]:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: -6px; }
/* The ember's haze rising from under the tab shown. */
.menu-tabs > [aria-selected=true]::before { content: ""; position: absolute; left: 50%; bottom: -40px; width: 220px; height: 90px; translate: -50% 0;
  border-radius: 50%; pointer-events: none; background: radial-gradient(closest-side, var(--ember-haze), transparent); }
/* The cursor: a brush stroke of ember along the rule under the tab shown, and its diamond on the rule. */
.menu-cursor { position: absolute; left: calc(var(--at) * var(--tab-w)); bottom: 0; width: var(--tab-w); height: 0; pointer-events: none; }
.menu-cursor::before { content: ""; position: absolute; left: 12px; right: 12px; top: -5px; height: 5px;
  background: linear-gradient(90deg, var(--accent-deep), var(--accent-lit) 50%, var(--accent-deep));
  mask: var(--brush-h) 0 0 / 100% 100% no-repeat; filter: drop-shadow(0 0 8px var(--accent-glow)); }
.menu-cursor::after { content: ""; position: absolute; left: 50%; top: -1px; width: 9px; height: 9px; margin: -4px 0 0 -4.5px; rotate: 45deg;
  background: var(--accent-hi); box-shadow: 0 0 12px 2px var(--accent-glow); }
.menu-end { justify-self: end; align-self: center; display: flex; align-items: center; gap: 14px; }
.menu-bar .menu-end > .close { width: 42px; height: 42px; margin: 0; border: 1px solid var(--line-strong); border-radius: 50%; color: var(--paper); }
.menu-bar .menu-end > .close::before, .menu-bar .menu-end > .close::after { width: 16px; margin-left: -8px; }
.menu-bar .menu-end > .close:is(:hover, :focus-visible) { border-color: var(--accent-hi); background: none; box-shadow: 0 0 14px var(--accent-glow); }
/* The tab's title, large, over a flourish: two brush strokes round an ember diamond. */
.menu-page > .title { position: relative; flex: none; width: min(100% - 2 * var(--gutter), var(--page-w)); margin: clamp(16px, 4.5vh, 48px) auto 0;
  padding: 0 0 24px; }
.menu-page > .title h1 { margin: 0; font: 500 clamp(34px, 5.4vh, 60px)/1.1 var(--face); letter-spacing: 0.005em; color: var(--paper-bright);
  text-shadow: 0 4px 30px var(--shadow); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu-page > .title::before { content: ""; position: absolute; left: 2px; bottom: 6px; width: 240px; height: 4px; opacity: 0.7;
  background: linear-gradient(90deg, var(--paper-muted) 45%, transparent 45% 55%, var(--line-bright) 55%);
  mask: var(--brush-h) 0 0 / 45% 100% no-repeat, var(--brush-h) 100% 0 / 45% 100% no-repeat; }
.menu-page > .title::after { content: ""; position: absolute; left: 118px; bottom: 4px; width: 8px; height: 8px; rotate: 45deg;
  background: var(--accent-hi); box-shadow: 0 0 10px var(--accent-glow); }
.menu-page > .body { width: min(100% - 2 * var(--gutter), var(--page-w)); margin: 0 auto clamp(16px, 4vh, 48px); padding: clamp(12px, 2.6vh, 30px) 0 0; }
/* Its way in, as it opens. */
.menu[data-enter=open] :is(.menu-mark, .menu-end) { animation: menu-down 0.7s var(--ease-out) 0.15s both; }
.menu[data-enter=open] .menu-tabs > [role=tab] { animation: menu-down 0.6s var(--ease-out) calc(0.18s + var(--i) * 0.045s) both; }
.menu[data-enter=open] .menu-step { animation: menu-fade 0.6s ease-out 0.5s both; }
.menu[data-enter=open] .menu-bar::after { animation: menu-unfold 0.9s var(--ease-out) 0.1s both; }
.menu[data-enter=open] .menu-cursor::before { animation: menu-paint 0.55s var(--ease-out) 0.55s both; }
.menu[data-enter=open] .menu-cursor::after, .menu[data-enter=open] .menu-tabs > [aria-selected=true]::before {
  animation: menu-pop 0.5s var(--ease-spring) 0.75s both; }
.menu[data-enter=open] .menu-page > .title { animation: menu-rise 0.8s var(--ease-out) 0.35s both; }
.menu[data-enter=open] .menu-page > .title h1 { animation: menu-track 1.1s var(--ease-out) 0.35s both; }
.menu[data-enter=open] .menu-page > .title::before { animation: menu-paint 0.7s var(--ease-out) 0.6s both; }
.menu[data-enter=open] .menu-page > .title::after { animation: menu-pop 0.5s var(--ease-spring) 0.9s both; }
.menu[data-enter=open] .menu-page > .body { animation: menu-rise 0.8s var(--ease-out) 0.5s both; }
/* A page turned to another tab. */
.menu[data-enter=turn] .menu-cursor { animation: menu-glide 0.5s var(--ease-out) both; }
.menu[data-enter=turn] .menu-page > :is(.title, .body) { animation: menu-turn 0.45s var(--ease-out) both; }
@keyframes menu-sink { from { backdrop-filter: none; -webkit-backdrop-filter: none; } }
@keyframes menu-fade { from { opacity: 0; } }
@keyframes menu-down { from { opacity: 0; translate: 0 -18px; } }
@keyframes menu-rise { from { opacity: 0; translate: 0 18px; } }
@keyframes menu-turn { from { opacity: 0; translate: 0 10px; } }
@keyframes menu-track { from { letter-spacing: 0.08em; } }
@keyframes menu-paint { from { clip-path: inset(-20px 100% -20px -20px); } to { clip-path: inset(-20px); } }
@keyframes menu-pop { from { opacity: 0; scale: 0.2; } }
@keyframes menu-unfold { from { clip-path: inset(0 50%); } to { clip-path: inset(0); } }
@keyframes menu-glide { from { translate: calc((var(--from) - var(--at)) * var(--tab-w)) 0; } }
@keyframes menu-drift { to { translate: -60px 0; } }
@keyframes menu-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes menu-ember { 0% { opacity: 0; translate: 0 0; } 12% { opacity: var(--o); } 70% { opacity: calc(var(--o) * 0.6); }
  100% { opacity: 0; translate: var(--x) calc(-1 * var(--h)); } }
/* A narrow view: the mark keeps only its shuriken; a narrower one drops the steps and the key hint,
   and a very narrow one keeps the tabs only their runes. */
@media (max-width: 1480px) { .menu-mark span { display: none; } }
@media (max-width: 1080px) { .menu-step, .menu-end kbd { display: none; } }
@media (max-width: 860px) {
  .overlay.menu { --tab-w: 48px; }
  .menu-tabs span { display: none; }
}

/* ---- A scroll's picture (.pic > svg + img; .rolled, .big; scroll_art.rs): a scroll you have
   unrolled with its icon painted on the paper, one you do not rolled and unlit; the ink of whatever
   holds it (`r-*`) bands, caps and ties it. Its screen sizes it. ---------------------------------- */
.pic { position: relative; display: block; flex: none; width: 80px; height: 55px;
  svg { display: block; width: 100%; height: 100%; overflow: visible; }
  img { position: absolute; left: 50%; top: 50%; height: 58%; width: auto; aspect-ratio: 1;
    transform: translate(-50%, -50%); pointer-events: none; }
  &.big { width: 220px; height: 152px; }
  &.big img { filter: drop-shadow(0 1px 1.5px var(--shadow-soft)); }
}

/* ---- The book (.body.book-body > .book-stand > nav.chapters + article.book; src/dialogs/book.rs):
   every tab of the M menu lies on it. A book open on the dark, two pages of washi (.page.verso,
   .page.recto, both .washi) bound at a gutter inside the lip of an ink cover, their edges stacked
   at either side and shaded into the binding. The tab's sub-views are paper slips (.fusen)
   standing out of its top edge, the open one tallest with an ember edge. A page is its running
   head (.running: its name in .caps, or its leaves, .contents > .leaf, the open one underlined in
   ember), its body (.page-body, scrolling), and its folio when it has one (.folio). A spread's
   head is its title over the HUD's sumi rule (.spread-head > h2 + img.rule); the bottom corners'
   arrows turn it (.turn.prev, .turn.next). A picture may lie across both pages (.across), under
   the gutter's shade, with the pages' words over it. ------------------------------------------- */
.body.book-body { display: grid; padding: 14px 30px 24px; overflow: hidden; }
.book-body {
  /* The book keeps a reader's proportions on a tall view: no taller than a spread's pictures need,
     lying in the middle of the dark. */
  .book-stand { display: grid; grid-template-rows: auto minmax(0, 800px); align-content: center; width: min(100%, 1400px); min-height: 0;
    margin: 0 auto; }

  /* The tab's sub-views: slips of paper standing out of the book's top edge, the open one tallest. */
  .chapters { position: relative; z-index: 0; display: flex; align-items: flex-end; justify-content: flex-end; gap: 6px;
    height: 34px; margin: 0 0 -8px; padding: 0 70px; }
  .fusen { display: flex; align-items: flex-start; height: 30px; padding: 7px 18px 0; border: 0; border-radius: 2px 2px 0 0;
    background: var(--washi-cloud), var(--washi-shade); color: var(--sumi-soft); cursor: pointer;
    font: 600 11px/1.2 var(--face); letter-spacing: 0.2em; text-transform: uppercase; box-shadow: 0 -3px 8px var(--shadow-soft);
    &:hover { color: var(--sumi); }
    &[aria-current=true] { height: 40px; padding-top: 10px; color: var(--sumi); background: var(--washi-cloud), var(--washi);
      box-shadow: inset 0 3px 0 var(--accent-on-paper), 0 -3px 10px var(--shadow-soft); }
    &:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 2px; }
  }

  /* The book: its cover's lip round the pages, the pages' edges stacked at either side, the
     gutter's shade where they bend into the binding. */
  .book { position: relative; z-index: 1; display: grid; grid-template-columns: 1fr 1fr; min-height: 0; padding: 9px 11px;
    border-radius: 5px; background: var(--grain), var(--ink); border: 1px solid var(--line-strong);
    box-shadow: 0 34px 70px var(--shadow), 0 6px 18px var(--shadow-soft); }
  .page { position: relative; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; min-width: 0; min-height: 0;
    padding: 22px 46px 16px; }
  .verso { grid-area: 1 / 1; border-radius: 3px 0 0 3px; padding-right: 54px;
    box-shadow: -2px 1px 0 var(--washi-shade), -4px 2px 0 var(--washi), -6px 3px 0 var(--washi-shade);
    background: linear-gradient(90deg, transparent 84%, var(--sumi-wash) 94%, var(--sumi-shade)),
      var(--washi-speck), var(--washi-fibre), var(--washi-cloud), var(--washi); }
  .recto { grid-area: 1 / 2; border-radius: 0 3px 3px 0; padding-left: 54px;
    box-shadow: 2px 1px 0 var(--washi-shade), 4px 2px 0 var(--washi), 6px 3px 0 var(--washi-shade);
    background: linear-gradient(270deg, transparent 86%, var(--sumi-wash) 95%, var(--sumi-shade)),
      var(--washi-speck), var(--washi-fibre), var(--washi-cloud), var(--washi); }

  /* The running heads: the page's name in small capitals, or its leaves, the one open underlined. */
  .running { display: flex; align-items: center; min-height: 22px; margin-bottom: 10px; }
  .recto .running { justify-content: flex-end; }
  .contents { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 4px 22px; }
  .leaf { position: relative; padding: 3px 0; border: 0; background: none; cursor: pointer; color: var(--sumi-faint);
    font: 600 11px/1.2 var(--face); letter-spacing: 0.18em; text-transform: uppercase;
    &:hover { color: var(--accent-on-paper); }
    &[aria-current=page] { color: var(--sumi); }
    &[aria-current=page]::after { content: ""; position: absolute; left: -2px; right: -2px; bottom: -3px; height: 3px;
      background: var(--accent-on-paper); mask: var(--brush-h) 0 0 / 100% 100% no-repeat; }
    &:focus-visible { outline: 1px solid var(--accent-on-paper); outline-offset: 3px; }
  }
  /* A page's body scrolls; while more of it lies below, its foot fades into the paper. */
  .page-body { min-height: 0; overflow-y: auto; scrollbar-color: var(--sumi-line) transparent;
    animation: page-more linear both; animation-timeline: scroll(self); }
  .page-body section + section { margin-top: 18px; }
  .folio { display: flex; align-items: center; justify-content: center; gap: 10px; padding-top: 8px;
    font: 500 12px/1 var(--face); font-variant-numeric: tabular-nums; color: var(--sumi-faint);
    &::before, &::after { content: ""; width: 5px; height: 5px; rotate: 45deg; border: 1px solid var(--sumi-line); }
  }

  /* Turning: the corners' arrows, each with the spread it turns to. */
  .turn { position: absolute; bottom: 20px; z-index: 2; display: flex; align-items: center; gap: 6px; padding: 4px 6px;
    border: 0; background: none; cursor: pointer; color: var(--sumi-soft);
    font: 600 10.5px/1.2 var(--face); letter-spacing: 0.18em; text-transform: uppercase;
    svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
    &.prev { left: 40px; }
    &.next { right: 40px; flex-direction: row-reverse; }
    &:hover { color: var(--accent-on-paper); }
    &:focus-visible { outline: 1px solid var(--accent-on-paper); outline-offset: 2px; }
  }

  /* A spread's head: its title over the sumi rule. */
  .spread-head { margin-bottom: 8px;
    .rule { display: block; width: 200px; height: auto; margin-top: 8px; }
  }

  /* A picture across both pages: it lies over the paper of both, the gutter's shade laid over it
     again where the pages bend into the binding; the pages' words lie over the picture, and let
     the pointer through to it wherever they hold nothing. The tab places its picture inside. */
  .across { position: relative; isolation: isolate; grid-area: 1 / 1 / 2 / -1; min-width: 0; min-height: 0;
    &::after { content: ""; position: absolute; top: 0; bottom: 0; left: calc(50% - 60px); width: 120px; z-index: 1; pointer-events: none;
      background: linear-gradient(90deg, transparent, var(--sumi-wash) 35%, var(--sumi-shade) 50%, var(--sumi-wash) 65%, transparent); }
  }
  .book:has(> .across) .page > * { position: relative; z-index: 2; pointer-events: none; }
  .book:has(> .across) .page > * > * { pointer-events: auto; }
}
/* More below: the page's foot fading, until it is scrolled to its end (a scroll timeline; a page
   that does not scroll has none, and no fade). */
@keyframes page-more { 0%, 97% { mask-image: linear-gradient(0deg, transparent, var(--ink) 28px); } 100% { mask-image: none; } }
/* A short view: the pages' margins and heads draw closer. */
@media (max-height: 800px) {
  .body.book-body { padding-top: 6px; padding-bottom: 14px; }
  .book-body {
    .page { padding: 16px 38px 12px; }
    .verso { padding-right: 46px; }
    .recto { padding-left: 46px; }
    .running { margin-bottom: 4px; }
    .spread-head h2 { font-size: 28px; }
    .spread-head .rule { margin-top: 4px; }
    .turn { bottom: 12px; }
  }
}

/* ---- On paper (.washi): words and components in the paper's inks, and the parts only paper has.
   Words: a heading (h2, h3) and the lede under it in sumi, a paragraph in sumi-soft. The
   components keep their shapes and take the paper's inks: a word button the accent on paper,
   a key the HUD's cinnabar seal (--seal, which src/panels/hud.rs puts on the page from
   data/ui/icons/seal.svg; without it, a flat block of the same ink), a switch, a field, an entry,
   a meter in gold ink. The parts of paper: a ledger (lines ruled by hairlines, the one picked
   washed in the accent with an edge of it), a stamp (words in the seal, pressed askew), a slip
   (a smaller sheet laid on a page, pinned at its top by a seal) and a portrait (a picture in an
   ink ring). Here, after the components, so a state on paper wins over the same state on
   lacquer. ---------------------------------------------------------------------------------------- */
.washi h2:where(:not(.caps)) { margin: 0; font: 600 34px/1.1 var(--face); letter-spacing: 0.005em; color: var(--sumi); }
.washi h3:where(:not(.caps)) { margin: 0; font: 600 18px/1.25 var(--face); color: var(--sumi); }
.washi .lede { margin: 2px 0 0; font: italic 400 13.5px/1.35 var(--face); color: var(--sumi-faint); }
:where(.washi) p:where(:not([class])) { font: 400 15px/1.6 var(--face); color: var(--sumi-soft); }
.washi .of { color: var(--sumi-faint); }
/* A word button on paper. */
.washi .btn { color: var(--accent-on-paper); }
.washi .btn.quiet { color: var(--sumi-faint); }
.washi .btn.danger { color: var(--vermilion-ink); }
.washi .btn.on { color: var(--sumi); }
.washi .btn.on::after { background: var(--accent-on-paper); }
.washi .btn:hover:not(:disabled) { color: var(--sumi); }
.washi .btn.danger:hover:not(:disabled) { color: var(--vermilion-ink); }
.washi .btn:focus-visible { outline-color: var(--accent-on-paper); }
.washi .btn:disabled { color: var(--sumi-faint); opacity: 0.6; }
.washi .btn .n { color: var(--sumi); }
.washi .cta:focus-visible { outline-color: var(--accent-on-paper); }
/* A key on paper: the HUD's seal, its letters washi. */
.washi kbd { display: inline-grid; place-items: center; min-width: 26px; height: 22px; padding: 0 5px; border: 0 solid transparent;
  border-radius: 0; border-image: var(--seal, linear-gradient(var(--accent-on-paper), var(--accent-on-paper))) 8 10 fill / 8px 10px round;
  background: none; font: 700 10.5px/1 var(--face); letter-spacing: 0.06em; color: var(--washi); }
/* A switch on paper: a slot of sumi wash, its diamond lit in the accent on paper when on. */
.washi input[role=switch] { background: var(--sumi-wash); box-shadow: inset 0 0 0 1px var(--sumi-line); }
.washi input[role=switch]::after { background: var(--sumi-faint); }
.washi input[role=switch]:checked { background: var(--accent-on-paper-wash); box-shadow: inset 0 0 0 1px var(--accent-on-paper); }
.washi input[role=switch]:checked::after { background: var(--accent-on-paper); }
.washi :is(input[type=range], input[role=switch]):focus-visible { outline-color: var(--accent-on-paper); }
/* A field on paper: a well of sumi wash inside a hairline; focus rings it in the accent on paper. */
.washi .field > label, .washi .field .hint, .washi .input > .lead { color: var(--sumi-faint); }
.washi .input input { color: var(--sumi); caret-color: var(--accent-on-paper); background: var(--sumi-wash);
  border-color: var(--sumi-line); box-shadow: inset 0 1px 2px var(--sumi-wash); }
.washi .input input::placeholder { color: var(--sumi-faint); }
.washi .input input:hover { border-color: var(--sumi-faint); }
.washi .input input:focus-visible { border-color: var(--accent-on-paper);
  box-shadow: inset 0 1px 2px var(--sumi-wash), 0 0 0 3px var(--accent-on-paper-ring); }
.washi .input:has(input:focus-visible) > .lead { color: var(--accent-on-paper); }
.washi .input input[aria-invalid=true] { border-color: var(--vermilion-ink); }
.washi .input input[aria-invalid=true]:focus-visible { box-shadow: inset 0 1px 2px var(--sumi-wash), 0 0 0 3px var(--vermilion-ink-wash); }
.washi .input input:-webkit-autofill { -webkit-text-fill-color: var(--sumi); caret-color: var(--accent-on-paper); }
.washi .input .reveal { color: var(--sumi-faint); }
.washi .input .reveal:hover { color: var(--sumi); background: var(--sumi-wash); }
.washi .input .reveal:focus-visible { outline-color: var(--accent-on-paper); }
.washi .input .reveal[aria-pressed=true] { color: var(--accent-on-paper); }
/* An entry, a meter. */
.washi .entry small { color: var(--sumi-faint); }
.washi .meter { background: var(--sumi-line); }
.washi .meter i { background: var(--gold-ink); }
/* A ledger (.ledger > line…): lines of a list on paper, ruled by hairlines; the line picked
   (aria-current, .on) washed in the accent on paper with an edge of it. A line is a grid its tab
   gives columns; a line that acts is a button. */
.washi .ledger { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; margin: 0; padding: 0; list-style: none;
  > * { display: grid; align-items: center; column-gap: 14px; padding: 11px 4px;
    border: 0 solid var(--sumi-line); border-top-width: 1px; }
  > :last-child { border-bottom-width: 1px; }
  > button { width: 100%; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
  > button:hover { background: var(--sumi-wash); }
  > button:focus-visible { outline: 1px solid var(--accent-on-paper); outline-offset: -1px; }
  > :is([aria-current]:not([aria-current=false]), .on) { background: linear-gradient(90deg, var(--accent-on-paper-wash), transparent 85%);
    box-shadow: inset 3px 0 0 var(--accent-on-paper); }
}
/* A stamp (.stamp): words in the cinnabar seal, pressed a little askew (a quest done, a battle won). */
.washi .stamp { display: inline-grid; place-items: center; padding: 7px 12px 6px calc(12px + 0.24em); rotate: -6deg;
  border: 0 solid transparent; border-image: var(--seal, linear-gradient(var(--accent-on-paper), var(--accent-on-paper))) 8 10 fill / 8px 10px round;
  font: 700 11px/1 var(--face); letter-spacing: 0.24em; text-transform: uppercase; white-space: nowrap; color: var(--washi); opacity: 0.92; }
/* A slip (.slip): a smaller sheet of washi laid on a page, its shadow on the page, pinned at its
   top by a small seal. Its tab places it. */
.washi .slip { position: relative; padding: 20px 24px 22px; color: var(--sumi);
  background: var(--washi-speck), var(--washi-fibre), var(--washi-cloud), var(--washi);
  box-shadow: 0 1px 0 var(--washi-shade), 0 12px 26px var(--sumi-shade), 0 2px 6px var(--sumi-shade);
  &::before { content: ""; position: absolute; top: -9px; left: 50%; width: 18px; height: 18px; translate: -50% 0; rotate: 45deg;
    background: var(--seal, var(--accent-on-paper)) center / 100% 100%; filter: drop-shadow(0 1px 1px var(--sumi-shade)); }
}
/* A portrait (.portrait > img; .small): a picture in an ink ring on its mat; the ring is sumi, gold
   when it is you (.you). Its tab may size it. */
.washi .portrait { position: relative; flex: none; display: block; width: 92px; height: 92px; overflow: hidden; border-radius: 50%;
  color: var(--sumi); background: var(--ink); box-shadow: 0 0 0 2px currentColor, 0 0 0 5px var(--washi), 0 0 0 6px var(--sumi-line);
  img { display: block; width: 100%; height: 100%; object-fit: cover; }
  &.small { width: 44px; height: 44px; box-shadow: 0 0 0 1.5px currentColor, 0 0 0 3px var(--washi), 0 0 0 4px var(--sumi-line); }
  &.you { color: var(--gold-ink); }
  /* A look not known: a shadow of a head and shoulders on the mat. */
  &.unseen { background: radial-gradient(circle at 50% 40%, var(--paper-fill) 17%, transparent 18%),
    radial-gradient(48% 30% at 50% 100%, var(--paper-fill) 97%, transparent 100%), var(--ink); }
  /* A free seat: a dashed ring, no mat. */
  &.free { background: none; box-shadow: none; border: 1.5px dashed var(--sumi-faint); opacity: 0.6; }
}
/* The kit's parts on paper (character_sheet.rs): a key's slot (.socket > img, kbd, .roman; .empty,
   .fits, .sel, .dim, .waits, .locked), a skill as a small picture (.mini), a skill's picture in an
   ensō (.enso), and a scroll hanging, large (.hanging: scroll_art::hanging). */
.washi {
  /* A slot: a well of sumi wash, its skill's picture, its key's seal over its head (a technique's
     numeral in its corner), its group's ink its lip. */
  .socket {
    position: relative; display: grid; place-items: center; width: 100%; aspect-ratio: 1; padding: 0; border: 0; border-radius: 3px;
    background: var(--sumi-wash); box-shadow: inset 0 0 0 1px var(--sumi-line), inset 0 2px 6px var(--sumi-wash); cursor: pointer;
    img { width: 68%; height: 68%; filter: drop-shadow(0 2px 2px var(--sumi-shade)); }
    &::after { content: ""; position: absolute; left: 10%; right: 10%; bottom: -1px; height: 3px; background: currentColor;
      mask: var(--brush-h) 0 0 / 100% 100% no-repeat; }
    kbd { position: absolute; top: -9px; left: 50%; translate: -50% 0; z-index: 1; }
    .roman { position: absolute; top: 5px; left: 7px; font: 700 10px/1 var(--face); letter-spacing: 0.08em; color: var(--sumi-faint); }
    &.empty { background: none; box-shadow: inset 0 0 0 1px var(--sumi-line); }
    &.empty::before { content: "+"; font: 300 22px/1 var(--face); color: var(--sumi-faint); }
    &.empty::after { display: none; }
    &:hover { box-shadow: inset 0 0 0 1px var(--accent-on-paper-ring), inset 0 2px 6px var(--sumi-wash); }
    &.fits { box-shadow: inset 0 0 0 1.5px var(--accent-on-paper), 0 0 0 4px var(--accent-on-paper-wash); }
    &.sel { background: var(--accent-on-paper-wash);
      box-shadow: inset 0 0 0 1.5px var(--accent-on-paper), 0 0 0 4px var(--accent-on-paper-wash); }
    &.sel::before { content: ""; position: absolute; top: -5px; right: -5px; width: 10px; height: 10px; rotate: 45deg;
      background: var(--accent-on-paper); box-shadow: 0 0 0 2px var(--washi); }
    &.dim { opacity: 0.35; }
    &.waits img { opacity: 0.4; }
    &.locked { cursor: default; }
    &[draggable=true] { cursor: grab; }
    &:focus-visible { outline: 1px solid var(--accent-on-paper); outline-offset: 3px; }
  }
  /* A skill as a small picture (.mini > img; .on-kit its group's diamond): the skills one knows. */
  .mini {
    position: relative; display: grid; place-items: center; width: 42px; height: 42px; padding: 0; border: 0; border-radius: 3px;
    background: var(--sumi-wash); box-shadow: inset 0 0 0 1px var(--sumi-line); cursor: pointer;
    img { width: 30px; height: 30px; }
    &.proto img { filter: grayscale(0.6); opacity: 0.75; }
    .on-kit { position: absolute; right: -3px; bottom: -3px; width: 8px; height: 8px; rotate: 45deg; background: currentColor;
      box-shadow: 0 0 0 2px var(--washi); }
    .lv { right: 2px; bottom: 2px; font-size: 8.5px; }
    &:hover { box-shadow: inset 0 0 0 1px var(--accent-on-paper-ring); }
    &.fits { box-shadow: inset 0 0 0 1.5px var(--accent-on-paper); }
    &.sel { background: var(--accent-on-paper-wash); box-shadow: inset 0 0 0 1.5px var(--accent-on-paper); }
    &.dim { opacity: 0.3; }
    &.idle { opacity: 0.45; }
    &.needs img { opacity: 0.45; }
    &[draggable=true] { cursor: grab; }
    &:focus-visible { outline: 1px solid var(--accent-on-paper); outline-offset: 2px; }
  }
  /* A skill's picture in the HUD's ensō (.enso > img.ring + img; .empty): a skill's page. */
  .enso {
    position: relative; flex: none; display: grid; place-items: center; width: 112px; height: 112px;
    .ring { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0.85; }
    img:not(.ring) { position: relative; width: 62px; height: 62px; filter: drop-shadow(0 3px 3px var(--sumi-shade)); }
    &.empty .ring { opacity: 0.3; }
  }
  /* A hanging scroll, large: its batten across the head, the picture on washi between bands of
     its rarity's ink, its rod across the foot and its cord. */
  .hanging {
    position: relative; flex: none; display: grid; justify-items: center; width: 210px; margin-top: 4px;
    .batten { position: relative; z-index: 1; width: 200px; height: 9px; background: center / auto 100% repeat-x; }
    .sheet { display: grid; place-items: center; width: 190px; height: 270px; margin: -3px 0 -4px;
      background: var(--washi-speck), var(--washi-fibre), var(--washi-cloud), var(--washi);
      box-shadow: inset 0 12px 0 -6px currentColor, inset 0 -12px 0 -6px currentColor, 0 12px 24px var(--sumi-shade), 0 1px 3px var(--sumi-shade);
      img { width: 136px; height: 136px; filter: drop-shadow(0 4px 4px var(--sumi-shade)); } }
    .rod { position: relative; z-index: 1; width: 216px; height: 16px; box-sizing: border-box; border: 0 solid transparent;
      border-width: 0 16px; border-image-slice: 0 10 fill; border-image-width: 0 16px; border-image-repeat: stretch round; }
    .cord { position: absolute; right: 8px; bottom: -30px; width: 3px; height: 40px; border-radius: 2px; background: currentColor; rotate: -12deg; }
    &.rolled { padding-top: 70px; .pic.big { width: 200px; height: 138px; } }
  }
}
/* A ring of ink holding a picture (.roundel > img): a quest, a battle. Its screen sizes it. */
.washi .roundel { display: grid; place-items: center; flex: none; width: 48px; height: 48px; border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--sumi-line);
  img { width: 62%; height: 62%; } }
/* Paper's inks for what the signals give on lacquer: a skill's group, a faint word, a switch's words. */
.washi .g-setup { color: var(--jade-ink); }
.washi .g-mobility { color: var(--azure-ink); }
.washi .g-surge { color: var(--gold-ink); }
.washi .g-weapon { color: var(--sumi); }
.washi .g-action { color: var(--sumi-soft); }
.washi .faint { color: var(--sumi-faint); }
.washi .show-all { color: var(--sumi-soft); &:hover { color: var(--sumi); } }

/* ---- Presses: everything else you click (.press, tabs, the segmented well's choices, chips, the
   close) dips under the pointer and springs back on release. A large pick sets --press to dip
   less. scale and translate, not transform, so a press never fights a hover's own transform. ----- */
:where(.press, .tabs > button, .segmented > *, .chip, .close) {
  transition: color 0.15s, background-color 0.15s, border-color 0.15s, box-shadow 0.15s, opacity 0.15s,
    scale 0.35s var(--ease-spring), translate 0.35s var(--ease-spring); }
:where(.press, .tabs > button, .segmented > *, .chip, .close):active:not(:disabled, :has(input:disabled)) {
  scale: var(--press, 0.95); transition-duration: 0.15s, 0.15s, 0.15s, 0.15s, 0.15s, 0.06s, 0.06s; }

/* ---- Still motion: no squash, sheen or burst; slow spinners; colour changes only. ---------------- */
@media (prefers-reduced-motion: reduce) {
  .cta, .cta::before { transition: filter 0.15s !important; translate: none !important; scale: none !important; }
  .cta::after, .burst { display: none; }
  .cta .spinner { animation-duration: 2s; }
  .btn:active:not(:disabled), .input .reveal:active { translate: none; scale: none; }
  :where(.press, .tabs > button, .segmented > *, .chip, .close):active { scale: none; }
  .overlay *, .overlay *::before, .overlay *::after { transition: none !important; }
  .overlay.menu, .overlay.menu *, .overlay.menu *::before, .overlay.menu *::after { animation: none !important; }
  .menu-scene .embers { display: none; }
}
