:root {
  color-scheme: light;
  --paper: #ffffff;
  --ink: #16171a;
  --dim: #6b6e77;
  --rule: #e6e4de;
  --grid: #efeee9;
  --band: #faf9f6;
  --link: #1c5f8b;
  --mention-time: #935409;
  --quote: #d9b26a;
  --dot-ring: #ffffff;
  --mark: #fdf1d3;
}

/* Dark is a real theme rather than an inversion: the hairlines and 10px type
 * that make the chart readable need their own contrast, not a filter. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --paper: #14151a;
  --ink: #e9e7e2;
  --dim: #9a9ba4;
  --rule: #2b2d35;
  --grid: #21232a;
  --band: #191b21;
  --link: #79b8d1;
  --mention-time: #e6ba74;
  --quote: #b98f3e;
  --dot-ring: #14151a;
  --mark: #2c2717;
}

* { box-sizing: border-box; }
html { background: var(--paper); }
body {
  margin: 0; color: var(--ink);
  font: 15px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}
/* Behind every page, very faint: a Doré engraving for Paradise Lost, traced
 * to vector shapes in five greys (bg.svg).
 * A fixed layer rather than background-attachment: fixed, which iOS Safari
 * ignores and so stretches over the whole page. `cover` fills the window and
 * never distorts. The url's ?v= is stamped by `thefallen build`. */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: url(bg.svg?v=176e906eb3) center / cover no-repeat; opacity: .08;
}
:root[data-theme="dark"] body::before { opacity: .06; filter: invert(1); }

header { padding: 1.3rem 1.6rem 1rem; border-bottom: 1px solid var(--rule); }
h1 { margin: 0 0 .3rem; font-size: 1.45rem; letter-spacing: -.01em; font-weight: 650; }
/* The title is lettered in Aktura, outlined to a path (no font to load); its
 * box is the letters' own, so the height is that of the tallest stroke. */
h1 .title-mark { display: block; height: 2.1rem; width: auto; max-width: 100%; margin: .15rem 0 .45rem; }
.lede { margin: 0 0 .55rem; max-width: 66ch; }
.note {
  margin: 0 0 .55rem; max-width: 66ch; color: var(--dim); font-size: .85rem;
  border-left: 3px solid var(--quote); padding-left: .75rem;
}
.note p { margin: 0 0 .45rem; }
.note p:last-child { margin-bottom: 0; }
.corpus { margin: 0; color: var(--dim); font-size: .78rem; }
a { color: var(--link); }

main { display: flex; align-items: flex-start; }
#stage { position: relative; flex: 1; min-width: 0; }
.lane-label { font-variant-numeric: tabular-nums; }
#chart { width: 100%; display: block; cursor: grab; touch-action: pan-y; }
#chart.dragging { cursor: grabbing; }
/* Dragging the timeline pans it, never selects its labels. Scope this to the
 * SVG so hover cards, detail panels and the rest of the page remain selectable. */
#chart, #chart * { -webkit-user-select: none; user-select: none; }
#hint {
  position: sticky; bottom: 0; margin: 0; padding: .4rem 1rem;
  color: var(--dim); font-size: .75rem;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  border-top: 1px solid var(--rule); pointer-events: none;
}

/* ── find a figure ── */
#find { padding: .55rem 1rem .45rem; }
#find-input {
  font: inherit; font-size: .85rem; width: min(22rem, 100%);
  color: var(--ink); background: var(--band);
  border: 1px solid var(--rule); border-radius: 999px; padding: .35rem .8rem;
}
#find-input:focus { outline: 2px solid var(--link); outline-offset: 1px; }
#find-input.missing { border-color: #c0392b; }
/* A found face rings out a few times, then stays selected. */
.face.selected .portrait-ring { stroke-width: 3; }
.face.found .portrait-ring { animation: found-pulse .8s ease-out 3; }
@keyframes found-pulse {
  0% { stroke-width: 3; } 50% { stroke-width: 5.5; stroke-opacity: .55; } 100% { stroke-width: 3; }
}

/* ── chart ── */
.grid line { stroke: var(--grid); }
.axis-band { fill: var(--band); }
.axis-rule { stroke: var(--rule); }
.axis text {
  fill: var(--dim); font-size: 11px; font-variant-numeric: tabular-nums;
}
.lane-total { font-weight: 650; }
.corpus-total { font-size: 9.5px; font-weight: 550; }
/* See-through, so the background shows evenly behind every row, not only
 * between the stripes. */
.band { fill: var(--band); fill-opacity: .55; }
/* The row of the figure last picked, kept after its details close. */
.row-mark { fill: var(--mark); }
.row-mark-edge { fill: var(--quote); }
.lane-label { fill: var(--dim); font-size: 11px; text-anchor: end; }
.lane-gap { stroke-width: 1; opacity: .28; stroke-dasharray: 2 3; }

/* The reserved margin is not another year on the axis. Undated figures have
 * a named entry and hollow/dashed marker; hover gathers their full lineup. */
.undated-rule { stroke: var(--rule); pointer-events: none; }
.undated-column text { fill: var(--dim); font-size: 10px; }
.undated-column .undated-heading { fill: var(--ink); font-size: 11px; font-weight: 650; }
.undated-face .face-dot { fill: var(--paper); stroke: var(--dim); stroke-dasharray: 2 1; }
.undated-face .portrait-ring { stroke: var(--dim); stroke-dasharray: 3 2; }
.undated-face .hidden-count { fill: var(--dim); }
.undated-extra { opacity: 0; pointer-events: none; }
.lane.gathered .undated-extra { opacity: 1; pointer-events: auto; }
/* Only faces leave the dated plot when gathered, never its bars or grid. */
.lane.gathered .dated-faces { clip-path: none; }

/* Lifespan bars blend where they overlap, so two faces alive at once read as
 * a third colour. isolation keeps the blending inside its own lane instead
 * of reaching through to the stripe behind it. The direction differs by
 * theme: on paper the bars multiply and overlaps darken, on a dark ground
 * they screen and overlaps brighten. */
.lane .bars { isolation: isolate; }
.life { mix-blend-mode: multiply; }
:root[data-theme="dark"] .life { mix-blend-mode: screen; }
.face-dot { stroke: var(--dot-ring); stroke-width: 1.5; }
.face-name { font-size: 10.5px; fill: var(--ink); }
.runs-on { font-size: 13px; opacity: .75; }
.hidden-count { font-size: 10px; opacity: .7; font-variant-numeric: tabular-nums; }
.face { cursor: pointer; }
.face:hover .face-name, .face.selected .face-name { font-weight: 700; }
.face:hover .face-dot, .face.selected .face-dot { r: 6; }

/* ── panel ── */
aside {
  width: 21rem; flex: none; border-left: 1px solid var(--rule);
  padding: 1.1rem 1.2rem; position: sticky; top: 0; max-height: 100vh; overflow-y: auto;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
}
aside h2 { margin: 0 0 .2rem; font-size: 1.05rem; }
aside .panel-controls {
  display: flex; justify-content: flex-end; position: sticky; top: -1.1rem;
  background: var(--paper); padding: .35rem 0; margin-bottom: .4rem; z-index: 1;
}
aside .detail-portrait {
  display: block; width: 100%; aspect-ratio: 1; border-radius: 50%; object-fit: cover;
  border: 1px solid var(--rule); margin: 0 0 .8rem;
}
aside h3 { font-size: .85rem; margin: 1.1rem 0 .35rem; }
aside .section-note { color: var(--dim); font-size: .76rem; margin: 0 0 .5rem; }
aside .mentions { font-size: .8rem; }

/* The figure's line as a strip: tap a face to go to it. */
.lineup {
  list-style: none; margin: 0 0 .2rem; padding: .2rem .1rem .45rem;
  display: flex; gap: .35rem; overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
}
.lineup li { flex: none; scroll-snap-align: center; }
.lineup button {
  display: flex; flex-direction: column; align-items: center; width: 4.4rem;
  font: inherit; color: var(--ink); background: none; border: 0; padding: .15rem;
  border-radius: 8px; cursor: pointer;
}
.lineup button:hover { background: var(--band); }
.lineup img, .lineup-dot {
  width: 2.9rem; height: 2.9rem; border-radius: 50%; object-fit: cover;
  border: 2px solid var(--rule);
}
.lineup-dot {
  display: grid; place-items: center; background: var(--band); color: var(--dim);
  font-weight: 650;
}
.lineup button[aria-current] { cursor: default; background: var(--mark); }
.lineup button[aria-current] img, .lineup button[aria-current] .lineup-dot { border-color: var(--quote); }
.lineup-name {
  font-size: .68rem; line-height: 1.2; margin-top: .2rem; text-align: center;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.lineup-year { font-size: .62rem; color: var(--dim); font-variant-numeric: tabular-nums; }

/* top-right actions: the community and tip links, and the theme toggle */
.top-actions {
  position: absolute; top: 1.3rem; right: 1.6rem;
  display: flex; align-items: center; gap: .5rem;
}
.pill {
  font: inherit; font-size: .8rem; color: var(--dim);
  background: var(--band); border: 1px solid var(--rule);
  border-radius: 999px; padding: .3rem .8rem; cursor: pointer;
  text-decoration: none; white-space: nowrap;
}
.pill:hover { color: var(--ink); border-color: var(--dim); }
/* Too narrow to share the title's line: sit above it instead. */
@media (max-width: 600px) {
  .top-actions { position: static; justify-content: flex-end; flex-wrap: wrap; margin-bottom: .6rem; }
}
header { position: relative; }

/* hover card: the videos naming a figure */
#hover {
  position: absolute; z-index: 20; width: 21rem;
  transition: left .18s ease-out;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--rule); border-radius: 6px;
  padding: .7rem .8rem; font-size: .8rem;
  box-shadow: 0 6px 20px rgba(0,0,0,.18);
  /* Never taller than the window: a long video list scrolls inside the card. */
  max-height: calc(100dvh - 16px); overflow-y: auto; overscroll-behavior: contain;
}
/* Hovering, the head stays in view and only the list scrolls. The script caps
 * the card's height so it never covers the row it belongs to. */
#hover:not(.playing) { display: flex; flex-direction: column; overflow: hidden; }
#hover[hidden] { display: none; }
#hover .card-head { display: flow-root; flex: none; }
#hover:not(.playing) .mentions { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
#hover strong { display: block; font-size: .95rem; }
#hover .bio, #panel .bio { color: var(--dim); margin: .15rem 0; overflow-wrap: anywhere; }
#hover .sub, #panel .sub { color: var(--dim); font-size: .76rem; margin-bottom: .5rem; }
.mentions { list-style: none; margin: 0; padding: 0; display: grid; gap: .15rem; }
/* Keep the date with its first timestamp; later times can wrap between links. */
.mentions li a { font-variant-numeric: tabular-nums; white-space: nowrap; text-decoration: none; }
/* Date and time are distinct even inside the first, shared link. Put each
 * underline on its own span so it follows that span's color. */
.mention-date { color: var(--link); text-decoration: underline; }
.mention-time { color: var(--mention-time); text-decoration: underline; }
.mentions li.none { color: var(--dim); font-style: italic; }

/* A video turns this same card into a pinned, scrollable player. It must not
 * vanish when the pointer enters its controls or leaves the row. */
#hover.playing {
  position: fixed; width: min(26rem, calc(100vw - 24px));
  max-height: calc(100dvh - 24px); overflow-y: auto; overscroll-behavior: contain;
  transition: none;
}
#hover.playing img.portrait { display: none; }

/* The pinned player's link back to its face: under the card, over the page,
 * never in the way of a click. Colour comes from the face's own ring. */
#video-tether {
  position: fixed; inset: 0; width: 100vw; height: 100vh;
  z-index: 19; pointer-events: none; overflow: visible;
}
#video-tether .tether-wedge { fill: currentColor; opacity: .1; }
#video-tether .tether-edges {
  fill: none; stroke: currentColor; stroke-width: 6; stroke-linecap: round; opacity: .45;
}
#video-tether .tether-ring { fill: none; stroke: currentColor; stroke-width: 3; opacity: .8; }
#hover .video-controls {
  display: flex; justify-content: space-between; align-items: center; gap: .5rem;
  position: sticky; top: -.7rem; z-index: 1; background: var(--paper);
  padding: .4rem 0; margin-bottom: .35rem;
  cursor: grab; touch-action: none; user-select: none;
}
#hover .close-video, #hover .drag-video, #hover .native-action, #panel .close-panel {
  font: inherit; color: var(--ink); background: var(--band);
  border: 1px solid var(--rule); border-radius: 4px; padding: .25rem .5rem; cursor: pointer;
}
#hover .drag-video { cursor: grab; }
#hover.moving, #hover.moving .video-controls, #hover.moving .drag-video { cursor: grabbing; }
/* Keep native controls from stealing a toolbar drag without interrupting media. */
#hover.moving .native-player { pointer-events: none; }
#hover .video-note { color: var(--dim); margin: .4rem 0 .65rem; }
#hover .video-stage { position: relative; overflow: hidden; }
#hover .native-player { display: block; width: 100%; max-height: 72dvh; background: #000; }
#hover .native-player[hidden] { display: none; }
#hover .native-status { color: var(--dim); font-size: .75rem; margin: .45rem 0; }
#hover .player-shell { position: relative; background: #000; }
#hover .player-shell[hidden] { display: none; }
#hover .player-controls {
  position: absolute; z-index: 3; left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; gap: .4rem; padding: .45rem;
  color: #fff; background: linear-gradient(transparent, rgb(0 0 0 / .9));
}
#hover .player-controls button { color: #fff; background: transparent; border: 0; padding: .25rem; cursor: pointer; }
#hover .player-seek-wrap { position: relative; flex: 1; min-width: 4rem; }
#hover .player-seek { width: 100%; margin: 0; cursor: pointer; }
#hover .player-seek-tip {
  position: absolute; left: 0; bottom: 1.65rem; transform: translateX(-50%);
  padding: .18rem .35rem; color: #fff; background: rgb(0 0 0 / .88);
  border-radius: 3px; font-size: .72rem; pointer-events: none;
}
#hover .player-clock { white-space: nowrap; font-size: .72rem; font-variant-numeric: tabular-nums; }
#hover .player-volume { width: 4.5rem; }
#hover .player-shell:fullscreen .native-player { max-height: 100vh; height: 100vh; object-fit: contain; }
#hover .playback-speed {
  position: absolute; z-index: 2; top: .55rem; right: .55rem;
  display: block; margin: 0; padding: .25rem .4rem;
  color: #fff; background: rgb(0 0 0 / .72); border-radius: 5px;
  font-size: .8rem; font-weight: 650;
}
#hover .playback-speed select {
  font: inherit; color: #fff; background: #181818;
  border: 1px solid rgb(255 255 255 / .55); border-radius: 4px; padding: .2rem .35rem;
}
#hover .native-action { margin: .5rem 0; }
#hover .video-panel:not([data-native-state="active"]) .native-status {
  padding: .75rem; background: var(--band); color: var(--ink);
}
.video-link[aria-current="true"] { font-weight: 700; }

/* The portrait is the point of the card, not a decoration beside it. */
#hover img.portrait {
  width: 7rem; height: 7rem; border-radius: 50%;
  object-fit: cover; float: right; margin: 0 0 .5rem .7rem;
  border: 1px solid var(--rule);
}

.portrait-ring { fill: none; stroke-width: 1.6; }

/* portrait credits */
#credits { padding: 1.4rem 1.6rem; border-top: 1px solid var(--rule); }
#credits summary { font-size: 1rem; color: var(--dim); font-weight: 650; cursor: pointer; width: max-content; max-width: 100%; }
#credits summary:hover { color: var(--ink); }
#credits details[open] summary { margin-bottom: .4rem; }
#credits .credit-note { margin: 0 0 .8rem; color: var(--dim); font-size: .8rem; max-width: 70ch; }
#credits ul { list-style: none; margin: 0; padding: 0; columns: 2; column-gap: 2.5rem; font-size: .78rem; }
#credits li { color: var(--dim); break-inside: avoid; margin-bottom: .3rem; }
#credits strong { color: var(--ink); font-weight: 600; }

/* the accordion: folded stretches where nobody on the chart was alive */
.fold { fill: url(#fold-hatch); }
.fold-hatch { fill: var(--dim); opacity: .22; }
.fold-edge { stroke: var(--rule); stroke-width: 1; }
.fold-label { fill: var(--dim); font-size: 10.5px; font-variant-numeric: tabular-nums; }
.fold-caption { fill: var(--ink); font-size: 11px; }

/* gather: hover a face and its lane's other faces slide in to stand beside it */
.face { transition: transform .32s cubic-bezier(.2,.7,.2,1); will-change: transform; }
.lane.instant .face { transition: none; }
.lane.gathered .face-name,
.lane.gathered .hidden-count { opacity: 0; pointer-events: none; transition: opacity .15s; }
/* Rings and dots are scaled with their face, so keep their strokes thin or
 * they thicken into a halo. */
.lane.gathered .face .portrait-ring { stroke-width: 1.2; }
.lane.gathered .face.focus .portrait-ring { stroke-width: 1.6; }
/* A grown face overlaps the lifespan bars behind it; a gathered lane draws
 * its faces above everything else in the lane, and the lane above its
 * neighbours. */
.lane.gathered { isolation: isolate; }
.face-name { transition: opacity .15s; }

/* Both figure views link to the same verified profile. */
#hover strong a, #panel h2 a { color: inherit; text-decoration: none; }
#hover strong a::after, #panel h2 a::after { content: " \2197"; font-size: .75em; color: var(--dim); }
#hover strong a:hover, #panel h2 a:hover { text-decoration: underline; }

/* ── touchscreens ── */
.hint-touch { display: none; }
@media (hover: none) and (pointer: coarse) {
  .hint-mouse { display: none; }
  .hint-touch { display: inline; }
}

/* Phones held upright: details slide up over the lower part of the chart
 * instead of taking a column from it, and a playing reel -- they are portrait
 * videos -- spans the screen. */
@media (max-width: 700px) and (orientation: portrait) {
  header { padding: 1rem 1rem .8rem; }
  aside#panel {
    position: fixed; left: 0; right: 0; bottom: 0; top: auto; z-index: 15;
    width: auto; max-height: 62dvh;
    border-left: 0; border-top: 1px solid var(--rule); border-radius: 12px 12px 0 0;
    background: var(--paper); box-shadow: 0 -8px 24px rgba(0,0,0,.18);
  }
  aside .detail-portrait { width: 6rem; float: right; margin: 0 0 .5rem .8rem; }
  #hover.playing {
    left: 0 !important; top: 0 !important; width: 100vw;
    max-height: 100dvh !important; border-radius: 0;
  }
  #hover.playing .drag-video, #video-tether { display: none; }
}

/* Phones on their side: little height, so a narrower panel and portrait. */
@media (max-height: 500px) and (orientation: landscape) {
  aside { width: 17rem; }
  aside .detail-portrait { width: 5rem; float: right; margin: 0 0 .5rem .8rem; }
}
