:root {
  --bg: #14110f;
  --bg-raised: #1c1815;
  --bg-sunk: #0e0c0b;
  --ink: #e9e0cd;
  --ink-dim: #a99e8a;
  --ink-faint: #6f665a;
  --rule: #342d26;
  --rule-bright: #4c4137;
  --black-side: #c8102e;
  --green-side: #3f9163;
  --focus: #e6b95c;
  --radius: 4px;
  --shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background:
    radial-gradient(120% 80% at 50% 0%, #211b17 0%, var(--bg) 55%, var(--bg-sunk) 100%)
    fixed;
  color: var(--ink);
  font: 400 16px/1.6 "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  padding-bottom: 4rem;
}

h1, h2, h3 { font-weight: 600; line-height: 1.15; margin: 0 0 .5rem; letter-spacing: .01em; }

a { color: var(--ink); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: -999px; top: 0; z-index: 50;
  background: var(--focus); color: #1b1409; padding: .6rem 1rem; border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus { left: 0; }

:where(button, input, select, [tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* ── masthead ─────────────────────────────────────────────────────────── */

.masthead {
  max-width: 60rem;
  margin: 0 auto;
  padding: 3.5rem 1.25rem 2rem;
  text-align: center;
}

.eyebrow {
  margin: 0 0 1rem;
  font-size: .74rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.masthead h1 {
  font-size: clamp(2.1rem, 6.5vw, 3.6rem);
  margin-bottom: 1rem;
}

.lede { margin: 0 auto; max-width: 42rem; color: var(--ink-dim); }

.cutoff {
  margin: 1.5rem auto 0;
  display: inline-block;
  padding: .4rem .9rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-size: .78rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ── controls ─────────────────────────────────────────────────────────── */

.controls {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.75rem;
  align-items: flex-end;
  padding: 1rem clamp(1rem, 4vw, 3rem);
  background: rgba(14, 12, 11, .93);
  backdrop-filter: blur(10px);
  border-block: 1px solid var(--rule);
}

.control { border: 0; padding: 0; margin: 0; min-width: 0; }

.control > label, .control legend {
  display: block;
  padding: 0;
  margin-bottom: .4rem;
  font-size: .68rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.control-search { flex: 1 1 15rem; max-width: 22rem; }

#q, #house-select {
  width: 100%;
  background: var(--bg-raised);
  color: var(--ink);
  border: 1px solid var(--rule-bright);
  border-radius: var(--radius);
  padding: .5rem .7rem;
  font: inherit;
  font-size: .92rem;
}

#q::placeholder { color: var(--ink-faint); }

#house-select { min-width: 12rem; }

.count { margin: .35rem 0 0; font-size: .76rem; color: var(--ink-faint); min-height: 1.2em; }

.chips { display: flex; flex-wrap: wrap; gap: .35rem; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .34rem .7rem;
  background: var(--bg-sunk);
  border: 1px solid var(--rule-bright);
  border-radius: 999px;
  font: inherit;
  font-size: .8rem;
  color: var(--ink-dim);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

.chip .dot { width: .55rem; height: .55rem; border-radius: 50%; background: var(--chip, var(--ink-faint)); }
.chip[aria-pressed="true"] {
  background: color-mix(in srgb, var(--chip) 22%, var(--bg-raised));
  border-color: var(--chip);
  color: var(--ink);
}
.chip:hover { color: var(--ink); border-color: var(--chip, var(--focus)); }
.chip:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

.control-flags { display: flex; flex-wrap: wrap; align-items: center; gap: .9rem; }

.toggle { display: inline-flex; align-items: center; gap: .45rem; font-size: .85rem; color: var(--ink-dim); cursor: pointer; }
.toggle input { accent-color: var(--focus); width: 1rem; height: 1rem; }

.reset {
  background: none;
  border: 1px solid var(--rule-bright);
  border-radius: var(--radius);
  color: var(--ink-dim);
  font: inherit;
  font-size: .82rem;
  padding: .38rem .8rem;
  cursor: pointer;
}
.reset:hover { color: var(--ink); border-color: var(--focus); }

/* ── tree ─────────────────────────────────────────────────────────────── */

.tree { padding: 2rem clamp(1rem, 4vw, 3rem) 0; }

.tree-head {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: baseline;
  justify-content: space-between;
  max-width: 90rem;
  margin: 0 auto .75rem;
}

.tree-head h2 { font-size: 1.4rem; margin: 0; }

.zoombar { display: flex; align-items: center; gap: .3rem; }

.zoombar button {
  width: 2.1rem; height: 2.1rem;
  background: var(--bg-raised);
  border: 1px solid var(--rule-bright);
  border-radius: var(--radius);
  color: var(--ink);
  font: inherit;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}
.zoombar button.wide { width: auto; padding: 0 .8rem; font-size: .82rem; }
.zoombar button:hover { border-color: var(--focus); }
.zoombar output { min-width: 3.4rem; text-align: center; font-size: .78rem; color: var(--ink-faint); }

.canvas {
  position: relative;
  max-width: 90rem;
  margin: 0 auto;
  height: min(72vh, 720px);
  /* The canvas owns every gesture that starts inside it: no page pan, no page
     zoom, and no scroll chaining to the section behind it when a drag runs off
     the edge. tree.js cancels the touch and gesture events Safari would still
     act on despite this. */
  overscroll-behavior: contain;
  -webkit-user-select: none;
  user-select: none;
  background:
    linear-gradient(rgba(255, 255, 255, .012) 1px, transparent 1px) 0 0 / 100% 34px,
    var(--bg-sunk);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
  touch-action: none;
  cursor: grab;
}
.canvas.dragging { cursor: grabbing; }

/* ── full screen ───────────────────────────────────────────────────────
   One class drives both modes, so the layout, the controls and the exit are
   identical whether the browser handed us the Fullscreen API or we had to pin
   the section over the page ourselves. iPhone Safari is the second case: it
   has no element fullscreen at all. */

.tree.immersive {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 100dvh;
  z-index: 90;
  display: flex;
  flex-direction: column;
  margin: 0;
  padding:
    max(.75rem, env(safe-area-inset-top)) clamp(.75rem, 3vw, 1.5rem)
    max(.75rem, env(safe-area-inset-bottom));
  background:
    radial-gradient(120% 80% at 50% 0%, #211b17 0%, var(--bg) 55%, var(--bg-sunk) 100%);
  overscroll-behavior: contain;
}
.tree.immersive .tree-head { max-width: none; margin: 0 0 .5rem; }
.tree.immersive .canvas {
  flex: 1 1 auto;
  height: auto;
  min-height: 0;
  max-width: none;
}
.tree.immersive .hint,
.tree.immersive .legend { max-width: none; margin-top: .5rem; }

/* Full screen on a small window means the canvas and the controls, nothing
   else. The heading stays in the accessibility tree: it is what names the
   section. */
@media (max-height: 620px), (max-width: 760px) {
  .tree.immersive .hint,
  .tree.immersive .legend { display: none; }
  .tree.immersive .tree-head h2 {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .tree.immersive .tree-head { justify-content: center; }
}

/* Fullscreen paints its own backdrop black, which would show through the
   section's transparent background for the split second before the class
   lands. */
.tree:fullscreen { background: var(--bg); }
.tree:-webkit-full-screen { background: var(--bg); }
.tree::backdrop { background: var(--bg); }

/* Fallback scroll lock. Fixing the body is the only thing iOS Safari honours;
   the offset keeps the page where the reader left it. */
body.scroll-locked {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overflow: hidden;
}

#svg { width: 100%; height: 100%; display: block; }

.empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  margin: 0;
  color: var(--ink-faint);
  font-size: .95rem;
  pointer-events: none;
}
.empty[hidden], .roster-grid li[hidden] { display: none; }

/* tree links */

.link { fill: none; stroke: var(--rule-bright); stroke-width: 1.6; }
.link-liaison { stroke-dasharray: 5 4; }
.link-alleged { stroke: #8a6a3b; stroke-dasharray: 2 5; stroke-linecap: round; }
.link.dim { opacity: .18; }

/* tree nodes */

.node { cursor: pointer; }
.node .plate { fill: var(--bg-raised); stroke: var(--rule-bright); stroke-width: 1; }
.node .mono { fill: var(--ink-faint); font-size: 30px; font-weight: 600; text-anchor: middle; letter-spacing: .06em; }
.node .mono-bg { fill: #241e19; }
.node .stripe { stroke-width: 3; }
.node .band { fill: rgba(10, 8, 7, .82); }
.node .nm { fill: var(--ink); font-size: 13.5px; text-anchor: middle; }
.node .nm2 { fill: var(--ink-dim); font-size: 11.5px; text-anchor: middle; }
.node .pip { stroke: #14110f; stroke-width: 1.5; }
.node .frame { fill: none; stroke: transparent; stroke-width: 2; }

.node:hover .frame, .node:focus-visible .frame { stroke: var(--focus); }
.node:focus { outline: none; }
.node:focus-visible .plate { stroke: var(--focus); }

.node.dim { opacity: .17; }
.node.dim .frame { stroke: transparent; }
.node.hit .plate { stroke: var(--focus); stroke-width: 1.8; }

.hint {
  max-width: 90rem;
  margin: .75rem auto 0;
  font-size: .82rem;
  color: var(--ink-faint);
}

kbd {
  font: inherit;
  font-size: .78rem;
  border: 1px solid var(--rule-bright);
  border-bottom-width: 2px;
  border-radius: 3px;
  padding: 0 .3rem;
  color: var(--ink-dim);
}

.legend {
  max-width: 90rem;
  margin: 1rem auto 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: .4rem 1.4rem;
  font-size: .78rem;
  color: var(--ink-faint);
}
.legend li { display: flex; align-items: center; gap: .45rem; }
.legend .swatch { width: 1.4rem; height: 0; border-top: 2px solid currentColor; }
.legend .swatch.pip { width: .6rem; height: .6rem; border: 0; border-radius: 50%; background: currentColor; }

/* ── roster ───────────────────────────────────────────────────────────── */

.roster, .season { padding: 3rem clamp(1rem, 4vw, 3rem) 0; }
.roster > *, .season > * { max-width: 90rem; margin-inline: auto; }

.roster h2, .season h2 { font-size: 1.4rem; }
.section-note { color: var(--ink-dim); max-width: 46rem; margin: 0 0 1.5rem; font-size: .95rem; }

.roster-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: .75rem;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}

.card {
  display: flex;
  gap: .8rem;
  width: 100%;
  text-align: left;
  padding: .6rem;
  background: var(--bg-raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.card:hover { border-color: var(--rule-bright); }
.card img {
  width: 54px; height: 72px; flex: none;
  object-fit: cover;
  border-radius: 2px;
  background: #241e19;
  border-left: 3px solid var(--swatch, var(--rule-bright));
}
.card .card-name { display: block; font-size: .98rem; }
.card .card-meta { display: block; font-size: .78rem; color: var(--ink-dim); margin-top: .15rem; }
.card .card-status { display: inline-flex; align-items: center; gap: .35rem; font-size: .74rem; color: var(--ink-faint); margin-top: .3rem; }
.card .card-status::before { content: ""; width: .5rem; height: .5rem; border-radius: 50%; background: var(--pip, var(--ink-faint)); }
.card[hidden] { display: none; }

.roster .empty { position: static; padding: 2.5rem 0; text-align: center; }

/* ── season list ──────────────────────────────────────────────────────── */

.episodes { list-style: none; counter-reset: ep; padding: 0; margin: 0; display: grid; gap: .6rem; }
.episodes li {
  counter-increment: ep;
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  gap: .8rem;
  padding: .75rem .9rem;
  background: var(--bg-raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
.episodes li::before {
  content: counter(ep);
  font-size: 1.2rem;
  color: var(--ink-faint);
  text-align: center;
}
.episodes .ep-title { font-size: 1rem; }
.episodes .ep-beats { font-size: .86rem; color: var(--ink-dim); margin: .2rem 0 0; }

/* ── colophon ─────────────────────────────────────────────────────────── */

.colophon {
  margin: 4rem auto 0;
  max-width: 90rem;
  padding: 2.5rem clamp(1rem, 4vw, 3rem) 0;
  border-top: 1px solid var(--rule);
  display: grid;
  gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  font-size: .88rem;
  color: var(--ink-dim);
}
.colophon h2 { font-size: .72rem; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-faint); }
.colophon ul { padding-left: 1.1rem; margin: 0; }
.colophon li { margin-bottom: .5rem; }
.colophon .fine { color: var(--ink-faint); font-size: .8rem; }

/* A dropped script would otherwise leave a page that looks fine and does
 * nothing. The loader in index.html unhides this instead. */
.boot-error {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  transform: translateX(-50%);
  z-index: 60;
  margin: 0;
  max-width: min(34rem, calc(100vw - 2rem));
  padding: .75rem 1.1rem;
  border: 1px solid #7d2c2c;
  border-radius: .4rem;
  background: #24100f;
  color: #f0d6d2;
  font-size: .9rem;
  box-shadow: 0 .6rem 1.6rem rgba(0, 0, 0, .55);
}
.boot-error[hidden] { display: none; }

/* ── profile dialog ───────────────────────────────────────────────────── */

.profile {
  width: min(46rem, calc(100vw - 2rem));
  max-height: min(88svh, 52rem);
  padding: 0;
  border: 1px solid var(--rule-bright);
  border-radius: var(--radius);
  background: var(--bg-raised);
  color: var(--ink);
  box-shadow: var(--shadow);
  overflow: visible;
}
.profile::backdrop { background: rgba(6, 5, 4, .78); backdrop-filter: blur(3px); }

.profile-close { position: absolute; top: .4rem; right: .4rem; margin: 0; z-index: 2; }
.profile-close button {
  width: 2.2rem; height: 2.2rem;
  background: rgba(10, 8, 7, .7);
  border: 1px solid var(--rule-bright);
  border-radius: var(--radius);
  color: var(--ink);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
}

.profile-body { overflow-y: auto; max-height: min(88svh, 52rem); border-radius: inherit; }

.p-head { display: grid; grid-template-columns: 11rem 1fr; gap: 1.5rem; padding: 1.5rem; border-bottom: 1px solid var(--rule); }
/* Direct child only: this is the big plate down the left of the panel, and
   the head also contains a house badge whose small round sigil a descendant
   selector would blow up to portrait size. */
.p-head > img { width: 11rem; height: 14.7rem; object-fit: cover; border-radius: 2px; background: #241e19; border-left: 4px solid var(--swatch); }
.p-title { min-width: 0; }
.p-title h2 { font-size: clamp(1.5rem, 4vw, 2rem); margin: 0; }
.p-epithet { margin: .2rem 0 0; color: var(--ink-dim); font-style: italic; }
.p-title h2 { margin: 0; }
.p-tags { display: flex; flex-wrap: wrap; gap: .35rem; margin: .9rem 0 0; padding: 0; list-style: none; }
.p-tags li {
  font-size: .74rem; letter-spacing: .05em; text-transform: uppercase;
  border: 1px solid var(--rule-bright); border-radius: 999px; padding: .2rem .6rem; color: var(--ink-dim);
}
.p-tags li.side { border-color: var(--swatch); color: var(--ink); }
.p-status { margin: .9rem 0 0; font-size: .9rem; display: flex; gap: .5rem; align-items: baseline; }
.p-status .pip { width: .55rem; height: .55rem; border-radius: 50%; background: var(--pip); flex: none; translate: 0 -.1rem; }

.p-section { padding: 1.25rem 1.5rem; border-bottom: 1px solid var(--rule); }
.p-section:last-child { border-bottom: 0; }
.p-section h3 { font-size: .7rem; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: .5rem; }
.p-section p { margin: 0 0 .7rem; }
.p-section p:last-child { margin-bottom: 0; }

.p-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: .9rem 1.2rem; margin: 1rem 0 0; }
.p-facts > div { min-width: 0; }
.p-facts dt { font-size: .68rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); }
.p-facts dd { margin: .2rem 0 0; font-size: .92rem; }

.rel-group { margin-bottom: .8rem; }
.rel-group:last-child { margin-bottom: 0; }
.rel-label { font-size: .68rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); display: block; margin-bottom: .35rem; }
.rel-list { display: flex; flex-wrap: wrap; gap: .35rem; list-style: none; padding: 0; margin: 0; }
.rel-list li { display: inline-flex; align-items: center; gap: .3rem; }
.rel {
  background: var(--bg-sunk);
  border: 1px solid var(--rule-bright);
  border-radius: 999px;
  color: var(--ink);
  font: inherit;
  font-size: .84rem;
  padding: .25rem .75rem;
  cursor: pointer;
}
.rel:hover { border-color: var(--focus); }
.rel .rel-note { color: var(--ink-faint); font-size: .76rem; }
.rel[disabled] { cursor: default; opacity: .55; }

.p-sources { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: .35rem; }
.p-sources li {
  font-size: .76rem; color: var(--ink-dim);
  border: 1px dashed var(--rule-bright); border-radius: var(--radius); padding: .18rem .5rem;
}

.p-offscreen {
  margin: .9rem 0 0;
  font-size: .84rem;
  color: var(--ink-faint);
  border-left: 2px solid var(--rule-bright);
  padding-left: .7rem;
}

/* Portrait that failed to decode: a plate with initials, never a broken icon. */
.mono-fallback {
  display: grid;
  place-items: center;
  flex: none;
  background: #241e19;
  color: var(--ink-faint);
  letter-spacing: .06em;
  border-radius: 2px;
}
.card .mono-fallback { width: 54px; height: 72px; font-size: 1.1rem; border-left: 3px solid var(--swatch, var(--rule-bright)); }
.p-head .mono-fallback { width: 11rem; height: 14.7rem; font-size: 2.6rem; border-left: 4px solid var(--swatch); }

.rel i { width: .45rem; height: .45rem; border-radius: 50%; display: inline-block; margin-right: .4rem; translate: 0 -.06rem; }
.rel-note-block { font-size: .84rem; color: var(--ink-faint); margin: .8rem 0 0; border-left: 2px solid var(--rule-bright); padding-left: .7rem; }
.side-for { color: var(--ink-faint); }

/* ── section jump links ───────────────────────────────────────────────── */

.jump {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .4rem;
  margin: 1.4rem 0 0;
}
.jump a {
  text-decoration: none;
  font-size: .78rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-dim);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: .38rem .85rem;
}
.jump a:hover, .jump a:focus-visible { color: var(--ink); border-color: var(--focus); }

/* ── houses and dragons ───────────────────────────────────────────────── */

.houses, .dragons, .realm { padding: 3rem clamp(1rem, 4vw, 3rem) 0; }
.houses > *, .dragons > *, .realm > * { max-width: 90rem; margin-inline: auto; }
.houses h2, .dragons h2, .realm h2 { font-size: 1.4rem; }
.houses .empty, .dragons .empty { position: static; padding: 2.5rem 0; text-align: center; }
.house-grid li[hidden], .dragon-grid li[hidden] { display: none; }

.house-grid {
  list-style: none; padding: 0; margin: 1.25rem 0 0;
  display: grid; gap: .75rem;
  grid-template-columns: repeat(auto-fill, minmax(13.5rem, 1fr));
}

.house-card {
  position: relative;
  width: 100%;
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  align-items: center;
  gap: .85rem;
  text-align: left;
  background: var(--bg-raised);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--side, var(--rule-bright));
  border-radius: var(--radius);
  color: inherit;
  font: inherit;
  padding: .7rem;
  cursor: pointer;
}
.house-card:hover { border-color: var(--rule-bright); border-left-color: var(--side, var(--rule-bright)); }
.house-sigil {
  width: 4.5rem; height: 4.5rem; object-fit: cover;
  border-radius: 2px; background: #241e19; display: block;
}
.house-text { min-width: 0; }
.house-name { display: block; font-size: 1rem; }
.house-seat { display: block; font-size: .78rem; color: var(--ink-dim); margin-top: .15rem; }
.house-side { display: block; font-size: .72rem; color: var(--side, var(--ink-faint)); margin-top: .25rem; }
.house-flag {
  position: absolute; right: .45rem; bottom: .4rem;
  font-size: .6rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-faint); border: 1px dashed var(--rule-bright);
  border-radius: 999px; padding: .1rem .4rem;
}

/* Same shape and rhythm as a house card: a square of art on the left, the
 * facts on the right. A dragon used to get a wide plate above its name, which
 * made one dragon three times the height of one lord for no extra information. */
.dragon-grid {
  list-style: none; padding: 0; margin: 1.25rem 0 0;
  display: grid; gap: .75rem;
  grid-template-columns: repeat(auto-fill, minmax(13.5rem, 1fr));
}

.dragon-card {
  position: relative;
  width: 100%;
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  align-items: center;
  gap: .85rem;
  text-align: left;
  background: var(--bg-raised);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--hue, var(--rule-bright));
  border-radius: var(--radius);
  color: inherit;
  font: inherit;
  padding: .7rem;
  cursor: pointer;
}
.dragon-card:hover { border-color: var(--rule-bright); border-left-color: var(--hue, var(--rule-bright)); }
.dragon-plate {
  width: 4.5rem; height: 4.5rem; object-fit: cover;
  border-radius: 2px; background: #241e19; display: block;
}
.dragon-text { display: block; min-width: 0; }
.dragon-name { display: block; font-size: 1rem; }
.dragon-epithet {
  display: block; font-size: .74rem; font-style: italic; color: var(--ink-dim);
  margin-top: .1rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dragon-rider { display: block; font-size: .78rem; color: var(--ink-dim); margin-top: .2rem; }
.dragon-status { display: inline-flex; align-items: center; gap: .35rem; font-size: .72rem; color: var(--ink-faint); margin-top: .2rem; }
.dragon-status i { width: .5rem; height: .5rem; border-radius: 50%; display: inline-block; }
.dragon-card .house-flag { right: .45rem; bottom: .4rem; }

/* Art that never decoded reads as an empty plate, never a broken-image icon. */
.art-missing {
  background:
    repeating-linear-gradient(45deg, #221c18 0 6px, #1c1714 6px 12px);
  object-fit: cover;
}

/* ── the map and the episode player ───────────────────────────────────── */

.player {
  margin: 1.25rem 0 1rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: linear-gradient(180deg, #1f1a16 0%, var(--bg-raised) 100%);
  box-shadow: inset 0 1px 0 rgba(233, 224, 205, .05);
  padding: .8rem .9rem;
}
.player-bar { display: flex; align-items: center; gap: .45rem; }
.player-bar button {
  height: 2.1rem; min-width: 2.1rem; padding: 0 .55rem;
  background: var(--bg-sunk); border: 1px solid var(--rule-bright);
  color: var(--ink); border-radius: var(--radius);
  font: inherit; font-size: .85rem; cursor: pointer;
  transition: border-color .2s, color .2s, background .2s;
}
.player-bar button:hover { border-color: var(--focus); color: var(--focus); background: #17130f; }
.player-bar button.wide { padding: 0 .75rem; font-size: .8rem; }
.player-bar .play { min-width: 4.6rem; font-size: .82rem; letter-spacing: .08em; text-transform: uppercase; }
.player-bar .play.playing { border-color: var(--focus); color: var(--focus); }

/* The slider is the spine of the section, so it gets a real track and thumb
 * rather than the accent-color default, which renders differently in every
 * browser and reads as a form control. */
#ep-range {
  flex: 1 1 auto; min-width: 4rem; height: 2.1rem;
  appearance: none; -webkit-appearance: none;
  background: transparent; cursor: pointer;
}
#ep-range::-webkit-slider-runnable-track {
  height: 4px; border-radius: 2px;
  background: linear-gradient(90deg, #4c4137 0%, #2b2521 100%);
}
#ep-range::-moz-range-track { height: 4px; border-radius: 2px; background: #3a322b; }
#ep-range::-moz-range-progress { height: 4px; border-radius: 2px; background: var(--focus); }
#ep-range::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none;
  width: 15px; height: 15px; margin-top: -5.5px; border-radius: 50%;
  background: var(--focus); border: 2px solid #17130f;
  box-shadow: 0 0 0 1px rgba(230, 185, 92, .45), 0 2px 5px rgba(0, 0, 0, .55);
}
#ep-range::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--focus); border: 2px solid #17130f;
}
#ep-range:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }

.ep-now { margin: .75rem 0 0; font-size: .9rem; }
.ep-now .ep-key {
  font-size: .72rem; letter-spacing: .12em; color: var(--focus);
  border: 1px solid var(--rule-bright); border-radius: 999px; padding: .1rem .45rem;
}
.ep-now .ep-title { font-size: 1rem; letter-spacing: .01em; }
.ep-now .ep-summary { display: block; color: var(--ink-dim); font-size: .86rem; margin-top: .3rem; }

.realm-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: minmax(0, 1.55fr) minmax(17rem, 1fr);
  align-items: start;
}

/* The painted plate runs from near-black water to lit parchment, so everything
 * drawn over it carries its own dark seat or halo. Nothing here relies on the
 * plate being any one brightness. */
.atlas {
  position: relative;
  height: min(74svh, 44rem);
  background: #090d10;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
  touch-action: none;
  overscroll-behavior: contain;
  cursor: grab;
}
.atlas.dragging { cursor: grabbing; }
#atlas-svg { width: 100%; height: 100%; display: block; touch-action: none; }
#atlas-svg:focus { outline: none; }
.atlas.gliding #atlas-viewport { transition: transform .6s cubic-bezier(.3, .7, .3, 1); }

.map-base { opacity: 0; transition: opacity .5s ease-out; }
.atlas.base-ready .map-base { opacity: 1; }

/* The flat land the plate replaced. Only shown when the plate never arrives. */
.base-fallback { display: none; }
.atlas.no-base .base-fallback { display: block; }
.sea-shelf { fill: none; stroke: #1a2830; stroke-width: 14; stroke-linejoin: round; }
.land { fill: #241f1a; }
.islet { stroke: #6b5a45; stroke-width: 1.2; }

/* Drawn in screen units so the coast stays a hairline of ink at every zoom
 * instead of thickening into a band. */
.coast {
  fill: none; stroke: #d8bd92; stroke-width: .9; stroke-linejoin: round;
  vector-effect: non-scaling-stroke; opacity: .34;
}
.atlas.no-base .coast { opacity: .8; }

.feature-wall path { fill: none; stroke-linecap: round; pointer-events: none; }
.wall-base { stroke: #0b1418; stroke-width: 8; opacity: .75; }
.wall-face { stroke: #9fc4d2; stroke-width: 3.4; opacity: .72; }
.wall-crest { stroke: #e4f2f7; stroke-width: 1.2; stroke-dasharray: 2.5 3.5; opacity: .78; }

/* Sea names sit on the darkest part of the plate, which is where a thin italic
 * face is easiest to lose. The halo does the work: it is wide enough to clear
 * the ink wash under every letter, so the fill can stay cool rather than going
 * white to be read. tools/verify.py measures this. */
.sea-label {
  fill: #a9cbda; font-size: 15px; font-style: italic;
  letter-spacing: .22em; text-transform: uppercase;
  paint-order: stroke; stroke: #04070a; stroke-width: 4.2; stroke-linejoin: round;
  opacity: .92; pointer-events: none;
}
.region-label {
  fill: #f0dcb4; font-size: 12.5px; font-weight: 600;
  letter-spacing: .26em; text-transform: uppercase;
  paint-order: stroke; stroke: #120d08; stroke-width: 3.8; stroke-linejoin: round;
  opacity: .88; pointer-events: none;
}

.place { cursor: pointer; }
.place:focus { outline: none; }
.place .mk-seat { fill: #0d0b09; opacity: .62; transition: opacity .25s; }
.place .mk {
  fill: #e2cfae; stroke: #100d0a; stroke-width: .9; stroke-linejoin: round;
  transition: fill .25s;
}
.place .mk-hollow { fill: none; stroke: #e2cfae; stroke-width: 1.7; }
.place .mk-ring { fill: none; stroke: #e2cfae; stroke-width: 1.1; opacity: .55; }
.place .place-label {
  fill: #e8dcc4; font-size: 11px; font-weight: 500; letter-spacing: .05em;
  paint-order: stroke; stroke: #0c0a08; stroke-width: 3.6; stroke-linejoin: round;
  pointer-events: none; transition: fill .25s;
}
.place .pulse { fill: none; stroke: var(--focus); stroke-width: 0; opacity: 0; }
.place:hover .mk-seat, .place:focus-visible .mk-seat, .place.active .mk-seat { opacity: .88; }
.place:hover .mk, .place:focus-visible .mk { fill: var(--focus); }
.place:hover .mk-hollow, .place:focus-visible .mk-hollow { fill: none; stroke: var(--focus); }
.place:hover .place-label, .place:focus-visible .place-label { fill: #fff4dc; }
.place:focus-visible .pulse { stroke-width: 2; opacity: 1; }

.place.active .mk { fill: var(--focus); }
.place.active .mk-hollow { fill: none; stroke: var(--focus); }
.place.active .place-label { fill: #fff4dc; }
.place.hit-battle .mk, .place.hit-battle .mk-hollow { fill: #e0714f; stroke-width: .9; }
.place.hit-death .mk, .place.hit-death .mk-hollow { fill: var(--black-side); }
.place.hit-dragon .mk, .place.hit-dragon .mk-hollow { fill: #f0a24a; }
.place.active .pulse { stroke-width: 1.6; opacity: .9; animation: place-pulse 1.8s ease-out infinite; }

@keyframes place-pulse {
  from { r: 8; opacity: .75; }
  to   { r: 22; opacity: 0; }
}

/* The route before the line reaches it, so a long flight has somewhere to go. */
.arc-track {
  fill: none; stroke: currentColor; stroke-width: 1; stroke-linecap: round;
  stroke-dasharray: 3 5; opacity: .2; color: var(--focus);
}
.arc {
  fill: none; stroke: var(--focus); stroke-width: 2.1; stroke-linecap: round;
  stroke-dasharray: 1 1; stroke-dashoffset: 1;
  transition: stroke-dashoffset 1.4s cubic-bezier(.32, 0, .18, 1);
  opacity: .9;
}
.arc.arc-drawn { stroke-dashoffset: 0; }
.arc-tip { fill: var(--focus); opacity: .9; }
.arc-head {
  opacity: 0;
  transition: opacity .3s ease-out;
  filter: drop-shadow(0 0 4px rgba(230, 185, 92, .85));
}
.arc-head .head-glyph { fill: #fff3d8; stroke: none; }
.arc-head.flying { opacity: 1; }

.arc-battle, .arc-battle.arc-track { stroke: #e0714f; color: #e0714f; }
.arc-death, .arc-death.arc-track { stroke: var(--black-side); color: var(--black-side); }
.arc-dragon, .arc-dragon.arc-track { stroke: #f0a24a; color: #f0a24a; }
circle.arc-battle { fill: #e0714f; stroke: none; }
circle.arc-death { fill: var(--black-side); stroke: none; }
circle.arc-dragon { fill: #f0a24a; stroke: none; }

/* How a route is travelled, told by the line as well as by the mark that runs
 * along it. Boots leave a short broken trail, a fleet leaves a long wake, a
 * dragon leaves an unbroken line, riders leave dash and dot. The dash lengths
 * are on the track, because the line itself uses its dash array to draw on. */
.arc-track.mode-march { stroke-dasharray: 2 4; }
.arc-track.mode-fleet { stroke-dasharray: 11 6; opacity: .26; }
.arc-track.mode-flight { stroke-dasharray: none; opacity: .16; }
.arc-track.mode-ride { stroke-dasharray: 7 4 1.5 4; }

.arc.mode-march { stroke-width: 2.6; transition-duration: 2.4s; }
.arc.mode-fleet { stroke-width: 2.2; transition-duration: 2s; }
.arc.mode-flight { stroke-width: 1.8; transition-duration: 1.1s; }
.arc.mode-ride { stroke-width: 2; transition-duration: 1.6s; }

.arc.mode-march { stroke: #d8b06a; }
.arc-track.mode-march { color: #d8b06a; }
.arc.mode-fleet { stroke: #7fb3c8; }
.arc-track.mode-fleet { color: #7fb3c8; }
.arc.mode-flight { stroke: #f0a24a; }
.arc-track.mode-flight { color: #f0a24a; }
.arc.mode-ride { stroke: #c8b79a; }
.arc-track.mode-ride { color: #c8b79a; }
circle.arc-tip.mode-march { fill: #d8b06a; }
circle.arc-tip.mode-fleet { fill: #7fb3c8; }
circle.arc-tip.mode-flight { fill: #f0a24a; }
circle.arc-tip.mode-ride { fill: #c8b79a; }
.arc-head.mode-fleet .head-glyph { fill: #dff0f8; }
.arc-head.mode-flight .head-glyph { fill: #ffd9a2; }

/* A battle or a death gets a mark of its own. A pin that only changes colour
 * is not readable on a phone held at arm's length. */
.map-mark { pointer-events: none; }
.map-mark .mark-ink { fill: none; stroke-width: 2.2; stroke-linecap: round; }
.map-mark .mark-ring { fill: none; stroke-width: 1.1; opacity: .55; }
.mark-battle .mark-ink, .mark-battle .mark-ring { stroke: #ff8a63; }
.mark-death .mark-ink, .mark-death .mark-ring { stroke: #ff5f74; }
.map-mark { animation: mark-in .45s ease-out both; }
@keyframes mark-in {
  from { opacity: 0; transform-box: fill-box; }
  to { opacity: 1; }
}

/* The key. Sits bottom right, over the sea names, which is the one part of the
 * chart nobody needs to read twice. */
.map-key {
  position: absolute; right: .55rem; bottom: .5rem; margin: 0;
  list-style: none; padding: .45rem .6rem;
  display: grid; gap: .18rem;
  border: 1px solid var(--rule-bright); border-radius: var(--radius);
  background: rgba(9, 13, 16, .82);
  backdrop-filter: blur(6px);
  font-size: .68rem; line-height: 1.35; color: var(--ink-dim);
  max-width: 12rem; pointer-events: none;
}
.map-key li { display: grid; grid-template-columns: 1.35rem 1fr; align-items: center; gap: .3rem; }
.key-art { width: 1.35rem; height: 1.35rem; overflow: visible; }
.key-line { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.key-line.mode-march { color: #d8b06a; stroke-dasharray: 3 3; }
.key-line.mode-fleet { color: #7fb3c8; stroke-dasharray: 8 4; }
.key-line.mode-flight { color: #f0a24a; }
.key-line.mode-ride { color: #c8b79a; stroke-dasharray: 6 3 1.5 3; }
.key-head path { fill: #fff3d8; }
.key-head.mode-fleet path { fill: #dff0f8; }
.key-head.mode-flight path { fill: #ffd9a2; }
.key-pin circle { fill: var(--focus); }
.key-pin .key-pin-ring { fill: none; stroke: var(--focus); stroke-width: 1.4; opacity: .6; }

.atlas-zoom { position: absolute; right: .5rem; top: .5rem; display: flex; gap: .3rem; }
.atlas-zoom button {
  width: 2rem; height: 2rem; padding: 0;
  background: rgba(10, 13, 16, .88); border: 1px solid var(--rule-bright);
  color: var(--ink); border-radius: var(--radius); font: inherit; cursor: pointer;
  backdrop-filter: blur(6px);
  transition: border-color .2s, color .2s;
}
.atlas-zoom button.wide { width: auto; padding: 0 .6rem; font-size: .8rem; }
.atlas-zoom button:hover { border-color: var(--focus); color: var(--focus); }
/* ── the beat list ────────────────────────────────────────────────────── */

.beats h3 { font-size: .7rem; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-faint); }
.beats { max-height: min(74svh, 44rem); overflow-y: auto; padding-right: .3rem; }

.beat-list { list-style: none; padding: 0; margin: 0; display: grid; gap: .55rem; }
.beat {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--rule-bright);
  border-radius: var(--radius);
  background: var(--bg-raised);
  padding: .6rem .7rem;
}
.beat-battle { border-left-color: #d05a3c; }
.beat-death { border-left-color: var(--black-side); }
.beat-dragon { border-left-color: #e0913f; }
.beat-arrival, .beat-move { border-left-color: var(--focus); }
.beat-political { border-left-color: #6a7fa0; }

.beat-head { margin: 0 0 .3rem; display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; }
.beat-kind { font-size: .64rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); font-style: normal; }
.beat-arrow { color: var(--ink-faint); }
.beat-place {
  background: none; border: 0; padding: 0; margin: 0;
  color: var(--ink); font: inherit; font-size: .84rem;
  border-bottom: 1px dotted var(--rule-bright); cursor: pointer;
}
.beat-place:hover { color: var(--focus); border-bottom-color: var(--focus); }
.beat-text { margin: 0; font-size: .88rem; color: var(--ink); }
.beat-who { margin: .45rem 0 0; display: flex; flex-wrap: wrap; gap: .3rem; }

.beat-list-inline { gap: .4rem; }
.beat-list-inline li {
  display: flex; gap: .5rem; align-items: baseline;
  font-size: .88rem; color: var(--ink-dim);
}

.ep-chip {
  flex: none;
  background: var(--bg-sunk); border: 1px solid var(--rule-bright);
  color: var(--focus); border-radius: 999px;
  font: inherit; font-size: .68rem; letter-spacing: .08em;
  padding: .1rem .45rem; cursor: pointer;
}
.ep-chip:hover { border-color: var(--focus); }

.rel-sm { font-size: .76rem; padding: .15rem .45rem; }
.rel-dragon { border-color: var(--hue, var(--rule-bright)); color: var(--ink); }
.rel-flat { cursor: default; }

/* ── house, dragon and place panels ───────────────────────────────────── */

.p-head-house, .p-head-dragon { grid-template-columns: 11rem 1fr; }
.p-head-house .p-sigil { width: 11rem; height: 11rem; border-left: 0; border-top: 4px solid var(--rule-bright); }
.p-head-dragon .p-plate { width: 11rem; height: 7.35rem; border-left: 0; border-top: 4px solid var(--hue, var(--rule-bright)); }
.p-head-place { grid-template-columns: 1fr; }

.house-badge {
  display: inline-flex; align-items: center; gap: .5rem;
  margin: 1rem 0 0; padding: .3rem .7rem .3rem .3rem;
  background: var(--bg-sunk); border: 1px solid var(--rule-bright);
  border-radius: 999px; color: var(--ink); font: inherit; font-size: .82rem; cursor: pointer;
}
.house-badge:hover { border-color: var(--focus); }
.house-badge-art { width: 1.9rem; height: 1.9rem; border-radius: 50%; object-fit: cover; background: #241e19; }

.p-dragon-list { list-style: none; padding: 0; margin: 0; display: grid; gap: .6rem; }
.p-dragon {
  width: 100%; display: grid; grid-template-columns: 8rem 1fr; gap: .8rem; align-items: center;
  text-align: left; background: var(--bg-sunk);
  border: 1px solid var(--rule); border-left: 3px solid var(--hue, var(--rule-bright));
  border-radius: var(--radius); color: inherit; font: inherit; padding: .5rem; cursor: pointer;
}
.p-dragon:hover { border-color: var(--hue, var(--focus)); }
.p-dragon-art { width: 8rem; height: 5.35rem; object-fit: cover; border-radius: 2px; background: #241e19; }
.p-dragon-name { display: block; font-size: 1rem; }
.p-dragon-meta { display: block; font-size: .74rem; color: var(--ink-faint); margin-top: .1rem; }
.p-dragon-note { display: block; font-size: .8rem; color: var(--ink-dim); margin-top: .3rem; }

.rider-list { list-style: none; padding: 0; margin: 0; display: grid; gap: .5rem; }
.rider-list li { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.rider-kind { font-size: .64rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); flex: none; }
.rider-note { font-size: .82rem; color: var(--ink-dim); flex-basis: 100%; }

.p-uncertain {
  margin: 0; padding: 1rem 1.5rem; font-size: .86rem; color: var(--ink-dim);
  background: rgba(224, 145, 63, .08); border-bottom: 1px solid var(--rule);
}
.p-uncertain strong { color: var(--focus); font-weight: 600; }
.fine { color: var(--ink-faint); font-size: .8rem; }

/* ── responsive ───────────────────────────────────────────────────────── */

@media (max-width: 760px) {
  body { font-size: 15px; }
  /* The tree is the working surface on a phone. Let it reach both viewport edges. */
  .tree { padding: 2rem 0 0; }
  .tree-head, .tree > .hint, .tree > .legend { margin-left: 1rem; margin-right: 1rem; }
  .canvas { border-left: 0; border-right: 0; border-radius: 0; }
  .masthead { padding: 2.25rem 1.25rem 1.25rem; }
  .lede { font-size: .95rem; }
  .cutoff { margin-top: 1.1rem; }
  .controls { position: static; gap: .9rem 1.25rem; }
  .control-search { max-width: none; flex-basis: 100%; }
  .canvas { height: 62svh; }
  .tree-head { align-items: center; }
  .p-head { grid-template-columns: 1fr; gap: 1rem; }
  .p-head > img, .p-head .mono-fallback { width: 8.25rem; height: 11rem; font-size: 2rem; }
  .profile {
    width: 100vw;
    max-width: 100vw;
    max-height: 92svh;
    margin: auto 0 0;
    border-radius: var(--radius) var(--radius) 0 0;
    border-bottom: 0;
  }
  .profile-body { max-height: 92svh; }

  /* The map is the working surface here too, so it also reaches both edges. */
  .realm { padding-left: 0; padding-right: 0; }
  .realm > h2, .realm > .section-note, .realm > .player, .realm > .hint { margin-left: 1rem; margin-right: 1rem; }
  .realm-grid { grid-template-columns: 1fr; gap: .75rem; }
  .atlas { height: 62svh; border-left: 0; border-right: 0; border-radius: 0; }
  /* The key gives up its labels on a phone rather than eating the chart. */
  .map-key { max-width: 8.5rem; font-size: .62rem; padding: .35rem .45rem; gap: .1rem; }
  .map-key li { grid-template-columns: 1.1rem 1fr; }
  .key-art { width: 1.1rem; height: 1.1rem; }
  .beats { max-height: none; overflow: visible; margin-left: 1rem; margin-right: 1rem; }
  .player-bar { flex-wrap: wrap; }
  #ep-range { order: 3; flex-basis: 100%; }
  .house-grid { grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr)); }
  .dragon-grid { grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr)); }
  .p-head-house, .p-head-dragon { grid-template-columns: 1fr; }
  .p-head-house .p-sigil { width: 8.25rem; height: 8.25rem; }
  .p-head-dragon .p-plate { width: 11rem; height: 7.35rem; }
  .p-dragon { grid-template-columns: 6.5rem 1fr; }
  .p-dragon-art { width: 6.5rem; height: 4.35rem; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  /* A .01ms infinite pulse is a repaint loop, not a stilled animation. */
  .place.active .pulse { animation: none !important; opacity: .55; }
  .atlas.gliding #atlas-viewport { transition: none; }
  /* atlas.js already skips the flying head here; this covers the plate fade. */
  .map-base { transition: none; }
}
