/* ============================================================
   Resonate — THE RESONANT FIELD
   The map is the entire interface, and it is paper: the tiles
   are grey and stay grey. Colour on this field means one thing,
   a mark and the domain it belongs to. The interface itself
   wears a single tone (--hue, --split) that you choose and that
   never moves on its own: one field, one ink, and one
   counter-ink reserved for other people.
   Type: Bricolage Grotesque variable + Fragment Mono.
   No panels, no buttons, no boxes: typography on a field.
   ============================================================ */

@property --hue { syntax: '<number>'; inherits: true; initial-value: 300; }
@property --split { syntax: '<number>'; inherits: true; initial-value: -225; }

:root {
  /* Role constants, solved rather than chosen. Lightness is fixed per role,
     so every hue on the wheel carries the same contrast: measured across all
     ten hues this app can be in, ink lands 12.9:1 and no text tier is under
     4.5:1. Chroma is held under the sRGB ceiling for its lightness, so no
     role has to be bent back into the gamut by the browser. */
  --L-f: 0.965; --C-f: 0.008;   /* the field: paper */
  --L-i: 0.27;  --C-i: 0.047;   /* the ink: yours. petrol's gamut ceiling; the field carries the hue */
  --L-c: 0.45;  --C-c: 0.060;   /* the counter: someone else's */

  --field-hue: calc(var(--hue) + var(--split));
  --field: oklch(var(--L-f) var(--C-f) var(--field-hue));
  --ink: oklch(var(--L-i) var(--C-i) var(--hue));
  --ink-2: color-mix(in oklch, var(--ink) 84%, var(--field));
  --ink-3: color-mix(in oklch, var(--ink) 62%, var(--field));
  /* the boundary of something you can act on: never under 3:1 */
  --edge: color-mix(in oklch, var(--ink) 47%, var(--field));
  /* a hairline between rows, and nothing that carries meaning alone */
  --ink-4: color-mix(in oklch, var(--ink) 24%, var(--field));
  /* another voice is told apart by weight as well as by hue: at the ink's own
     lightness it was 1.0:1 from yours, which is no distinction at all */
  --counter: oklch(var(--L-c) var(--C-c) calc(var(--hue) + 150));
  --scrim: color-mix(in oklab, var(--field) 75%, transparent);

  --font: "Bricolage Grotesque", system-ui, sans-serif;
  --mono: "Fragment Mono", ui-monospace, monospace;

  --e-reflex: cubic-bezier(0.3, 0.7, 0, 1);
  --e-enter: cubic-bezier(0.19, 1, 0.22, 1);
  --e-cut: cubic-bezier(0.55, 0, 1, 0.45);
  --mo-reflex: 180ms;
  --mo-enter: 460ms;

  transition:
    --hue 800ms cubic-bezier(0.32, 0, 0.16, 1),
    --split 500ms cubic-bezier(0.32, 0, 0.16, 1);
}

/* rest state: BONE × IODINE, cross-hued; dark swaps the families */
:root { --hue: 300; --split: -225; }
/* the mark role: a domain's colour must read as a colour, not as tinted ink.
   measured against the field across all eight stations, 0.46/0.15 holds
   5.4:1 to 7.0:1 in day and 0.78/0.15 holds 8.6:1 to 10.3:1 at night. */
:root { --L-m: 0.46; --C-m: 0.15; }
:root[data-theme="dark"] {
  --hue: 75; --split: 225;
  --L-m: 0.78; --C-m: 0.15;
  --L-f: 0.17; --C-f: 0.024;
  --L-i: 0.93; --C-i: 0.033;   /* 0.04 fell outside sRGB at five of the ten hues */
  --L-c: 0.75; --C-c: 0.075;
}

@supports not (color: oklch(0% 0 0)) {
  :root { --field: #F1EFE8; --ink: #3E2E57; --ink-2: #5D5372; --ink-3: #6E6484; --edge: #8E86A0; --ink-4: #C4BED0; --counter: #4E7A5E; }
  :root[data-theme="dark"] { --field: #1D1526; --ink: #EAE3D2; --ink-2: #C3C8B5; --ink-3: #A9AE9B; --edge: #8A8F7D; --ink-4: #55594D; --counter: #9FBE86; }
}

* { margin: 0; padding: 0; box-sizing: border-box; }
[hidden] { display: none !important; }

/* iOS Safari lays fixed elements out against a viewport that runs underneath
   its floating toolbar, so anything anchored to the bottom is buried. dvh is
   the visible height, and every full-screen surface is sized by it. */
:root { --app-h: 100vh; --chrome-gap: 0px; }
@supports (height: 100dvh) {
  /* what the browser's own chrome is covering: the gap between the layout
     viewport a fixed element sees and the part of it you can actually look at */
  :root { --app-h: 100dvh; --chrome-gap: calc(100vh - 100dvh); }
}

html, body {
  height: var(--app-h);
  width: 100%;
  overscroll-behavior: none;
}
/* nothing may drift sideways: the page itself never scrolls */
html { overflow: hidden; }

body {
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--field);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  position: fixed;
  inset: 0;
  height: var(--app-h);
}

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, textarea { font: inherit; color: inherit; }
a { color: inherit; }
.mono { font-family: var(--mono); }

:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* halo that lets type sit on live tiles — the only chrome allowed */
.halo, .fm, .add-confirm, .map-label {
  text-shadow:
    -1px -1px 0 var(--field), 1px -1px 0 var(--field),
    -1px 1px 0 var(--field), 1px 1px 0 var(--field),
    0 0 12px var(--field);
}

/* ---------- the field ---------- */

.app { position: fixed; inset: 0; height: var(--app-h); }

#map { position: absolute; inset: 0; background: var(--field); z-index: 0; }
.leaflet-container { font: inherit; background: var(--field); }
.leaflet-control-attribution { display: none; }

/* The map is paper and stays paper. Colour on this field means one thing only:
   a mark, and the domain it belongs to. A tinted world would compete with the
   very marks it is there to hold, so the tiles are stripped to grey and the
   invert-amplify-invert keeps linework dark while the ground stays light. */
#map .leaflet-tile-pane {
  filter: grayscale(1) invert(1) brightness(2.05) invert(1) contrast(1.02);
}
:root[data-theme="dark"] #map .leaflet-tile-pane {
  filter: grayscale(1) brightness(1.55) contrast(1.04) brightness(1.02);
}

.locate-dot { stroke: var(--ink); fill: none; }

body.dropping::after {
  content: "drop the photo. the field will place it";
  position: fixed; inset: 0; height: var(--app-h); z-index: 200;
  display: grid; place-items: center;
  background: var(--scrim);
  font-size: clamp(20px, 3vw, 34px);
  font-variation-settings: 'opsz' 96, 'wdth' 84, 'wght' 560;
  color: var(--ink);
  pointer-events: none;
}

/* ---------- corner marks ---------- */

.fm {
  position: absolute; z-index: 20;
  appearance: none;
  color: var(--ink);
  font-family: var(--font);
  /* every word over the field carries its own light, so linework can never
     take a letter from it, in sun or in shade */
  text-shadow:
    0 0 6px var(--field), 0 0 6px var(--field),
    0 0 16px var(--field), 0 0 30px var(--field);
}
.fm-nw {
  top: max(18px, env(safe-area-inset-top)); left: 22px;
  text-align: left;
  font-size: 12px; letter-spacing: 0.34em; text-transform: uppercase;
  font-variation-settings: 'wght' 600;
  padding: 8px 10px; margin: -8px -10px;
  transform: translate(0, 0);
  transition:
    font-size 1.15s var(--e-enter),
    left 1.15s var(--e-enter),
    top 1.15s var(--e-enter),
    transform 1.15s var(--e-enter),
    letter-spacing 1.15s var(--e-enter);
}
.fm-nw:hover { letter-spacing: 0.42em; }
.fm-word {
  border-bottom: max(1.5px, 0.045em) solid var(--ink-3);
  padding-bottom: 0.25em;
  transition: border-color var(--mo-reflex) var(--e-reflex);
}
.fm-nw:hover .fm-word { border-color: var(--ink); }
.fm-hint {
  display: block;
  margin-top: 9px;
  font-size: 11.5px; letter-spacing: 0.02em; text-transform: none;
  font-variation-settings: 'wght' 430;
  color: var(--ink-2);
  animation: hint-breathe 2.6s ease-in-out infinite alternate;
  transition: font-size 1.15s var(--e-enter);
}
@keyframes hint-breathe { from { opacity: 0.78; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .fm-hint { animation: none; } }
.fm-count {
  margin-left: 0.9em; font-size: 10.5px; letter-spacing: 0.1em;
  color: var(--ink-2); text-transform: none;
  transition: font-size 1.15s var(--e-enter);
}

/* the start: the name stands in the middle of the field, and wanders to
   its corner once the field is in use */
body.hero .fm-nw {
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  font-size: clamp(40px, 12.5vw, 132px);
  letter-spacing: 0.05em;
  text-align: center;
}
body.hero .fm-nw .fm-count { display: block; margin: 0.9em 0 0; font-size: 0.14em; }
body.hero .fm-nw .fm-hint { margin-top: 0.5em; font-size: 0.17em; }
@media (prefers-reduced-motion: reduce) {
  .fm-nw, .fm-count, .fm-hint { transition: none; }
}

.fm-s {
  bottom: max(16px, env(safe-area-inset-bottom)); left: 50%; transform: translateX(-50%);
  font-size: 17px;
  font-variation-settings: 'wght' 450;
  color: var(--ink-2);
  padding: 12px 22px;
  white-space: nowrap;
  max-width: 100vw;
  transition: color var(--mo-reflex) var(--e-reflex);
}
.fm-s:hover { color: var(--ink); }
.fm-s kbd { font-family: var(--mono); font-size: 11px; margin-left: 0.8em; border-bottom: 1px solid var(--ink-3); }
.fm-se {
  right: 22px; bottom: max(16px, env(safe-area-inset-bottom));
  font-size: 9.5px; letter-spacing: 0.08em; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.fm-sw { left: 22px; bottom: max(16px, env(safe-area-inset-bottom)); font-size: 8.5px; color: var(--ink-3); }
.fm-sw a { color: var(--ink-3); text-decoration: none; }
.fm-sw a:hover { color: var(--ink-2); text-decoration: underline; }

/* ---------- resonance marks ---------- */

.mark-icon { background: none; border: 0; }
/* --mk-hue arrives on the element from the place's first tag. Its lightness
   and chroma are the ink's, so every station on the wheel keeps the same
   contrast against the field. Untagged falls back to plain ink. */
.mark, .way, .way-cap, .wc-ring { --tone: oklch(var(--L-m) var(--C-m) var(--mk-hue, var(--hue))); }
.mark { color: var(--tone); width: 44px; height: 44px; }
.mark svg { overflow: visible; }
/* the whole box takes the tap, not only the ring */
.mk-hit { fill: transparent; }
/* the field's own colour behind the ring, so linework never swallows it */
.mk-halo {
  fill: none; stroke: var(--field); stroke-width: 3.6; opacity: 0.9;
  transform-origin: 22px 22px;
  animation: breathe 5200ms ease-in-out infinite;
  animation-delay: var(--seed, 0ms);
}
.mk-ring {
  fill: none; stroke: currentColor; stroke-width: 1.9;
  transform-origin: 22px 22px;
  animation: breathe 5200ms ease-in-out infinite;
  animation-delay: var(--seed, 0ms);
}
.mk-dot { fill: currentColor; }
.mark.wish .mk-ring { stroke-dasharray: 2.4 3.4; }
.mark.wish .mk-dot { fill: none; stroke: currentColor; stroke-width: 1.3; }
.mark.sel .mk-ring { stroke-width: 2.6; animation: none; transform: scale(1.26); }
.mark.sel .mk-halo { animation: none; transform: scale(1.26); }
.mark:hover .mk-ring, .mark:hover .mk-halo { animation-play-state: paused; transform: scale(1.18); transition: transform 160ms var(--e-reflex); }
/* it breathes in size only: a mark that fades is a mark you cannot find */
@keyframes breathe { 50% { transform: scale(1.1); } }

/* provenance graft: a 40° arc at the donor's signature angle, in counter-ink */
.graft {
  fill: none; stroke: var(--counter); stroke-width: 1.2;
  stroke-dasharray: 40 320;
  transform: rotate(var(--sig, 0deg));
  transform-box: fill-box; transform-origin: center;
}

/* the field acknowledges a fix: one ripple past the edge of the world */
.field-ripple {
  position: absolute; z-index: 640; pointer-events: none;
  width: 280vmax; height: 280vmax; margin: -140vmax 0 0 -140vmax;
  border-radius: 50%;
  border: 1.5px solid var(--ink);
  transform: scale(0.002); opacity: 0.9;
  animation: fripple 1600ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes fripple { to { transform: scale(1); opacity: 0; } }

/* clusters: a numeral in a thin ring */
.station-icon { background: none; border: 0; }
.station { position: relative; width: 100%; height: 100%; color: var(--ink); }
.st-ring { fill: color-mix(in srgb, var(--field) 88%, transparent); stroke: currentColor; stroke-width: 1.8; }
.station-n {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: 14px; font-variation-settings: 'wght' 640;
  font-variant-numeric: tabular-nums;
}

/* typeset labels */
.leaflet-tooltip.map-label {
  background: none; border: 0; box-shadow: none; padding: 0;
  font-family: var(--font);
  font-size: 12.5px;
  font-variation-settings: 'wght' 500;
  color: var(--ink);
}
.leaflet-tooltip.map-label.wish { font-variation-settings: 'wght' 300; }
.leaflet-tooltip.map-label::before { display: none; }

/* ---------- correspondents: the counter-ink ---------- */

.mark.corr { color: var(--counter); }
.corr-arcs {
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-dasharray: 104 76; /* two arcs, two apertures */
  transform: rotate(var(--sig, 0deg));
  transform-box: fill-box; transform-origin: center;
}
.corr-pole { fill: none; stroke: currentColor; stroke-width: 1.3; }
.mark.corr { animation: corr-breathe 7s ease-in-out infinite; animation-delay: calc(var(--sig, 0deg) / 30deg * -0.6s); }
@keyframes corr-breathe { 50% { transform: scale(1.05); } }
.leaflet-tooltip.map-label.corr-label { color: var(--counter); }

.prov { font-size: 11.5px; color: var(--ink-2); }
.prov b { font-variation-settings: 'wght' 640; color: var(--counter); }

/* ---------- add-confirm (right-click / long-press / photo) ---------- */

.add-confirm {
  position: fixed; z-index: 35;
  left: 22px; right: 22px;
  bottom: calc(var(--chrome-gap) + env(safe-area-inset-bottom) + 64px);
  display: flex; gap: 14px; align-items: baseline;
  text-align: left;
  font-size: clamp(16px, 2.2vw, 22px);
  font-variation-settings: 'opsz' 40, 'wght' 560;
  color: var(--ink);
}
.add-confirm small { font-family: var(--mono); font-size: 10px; color: var(--ink-2); }
.add-confirm em { margin-left: auto; font-style: normal; font-size: 12px; letter-spacing: 0.22em; text-transform: uppercase; border-bottom: 1.5px solid var(--ink); padding-bottom: 2px; }

/* ---------- the command line ---------- */

.cmd {
  position: fixed; inset: 0; height: var(--app-h); z-index: 50;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 0 clamp(20px, 7vw, 120px) 14vh;
  background: linear-gradient(
    180deg,
    transparent 0,
    color-mix(in srgb, var(--field) 86%, transparent) 9%,
    var(--field) 22%);
  animation: cmd-in 200ms var(--e-enter) both;
}
@keyframes cmd-in { from { opacity: 0; } }
#paletteInput {
  appearance: none; background: none; border: 0; outline: 0;
  width: 100%;
  border-bottom: 1.5px solid var(--ink);
  padding: 0.12em 0;
  color: var(--ink);
  font-size: clamp(28px, 5vw, 46px);
  font-variation-settings: 'opsz' 96, 'wdth' 86, 'wght' 340;
  caret-color: var(--ink);
}
#paletteInput::placeholder { color: var(--ink-3); }
.cmd-results { display: flex; flex-direction: column-reverse; margin-bottom: 28px; max-height: 55vh; overflow-y: auto; scrollbar-width: none; }
.cmd-section {
  font-size: 10px; letter-spacing: 0.3em; text-transform: uppercase;
  color: var(--ink-3); padding: 14px 0 4px;
}
.cmd-row {
  display: flex; align-items: baseline; gap: 18px;
  padding: 7px 0;
  text-align: left; width: 100%;
}
.cmd-row .row-name {
  font-size: clamp(17px, 2vw, 22px);
  font-variation-settings: 'opsz' 40, 'wdth' 92, 'wght' 430;
  transition: font-variation-settings 160ms var(--e-reflex);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cmd-row.hl .row-name, .cmd-row:hover .row-name { font-variation-settings: 'opsz' 40, 'wdth' 100, 'wght' 720; }
.cmd-row .row-sub {
  margin-left: auto; flex-shrink: 0;
  font-family: var(--mono); font-size: 10px;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--ink-2); white-space: nowrap;
}
.cmd-row.hl .row-sub { color: var(--ink); }
.cmd-hint { font-size: 12px; color: var(--ink-3); padding: 10px 0; }

/* ---------- the index: a summoned poster ---------- */

.index {
  position: fixed; inset: 0; height: var(--app-h); z-index: 40;
  overflow-y: auto; overscroll-behavior: contain;
  background: color-mix(in oklab, var(--field) 92%, transparent);
  /* the field stays visible behind a summoned surface, but its place names
     must not be readable through the copy: blurring the backdrop keeps the
     map present as ground and takes its letterforms out of the argument.
     where a browser cannot blur, the surface simply closes up instead. */
  backdrop-filter: blur(20px) saturate(1.05);
  -webkit-backdrop-filter: blur(20px) saturate(1.05);
  padding: clamp(20px, 5vw, 72px);
  padding-top: max(clamp(20px, 5vw, 72px), env(safe-area-inset-top));
  scrollbar-width: thin;
}
.index-head {
  position: sticky; top: 0; z-index: 2;
  padding-bottom: 18px;
  background: var(--field);
}
.index-head::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%;
  height: 26px; pointer-events: none;
  background: linear-gradient(var(--field), transparent);
}
.index-count {
  font-size: clamp(88px, 17vh, 200px);
  line-height: 0.84; letter-spacing: -0.02em;
  font-variation-settings: 'opsz' 96, 'wdth' 76, 'wght' 780;
  font-variant-numeric: tabular-nums;
}
.index-count small {
  font-size: 12px; letter-spacing: 0.34em; text-transform: uppercase;
  font-variation-settings: 'wght' 500;
  margin-left: 0.7em; vertical-align: 0.6em;
}
.index-line {
  display: flex; flex-wrap: wrap; gap: 4px 24px;
  margin-top: 12px;
  font-size: 12px; letter-spacing: 0.22em; text-transform: uppercase;
}
.index-line button {
  padding: 9px 0;
  color: var(--ink-2);
  letter-spacing: inherit; text-transform: inherit;
  transition: color var(--mo-reflex) var(--e-reflex);
}
.index-x {
  position: fixed;
  top: max(18px, env(safe-area-inset-top)); right: 22px;
  z-index: 3;
  font-size: 11px; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--ink-2);
  padding: 10px 0 10px 14px;
}
.index-x:hover { color: var(--ink); }
/* the hub: a table of contents — each surface states its role */
.index-go {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 2px 30px;
  margin-top: 16px;
}
.index-go button {
  display: flex; flex-direction: column; gap: 2px;
  text-align: left;
  padding: 8px 0 10px;
  border-bottom: 1px solid var(--ink-4);
  transition: border-color var(--mo-reflex) var(--e-reflex);
}
.index-go button:hover { border-color: var(--ink); }
.go-word {
  font-size: 13px; letter-spacing: 0.22em; text-transform: uppercase;
  font-variation-settings: 'wght' 640;
  color: var(--ink);
}
.go-sub {
  font-size: 12px; line-height: 1.35;
  color: var(--ink-2);
}

/* keys: a whisper at the very bottom, keyboards only */
.index-keys { display: none; }
@media (min-width: 761px) {
  .index-keys { display: block; margin-top: 8vh; padding-bottom: 2vh; }
  .index-keys button {
    font-family: var(--mono);
    font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--ink-3);
  }
  .index-keys button:hover { color: var(--ink); }
}

.poster-sub {
  margin-top: 10px;
  font-size: 13.5px;
  color: var(--ink-2);
  max-width: 46ch;
}
.index-line button:hover { color: var(--ink-2); }
.index-line button[aria-pressed="true"] { color: var(--ink); box-shadow: 0 2px 0 var(--ink); }
/* a chip is drawn in the colour it commands, so the vocabulary and the field
   are visibly one thing */
#filterChips button[data-tag] { --tone: oklch(var(--L-m) var(--C-m) var(--mk-hue, var(--hue))); }
#filterChips button[data-tag][aria-pressed="true"] { color: var(--tone); box-shadow: 0 2px 0 var(--tone); }
/* the tone word is written in the tone it names. it carries the push to the
   right-hand end of the line, and the theme word follows it. */
.tone-word { color: oklch(var(--L-m) var(--C-m) var(--hue)) !important; }
/* tone and theme are one pair: they take the right-hand end of the line
   together, and when the line breaks they go over together */
.line-end { margin-left: auto; display: flex; gap: 24px; }
.index-line button sup { font-family: var(--mono); font-size: 8px; letter-spacing: 0; margin-left: 3px; vertical-align: 0.5em; }
.ix-sorts button[aria-pressed="true"] { box-shadow: none; font-variation-settings: 'wght' 750; }

.index-list { margin-top: 32px; }
@media (min-width: 1024px) { .index-list { column-count: 2; column-gap: 7vw; } }
@media (min-width: 1680px) { .index-list { column-count: 3; } }

.ix {
  break-inside: avoid;
  display: block; width: 100%;
  text-align: left;
  padding: 10px 0;
  color: var(--ink);
  border-bottom: 1px solid var(--ink-4);
}
.ix-l1 { display: flex; align-items: baseline; gap: 14px; }
.ix-no { font-family: var(--mono); font-size: 10px; color: var(--ink-3); flex-shrink: 0; }
.ix-name {
  font-size: clamp(20px, 2.4vw, 30px);
  line-height: 1.08;
  font-variation-settings: 'opsz' 40, 'wdth' 92, 'wght' 450;
  transition: font-variation-settings 200ms var(--e-reflex);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ix:hover .ix-name, .ix:focus-visible .ix-name, .ix.selected .ix-name {
  font-variation-settings: 'opsz' 40, 'wdth' 100, 'wght' 720;
}
.ix.wish .ix-name { font-variation-settings: 'opsz' 40, 'wdth' 92, 'wght' 290; }
.ix.wish:hover .ix-name, .ix.wish.selected .ix-name { font-variation-settings: 'opsz' 40, 'wdth' 100, 'wght' 480; }
.ix-datum { margin-left: auto; flex-shrink: 0; font-family: var(--mono); font-size: 10px; color: var(--ink-2); }
.ix-meta {
  display: flex; gap: 14px;
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-2);
  margin-top: 3px;
}
.ix-meta .prov { font-size: 10px; letter-spacing: 0.06em; text-transform: none; }

.index.opening .ix {
  animation: rise var(--mo-enter) var(--e-enter) both;
  animation-delay: calc(min(var(--i, 0), 18) * 16ms);
}
@keyframes rise { from { opacity: 0; transform: translateY(9px); } }

.ix-empty {
  padding: 12vh 0 0;
  max-width: 30ch;
  font-size: clamp(26px, 4vw, 48px);
  line-height: 1.12;
  font-variation-settings: 'opsz' 96, 'wdth' 82, 'wght' 300;
}
.ix-empty b { font-variation-settings: 'opsz' 96, 'wdth' 82, 'wght' 680; }
.ix-empty .word-btn { display: inline; font: inherit; border-bottom: 2px solid var(--ink); }
.ix-empty p { margin-top: 3vh; font-size: 14px; font-variation-settings: 'wght' 400; color: var(--ink-2); max-width: 42ch; }

/* ---------- word buttons (actions as typography) ---------- */

.word-btn {
  font-size: 12px; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1.5px solid var(--ink-3);
  padding-bottom: 2px;
  transition: border-color var(--mo-reflex) var(--e-reflex);
}
.word-btn:hover { border-color: var(--ink); }
.word-btn.quiet { color: var(--ink-2); border-color: var(--edge); }
.word-btn.quiet:hover { color: var(--ink); }

/* ---------- the plate ---------- */

.plate {
  position: fixed; top: 0; right: 0; z-index: 30;
  height: var(--app-h);
  width: min(460px, 92vw);
  overflow-y: auto; overscroll-behavior: contain;
  padding: clamp(24px, 4vh, 56px) clamp(20px, 2.5vw, 44px) 48px 120px;
  background: linear-gradient(90deg, transparent, color-mix(in oklab, var(--field) 96%, transparent) 120px);
  scrollbar-width: none;
  animation: plate-in 300ms var(--e-enter) both;
}
@keyframes plate-in { from { opacity: 0; transform: translateX(24px); } }
/* on a phone the plate is a bottom sheet: it rises, it does not sidle */
@keyframes plate-up { from { opacity: 0; transform: translateY(28px); } }
.plate-eyebrow {
  display: flex; justify-content: space-between; gap: 10px;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em;
  color: var(--ink-2);
}
.plate-eyebrow button { font: inherit; color: inherit; letter-spacing: inherit; }
.plate-eyebrow button:hover { color: var(--ink); }
.plate-name {
  margin-top: 12px;
  font-size: clamp(34px, 3.6vw, 52px);
  line-height: 0.98; letter-spacing: -0.01em;
  font-variation-settings: 'opsz' 96, 'wdth' 84, 'wght' 640;
  outline: 0;
  overflow-wrap: anywhere;
}
.plate-name:focus { box-shadow: 0 2px 0 var(--ink); }
.plate-sub { margin-top: 8px; font-size: 12.5px; color: var(--ink-2); }
.plate-prov { margin-top: 6px; }

.plate-words {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin-top: 20px;
  font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase;
}
.plate-words button { color: var(--ink-3); letter-spacing: inherit; text-transform: inherit; padding: 3px 0; }
.plate-words button:hover { color: var(--ink-2); }
.plate-words button[aria-pressed="true"] { color: var(--ink); box-shadow: 0 2px 0 var(--ink); }

.stars-line { display: flex; gap: 4px; margin-top: 18px; }
.stars-line button { font-size: 17px; line-height: 1; color: var(--ink-3); padding: 3px 2px; transition: color var(--mo-reflex); }
.stars-line button.on { color: var(--ink); }
.stars-line button:hover { color: var(--ink-2); }

.plate-sec { margin-top: 30px; }
.plate-sec-head {
  display: flex; align-items: baseline; justify-content: space-between;
  font-size: 10px; letter-spacing: 0.3em; text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 8px;
}
.plate-sec-head .dictate { font-family: var(--mono); font-size: 9px; letter-spacing: 0.12em; color: var(--ink-2); border-bottom: 1px solid var(--edge); }
.plate-sec-head .dictate:hover { color: var(--ink); border-color: var(--ink-2); }
.plate-sec-head .dictate.listening { color: var(--counter); border-color: var(--counter); animation: listen 1.2s ease-in-out infinite; }
@keyframes listen { 50% { opacity: 0.45; } }

.note-input {
  width: 100%;
  background: none; border: 0; outline: 0; resize: vertical;
  min-height: 70px;
  font-family: var(--font);
  font-size: 15px; line-height: 1.6;
  color: var(--ink);
  border-left: 1.5px solid var(--edge);
  padding-left: 14px;
}
.note-input:focus { border-left-color: var(--ink); }
.note-input::placeholder { color: var(--ink-3); }

.text-input {
  width: 100%;
  background: none; border: 0; outline: 0;
  border-bottom: 1px solid var(--edge);
  padding: 5px 0 7px;
  font-size: 13.5px;
}
.text-input:focus { border-bottom-color: var(--ink); }
.text-input::placeholder { color: var(--ink-3); }

.photo-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.fig { position: relative; }
.fig img {
  width: 100%; display: block; aspect-ratio: 4 / 3; object-fit: cover;
  filter: grayscale(1) sepia(0.35) hue-rotate(calc((var(--field-hue) - 40) * 1deg)) contrast(0.95);
  transition: filter 300ms var(--e-reflex);
}
.fig:hover img { filter: none; }
.fig .ph-x {
  position: absolute; top: 6px; right: 6px;
  font-family: var(--mono); font-size: 10px;
  color: var(--field); background: var(--ink);
  padding: 2px 7px;
  opacity: 0; transition: opacity var(--mo-reflex);
}
.fig:hover .ph-x { opacity: 1; }
.photo-add {
  aspect-ratio: 4 / 3;
  border: 1px dashed var(--ink-3);
  display: grid; place-items: center;
  font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-3);
  transition: color var(--mo-reflex), border-color var(--mo-reflex);
}
.photo-add:hover { color: var(--ink); border-color: var(--ink); }

.plate-acts { display: flex; flex-wrap: wrap; gap: 12px 22px; margin-top: 34px; }
.plate-foot { margin-top: 26px; font-family: var(--mono); font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); }

/* ---------- posters (census · kept · voices · keys) ---------- */

.poster {
  position: fixed; inset: 0; height: var(--app-h); z-index: 55;
  overflow-y: auto; overscroll-behavior: contain;
  background: color-mix(in oklab, var(--field) 92%, transparent);
  /* the field stays visible behind a summoned surface, but its place names
     must not be readable through the copy: blurring the backdrop keeps the
     map present as ground and takes its letterforms out of the argument.
     where a browser cannot blur, the surface simply closes up instead. */
  backdrop-filter: blur(20px) saturate(1.05);
  -webkit-backdrop-filter: blur(20px) saturate(1.05);
  padding: clamp(20px, 5vw, 72px);
  padding-top: max(clamp(20px, 5vw, 72px), env(safe-area-inset-top));
  scrollbar-width: thin;
}
.poster-x { padding: 12px 0 12px 16px; }
.poster-head { display: flex; align-items: baseline; justify-content: space-between; }
.poster-word {
  font-size: clamp(64px, 12vh, 150px);
  line-height: 0.9; letter-spacing: -0.02em;
  font-variation-settings: 'opsz' 96, 'wdth' 76, 'wght' 780;
  text-transform: lowercase;
}
.poster-x { font-size: 11px; letter-spacing: 0.28em; text-transform: uppercase; color: var(--ink-2); }
.poster-x:hover { color: var(--ink); }
.poster-body { margin-top: 5vh; max-width: 760px; }

.stat-opening { font-size: clamp(20px, 2.6vw, 30px); line-height: 1.3; font-variation-settings: 'opsz' 96, 'wdth' 86, 'wght' 340; margin-bottom: 4vh; max-width: 26ch; }
.stat-opening em { font-style: normal; font-variation-settings: 'opsz' 96, 'wdth' 86, 'wght' 700; }
.stat-band { display: flex; gap: 7vw; margin-bottom: 5vh; }
.stat-cell .stat-num { font-size: clamp(40px, 7vh, 84px); line-height: 1; font-variation-settings: 'wdth' 78, 'wght' 740; font-variant-numeric: tabular-nums; }
.stat-cell .stat-lbl { font-size: 10px; letter-spacing: 0.3em; text-transform: uppercase; color: var(--ink-2); margin-top: 6px; }

.sec-head { font-size: 10px; letter-spacing: 0.3em; text-transform: uppercase; color: var(--ink-3); margin: 4vh 0 10px; }
.tally { display: flex; align-items: baseline; gap: 14px; padding: 6px 0; border-bottom: 1px solid var(--ink-4); }
.tally .name { font-size: 17px; font-variation-settings: 'wght' 460; }
.tally .n { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.country-cols { columns: 2; column-gap: 6vw; }
.country-cols .tally { break-inside: avoid; }

/* kept (settings) */
.set-sec { margin-bottom: 5vh; }
.set-row { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; padding: 8px 0; flex-wrap: wrap; }
.set-row-label { font-size: 17px; font-variation-settings: 'wght' 460; }
.set-row-sub { font-size: 12px; color: var(--ink-2); margin-top: 2px; max-width: 44ch; }
.word-row { display: flex; flex-wrap: wrap; gap: 8px 20px; }

.hue-stations { display: flex; flex-wrap: wrap; gap: 6px 16px; }
.hue-stations button {
  font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-3); padding: 3px 0;
}
.hue-stations button:hover { color: var(--ink-2); }
.hue-stations button[aria-pressed="true"] { color: var(--ink); box-shadow: 0 2px 0 var(--ink); }

.tag-rows .tally .word-btn { font-size: 10px; opacity: 0; transition: opacity var(--mo-reflex); }
.tag-rows .tally:hover .word-btn, .tag-rows .tally:focus-within .word-btn { opacity: 1; }
.tag-add { display: flex; flex-direction: column; gap: 16px; align-items: flex-start; margin-top: 4vh; }
.tag-add .text-input { max-width: 280px; font-size: 16px; }

/* voices (correspondence) */
.corr-row { padding: 3vh 0; border-bottom: 1px solid var(--ink-4); }
.corr-row-head { display: flex; align-items: baseline; gap: 20px; flex-wrap: wrap; }
.corr-glyph { color: var(--counter); flex-shrink: 0; align-self: center; }
.corr-name {
  font-size: clamp(30px, 4vw, 48px); line-height: 1;
  font-variation-settings: 'opsz' 96, 'wdth' 82, 'wght' 640;
  outline: 0;
}
.corr-name:focus { box-shadow: 0 2px 0 var(--ink); }
.corr-meta { font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-2); margin-top: 8px; }
.corr-ev { margin-top: 10px; font-size: 14px; color: var(--ink-2); max-width: 60ch; }
.corr-ev b { color: var(--ink); font-variation-settings: 'wght' 650; }
.corr-ev i { font-style: normal; font-variation-settings: 'wght' 600; color: var(--ink); }
.corr-ctl { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-top: 14px; align-items: baseline; }
.corr-empty { max-width: 34ch; }
.corr-empty .ce-law { font-size: clamp(28px, 4.6vw, 54px); line-height: 1.05; font-variation-settings: 'opsz' 96, 'wdth' 80, 'wght' 620; }
.corr-empty .ce-how { margin: 3vh 0; font-size: 15px; color: var(--ink-2); max-width: 46ch; }

/* keys */
.keys-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 10px 5vw; }
.key-row { display: flex; align-items: baseline; gap: 16px; padding: 7px 0; border-bottom: 1px solid var(--ink-4); }
.key-row kbd { font-family: var(--mono); font-size: 11px; min-width: 3ch; }
.key-row span { font-size: 13px; color: var(--ink-2); }

/* ---------- the resonance report ---------- */

.report {
  position: fixed; inset: 0; height: var(--app-h); z-index: 60;
  overflow-y: auto; overscroll-behavior: contain;
  background: color-mix(in oklab, var(--field) 92%, transparent);
  /* the field stays visible behind a summoned surface, but its place names
     must not be readable through the copy: blurring the backdrop keeps the
     map present as ground and takes its letterforms out of the argument.
     where a browser cannot blur, the surface simply closes up instead. */
  backdrop-filter: blur(20px) saturate(1.05);
  -webkit-backdrop-filter: blur(20px) saturate(1.05);
  padding: clamp(20px, 6vw, 90px);
}
.rp-eyebrow { font-size: 10px; letter-spacing: 0.34em; text-transform: uppercase; color: var(--ink-3); }
.rp-name {
  font-size: clamp(56px, 14vw, 190px);
  line-height: 0.88; letter-spacing: -0.02em;
  font-variation-settings: 'opsz' 96, 'wdth' 76, 'wght' var(--rp-w, 300);
  transition: font-variation-settings 1100ms var(--e-enter);
  overflow-wrap: anywhere;
}
.rp-verdict { margin-top: 4vh; font-size: clamp(24px, 3.4vw, 40px); font-variation-settings: 'opsz' 96, 'wdth' 86, 'wght' 680; }
.rp-verdict .rp-sub { display: block; font-size: 14px; font-variation-settings: 'wght' 380; color: var(--ink-2); margin-top: 6px; }
.rp-evidence { list-style: none; margin-top: 3vh; max-width: 56ch; }
.rp-evidence li { padding: 8px 0; border-bottom: 1px solid var(--ink-4); font-size: 15px; color: var(--ink-2); }
.rp-evidence b { color: var(--ink); font-variation-settings: 'wght' 680; font-variant-numeric: tabular-nums; }
.rp-evidence i { font-style: normal; color: var(--ink); font-variation-settings: 'wght' 600; }
.rp-case { margin-top: 6vh; }
.rp-case .sec-head { margin-top: 0; }
.rp-pick { display: flex; align-items: baseline; gap: 16px; width: 100%; text-align: left; padding: 9px 0; border-bottom: 1px solid var(--ink-4); }
.rp-pick .no { font-family: var(--mono); font-size: 10px; color: var(--ink-3); }
.rp-pick .nm { font-size: clamp(18px, 2.2vw, 26px); font-variation-settings: 'opsz' 40, 'wdth' 92, 'wght' 460; transition: font-variation-settings 180ms var(--e-reflex); }
.rp-pick:hover .nm { font-variation-settings: 'opsz' 40, 'wdth' 100, 'wght' 700; }
.rp-pick .why { margin-left: auto; flex-shrink: 0; font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-2); }
.rp-pick .adopt { flex-shrink: 0; font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--counter); border-bottom: 1px solid var(--counter); }
.rp-foot { display: flex; flex-wrap: wrap; gap: 14px 30px; margin-top: 7vh; }

/* ---------- the folio composer ---------- */

.fol-field { margin-bottom: 3vh; }
.fol-title {
  width: 100%;
  background: none; border: 0; outline: 0;
  border-bottom: 1.5px solid var(--ink);
  padding: 0.1em 0;
  font-size: clamp(26px, 4vw, 44px);
  font-variation-settings: 'opsz' 96, 'wdth' 84, 'wght' 620;
  color: var(--ink);
}
.fol-title::placeholder, .fol-ded::placeholder { color: var(--ink-3); }
.fol-ded {
  width: 100%;
  background: none; border: 0; outline: 0;
  border-bottom: 1px solid var(--ink-4);
  padding: 8px 0;
  font-size: 15px;
  color: var(--ink-2);
}
.fol-ded:focus { border-bottom-color: var(--ink); }
.fol-count { font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); margin: 3vh 0 8px; }
.fol-row {
  display: flex; align-items: baseline; gap: 16px;
  width: 100%; text-align: left;
  padding: 8px 0;
  border-bottom: 1px solid var(--ink-4);
  transition: opacity var(--mo-reflex);
}
.fol-row .nm { font-size: clamp(17px, 2vw, 24px); font-variation-settings: 'opsz' 40, 'wdth' 92, 'wght' 460; }
.fol-row .sub { margin-left: auto; flex-shrink: 0; font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-2); }
.fol-row .in { flex-shrink: 0; font-size: 10px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink); }
.fol-row[aria-pressed="false"] { opacity: 0.32; }
.fol-row[aria-pressed="false"] .in { color: var(--ink-3); }
.fol-acts { display: flex; flex-wrap: wrap; gap: 14px 30px; margin-top: 5vh; }

/* folio & ask reports ride the .report styles; held rows are quiet */
.rp-pick .held { flex-shrink: 0; font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }
.rp-ded { margin-top: 2vh; font-size: clamp(17px, 2.2vw, 24px); font-variation-settings: 'opsz' 96, 'wdth' 88, 'wght' 340; color: var(--ink-2); max-width: 40ch; }

/* voices section rows in the command line */
.cmd-row .row-name .after { color: var(--counter); }

/* the newsstand */
.news-search {
  width: 100%;
  background: none; border: 0; outline: 0;
  border-bottom: 1.5px solid var(--ink);
  padding: 0.1em 0;
  font-size: clamp(24px, 3.6vw, 40px);
  font-variation-settings: 'opsz' 96, 'wdth' 86, 'wght' 340;
  color: var(--ink);
  margin-bottom: 4vh;
}
.news-search::placeholder { color: var(--ink-3); }
.news-row {
  display: block; width: 100%; text-align: left;
  padding: 14px 0;
  border-bottom: 1px solid var(--ink-4);
}
.news-row .t1 { display: flex; align-items: baseline; gap: 16px; }
.news-row .nm {
  font-size: clamp(20px, 2.6vw, 32px);
  font-variation-settings: 'opsz' 40, 'wdth' 90, 'wght' 480;
  transition: font-variation-settings 180ms var(--e-reflex);
}
.news-row:hover .nm { font-variation-settings: 'opsz' 40, 'wdth' 100, 'wght' 720; }
.news-row .by { margin-left: auto; flex-shrink: 0; font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-2); }
.news-row .t2 { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 3px; font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); }
.news-row .why { color: var(--counter); }
.news-note { font-size: 12.5px; color: var(--ink-3); margin-top: 4vh; max-width: 52ch; }

/* ---------- toast ---------- */

.toast {
  position: fixed; bottom: calc(var(--chrome-gap) + 60px); left: 50%; transform: translateX(-50%);
  z-index: 1200;
  font-size: 10.5px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink);
  background: var(--field);
  padding: 8px 18px;
  box-shadow: 0 0 0 1px var(--ink-4), 0 8px 30px color-mix(in srgb, var(--ink) 12%, transparent);
  animation: cmd-in 140ms linear both;
  pointer-events: none;
  max-width: min(calc(100vw - 40px), 64ch);
  text-align: center;
  text-wrap: balance;
}

/* ---------- boot ---------- */

.boot #map, .boot .fm { animation: field-in 500ms var(--e-enter) both; }
@keyframes field-in { from { opacity: 0; } }

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .index, .poster, .report { background: var(--field); }
}

/* ---------- mobile ---------- */

@media (max-width: 760px) {
  .fm-nw { left: 16px; font-size: 13px; }
  .fm-s { font-size: 16px; }
  .fm-se { display: none; }
  .fm-sw { left: 16px; bottom: max(12px, env(safe-area-inset-bottom)); }
  .word-btn { font-size: 13px; padding: 10px 0 4px; }
  .index-line { font-size: 13px; }
  .index-head { position: static; background: none; } /* the list must not fight a tall sticky header */
  .index-go { grid-template-columns: 1fr 1fr; gap: 2px 18px; }
  .go-sub { font-size: 11.5px; }
  .ix-meta { font-size: 11px; }
  .cmd-row .row-sub { font-size: 11px; }
  .plate-eyebrow { font-size: 11px; }
  .stars-line button { font-size: 20px; padding: 6px 4px; }

  .plate {
    top: auto; bottom: 0; left: 0; right: 0; width: 100%;
    height: min(66vh, calc(var(--app-h) - 96px));
    animation-name: plate-up;
    padding: 84px 20px 40px;
    background: linear-gradient(0deg, var(--field) calc(100% - 90px), transparent);
  }
  .plate::before {
    content: ""; position: absolute; top: 64px; left: 50%;
    width: 48px; margin-left: -24px;
    border-top: 1.5px solid var(--ink-3);
  }
  .plate-name { font-size: 30px; }
  .index {
    padding: 18px;
    padding-top: max(18px, env(safe-area-inset-top));
    padding-bottom: max(18px, env(safe-area-inset-bottom));
  }
  .index-count { font-size: 84px; }
  .index-list { column-count: 1; }
  .ix-name { font-size: 21px; }
  .cmd {
    padding: 0 20px 12px;
    background: linear-gradient(
      180deg,
      transparent 0,
      color-mix(in srgb, var(--field) 88%, transparent) 5%,
      var(--field) 14%);
  }
  .cmd-results { max-height: 46vh; }
  #paletteInput { font-size: 24px; }
  .country-cols { columns: 1; }
  .stat-band { flex-wrap: wrap; gap: 24px; }
}

/* ---------- reduced motion: the still tier ---------- */

@media (prefers-reduced-motion: reduce) {
  :root { transition: none; }
  .mk-ring, .mk-halo, .mark.corr { animation: none !important; }
  .field-ripple { display: none; }
  .mark.sel .mk-ring { transform: scale(1.28); }
  .index.opening .ix { animation: ix-still 120ms linear both; animation-delay: 0ms; }
  @keyframes ix-still { from { opacity: 0; } }
  .rp-name { transition: none; }
  .cmd, .plate, .poster, .report { animation-duration: 100ms; animation-name: cmd-in; }
  .ix-name, .cmd-row .row-name, .rp-pick .nm, .fm-nw { transition: none; }
  .plate-sec-head .dictate.listening { animation: none; }
}

.how-body p { max-width: 58ch; font-size: 15px; line-height: 1.6; color: var(--ink); margin-bottom: 14px; }

.theme-word { color: var(--ink-2) !important; }
.theme-word:hover { color: var(--ink) !important; }
.edit-tags { color: var(--ink-3); font-size: 11px; letter-spacing: 0.22em; text-transform: uppercase; padding: 9px 0; }
.edit-tags:hover { color: var(--ink); }

.name-ask {
  position: fixed; inset: 0; height: var(--app-h); z-index: 90;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 0 clamp(20px, 7vw, 120px) 18vh;
  background: linear-gradient(180deg, transparent, var(--field) 70%);
}
.name-ask label {
  font-size: clamp(20px, 3vw, 30px);
  font-variation-settings: 'opsz' 96, 'wdth' 86, 'wght' 340;
  color: var(--ink-2);
  margin-bottom: 12px;
}
.name-ask input {
  appearance: none; background: none; border: 0; outline: 0;
  width: 100%;
  border-bottom: 1.5px solid var(--ink);
  padding: 0.12em 0;
  color: var(--ink);
  font-size: clamp(30px, 5vw, 48px);
  font-variation-settings: 'opsz' 96, 'wdth' 84, 'wght' 560;
}
.name-ask .word-row { margin-top: 24px; }

/* the name draws the eye by underlining itself, never by fading: at four
   tenths opacity the one thing a newcomer must notice looked disabled */
body.greet .fm-word { animation: word-pulse 1.8s ease-in-out 3; }
@keyframes word-pulse { 50% { border-bottom-color: var(--ink); } }
@media (prefers-reduced-motion: reduce) { body.greet .fm-word { animation: none; } }

/* ---------- the first evening ---------- */
#intro {
  position: fixed; inset: 0; height: var(--app-h); z-index: 2000;
  background: #17100d;
  cursor: pointer;
}
#intro video, #intro canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
#intro video {
  display: none;
  filter: saturate(0.92) contrast(1.05) brightness(0.94);
  /* the shot is square: on a portrait screen, hold the left of frame,
     where the face at the end of the take is */
  object-position: 32% center;
}
#intro.has-video video { display: block; }
#intro.has-video canvas { display: none; }
.intro-grain {
  position: absolute; inset: 0;
  background: var(--grain, none);
  background-size: 128px;
  opacity: 0.07;
  pointer-events: none;
}
/* the name fills the screen: textLength holds it to the width at any size.
   wide screens take it in one line, narrow ones break it in two. */
#intro.dissolve { animation: intro-out 1.4s ease forwards; pointer-events: none; }
#intro.brief.dissolve { animation-duration: 0.6s; }
@keyframes intro-out { to { opacity: 0; } }
body.entering #map { animation: field-enter 2.2s var(--e-enter) both; }
@keyframes field-enter { from { transform: scale(1.045); opacity: 0.6; } }

/* two-intent teaching lines in the command line */
.cmd-teach { padding: 8px 0; font-size: 13.5px; color: var(--ink-2); }
.cmd-teach b { color: var(--ink); font-variation-settings: 'wght' 650; }

.mark.proposed { opacity: 0.85; }
.mark.proposed .mk-ring { animation: breathe 2600ms ease-in-out infinite; }

/* ---------- the sheet: the atlas typeset for paper, or pdf ---------- */
#sheet { display: none; }

@media print {
  body > *:not(#sheet) { display: none !important; }
  /* the screen pins the body to one visible viewport so iOS cannot drift it.
     paper has no viewport: unpin it, or the atlas prints as a single page. */
  html, body {
    background: #fff !important;
    position: static !important;
    overflow: visible !important;
    height: auto !important;
    width: auto !important;
  }
  #sheet { position: static; height: auto; }
  @page { margin: 16mm 18mm 20mm; }

  #sheet {
    display: block;
    color: #000;
    background: #fff;
    font-family: 'Bricolage Grotesque', system-ui, sans-serif;
  }
  #sheet .mono { font-family: 'Fragment Mono', ui-monospace, monospace; }

  .sh-head { padding-bottom: 5mm; border-bottom: 0.6pt solid #000; margin-bottom: 6mm; }
  .sh-mast { font-size: 8.5pt; letter-spacing: 0.34em; text-transform: uppercase; }
  .sh-title {
    margin: 4mm 0 0;
    font-size: 30pt; line-height: 1.04;
    font-variation-settings: 'opsz' 96, 'wdth' 84, 'wght' 640;
    letter-spacing: -0.015em;
  }
  .sh-ded { margin: 2.5mm 0 0; font-style: italic; font-size: 11.5pt; }
  .sh-signed { margin: 3mm 0 0; font-size: 8pt; letter-spacing: 0.06em; }

  .sh-city {
    margin: 8mm 0 3mm; padding-top: 2.5mm;
    font-size: 8.5pt; letter-spacing: 0.22em; text-transform: uppercase;
    border-top: 0.6pt solid #000;
    break-after: avoid;
  }
  .sh-head + .sh-city { border-top: 0; padding-top: 0; margin-top: 0; }
  .sh-entry { break-inside: avoid; margin: 0 0 5mm; }
  .sh-line { display: flex; align-items: baseline; gap: 3mm; }
  .sh-no { font-size: 7.5pt; }
  .sh-name { margin: 0; font-size: 13pt; font-variation-settings: 'opsz' 40, 'wght' 560; }
  .sh-meta { margin-top: 0.8mm; font-size: 9.5pt; font-style: italic; }
  .sh-note { margin: 1.2mm 0 0; font-size: 10pt; line-height: 1.45; max-width: 150mm; }
  .sh-coords { margin-top: 1mm; font-size: 7.5pt; }

  .sh-colophon {
    margin-top: 10mm; padding-top: 2.5mm;
    border-top: 0.6pt solid #000;
    font-size: 7.5pt; letter-spacing: 0.12em;
  }
}

/* ---------- the threshold: plain words, then a choice ---------- */
.intro-skip {
  position: absolute; z-index: 3;
  right: max(18px, env(safe-area-inset-right));
  bottom: max(20px, env(safe-area-inset-bottom));
  padding: 10px 18px;
  font-size: 12px; letter-spacing: 0.22em; text-transform: uppercase;
  font-variation-settings: 'wght' 500;
  color: rgba(247, 242, 232, 0.92);
  border: 1px solid rgba(247, 242, 232, 0.38);
  border-radius: 999px;
  background: rgba(10, 7, 5, 0.34);
  transition: border-color 200ms var(--e-reflex), background 200ms var(--e-reflex);
}
.intro-skip:hover { border-color: rgba(247, 242, 232, 0.8); background: rgba(10, 7, 5, 0.55); }

.threshold {
  position: fixed; inset: 0; height: var(--app-h); z-index: 2400;
  display: flex; flex-direction: column; justify-content: center;
  overflow-y: auto; overscroll-behavior: contain;
  gap: 14px;
  padding: max(28px, env(safe-area-inset-top)) clamp(24px, 7vw, 108px) max(28px, env(safe-area-inset-bottom));
  background: var(--field);
  animation: threshold-in 700ms var(--e-enter) both;
}
@keyframes threshold-in { from { opacity: 0; } }
.th-what {
  font-size: clamp(30px, 6.4vw, 68px);
  line-height: 1.02;
  letter-spacing: -0.02em;
  font-variation-settings: 'opsz' 96, 'wdth' 88, 'wght' 620;
  max-width: 17ch;
}
.th-plain { font-size: clamp(16px, 2.1vw, 21px); max-width: 42ch; color: var(--ink); }
.th-quiet { font-size: clamp(14px, 1.7vw, 17px); max-width: 42ch; color: var(--ink-2); }
.th-go { display: flex; flex-wrap: wrap; gap: 10px 26px; margin-top: 18px; }
.th-go .word-btn { font-size: clamp(15px, 1.9vw, 19px); }
.th-how {
  margin-top: 10px; align-self: start;
  font-size: 13px; color: var(--ink-2);
  border-bottom: 1px solid var(--ink-3); padding-bottom: 2px;
}
.th-how:hover { color: var(--ink); border-color: var(--ink); }

/* a sample place says so until you make it yours */
.ix-sample, .p-sample {
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-3); border: 1px solid var(--ink-4); border-radius: 2px;
  padding: 1px 5px; margin-left: 8px; white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) { .threshold { animation: none; } }

/* ---------- handing over ---------- */
.sh-what { margin-bottom: 20px; }
.sh-list { list-style: none; margin: 0 0 16px; }
.sh-list li { font-size: 15px; padding: 3px 0 3px 16px; position: relative; color: var(--ink-2); }
.sh-list li::before { content: ''; position: absolute; left: 2px; top: 12px; width: 6px; height: 1px; background: var(--ink-3); }
.sh-list b { color: var(--ink); font-variation-settings: 'wght' 620; }
.sh-warn { font-size: 14.5px; color: var(--ink); margin: 14px 0 8px; max-width: 46ch; }
.sh-size { font-size: 11px; color: var(--ink-2); letter-spacing: 0.04em; }
.beta-mark {
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.16em; text-transform: uppercase;
  border: 1px solid var(--ink-3); border-radius: 2px; padding: 1px 5px; margin-left: 8px;
  color: var(--ink-2);
}

/* ---------- ways: the line through the field ---------- */

/* the casing carries the field's own colour so no linework can break the way */
.way-casing { stroke: var(--field); fill: none; opacity: 0.92; }
.way {
  stroke: var(--tone); fill: none;
  transition: stroke-width 220ms var(--e-reflex);
}
.way.wish { stroke-dasharray: 1 7; stroke-linecap: round; }
.way.sel { stroke: var(--tone); }
.way:hover { cursor: pointer; }
/* a selected way is drawn on, from its beginning */
.way.sel { stroke-dasharray: 4000; animation: way-draw 1400ms var(--e-enter) forwards; }
@keyframes way-draw { from { stroke-dashoffset: 4000; } to { stroke-dashoffset: 0; } }
.way.sel.wish { animation: none; stroke-dasharray: 1 7; }

.way-cap-icon { background: none; border: 0; }
.way-cap { color: var(--tone); }
.wc-halo { fill: var(--field); stroke: var(--field); stroke-width: 3.4; }
.wc-ring { fill: var(--field); stroke: currentColor; stroke-width: 1.8; }
.way-cap.end .wc-ring { fill: currentColor; }

.way-cursor-icon { background: none; border: 0; }
.way-cursor { color: var(--ink); }
.wcur-halo { fill: none; stroke: var(--field); stroke-width: 4; }
.wcur-ring { fill: none; stroke: currentColor; stroke-width: 2; }
.wcur-dot { fill: currentColor; }

/* the measure: what the way asks of you, set as a table of figures */
.way-measure {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(88px, 1fr));
  gap: 14px 18px;
  margin: 22px 0 8px;
  padding: 16px 0;
  border-top: 1px solid var(--ink-4);
  border-bottom: 1px solid var(--ink-4);
}
.way-measure dt {
  font-size: 8.5px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-2); margin-bottom: 5px;
}
.way-measure dd {
  font-family: var(--font);
  font-size: 20px; font-variation-settings: 'opsz' 40, 'wght' 560;
  font-variant-numeric: tabular-nums;
}

/* the ground, drawn as a section: a ridge over hatching that thickens with
   the steepness, so a wall reads as a wall */
.pf-wrap {
  position: relative;
  margin-top: 10px;
  height: 132px;
  cursor: crosshair;
  touch-action: none;
}
.pf { display: block; width: 100%; height: 100%; overflow: visible; }
.pf-hatch {
  stroke: var(--ink);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  opacity: calc(0.1 + var(--g, 0) * 0.5);
}
.pf-ridge {
  fill: none; stroke: var(--ink); stroke-width: 1.6;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: round;
}
.pf-high { fill: var(--field); stroke: var(--ink); stroke-width: 1.4; vector-effect: non-scaling-stroke; }
.pf-rule { stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; opacity: 0.75; }
.pf-read { font-size: 10px; color: var(--ink); font-variant-numeric: tabular-nums; }
.pf-axis {
  display: flex; justify-content: space-between;
  margin-top: 6px;
  font-size: 9px; letter-spacing: 0.12em; color: var(--ink-2);
}

/* a way in the index */
.ix-band {
  margin: 26px 0 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--ink-4);
  font-size: 9px; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--ink-2);
  break-inside: avoid;
}
.ix.way .ix-no { letter-spacing: 0; }
.ix-ways {
  display: block; margin-top: 4px;
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-2);
}

@media (prefers-reduced-motion: reduce) {
  .way.sel { animation: none; stroke-dasharray: none; }
}

/* the section prints as ground, in ink */
@media print {
  .sh-profile { break-inside: avoid; margin: 2mm 0 3mm; }
  .sh-profile svg { width: 100%; height: 26mm; display: block; }
  .sh-profile .pf-hatch { stroke: #000; opacity: calc(0.12 + var(--g, 0) * 0.45); }
  .sh-profile .pf-ridge { stroke: #000; stroke-width: 0.7; fill: none; }
  .sh-profile .pf-high { fill: #fff; stroke: #000; stroke-width: 0.6; }
  .sh-measure { font-size: 9pt; margin-top: 1mm; }
}

/* ---------- the shelf ---------- */
.fol-shelf-row {
  display: flex; flex-direction: column; gap: 3px;
  width: 100%; text-align: left;
  padding: 16px 0;
  border-bottom: 1px solid var(--ink-4);
}
.fol-shelf-row:hover .fs-title { font-variation-settings: 'opsz' 40, 'wdth' 100, 'wght' 700; }
.fs-title {
  font-size: 22px;
  font-variation-settings: 'opsz' 40, 'wdth' 92, 'wght' 560;
  transition: font-variation-settings 160ms var(--e-reflex);
}
.fs-meta { font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); }
.fs-names { font-size: 13px; color: var(--ink-2); }
.fs-ded { font-size: 13px; font-style: italic; color: var(--ink-2); }
.fol-back {
  font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-2); padding: 2px 0 14px;
}
.fol-back:hover { color: var(--ink); }

/* ---------- visiting ---------- */
.visit-bar {
  position: fixed; z-index: 1100;
  top: max(14px, env(safe-area-inset-top)); left: 50%; transform: translateX(-50%);
  display: flex; align-items: baseline; gap: 16px;
  padding: 8px 16px;
  background: var(--field);
  box-shadow: 0 0 0 1px var(--edge);
}
.visit-bar .mono { font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--counter); }


/* ---------- the mark on the film ---------- */
/* It sits where the hero wordmark sits, at the same size and letterspacing, so
   the dissolve turns the evening into a field beneath a word that never moves.
   White here, ink there: the letters appear to change colour, not to vanish. */
.intro-mark {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  font-family: var(--font);
  font-size: clamp(40px, 12.5vw, 132px);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  font-variation-settings: 'wght' 600;
  color: #f7f2ea;
  white-space: nowrap;
  pointer-events: none;
  text-shadow: 0 2px 40px rgba(8, 5, 3, 0.55), 0 0 90px rgba(8, 5, 3, 0.35);
  animation: mark-in 1600ms var(--e-enter) 300ms both;
}
.intro-mark-word {
  border-bottom: max(1.5px, 0.045em) solid rgba(247, 242, 234, 0.62);
  padding-bottom: 0.25em;
}
@keyframes mark-in { from { opacity: 0; } }
#intro.brief .intro-mark { animation-duration: 500ms; animation-delay: 0ms; }
@media (prefers-reduced-motion: reduce) { .intro-mark { animation: none; } }

/* read again, once the choosing is done: the words stay, the choices go */
.threshold.revisited .th-go,
.threshold.revisited .th-how { display: none; }
.threshold.revisited::after {
  content: "press escape to go back to the field";
  font-family: var(--mono);
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-2);
  margin-top: 30px;
}
