/* =========================================================================
   SKENE AGENTIC — design system
   Bone paper, ink, one signal blue. Space Grotesk for structure, Newsreader
   for prose, IBM Plex Mono for labels and counts. Deliberately not the
   Skene Creative system: the two sites share one thing, the brushstroke S.
   Mobile-first. No frameworks. No build step.
   ========================================================================= */

:root {
  /* ---- page surround: light gray with a violet cast, so it reads as
         cool next to the indigo field rather than fighting it ---- */
  --bg:         #f3ecda;
  --surface:    #f9f5e9;

  /* ---- THE HIVE: the field inside the nav frame ----
         Honey: the comb gone literal. A faded honey field, black ink, ivory
         panes, and the walls in wax — the warm ramp below carries volume.
         Deliberately desaturated. ivory, paper and the dark fields survive
         as data-palette alternates below. */
  --field:      #ecdfbe;
  --cell-empty: #e4d6ae;
  --cell-line:  rgba(122, 94, 38, 0.15);
  --cell:       #fdf9ee;   /* a named cell is a clean pane of ivory */
  --occ-glow:   none;
  --ghost-fill:        rgba(140, 115, 60, 0.06);
  --ghost-fill-faint:  rgba(140, 115, 60, 0.03);
  --ghost-fill-hover:  rgba(140, 115, 60, 0.13);
  --ghost-ink-hover:   #5c5138;
  --tog-border: rgba(122, 94, 38, 0.25);
  --tog-bg:     rgba(253, 249, 238, 0.8);

  /* ---- the wall ramp: volume in hue as well as weight ----
         Type codes are gone (Brian, 26 Jul: the triad never carried over to
         Authors or Projects). The wall now says one thing twice — thin pale
         gold for sparse, thick oxblood for full. */
  --w0: #c9ab5e;
  --w1: #b98a33;
  --w2: #b06a2c;
  --w3: #96482a;
  --w4: #7e3030;

  /* ---- ink ---- */
  --text:       #191713;
  --text-soft:  #4a4536;
  --text-faint: #8a8570;
  --line:       rgba(30, 26, 16, 0.17);
  --line-soft:  rgba(30, 26, 16, 0.08);

  /* ---- ink on the field ---- */
  --on-field:        #3f3826;
  --on-field-faint:  #93876a;
  --on-field-panel:  rgba(253, 249, 238, 0.86);

  /* ---- signal ---- */
  --accent:     #7a5a12;   /* dark honey — links and controls */
  --accent-lit: #7a5a12;   /* on a light field the accent needs no lit twin */
  --hint:       #d8542a;
  --ghost:      #9a8f78;

  /* the old type triad survives only as UI accents (drawer tags, delete
     buttons) — the cells no longer wear it. Warm-tuned to match. */
  --t0: #a8821f;
  --t1: #b85a2b;
  --t2: #7e3030;

  --font-display: "Space Grotesk", Helvetica, Arial, sans-serif;
  --font-prose:   "Newsreader", Georgia, serif;
  --font-mono:    "IBM Plex Mono", ui-monospace, Menlo, monospace;

  --ease: cubic-bezier(0.22, 0.61, 0.24, 1);
  --gut:  clamp(1.25rem, 5vw, 4.5rem);
  --measure: 68ch;
}

/* Gold is the committed accent: indigo's complement is yellow-orange, and gold
   is the only warm note that does not collide with the teal / blue / vermillion
   type codes on the cell edges. The alternates are kept, unswitched, so any of
   them can be tried by putting data-palette="blue" on <html>. */
[data-palette~="blue"] { --accent: #1f4fd8; --accent-lit: #7ea0ff; }
[data-palette~="cyan"] { --accent: #0d7d92; --accent-lit: #4fd8e8; }
[data-palette~="bone"] { --bg: #eeeae1; --surface: #f7f4ed; }

/* Dark field alternates — the lattice as lit windows in a dark comb.
   indigo is the original; slate pulls its violet toward blue-gray; graphite
   is neutral. Any of them via data-palette on <html>. They share the dark
   ghost/glow/control clothes set once below. */
[data-palette~="indigo"] {
  --field: #12142e; --cell-empty: #1c2049; --cell-line: rgba(174, 184, 255, 0.16);
  --on-field: #cfd3f0; --on-field-faint: #8b8fbb; --on-field-panel: rgba(28, 32, 73, 0.86);
  --ghost: #8b8fc0;
}
[data-palette~="slate"] {
  --field: #101725; --cell-empty: #1a2436; --cell-line: rgba(148, 170, 210, 0.15);
  --on-field: #ccd6ea; --on-field-faint: #8595b4; --on-field-panel: rgba(24, 34, 52, 0.86);
  --ghost: #8494b8;
}
[data-palette~="graphite"] {
  --field: #17181c; --cell-empty: #232529; --cell-line: rgba(205, 210, 225, 0.13);
  --on-field: #d2d4dc; --on-field-faint: #8e91a0; --on-field-panel: rgba(32, 34, 40, 0.88);
  --ghost: #9297ab;
}
[data-palette~="indigo"], [data-palette~="slate"], [data-palette~="graphite"],
[data-palette~="forest"] {
  --cell: #f7f5ef; --accent-lit: #f0b849;
  /* the wall ramp needs to burn brighter against a dark field */
  --w0: #cfc08c; --w1: #e2b452; --w2: #eda63a; --w3: #ee8838; --w4: #e2632f;
  --occ-glow: drop-shadow(0 0 6px rgba(159, 176, 255, 0.28));
  --ghost-fill: rgba(140, 150, 230, 0.07); --ghost-fill-faint: rgba(140, 150, 230, 0.035);
  --ghost-fill-hover: rgba(160, 172, 255, 0.16); --ghost-ink-hover: #dfe3ff;
  --tog-border: rgba(174, 184, 255, 0.24); --tog-bg: var(--on-field-panel);
}

/* Mandai explorations — dark green, ivory, and yellow.
   forest is the dark hero: a deep green field, ivory panes, the yellow held
   for signal. ivory is the same brand turned to daylight: warm ivory field,
   deep green as the working accent. */
[data-palette~="forest"] {
  --field: #0f1f16; --cell-empty: #182b1f; --cell-line: rgba(178, 210, 178, 0.14);
  --on-field: #d9e0d0; --on-field-faint: #8fa48c; --on-field-panel: rgba(22, 40, 29, 0.88);
  --bg: #ece9dd; --surface: #f6f4ea;
  --cell: #faf7ea; --accent: #8a6d0b; --accent-lit: #f2c136;
  --ghost: #93a795;
  --occ-glow: drop-shadow(0 0 6px rgba(178, 226, 170, 0.24));
  --ghost-fill: rgba(160, 205, 160, 0.06); --ghost-fill-faint: rgba(160, 205, 160, 0.03);
  --ghost-fill-hover: rgba(185, 226, 180, 0.14); --ghost-ink-hover: #dcecd8;
  --tog-border: rgba(178, 210, 178, 0.24); --tog-bg: var(--on-field-panel);
}
/* Ivory — the Mandai brand in daylight: warm ivory field, deep green
   working accent. Was briefly the default; honey superseded it. */
[data-palette~="ivory"] {
  --field: #e9e5d3; --cell-empty: #e0dcc9; --cell-line: rgba(72, 68, 42, 0.13);
  --on-field: #414636; --on-field-faint: #8d8c74; --on-field-panel: rgba(253, 251, 242, 0.86);
  --bg: #eeebdf; --surface: #f7f5eb;
  --cell: #fdfbf2; --accent: #1d6b45; --accent-lit: #1d6b45;
  --ghost: #75816e;
  --ghost-fill: rgba(95, 125, 95, 0.06); --ghost-fill-faint: rgba(95, 125, 95, 0.03);
  --ghost-fill-hover: rgba(95, 125, 95, 0.13); --ghost-ink-hover: #45543f;
  --tog-border: rgba(72, 68, 42, 0.25); --tog-bg: rgba(253, 251, 242, 0.8);
}

[data-palette~="paper"] {
  --field: #e5e3da; --cell-empty: #dddbd0; --cell-line: rgba(60, 58, 48, 0.13);
  --on-field: #43443a; --on-field-faint: #8b8a7c; --on-field-panel: rgba(255, 253, 246, 0.85);
  --bg: #eae9f0; --surface: #f4f3f8;
  --cell: #fdfcf8; --accent: #9a6a05; --accent-lit: #9a6a05;
  --ghost: #70739a;
  --ghost-fill: rgba(90, 95, 150, 0.06); --ghost-fill-faint: rgba(90, 95, 150, 0.03);
  --ghost-fill-hover: rgba(90, 95, 150, 0.13); --ghost-ink-hover: #4a4d78;
  --tog-border: rgba(60, 58, 48, 0.25); --tog-bg: rgba(255, 253, 246, 0.8);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
/* fine grain over the whole page, the way paper has tooth */
body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 60;
  opacity: 0.03; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' seed='11' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

h1, h2, h3 { font-weight: 500; letter-spacing: -0.015em; line-height: 1.12; margin: 0; text-wrap: balance; }
a { color: var(--accent); }
::selection { background: rgba(31, 79, 216, 0.16); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.skip { position: absolute; left: -9999px; }
.skip:focus { left: var(--gut); top: 0.5rem; z-index: 99; background: var(--surface);
  padding: 0.5rem 0.8rem; border: 1px solid var(--line); border-radius: 2px; }

/* ============ header ============ */
.hdr {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.85rem var(--gut);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
}
.brand { display: flex; align-items: center; gap: 0.6rem; text-decoration: none; }
.brand svg { width: 16px; height: 20px; display: block; }
.brand svg path { fill: var(--accent); }
.brand-name { font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.24em;
  text-transform: uppercase; color: var(--text); }
.brand-name em { font-style: normal; color: var(--text-faint); }
.hdr nav { margin-left: auto; display: flex; gap: 1.2rem; }
.hdr nav a { font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.12em;
  text-transform: uppercase; text-decoration: none; color: var(--text-faint);
  transition: color 0.25s var(--ease); }
.hdr nav a:hover, .hdr nav a[aria-current="page"] { color: var(--accent); }
@media (max-width: 620px) { .hdr nav { gap: 0.85rem; } .hdr nav a { font-size: 0.62rem; } }

/* ============ page furniture ============ */
.wrap { padding: clamp(1.75rem, 6vh, 4rem) var(--gut) 4rem; max-width: 1500px; margin: 0 auto; }
.wrap--hub { padding-top: clamp(1rem, 2.4vh, 1.75rem); padding-bottom: 2.4rem; }
.narrow { max-width: 860px; }
.kicker { font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--accent); }
.rule { width: 46px; height: 2px; background: var(--accent); border: 0; margin: 0; }
.head { display: grid; gap: 0.85rem; margin-bottom: 1.3rem; }
.head h1 { font-size: clamp(1.6rem, 4vw, 2.6rem); }
/* the hub headline earns almost no vertical room: the map is the page */
.head--hub { gap: 0.3rem; margin-bottom: 0.7rem; }
.head--hub h1 { font-size: clamp(2rem, 5.4vw, 3.4rem); font-weight: 700; letter-spacing: -0.03em; }
.head--hub .lede { font-size: 1rem; line-height: 1.55; max-width: 96ch; }
.lede { font-family: var(--font-prose); color: var(--text-soft); font-size: 1.125rem;
  line-height: 1.7; max-width: var(--measure); }
.prose { font-family: var(--font-prose); color: var(--text-soft); font-size: 1.0625rem;
  line-height: 1.7; max-width: var(--measure); }
.prose + .prose { margin-top: 0.85rem; }
.prose code, .mono { font-family: var(--font-mono); font-size: 0.86em;
  background: rgba(20, 22, 26, 0.06); padding: 0.1em 0.35em; border-radius: 2px; }
h2.sec { font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--text-faint); font-weight: 400;
  margin: 2.4rem 0 0.9rem; }

.btn { display: inline-block; font-family: var(--font-mono); font-size: 0.66rem;
  letter-spacing: 0.14em; text-transform: uppercase; text-decoration: none;
  border: 1px solid var(--line); background: none; color: var(--text-soft);
  padding: 0.5rem 0.9rem; border-radius: 2px; cursor: pointer;
  transition: all 0.22s var(--ease); }
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn--solid { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn--solid:hover { filter: brightness(1.1); color: #fff; }

/* ============ the comb ============ */
.tabs { display: flex; gap: 0; border-bottom: 1px solid var(--line); margin-bottom: 0.5rem;
  overflow-x: auto; }
.tab { font-family: var(--font-display); font-size: 0.95rem; font-weight: 500;
  letter-spacing: -0.01em; border: 0; background: none; color: var(--text-faint);
  padding: 0.55rem 1.05rem 0.6rem; cursor: pointer; white-space: nowrap;
  border-bottom: 2px solid transparent; margin-bottom: -1px; transition: all 0.22s var(--ease); }
.tab:hover { color: var(--text); }
.tab[aria-selected="true"] { color: var(--text); border-bottom-color: var(--accent); }
.tab .c { font-family: var(--font-mono); font-size: 0.62rem; color: var(--text-faint); margin-left: 0.4rem; }
.tab .nu { display: inline-block; min-width: 15px; height: 15px; line-height: 15px;
  border-radius: 8px; background: var(--hint); color: #fff; font-family: var(--font-mono);
  font-size: 0.55rem; text-align: center; margin-left: 0.4rem; padding: 0 4px; }

/* a portal tab is a temporary one — it arrives when you dive and leaves when
   you close it, so it wears its own mark and its own way out */
.tab--portal { color: var(--accent); }
.tab--portal .pg { margin-right: 0.35rem; opacity: 0.85; }
.tab--portal .xp { margin-left: 0.5rem; opacity: 0.4; font-size: 0.72rem; }
.tab--portal .xp:hover { opacity: 1; color: var(--t2); }
.tab--portal[aria-selected="true"] { color: var(--text); }

/* the control row under the tabs: zoom on the left, legend and toggles after */
.ctrl { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1rem; margin-bottom: 0.55rem; }
.ctrl .bar { flex: 1 1 320px; margin-bottom: 0; }
.bar { display: flex; flex-wrap: wrap; gap: 0.45rem 1.1rem; align-items: center; margin-bottom: 0.75rem; }
.key { display: inline-flex; align-items: center; gap: 0.4rem; font-family: var(--font-mono);
  font-size: 0.61rem; letter-spacing: 0.13em; text-transform: uppercase; color: var(--text-soft); }
.key i { width: 16px; height: 0; border-top: 2.5px solid currentColor; display: inline-block; }
.key.g i { border-top-style: dotted; }
/* the wall key: thin pale gold = sparse, thick oxblood = full */
.key.den i.w1 { border-top: 2px solid var(--w1); }
.key.den i.w4 { border-top: 6px solid var(--w4); }
.key span { color: var(--text-soft); }
.bar .spacer { flex: 1 1 auto; }
.tog { font-family: var(--font-mono); font-size: 0.63rem; letter-spacing: 0.13em;
  text-transform: uppercase; border: 1px solid var(--line); background: none;
  color: var(--text-soft); padding: 0.4rem 0.75rem; border-radius: 2px; cursor: pointer;
  transition: all 0.22s var(--ease); }
.tog:hover { border-color: var(--accent); color: var(--accent); }
.tog[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }

/* The nav frame mirrors the screen it is read on: 16:9 on a desktop, portrait
   on a phone. On a short window the ratio is held and the *width* gives way,
   so the frame never stretches — 19rem is the page chrome above it, which is
   what has to be paid for before the map gets its share. The tabs and the
   control row share the cap so their right edges stay flush with the frame. */
.comb { max-width: calc((100vh - 18rem) * 16 / 9); }
@supports (height: 100svh) { .comb { max-width: calc((100svh - 18rem) * 16 / 9); } }
/* on a laptop-height window the headline gives up some of its own room so the
   map can be whole rather than nearly whole */
@media (max-height: 940px) {
  .head--hub { gap: 0.2rem; margin-bottom: 0.5rem; }
  .head--hub h1 { font-size: clamp(1.8rem, 3.4vw, 2.3rem); }
  .head--hub .lede { font-size: 0.92rem; line-height: 1.45; max-width: none; }
  .wrap--hub { padding-top: 1rem; }
}
.plot { position: relative; aspect-ratio: 16 / 9;
  border: 1px solid rgba(22, 23, 43, 0.22); border-radius: 3px;
  background: var(--field); overflow: hidden; }
@media (max-width: 860px) {
  .comb { max-width: none; }
  .plot { aspect-ratio: 4 / 5;  max-height: 74vh; }
  /* the authoring controls are a desk job — a phone gets the map and the zoom */
  #edit, #tidy, #exp { display: none; }
  .ctrl { gap: 0.4rem 0.7rem; }
  .bar { gap: 0.3rem 0.7rem; }
  .key { font-size: 0.55rem; letter-spacing: 0.1em; }
  .epin { max-width: 116px; font-size: 0.5rem; padding: 0.2rem 0.4rem; }
}
@media (max-width: 560px) { .plot { aspect-ratio: 9 / 16; max-height: 72vh; } }
svg#grid { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

.cell .hx { fill: var(--cell-empty); stroke: var(--cell-line); stroke-width: 1.2;
  transition: fill 0.2s var(--ease), stroke 0.2s var(--ease); }
/* The wall says one thing twice. WEIGHT — five steps of stroke width, set
   per cell as --sw by the engine, scaling with the radius — is how much is
   stored here; the HUE deepens along the same ramp, pale gold for sparse
   through oxblood for full. The type triad is gone from the cells: it never
   carried over to Authors or Projects, and the freed channel went to
   volume. */
.cell.occ .hx { fill: var(--cell); stroke-width: var(--sw, 2.5px); filter: var(--occ-glow, none); }
.cell.occ.v0 .hx { stroke: var(--w0); }
.cell.occ.v1 .hx { stroke: var(--w1); }
.cell.occ.v2 .hx { stroke: var(--w2); }
.cell.occ.v3 .hx { stroke: var(--w3); }
.cell.occ.v4 .hx { stroke: var(--w4); }
.cell.occ.empty0 .hx { stroke-dasharray: 7 5; }
.cell.occ { cursor: pointer; }
.cell.occ:hover .hx { fill: url(#litHot); }
body.editing .cell.occ { cursor: grab; }
.cell.dragging { cursor: grabbing !important; }
.cell.dragging .hx { fill: url(#litHot); filter: url(#lift); }
.cell.target .hx { fill: url(#litHot); stroke: var(--accent-lit); stroke-width: 2.5; }

.cell.ghost { cursor: pointer; }
.cell.ghost .hx { fill: var(--ghost-fill); stroke: var(--ghost); stroke-width: 1.5;
  stroke-dasharray: 2 5; stroke-linecap: round; }
.cell.ghost:hover .hx { fill: var(--ghost-fill-hover); stroke-dasharray: none; stroke-width: 2.2; }
.cell.ghost .nm { fill: var(--ghost); font-weight: 500; }
.cell.ghost .ct, .cell.ghost .mk { fill: var(--ghost); }
.cell.ghost .ct { font-style: italic; opacity: 0.85; }
.cell.ghost .mk { opacity: 0.55; }
.cell.ghost:hover .nm, .cell.ghost:hover .ct { fill: var(--ghost-ink-hover); }
.cell.ghost.per .hx { stroke-dasharray: 1.5 7; stroke-width: 1.3; fill: var(--ghost-fill-faint); }
.cell.ghost.per .nm, .cell.ghost.per .ct { opacity: 0.72; }
.cell.ghost.per:hover .hx { stroke-dasharray: none; stroke-width: 2; fill: var(--ghost-fill-hover); }
body.editing .cell.ghost { opacity: 0.3; pointer-events: none; }

.cell text { pointer-events: none; user-select: none; }
.cell .nm { font-family: var(--font-display); font-weight: 700; fill: var(--text);
  text-transform: uppercase; letter-spacing: -0.008em; }
.cell .ct { font-family: var(--font-mono); font-weight: 500; fill: var(--text-soft); letter-spacing: 0.07em; }
.cell .un { font-family: var(--font-mono); font-weight: 500; fill: var(--hint); letter-spacing: 0.07em; }
.cell.empty0 .nm { fill: var(--text-faint); font-weight: 500; }
.cell.empty0 .ct { fill: var(--text-faint); font-style: italic; }

/* a portal: a hexagon inside a hexagon, mirroring the unread badge across the
   cell. One says something new is in here, the other says there is a whole
   map in here. */
.pmk { cursor: zoom-in; }
.pmk .phit { fill: transparent; stroke: none; }
.pmk .pring { fill: none; stroke: var(--accent); stroke-width: 1.6; }
.pmk .pdot { fill: var(--accent); }
.pmk:hover .pring { stroke: var(--accent-lit); stroke-width: 2.4; }
.pmk:hover .pdot { fill: var(--accent-lit); }
body.editing .pmk { display: none; }

.badge { pointer-events: none; }
.badge .bg2 { fill: var(--hint); }
.badge .bt { fill: #fff; font-family: var(--font-mono); font-weight: 500; text-anchor: middle; }
.cell.occ .badge { animation: breathe 2.8s var(--ease) infinite; }
@keyframes breathe { 0%, 100% { opacity: 0.92; } 50% { opacity: 0.62; } }

.cell.occ, .cell.bg, .cell.ghost { transform-box: fill-box; transform-origin: center; }
#grid.arriving .cell { opacity: 0; transform: scale(0.82); }
#grid.settled .cell { opacity: 1; transform: none;
  transition: opacity 0.42s var(--ease) var(--d, 0s), transform 0.52s var(--ease) var(--d, 0s); }

/* off-frame markers */
#edges { position: absolute; inset: 0; pointer-events: none; z-index: 14; }
.epin { position: absolute; pointer-events: auto; cursor: pointer; display: flex; align-items: center;
  gap: 0.3rem; font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--on-field); background: var(--on-field-panel);
  border: 1px solid var(--tog-border); border-radius: 999px; padding: 0.24rem 0.55rem;
  transform: translate(-50%, -50%); white-space: nowrap; max-width: 190px; overflow: hidden;
  box-shadow: 0 6px 16px -12px rgba(20, 22, 26, 0.6); transition: all 0.2s var(--ease); }
.epin:hover { border-color: var(--accent-lit); color: var(--accent-lit); }
.epin .ar { color: var(--on-field-faint); font-size: 0.7rem; line-height: 1; }
.epin.per .ar { color: var(--hint); }
.recen { position: absolute; right: 0.8rem; bottom: 0.7rem; z-index: 15; }

/* zoom: the frame is fixed, the cells scale inside it. The control sits on the
   page above the frame, under the tabs, so it never covers a cell. */
.zoomer { display: flex; align-items: stretch; gap: 0.25rem; }
.zoomer .zbtn { width: 28px; padding: 0; font-size: 0.95rem; line-height: 1; }
.zoomer .zbtn:disabled { opacity: 0.3; cursor: default; border-color: var(--line-soft); }
.zoomer .zlvl { min-width: 52px; font-family: var(--font-mono); font-size: 0.6rem;
  letter-spacing: 0.08em; color: var(--text-soft); background: none;
  border: 1px solid var(--line); border-radius: 2px; cursor: pointer;
  padding: 0 0.3rem; transition: all 0.22s var(--ease); }
.zoomer .zlvl:hover { border-color: var(--accent); color: var(--accent); }

/* the way back out of a portal, inside the frame where the map is */
.backpill { position: absolute; left: 0.8rem; top: 0.8rem; z-index: 16; }
.backpill[hidden] { display: none; }
.hintbar { position: absolute; left: 0.85rem; bottom: 0.7rem; font-family: var(--font-mono);
  font-size: 0.56rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--on-field-faint);
  background: var(--on-field-panel); border: 1px solid var(--tog-border);
  border-radius: 2px; padding: 0.3rem 0.5rem; }

/* the frame has a name — and, behind the name, a memory. Click it. */
.cosmos { position: absolute; right: 0.85rem; top: 0.85rem; z-index: 15; cursor: pointer;
  font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: 0.28em;
  text-transform: uppercase; color: var(--on-field-faint); }
.cosmos:hover { color: var(--accent-lit); }

/* every control that sits on the field wears the field's clothes */
.plot .tog { color: var(--on-field); border-color: var(--tog-border);
  background: var(--tog-bg); }
.plot .tog:hover { border-color: var(--accent-lit); color: var(--accent-lit); }
.plot .tog:disabled { opacity: 0.32; cursor: default;
  border-color: var(--tog-border); color: var(--on-field-faint); }

/* inline editor */
#ed { position: absolute; z-index: 30; display: none; width: 214px; padding: 0.7rem;
  background: #fbf9f4; border: 1px solid var(--line); border-radius: 3px;
  box-shadow: 0 20px 44px -22px rgba(20, 22, 26, 0.6); transform: translate(-50%, -50%); }
#ed.on { display: block; }
#ed label { display: block; font-family: var(--font-mono); font-size: 0.56rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--text-faint); margin-bottom: 0.2rem; }
#ed input, #ed select { width: 100%; font-family: var(--font-display); font-size: 0.85rem;
  color: var(--text); background: #fff; border: 1px solid var(--line); border-radius: 2px;
  padding: 0.32rem 0.4rem; margin-bottom: 0.5rem; }
#ed .row { display: flex; gap: 0.4rem; } #ed .row > div { flex: 1; }
#ed .acts { display: flex; gap: 0.4rem; }
#ed button { flex: 1; font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.12em;
  text-transform: uppercase; border: 1px solid var(--line); background: none; color: var(--text-soft);
  padding: 0.35rem; border-radius: 2px; cursor: pointer; }
#ed button.pri { background: var(--accent); border-color: var(--accent); color: #fff; }
#ed button.del:hover { border-color: var(--t2); color: var(--t2); }

/* drawer */
#pane { position: absolute; top: 0; right: 0; bottom: 0; width: min(430px, 88%); z-index: 25;
  background: var(--surface); border-left: 1px solid var(--line); padding: 1.4rem 1.4rem 2rem;
  overflow-y: auto; transform: translateX(103%); transition: transform 0.42s var(--ease);
  box-shadow: -24px 0 50px -34px rgba(20, 22, 26, 0.55); }
#pane.on { transform: none; }
#pane .x { position: absolute; top: 0.7rem; right: 0.8rem; border: 0; background: none;
  cursor: pointer; font-family: var(--font-mono); font-size: 0.75rem; color: var(--text-faint); padding: 0.3rem; }
#pane .x:hover { color: var(--t2); }
#pane .tag { font-family: var(--font-mono); font-size: 0.57rem; letter-spacing: 0.2em; text-transform: uppercase; }
#pane h2 { font-family: var(--font-display); font-weight: 500; font-size: 1.5rem;
  letter-spacing: -0.02em; margin: 0.45rem 0 0.15rem; }
#pane .cnt { font-family: var(--font-mono); font-size: 0.66rem; color: var(--text-faint); letter-spacing: 0.07em; }
#pane .cnt b { color: var(--hint); font-weight: 500; }
#pane .url { font-family: var(--font-mono); font-size: 0.6rem; color: var(--accent);
  margin-top: 0.55rem; word-break: break-all; }
#pane h3 { font-family: var(--font-mono); font-size: 0.57rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--text-faint); font-weight: 400; margin: 1.3rem 0 0.5rem; }
#pane h3 em { font-style: normal; color: var(--hint); }
#pane p { font-family: var(--font-prose); font-size: 0.99rem; line-height: 1.6;
  color: var(--text-soft); margin: 0 0 0.7rem; }
#pane ul { margin: 0; padding: 0; list-style: none; }
#pane li { font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-soft);
  padding: 0.3rem 0; border-bottom: 1px solid var(--line-soft); }
#pane li .bul { color: var(--text-faint); margin-right: 0.4rem; }
#pane .fr { display: block; width: 100%; text-align: left; background: none; cursor: pointer;
  border: 1px solid var(--line-soft); border-left: 2px solid var(--ghost); border-radius: 2px;
  padding: 0.5rem 0.6rem; margin-bottom: 0.35rem; transition: all 0.2s var(--ease); }
#pane .fr:hover { border-color: var(--accent); border-left-color: var(--accent); background: #fbf9f4; }
#pane .fr b { display: block; font-family: var(--font-display); font-weight: 500; font-size: 0.82rem;
  text-transform: uppercase; letter-spacing: 0.02em; color: var(--text); margin-bottom: 0.12rem; }
#pane .fr span { font-family: var(--font-prose); font-size: 0.87rem; color: var(--text-soft); line-height: 1.42; }
#pane .go { display: inline-block; margin-top: 1.1rem; font-family: var(--font-mono); font-size: 0.6rem;
  letter-spacing: 0.14em; text-transform: uppercase; text-decoration: none;
  border: 1px solid var(--accent); background: var(--accent); color: #fff;
  padding: 0.5rem 0.85rem; border-radius: 2px; cursor: pointer; }
#pane .go.alt { background: none; color: var(--text-soft); border-color: var(--line); margin-left: 0.3rem; }
#pane .go.alt:hover { border-color: var(--accent); color: var(--accent); }

/* hint card — the leaf */
.hintc { border: 1px solid var(--line-soft); border-left: 2px solid var(--hint); border-radius: 2px;
  padding: 0.6rem 0.7rem; margin-bottom: 0.5rem; background: rgba(255, 253, 248, 0.6); }
.hintc .kd { font-family: var(--font-mono); font-size: 0.53rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--hint); }
.hintc .kd .dt { color: var(--text-faint); margin-left: 0.5rem; }
.hintc a.ti { display: block; font-family: var(--font-display); font-weight: 500; font-size: 0.92rem;
  line-height: 1.25; color: var(--text); text-decoration: none; margin: 0.22rem 0 0.18rem; }
.hintc a.ti:hover { color: var(--accent); text-decoration: underline; }
.hintc .src { font-family: var(--font-mono); font-size: 0.6rem; color: var(--text-faint); }
.hintc .wy { font-family: var(--font-prose); font-size: 0.93rem; line-height: 1.45;
  color: var(--text-soft); margin-top: 0.3rem; }
.hintc .acts { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.5rem; }
.hintc button { font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.12em;
  text-transform: uppercase; border: 1px solid var(--line); background: none; color: var(--text-soft);
  padding: 0.28rem 0.55rem; border-radius: 2px; cursor: pointer; }
.hintc button.sav:hover { border-color: var(--accent); color: var(--accent); }
.hintc button.fil:hover { border-color: var(--accent); color: var(--accent); }
.hintc button.dis:hover { border-color: var(--t2); color: var(--t2); }
/* an item saved to watch later — a lighter leaf, keyed gold not vermillion */
.hintc.saved { display: block; border-left-color: var(--accent); text-decoration: none;
  background: color-mix(in srgb, var(--accent) 5%, transparent); }
.hintc.saved .ti { display: block; font-family: var(--font-display); font-weight: 500;
  font-size: 0.9rem; color: var(--text); margin: 0.1rem 0; }
.hintc.saved:hover .ti { color: var(--accent); }

/* ============ the inbox — proposed, unverified links ============
   A proposal is deliberately not a hint card: it hasn't been checked, so it
   wears its own look — a dashed left edge instead of a solid one — and its
   own button (Discard only; there is no File/Save yet to offer honestly). */
.pendc { border: 1px dashed var(--line-soft); border-left: 2px dashed var(--hint); border-radius: 2px;
  padding: 0.6rem 0.7rem; margin-bottom: 0.5rem; background: rgba(255, 253, 248, 0.4); }
.pendc .kd { font-family: var(--font-mono); font-size: 0.53rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--hint); }
.pendc .kd .dt { color: var(--text-faint); margin-left: 0.5rem; text-transform: none; letter-spacing: 0.04em; }
.pendc a.ti { display: block; font-family: var(--font-mono); font-size: 0.8rem; word-break: break-all;
  line-height: 1.35; color: var(--text-soft); text-decoration: none; margin: 0.22rem 0 0.18rem; }
.pendc a.ti:hover { color: var(--accent); text-decoration: underline; }
.pendc .wy { font-family: var(--font-prose); font-size: 0.88rem; line-height: 1.4;
  color: var(--text-soft); margin-top: 0.15rem; }
.pendc .acts { margin-top: 0.4rem; }
.pendc button { font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.12em;
  text-transform: uppercase; border: 1px solid var(--line); background: none; color: var(--text-soft);
  padding: 0.28rem 0.55rem; border-radius: 2px; cursor: pointer; }
.pendc button:hover { border-color: var(--t2); color: var(--t2); }

/* the propose form — a paste-a-link mini version of the note box, so it
   reads as kin to Workspace rather than a separate control */
.propose { display: grid; gap: 0.4rem; margin: 0.3rem 0 0.6rem; }
.propose .pin, .propose .psel { min-height: unset; padding: 0.45rem 0.6rem; }
.propose .pnote { min-height: 2.4rem; }
.propose .pin.bad { border-color: var(--t2); }
.propose select.wsin { font-family: var(--font-mono); font-size: 0.8rem; background: #fff; }

/* a hex tile or the tray, mid drag-over — the same dashed halo either way */
.cell.dropping .hx { fill: url(#litHot); stroke: var(--accent-lit); stroke-width: 2.5;
  stroke-dasharray: 4 3; }
#pane.dropping { box-shadow: inset 0 0 0 2px var(--accent-lit); }
[data-dropzone].dropping { outline: 2px dashed var(--accent-lit); outline-offset: 6px; }

/* the hub's own (+) — sits with the zoom controls, carries the pending count */
.inboxbtn { position: relative; }
.ibct { display: inline-flex; align-items: center; justify-content: center; min-width: 1.1rem;
  height: 1.1rem; margin-left: 0.35rem; padding: 0 0.3rem; border-radius: 999px;
  background: var(--accent); color: #fff; font-size: 0.58rem; }

/* ============ the workspace — notes and memory in the drawer ============ */
/* on a topic page the notes panel sits in the flow, boxed off from the article */
.ws-panel { display: block; margin: 0 0 2rem; padding: 1.1rem 1.3rem 1.3rem;
  background: var(--surface); border: 1px solid var(--line-soft); border-radius: 4px; }
.ws-panel .sec { margin-top: 0; }
/* the memory panel lives in the margin — plain, no box, quieter */
.ws-panel.plain { background: none; border: 0; padding: 0; margin-bottom: 1.8rem; }
.msub { font-family: var(--font-mono); font-size: 0.52rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--text-faint); margin: 1rem 0 0.3rem; }

/* ---- the Domain menu: the parent layer, left of the comb tabs ---- */
.tabrow { display: flex; align-items: stretch; gap: 0; }
.tabrow .tabs { flex: 1; }
#domain { position: relative; display: flex; align-items: stretch;
  border-bottom: 1px solid var(--line); margin-bottom: 0.5rem; }
.dbtn { display: inline-flex; align-items: center; gap: 0.4rem; cursor: pointer;
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--text-soft); background: none;
  border: 0; border-right: 1px solid var(--line); padding: 0.55rem 0.9rem 0.5rem;
  transition: color 0.2s var(--ease); }
.dbtn:hover { color: var(--accent); }
.dbtn[aria-expanded="true"] { color: var(--accent); }
.dlock, .dkey { font-size: 0.7em; opacity: 0.65; }
.dkey { color: var(--accent); opacity: 1; }
.dmenu { position: absolute; left: 0; top: 100%; z-index: 40; min-width: 268px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 3px;
  box-shadow: 0 14px 34px -18px rgba(30, 26, 16, 0.5); padding: 0.35rem; }
.dmenu[hidden] { display: none; }
.ditem { display: block; text-decoration: none; padding: 0.45rem 0.6rem; border-radius: 2px; }
a.ditem:hover { background: color-mix(in srgb, var(--accent) 9%, transparent); }
.ditem b { display: block; font-family: var(--font-mono); font-size: 0.62rem;
  letter-spacing: 0.14em; text-transform: uppercase; font-weight: 500; color: var(--text); }
.ditem span { display: block; font-family: var(--font-prose); font-size: 0.86rem;
  color: var(--text-soft); line-height: 1.4; margin-top: 0.1rem; }
.ditem .dnow { display: block; font-family: var(--font-mono); font-size: 0.52rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-faint); font-style: normal; }
.ditem.cur b { color: var(--accent); }
.ditem.priv b::before { content: "◆ "; color: var(--accent); }
.dform { border-top: 1px solid var(--line-soft); margin-top: 0.3rem; padding: 0.6rem; }
.dform label { display: block; font-family: var(--font-mono); font-size: 0.52rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 0.3rem; }
.dform input { width: 100%; box-sizing: border-box; font-family: var(--font-mono);
  font-size: 0.75rem; padding: 0.42rem 0.5rem; border: 1px solid var(--line);
  border-radius: 2px; background: #fff; color: var(--text); }
.dform input:focus { outline: none; border-color: var(--accent); }
.dform .go { margin-top: 0.4rem; width: 100%; font-family: var(--font-mono);
  font-size: 0.58rem; letter-spacing: 0.14em; text-transform: uppercase; cursor: pointer;
  padding: 0.42rem 0.6rem; border-radius: 2px; border: 1px solid var(--accent);
  color: var(--accent); background: color-mix(in srgb, var(--accent) 9%, transparent); }
.dform .go:hover { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.dform .go:disabled { opacity: 0.5; cursor: default; }
.dmsg { font-family: var(--font-mono); font-size: 0.56rem; letter-spacing: 0.05em;
  color: var(--text-faint); margin: 0.4rem 0 0; }
.dmsg.bad { color: var(--hint); }
.dlockbtn { width: calc(100% - 1.2rem); margin: 0.3rem 0.6rem 0.5rem; cursor: pointer;
  font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--text-soft); background: none;
  border: 1px solid var(--line); border-radius: 2px; padding: 0.38rem 0.5rem; }
.dlockbtn:hover { border-color: var(--hint); color: var(--hint); }
@media (max-width: 620px) {
  .dbtn { padding: 0.5rem 0.6rem; font-size: 0.55rem; }
  .dmenu { min-width: 230px; }
}

/* ---- page banner: the fitted image band above the content ----
   build.py writes the <img> straight into the markup. A cell whose art does
   not exist yet gets .banner--empty and no child, which the background rule
   below already renders as a plain field-coloured strip — nothing further is
   needed for it. Until 30 Jul 2026 js/banner.js drew a seeded honeycomb into
   this box when there was no image; it is in _archive/ with the reasoning. */
.banner { display: block; width: 100%; height: 168px; overflow: hidden;
  border: 1px solid var(--line-soft); border-radius: 4px; margin-bottom: 1.6rem;
  background: var(--field); }
.banner svg, .banner img { display: block; }
.banner img { width: 100%; height: 100%; object-fit: cover; object-position: center; }
@media (max-width: 700px) { .banner { height: 116px; } }

/* ---- topic page: three-column marginalia layout ----
   left margin = reference + navigation (memory, concepts, touches, frontier)
   centre      = the reading column (notes, explainers, papers)
   right margin= watch (video links) */
.topicwrap { max-width: 1200px; }
.topic-layout { display: grid; grid-template-columns: 216px minmax(0, 1fr) 248px;
  gap: 2.4rem; align-items: start; margin-top: 1.6rem; }
.topic-layout.noright { grid-template-columns: 216px minmax(0, 1fr); }
/* explicit row-1 on all three, or sparse auto-placement drops the margins
   (declared after the centre in source) into a phantom second row */
.col-left { grid-column: 1; grid-row: 1; }
.col-main { grid-column: 2; grid-row: 1; }
.col-right { grid-column: 3; grid-row: 1; }
.col-main .sec:first-child, .col-left > :first-child .sec { margin-top: 0; }
.stack { display: grid; gap: 0.9rem; }
.card.wide { min-height: 0; }
/* the margins speak more quietly than the centre */
.col-left .sec, .col-right .sec { font-size: 0.52rem; letter-spacing: 0.18em; margin-top: 1.6rem; }
.col-left .card, .col-right .card { padding: 0.6rem 0.75rem; }
.col-left .card h3, .col-right .card h3 { font-size: 0.9rem; }
.col-left .card p, .col-right .card p { font-size: 0.84rem; line-height: 1.45; }
.col-left .chips { gap: 0.3rem; }
.topic-back { max-width: 1200px; margin-top: 2.2rem; }
@media (max-width: 900px) {
  .topic-layout, .topic-layout.noright { grid-template-columns: 1fr; gap: 1.4rem; }
  .col-left, .col-main, .col-right { grid-column: 1; grid-row: auto; }
  .col-left .sec, .col-right .sec { font-size: 0.55rem; }
}
.ws { display: grid; gap: 0.45rem; margin-top: 0.3rem; }
.wsin { width: 100%; box-sizing: border-box; resize: vertical; min-height: 3.2rem;
  font-family: var(--font-prose); font-size: 0.93rem; line-height: 1.45; color: var(--text);
  background: #fff; border: 1px solid var(--line); border-radius: 2px; padding: 0.5rem 0.6rem; }
.wsin:focus { outline: none; border-color: var(--accent); }
/* Leave a note and Open the page share one row — same size, same level, both
   outlined; Leave a note carries only a subtle accent tint to prompt the eye */
.wsrow { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: stretch; }
#pane .wsrow .go, .ws-panel .wsrow .go {
  margin: 0; padding: 0.5rem 1rem; font-size: 0.6rem; line-height: 1;
  display: inline-flex; align-items: center; font-weight: 400;
  border: 1px solid var(--line); background: none; color: var(--text-soft); }
#pane .wsrow .go.wsadd, .ws-panel .wsrow .go.wsadd {
  border-color: var(--accent); color: var(--accent); font-weight: 500;
  background: color-mix(in srgb, var(--accent) 9%, transparent); }
#pane .wsrow .go.wsadd:hover, .ws-panel .wsrow .go.wsadd:hover {
  background: color-mix(in srgb, var(--accent) 16%, transparent); }
#pane .wsrow .go.alt:hover { border-color: var(--accent); color: var(--accent); }
.note { border: 1px solid var(--line-soft); border-left: 2px solid var(--accent); border-radius: 2px;
  padding: 0.5rem 0.7rem; margin-top: 0.5rem; background: #fbf9f4; }
.note .nd, .chg .nd { font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.12em;
  color: var(--text-faint); }
.note p { margin: 0.15rem 0 0; font-family: var(--font-prose); font-size: 0.93rem; line-height: 1.5; }
.mem { display: grid; gap: 0.45rem; }
.memf { border: 1px solid var(--line-soft); border-radius: 2px; padding: 0.5rem 0.7rem;
  cursor: pointer; display: grid; gap: 0.3rem; }
.memf:hover { border-color: var(--accent); }
.memf .ml { font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--text-faint); }
.memf .mv { margin: 0; font-family: var(--font-prose); font-size: 0.93rem; line-height: 1.5; }
.memf .mv0 { color: var(--text-faint); font-style: italic; }
.chg li { display: block; }

/* ============ topic pages ============ */
.topichead { display: grid; gap: 0.8rem; padding-bottom: 1.4rem; border-bottom: 1px solid var(--line-soft); }
.topichead .meta { font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.08em;
  color: var(--text-faint); }
.topichead .meta b { color: var(--hint); font-weight: 500; }
.topichead h1 { font-size: clamp(1.9rem, 5.5vw, 3.2rem); }

.grid { display: grid; gap: 1px; background: var(--line-soft); border: 1px solid var(--line-soft); }
@media (min-width: 700px)  { .grid.two   { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .grid.three { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 700px)  { .grid.three { grid-template-columns: repeat(2, 1fr); } }
.card { background: var(--bg); padding: 1.1rem 1.15rem 1.2rem; display: grid; gap: 0.4rem;
  align-content: start; text-decoration: none; color: inherit; position: relative;
  transition: background 0.3s var(--ease); }
a.card:hover { background: var(--surface); }
a.card::after { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--accent); transform: scaleY(0); transform-origin: top;
  transition: transform 0.35s var(--ease); }
a.card:hover::after { transform: scaleY(1); }
.card .lbl { font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--text-faint); }
.card h3 { font-size: 1.05rem; }
.card p { font-family: var(--font-prose); font-size: 0.95rem; line-height: 1.55;
  color: var(--text-soft); margin: 0; }
.card .tail { font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--accent); }
.card.dim .lbl, .card.dim h3, .card.dim p { color: var(--text-faint); }
.card.dim h3 { font-weight: 500; }

.chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.chip { display: inline-flex; align-items: center; gap: 0.35rem; font-family: var(--font-mono);
  font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase; text-decoration: none;
  color: var(--text-soft); border: 1px solid var(--line); border-radius: 999px;
  padding: 0.3rem 0.65rem; transition: all 0.2s var(--ease); }
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip .d { width: 7px; height: 7px; border-radius: 2px; background: currentColor; opacity: 0.55; }
.chip.ghosty { border-style: dashed; color: var(--ghost); }

.backhive { justify-self: start; margin-top: 0.15rem; }
.backhive:hover { border-color: var(--accent); color: var(--accent); }

.empty { font-family: var(--font-prose); font-size: 1.0625rem; color: var(--text-faint);
  font-style: italic; max-width: var(--measure); }

/* ============ footer ============ */
.ftr { padding: clamp(2.5rem, 7vh, 4rem) var(--gut); border-top: 1px solid var(--line-soft);
  display: flex; gap: 1.2rem; align-items: center; flex-wrap: wrap; }
.ftr svg { width: 24px; height: 30px; }
.ftr svg path { fill: var(--accent); }
.ftr .note { font-family: var(--font-mono); font-size: 0.65rem; letter-spacing: 0.1em;
  color: var(--text-faint); }
.ftr nav { margin-left: auto; display: flex; gap: 1rem; flex-wrap: wrap; }
.ftr nav a { font-family: var(--font-mono); font-size: 0.65rem; letter-spacing: 0.12em;
  text-transform: uppercase; text-decoration: none; color: var(--text-faint); }
.ftr nav a:hover { color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  #grid.arriving .cell { opacity: 1; transform: none; }
  .cell.occ .badge { animation: none; }
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ============ the waggle mark — hub opening animation (js/mark.js) ============
   A bee dances the brushstroke S on before the hub appears. Full-bleed overlay
   rather than a block in the page: §3 settles that the hub headline gets almost
   no vertical room and "the map is the page", so the intro must cost zero
   permanent layout. Fades itself out and removes itself from the DOM. */
.wm-intro { position: fixed; inset: 0; z-index: 9000; background: var(--field, #ecdfbe);
  display: flex; align-items: center; justify-content: center;
  transition: opacity 0.62s var(--ease, cubic-bezier(.4,0,.2,1)); }
.wm-intro.wm-out { opacity: 0; pointer-events: none; }
.wm-svg { width: min(46vh, 62vw); height: auto; overflow: visible; }
.wm-glyph { fill: var(--accent, #7a5a12); }
.wm-bee { transition: opacity 0.4s var(--ease, ease); }
.wm-skip { position: absolute; bottom: 8vh; left: 0; right: 0; text-align: center;
  font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.58rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-faint, #8c8073);
  opacity: 0.55; }
@media (prefers-reduced-motion: reduce) { .wm-skip { display: none; } }

/* =========================================================================
   SEARCH (30 Jul 2026) — a flex sibling inside .tabrow.
   It must add NO height to that row: verify.mjs asserts `zoomer under the
   tabs` and `whole frame fits a 1440x900 laptop`, both numerically, and a
   taller tab row breaks the 16:9 frame contract. Hence align-items:stretch
   on the box and no vertical padding beyond the tabs' own.
   ========================================================================= */
.srch { position: relative; display: flex; align-items: center; gap: 0.3rem;
  border-bottom: 1px solid var(--line); margin-bottom: 0.5rem;
  padding: 0 0.15rem 0 0.7rem; flex: 0 0 auto; }
.srch-l { font-size: 0.9rem; line-height: 1; color: var(--text-faint); cursor: text;
  transition: color 0.2s var(--ease); }
.srch:focus-within .srch-l { color: var(--accent); }
.srch-i { width: clamp(9rem, 19vw, 15rem); border: 0; background: none; outline: none;
  font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.04em;
  color: var(--text); padding: 0.5rem 0 0.55rem; }
.srch-i::placeholder { color: var(--text-faint); letter-spacing: 0.08em; }
.srch-i::-webkit-search-cancel-button { display: none; }
.srch-x { border: 0; background: none; cursor: pointer; color: var(--text-faint);
  font-size: 0.6rem; padding: 0.2rem 0.3rem; line-height: 1; }
.srch-x:hover { color: var(--accent); }

.sres { position: absolute; top: calc(100% + 2px); right: 0; z-index: 60;
  width: min(26rem, 84vw); max-height: min(60vh, 26rem); overflow-y: auto;
  background: var(--pane, #fdf9ee); border: 1px solid var(--line);
  box-shadow: 0 14px 34px rgba(5, 6, 15, 0.16); }
.sgrp { font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--text-faint); padding: 0.55rem 0.7rem 0.3rem;
  border-bottom: 1px solid var(--line-soft); display: flex; gap: 0.5rem; }
.sgrp .sct { color: var(--accent); }
.srow { display: block; width: 100%; text-align: left; border: 0; background: none;
  cursor: pointer; padding: 0.42rem 0.7rem 0.5rem; border-bottom: 1px solid var(--line-soft);
  transition: background 0.14s var(--ease); }
.srow:hover, .srow.on { background: var(--field, #ecdfbe); }
.srow .sl { display: block; font-family: var(--font-display); font-size: 0.86rem;
  color: var(--text); line-height: 1.25; }
.srow .ss { display: block; font-family: var(--font-mono); font-size: 0.55rem;
  letter-spacing: 0.05em; color: var(--text-faint); margin-top: 0.15rem; }
.smore, .sempty { font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.05em;
  color: var(--text-faint); padding: 0.45rem 0.7rem 0.55rem; }
.sempty b { color: var(--text); }
.sempty span { display: block; margin-top: 0.3rem; }

/* the map IS the result set: matches hold their fill, everything else recedes.
   Reuses the existing v0-v4 lightness vocabulary rather than inventing a new
   visual language for "present but quiet". */
/* `#grid.settled .cell { opacity: 1 }` (the arrive animation, ~line 370) is
   (1,2,0) and wins over a bare `.cell.dim`, so these have to be scoped under
   #grid too. Found by reading computed opacity, not by looking at a screenshot
   — the class was on the element the whole time and the map looked untouched. */
#grid.settled .cell.dim, #grid .cell.dim { opacity: 0.2; }
#grid .cell.dim, #grid .cell.hit { transition: opacity 0.24s var(--ease); }
#grid .cell.hit .hx { stroke: var(--accent);
  stroke-width: calc(var(--sw, 1px) * 1.5); }
#grid .cell.hit .nm { fill: var(--accent); }

/* an asset that search jumped to, flashed inside the drawer so the reason the
   match happened is what the eye lands on */
.hintc.found { box-shadow: 0 0 0 2px var(--accent); }

@media (max-width: 900px) {
  /* the gutter this lives in does not exist on a narrow screen, and the tab row
     already scrolls horizontally — a search box would fight it */
  .srch { display: none; }
}

/* =========================================================================
   THE INTAKE DOCK (30 Jul 2026) — the propose module in the top-right gutter.

   It used to be a full-width block in the centre reading column of every
   generated page, below the workspace. Brian moved it: "Resize and move the
   intake module here — globally." Collapsed to one affordance, anchored to the
   top-right of the page wrap, level with the banner.

   Absolutely positioned ON PURPOSE. `.topic-layout` runs col-left / col-main /
   col-right, and verify.mjs asserts both that a page with video has a right
   margin and that a videoless page collapses it (.topic-layout.noright). A dock
   in the flow would have to negotiate with both cases; a dock out of the flow
   negotiates with neither and costs the columns nothing.
   ========================================================================= */
.wrap { position: relative; }
.pdock-mount { position: absolute; top: 0; right: var(--gut); z-index: 40; margin: 0; padding: 0;
  border: 0; background: none; }
.pdock { display: flex; flex-direction: column; align-items: flex-end; gap: 0.35rem; }
.pdock-b { display: inline-flex; align-items: center; gap: 0.4rem; cursor: pointer;
  font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--text-soft);
  background: var(--pane, #fdf9ee); border: 1px solid var(--line);
  padding: 0.4rem 0.7rem 0.38rem; transition: color 0.2s var(--ease), border-color 0.2s var(--ease); }
.pdock-b:hover, .pdock.on .pdock-b { color: var(--accent); border-color: var(--accent); }
.pdock-n { display: inline-block; min-width: 14px; height: 14px; line-height: 14px;
  border-radius: 7px; background: var(--hint); color: #fff; font-size: 0.5rem;
  text-align: center; letter-spacing: 0; }
.pdock-p { width: min(20rem, 78vw); background: var(--pane, #fdf9ee);
  border: 1px solid var(--line); box-shadow: 0 12px 30px rgba(5, 6, 15, 0.14);
  padding: 0.55rem 0.6rem 0.6rem; }
.pdock-p .propose { margin: 0; }
.pdock-p .pnote { min-height: 2.6rem; }
/* the pending list inherits page-level heading scale; in a 20rem panel that
   reads as a shout */
.pdock-p h2, .pdock-p h3 { font-family: var(--font-mono); font-size: 0.55rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-faint);
  font-weight: 400; margin: 0.6rem 0 0.3rem; }
.pdock-p h2 em, .pdock-p h3 em { font-style: normal; color: var(--accent); }
.pdock-p .pend { font-size: 0.72rem; }

@media (max-width: 900px) {
  /* no gutter to sit in — fall back into the flow above the banner, full width */
  .pdock-mount { position: static; right: auto; margin: 0 0 0.6rem; }
  .pdock { align-items: stretch; }
  .pdock-p { width: auto; }
}

/* =========================================================================
   THE MARK'S GUTTER SLOT (30 Jul 2026)

   Brian's layout: the mark lives permanently in the left margin — the waggle
   dance on the hub, the static S on an interior page — instead of a full-screen
   title card that plays once and deletes itself.

   IT SITS IN THE OUTER MARGIN, NOT IN THE COLUMN. .wrap is max-width 1500px
   centred, so on a wide window there is real space outside it; that is where
   Brian drew the box. `right: calc(100% + ...)` puts the slot entirely outside
   the wrap, which means it costs the content column nothing — and that matters,
   because verify.mjs asserts the hub frame is 16:9 and that the whole frame
   fits a 1440x900 laptop. A slot in the flow would break both.

   THE CONSEQUENCE, STATED PLAINLY: below 1560px there is no outer margin to sit
   in, so the slot hides. That is inherent to the placement, not a bug — on a
   1440 laptop the mark is not visible. If it should be visible there, the mark
   has to move inside the column and the frame contract has to be renegotiated.
   ========================================================================= */
/* The slot has to FIT in the outer margin, which is (100vw - 1500px) / 2 once
   .wrap hits its cap. At 1800px that margin is 150px, and a 150px slot plus a
   1.1rem gap needs 168 — so the first attempt hung 18px off the left edge of
   the window. Size it from the space that actually exists and only show it once
   there is demonstrably room. */
.gutmark { position: absolute; top: 0; right: calc(100% + 1rem);
  width: min(clamp(76px, 7vw, 128px), calc((100vw - 1500px) / 2 - 1.4rem));
  display: block; }
.gutmark--static { opacity: 0.9; transition: opacity 0.24s var(--ease); }
.gutmark--static:hover { opacity: 1; }
.gutmark--static img { display: block; width: 100%; height: auto; }

/* the dance, in the slot: no fixed positioning, no field backdrop, no skip hint */
.wm-gut { position: relative; display: block; cursor: pointer; }
.wm-gut .wm-svg { width: 100%; height: auto; overflow: visible; }
.wm-gut.wm-set { cursor: pointer; }
.wm-gut.wm-set .wm-glyph { transition: opacity 0.3s var(--ease); }
.wm-gut:hover.wm-set .wm-glyph { opacity: 0.75; }

@media (max-width: 1800px) {
  /* below this there is no outer margin wide enough to hold the mark without it
     hanging off the window — so it is not shown at all. On a 1440 laptop the
     gutter mark is absent by design; moving it inside the column would mean
     renegotiating the 16:9 frame contract verify.mjs asserts. */
  .gutmark { display: none; }
}
