/* One stylesheet, no build step. Colours are chosen so that the generated
   pages, the index lists and the graph read as one site. */
:root {
  --ink: #1c2430;
  --muted: #6b7785;
  --line: #dce1e7;
  --paper: #ffffff;
  --wash: #f5f7f9;
  --person: #4a6fa5;
  --event: #b5651d;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  color: var(--ink);
  background: var(--paper);
  font: 16px/1.6 ui-serif, Georgia, "Times New Roman", serif;
}

/* The skip link is the first thing in the body so a keyboard reaches it before
   the header. It is moved off-screen rather than hidden, so it keeps its place
   in the tab order and appears when focused. */
.skip {
  position: absolute;
  left: -999rem;
  top: 0.75rem;
  z-index: 40;
  padding: 0.45rem 0.9rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 24px -12px rgba(28, 36, 48, 0.5);
  font-family: ui-sans-serif, system-ui, sans-serif;
  font-size: 0.9rem;
  text-decoration: none;
}
.skip:focus { left: 0.75rem; }

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  flex-wrap: wrap;
  padding: 0.85rem 1.5rem;
  border-bottom: 1px solid var(--line);
  background: var(--wash);
  font-family: ui-sans-serif, system-ui, sans-serif;
}

/* The wordmark: mark first, then the site name. The mark is decorative (empty
   alt), so the name is what a screen reader announces. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--ink);
  text-decoration: none;
}
.brand img { display: block; width: 1.6rem; height: 1.6rem; }
.brand-name { font-size: 1.05rem; font-weight: 650; letter-spacing: -0.01em; }
.brand:hover .brand-name { color: var(--person); }

/* Pills rather than plain links: with three destinations the current one is
   worth marking, and a filled pill does that without an extra label. */
.site-nav { display: flex; align-items: center; gap: 0.2rem; flex-wrap: wrap; }
.site-nav a {
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  color: var(--muted);
  font-size: 0.9rem;
  text-decoration: none;
}
.site-nav a:hover { color: var(--ink); background: #e9edf2; }
.site-nav a[aria-current="page"] {
  color: var(--ink);
  background: var(--paper);
  box-shadow: inset 0 0 0 1px var(--line);
  font-weight: 600;
}
.site-nav a:focus-visible { outline: 2px solid var(--person); outline-offset: 2px; }

main { max-width: 60rem; margin: 0 auto; padding: 1.5rem; }
/* Set by `main_class` in front matter, for pages that are not prose (the
   graph needs the full window). */
.main-wide { max-width: none; padding: 1.25rem 1.5rem 2rem; }

h1 { font-size: 1.75rem; line-height: 1.2; margin-top: 0; }
h2 { font-size: 1.15rem; margin: 1.5rem 0 0.5rem; }

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

.prose { max-width: 42rem; }
.kicker { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 0.8rem;
          letter-spacing: 0.04em; text-transform: uppercase; margin: 0; }
.muted { color: var(--muted); }

ul.index { list-style: none; padding: 0; margin: 0; }
ul.index li {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.28rem 0;
  border-bottom: 1px solid var(--line);
}
ul.index li a { flex: 1 1 auto; text-decoration: none; }
ul.index li a:hover { text-decoration: underline; }
/* The years are a right-hand column, not a suffix: tabular figures keep them
   aligned down the list, which is what makes a chronological list readable. */
ul.index .muted {
  margin-left: auto;
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
           gap: 2rem; }

/* Home furniture: a hero with the mark, the three ways in, and a count beside
   each column heading so the size of the set is visible before scrolling. */
.hero { display: flex; align-items: center; gap: 1.1rem; margin: 0 0 1.25rem; }
.hero img { flex: none; width: 4rem; height: 4rem; }
.hero h1 { margin: 0 0 0.15rem; font-size: 2rem; }
.hero p { margin: 0; max-width: 34rem; color: var(--muted); }

.quick-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0 0 2rem;
  font-family: ui-sans-serif, system-ui, sans-serif;
}
.quick-links a {
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--wash);
  color: var(--ink);
  font-size: 0.9rem;
  text-decoration: none;
}
.quick-links a:hover { border-color: var(--person); color: var(--person); background: var(--paper); }
/* The graph is the thing this site exists for, so it carries the accent. */
.quick-links a:first-child {
  background: var(--person);
  border-color: var(--person);
  color: #ffffff;
}
.quick-links a:first-child:hover { background: #3d5c8a; border-color: #3d5c8a; color: #ffffff; }
.quick-links a:focus-visible { outline: 2px solid var(--person); outline-offset: 2px; }

.list-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.list-head h1 { margin-bottom: 0.5rem; }
.count {
  font-family: ui-sans-serif, system-ui, sans-serif;
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.crosslink {
  margin: 1.25rem 0 0;
  font-family: ui-sans-serif, system-ui, sans-serif;
  font-size: 0.85rem;
  color: var(--muted);
}

/* Breadcrumbs and the previous/next pair are the two ways back into a list:
   one says where you are, the other says what is next to it. */
.crumbs {
  margin: 0 0 1rem;
  font-family: ui-sans-serif, system-ui, sans-serif;
  font-size: 0.8rem;
  color: var(--muted);
}
.crumbs ol {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.crumbs li { display: flex; gap: 0.35rem; }
.crumbs li + li::before { content: "/"; color: var(--line); }
.crumbs a { color: var(--muted); text-decoration: none; }
.crumbs a:hover { color: var(--ink); text-decoration: underline; }
.crumbs [aria-current="page"] { color: var(--ink); }

.pager {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  max-width: 42rem;
  margin: 2.5rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-family: ui-sans-serif, system-ui, sans-serif;
  font-size: 0.9rem;
}
.pager a { text-decoration: none; }
.pager a:hover { text-decoration: underline; }
.pager-label {
  display: block;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.pager-next { margin-left: auto; text-align: right; }

@media (max-width: 48rem) {
  .site-header { padding: 0.75rem 1rem; }
  .site-nav a { padding: 0.25rem 0.55rem; font-size: 0.85rem; }
  .hero { gap: 0.8rem; }
  .hero img { width: 2.75rem; height: 2.75rem; }
  .hero h1 { font-size: 1.6rem; }
  .pager { flex-direction: column; }
  .pager-next { margin-left: 0; text-align: left; }
}

.site-footer {
  max-width: 60rem;
  margin: 2rem auto 0;
  padding: 1rem 1.5rem 2rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.85rem;
  font-family: ui-sans-serif, system-ui, sans-serif;
}
.site-footer p { margin: 0.35rem 0 0; max-width: 42rem; }
.footer-brand {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--ink);
  font-weight: 600;
}
.footer-brand img { display: block; width: 1.15rem; height: 1.15rem; }
.footer-note { font-size: 0.8rem; color: #8b95a3; }

/* The graph page is a dark surface on purpose. It is a map rather than prose,
   and hairline links read far better on a dark ground than on white — the same
   reason Obsidian's graph view is dark. The canvas needs an explicit height:
   cytoscape measures the container once, and only re-measures when called. */
.graph-page {
  font-family: ui-sans-serif, system-ui, sans-serif;
  color: #e6e9ef;
  background: #16171d;
  border-radius: 18px;
  padding: 1.1rem 1.25rem 1.35rem;
  box-shadow: 0 1px 2px rgba(16, 18, 24, 0.3),
              0 30px 70px -50px rgba(16, 18, 24, 0.9);
}

.graph-intro {
  display: flex;
  align-items: baseline;
  gap: 0.25rem 2rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}

.graph-intro h1 {
  margin: 0;
  color: #f4f6fa;
  font-family: ui-serif, Georgia, "Times New Roman", serif;
}
.graph-blurb { max-width: 40rem; margin: 0; font-size: 0.9rem; color: #99a2b1; }
.graph-blurb p { margin: 0; }
.graph-blurb a { color: #a9bdf7; }

.graph-toolbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.6rem;
}

.graph-toolbar input[type="search"],
.graph-toolbar select {
  font: inherit;
  font-size: 0.9rem;
  color: #e6e9ef;
  background: #1d1f27;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 8px;
  padding: 0.4rem 0.6rem;
}

.graph-toolbar input[type="search"] { flex: 1 1 12rem; max-width: 22rem; }
.graph-toolbar input[type="search"]::placeholder { color: #6d7684; }
.graph-toolbar input[type="search"]:focus,
.graph-toolbar select:focus { outline: 2px solid #6f86f0; outline-offset: 1px; }

.graph-actions { display: flex; gap: 0.25rem; margin-left: auto; }
/* The generic `.graph-actions button` rule below is written for light pages;
   on this dark surface the same controls need their own colours. */
.graph-page .graph-actions button {
  color: #d3d8e2;
  background: #1d1f27;
  border-color: rgba(255, 255, 255, 0.09);
}
.graph-page .graph-actions button:hover { background: #262935; color: #ffffff; }
.graph-page .graph-actions button:focus-visible {
  outline: 2px solid #6f86f0;
  outline-offset: 1px;
}

.graph-actions button {
  display: grid;
  place-items: center;
  min-width: 2rem;
  height: 2rem;
  padding: 0 0.5rem;
  font: inherit;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.graph-actions button:hover { background: var(--wash); }

.graph-toolbar input:focus-visible,
.graph-toolbar select:focus-visible,
.graph-actions button:focus-visible,
.chip:focus-visible { outline: 2px solid var(--person); outline-offset: 2px; }

/* The side filter: a checkbox list in a popover, because sides are read in
   combination ("allied and british") and a native multi-select hides that behind
   a modifier key. */
.dropdown { position: relative; }

.dropdown-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font: inherit;
  font-size: 0.9rem;
  color: #e6e9ef;
  background: #1d1f27;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 8px;
  padding: 0.4rem 0.6rem;
  cursor: pointer;
}

.dropdown-toggle:hover,
.dropdown-toggle[aria-expanded="true"] { background: #262935; }
.dropdown-toggle:focus-visible { outline: 2px solid #6f86f0; outline-offset: 1px; }

.caret {
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: 0.7;
}

.dropdown-menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 0.35rem);
  left: 0;
  min-width: 12.5rem;
  padding: 0.35rem;
  color: #e6e9ef;
  background: #171922;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
}

.dropdown-menu[hidden] { display: none; }

.dropdown-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0;
  padding: 0.3rem 0.5rem 0.45rem;
  font-size: 0.7rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: #8b93a2;
}

.dropdown-all {
  font: inherit;
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  text-transform: none;
  color: #a9bdf7;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.dropdown-all:hover { color: #dfe4ec; text-decoration: underline; }
.dropdown-all:focus-visible { outline: 2px solid #6f86f0; outline-offset: 2px; }

.dropdown-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 16rem;
  overflow-y: auto;
}

.dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.28rem 0.5rem;
  border-radius: 6px;
  font-size: 0.82rem;
  cursor: pointer;
}

.dropdown-item:hover { background: #262935; }
.dropdown-item input { margin: 0; accent-color: #6f86f0; }
.dropdown-label { flex: 1 1 auto; }
.dropdown-count {
  color: #8b93a2;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

/* The view controls: two sliders and a three-way grouping switch, in the same
   popover shell as the side filter so the toolbar stays one row. */
.tune-menu { min-width: 15rem; }

.dropdown-range {
  display: block;
  width: 100%;
  margin: 0 0 0.65rem;
  padding: 0 0.5rem;
  box-sizing: border-box;
  accent-color: #6f86f0;
  cursor: pointer;
}

.dropdown-head output {
  color: #ccd2dd;
  letter-spacing: 0;
  text-transform: none;
  font-variant-numeric: tabular-nums;
}

.dropdown-choice {
  display: flex;
  gap: 0.25rem;
  margin: 0 0.5rem 0.4rem;
}

.dropdown-choice button {
  flex: 1 1 0;
  font: inherit;
  font-size: 0.78rem;
  color: #ccd2dd;
  background: #1d1f27;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 6px;
  padding: 0.3rem 0.2rem;
  cursor: pointer;
}

.dropdown-choice button:hover { background: #262935; }

.dropdown-choice button[aria-pressed="true"] {
  color: #ffffff;
  background: #2c3550;
  border-color: #6f86f0;
}

.dropdown-choice button:focus-visible {
  outline: 2px solid #6f86f0;
  outline-offset: 1px;
}

.legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 0.75rem;
  padding: 0;
  font-size: 0.78rem;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.2rem 0.6rem;
  font: inherit;
  cursor: pointer;
  color: #cfd4de;
  background: #1d1f27;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 999px;
}

.chip:hover { background: #262935; }

.chip[aria-pressed="false"] {
  color: #6d7684;
  background: transparent;
  border-style: dashed;
  text-decoration: line-through;
}

.swatch { width: 0.6rem; height: 0.6rem; border-radius: 50%; background: #7d9df0; }
.swatch.event { background: #e0913f; }
.swatch.line { width: 0.9rem; height: 0.16rem; border-radius: 2px; }

.graph-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 19rem;
  gap: 0.75rem;
  align-items: start;
}

.graph {
  height: clamp(26rem, 72vh, 50rem);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 14px;
  overflow: hidden;
  background-color: #101117;
  background-image: radial-gradient(120% 120% at 50% 0%,
                                    #1c1e27 0%, #14151b 55%, #101117 100%);
}

.panel {
  position: sticky;
  top: 1rem;
  max-height: calc(72vh + 2px);
  overflow: auto;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 14px;
  padding: 0.85rem 0.95rem;
  background: #1a1c23;
  color: #d8dde7;
  font-family: ui-sans-serif, system-ui, sans-serif;
  font-size: 0.875rem;
  overflow-wrap: anywhere;
}

.panel p { margin: 0.4rem 0; }
.panel h2 { margin: 0.15rem 0 0.25rem; font-size: 1.1rem; line-height: 1.25; color: #f2f4f8; }
.panel h3 {
  margin: 1rem 0 0.25rem;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #8b93a2;
}

.panel a { color: #a9bdf7; }
.panel .muted { color: #8b93a2; }
.panel .small { font-size: 0.8rem; }
.panel .error { color: #ff9b9b; }

.panel .badge {
  display: inline-block;
  margin: 0;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #11131a;
  background: #7d9df0;
}

.panel .badge[data-kind="event"] { background: #e0913f; }

.panel-list { list-style: none; margin: 0; padding: 0; }
.panel-list li {
  display: flex;
  gap: 0.5rem;
  padding: 0.35rem 0;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
}
.panel-list a { text-decoration: none; }
.panel-list a:hover { text-decoration: underline; }
.panel-list .small { display: block; color: #8b93a2; }

.dot { flex: none; width: 0.55rem; height: 0.55rem; border-radius: 50%; margin-top: 0.45rem; }

.panel-foot { margin-top: 1rem; }

.button {
  display: inline-block;
  padding: 0.35rem 0.8rem;
  border-radius: 8px;
  background: #4f63d8;
  color: #ffffff;
  font-size: 0.85rem;
  text-decoration: none;
}
.button:hover { background: #6175e6; }

/* Below this the panel cannot sit beside the canvas, so the shell stacks: the
   canvas first, then what it says about the node you touched. */
@media (max-width: 60rem) {
  .graph-shell { grid-template-columns: minmax(0, 1fr); }
  .panel { position: static; max-height: none; }
}

/* Phones. The problem on a 390px screen is not the type scale but the reading
   order: the blurb, four rows of toolbar and sixteen chips added up to more
   than a screenful, so the canvas — the reason the page exists — began below
   the fold. Here the order changes instead of just the sizes: heading, then
   controls, then the legend, then the canvas, and the blurb ("how to read
   this") after it. `display: contents` lifts the heading and the blurb out of
   their wrapper so each can be ordered on its own while the desktop layout
   keeps the two side by side.
   The side chips move into the "All sides" menu, which already lists every
   side with a count and a checkbox: on a phone the legend would otherwise be
   five rows of the same thing. `.graph` measures itself in `svh` so the URL
   bar sliding away does not resize the canvas under the reader's fingers, and
   inputs are set to 1rem because iOS Safari zooms the page whenever a
   smaller-text field takes focus — leaving the whole view oversized. */
@media (max-width: 48rem) {
  .main-wide { padding: 0.75rem 0.75rem 1.5rem; }
  .graph-page {
    display: flex;
    flex-direction: column;
    border-radius: 12px;
    padding: 0.75rem 0.7rem 0.9rem;
  }
  .graph-intro { display: contents; }
  .graph-intro h1 { order: 0; margin: 0 0 0.55rem; font-size: 1.4rem; }
  .graph-toolbar { order: 1; gap: 0.4rem; margin-bottom: 0.5rem; }
  .legend { order: 2; margin-bottom: 0.55rem; }
  .graph-shell { order: 3; gap: 0.5rem; }
  .graph-blurb { order: 4; margin: 0.9rem 0 0; font-size: 0.8rem; line-height: 1.5; }
  .graph-blurb p + p { margin-top: 0.5rem; }

  /* The canvas takes what the chrome above it leaves — header, title, three
     rows of controls and the legend come to roughly 345px — so the graph ends
     where the screen does rather than running past it. The `vh` line is the
     fallback; `svh` follows because on iOS the URL bar is part of `vh`, and a
     canvas that grows when the bar slides away shifts every node under the
     reader's finger. */
  .graph {
    height: max(16rem, calc(100vh - 345px));
    height: max(16rem, calc(100svh - 345px));
  }

  /* The search shares the first row with the zoom pair; the rest take the next
     two. `order` does the packing, because the markup is a single row on wide
     screens and splitting it there would mean two toolbars. */
  .graph-toolbar input[type="search"] { flex: 1 1 7rem; min-width: 0; max-width: none; order: 1; }
  .graph-toolbar select { flex: 1 1 6rem; order: 3; }
  .graph-toolbar input[type="search"],
  .graph-toolbar select,
  .dropdown-toggle { font-size: 1rem; }
  .graph-toolbar .dropdown { flex: 1 1 auto; order: 4; }
  .graph-toolbar .dropdown-toggle { width: 100%; justify-content: space-between; }
  .view-switch { order: 5; }
  /* The zoom pair rides beside the search, which leaves three rows in all. */
  .graph-actions { order: 2; }
  /* The two menus anchor to opposite edges so both stay on a 390px screen:
     the side filter is the last control in its row, the View menu the first
     in the next one. */
  #side-filter-menu { left: auto; right: 0; }
  .tune-menu { left: 0; right: auto; min-width: 0; width: 15rem; }

  /* Finger-sized targets, and a legend that stays one row: only the two kinds
     are chips here, so it never needs to scroll. */
  .graph-actions button { min-width: 2.6rem; height: 2.6rem; }
  .chip { padding: 0.3rem 0.7rem; }
  .legend .chip[data-side] { display: none; }
  .dropdown-item { padding: 0.45rem 0.5rem; }
  .panel { border-radius: 12px; }
}

/* The view switch reads as a segmented control, not as one of the legend's
   filter chips: those grey out and strike through, which would be a lie here. */
.view-switch {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 999px;
  background: #1d1f27;
}
.view-switch button {
  font: inherit;
  font-size: 0.78rem;
  padding: 0.2rem 0.7rem;
  color: #a8b0bd;
  background: transparent;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
}
.view-switch button:hover { color: #ffffff; }
.view-switch button[aria-pressed="true"] { color: #11131a; background: #dfe4ec; }
.view-switch button:focus-visible { outline: 2px solid #6f86f0; outline-offset: 1px; }

/* While the timeline is up the graph's own controls would be dead weight. */
.graph-page.is-timeline .graph-actions,
.graph-page.is-timeline .graph-toolbar select,
.graph-page.is-timeline .graph-toolbar .dropdown { display: none; }

/* The timeline: the same data and the same dark surface as the graph, read as
   time. A rail of events along the top, one row per person, one mark per
   authored link. It has no fixed height because its content is the point —
   seven rows today, and the rows are the reading. Only one of #graph and
   #timeline is ever rendered, so the shell's two columns keep their slots. */
.timeline {
  min-height: 14rem;
  padding: 0.4rem 0.6rem 0.2rem;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 14px;
  background: #101117;
  font-family: ui-sans-serif, system-ui, sans-serif;
  overflow-x: auto;
}
.timeline[hidden] { display: none; }

.timeline-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.1rem 0.2rem 0.3rem;
}
.timeline-range { margin: 0; font-size: 0.72rem; letter-spacing: 0.04em; color: #8b93a2; }

.timeline-toggle {
  font: inherit;
  font-size: 0.72rem;
  padding: 0.15rem 0.6rem;
  color: #cfd4de;
  background: #1d1f27;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 999px;
  cursor: pointer;
}
.timeline-toggle:hover { background: #262935; color: #ffffff; }
.timeline-toggle[aria-pressed="true"] { color: #11131a; background: #dfe4ec; }
.timeline-toggle:focus-visible { outline: 2px solid #6f86f0; outline-offset: 1px; }

.tl-svg { display: block; }

.tl-grid line { stroke: rgba(255, 255, 255, 0.05); stroke-width: 1; }
.tl-grid text { fill: #6d7684; font-size: 10px; text-anchor: middle; }

.tl-label { fill: #9aa4b2; font-size: 11px; }
.tl-band { fill: transparent; }
.tl-row:hover .tl-band { fill: rgba(255, 255, 255, 0.035); }
.tl-row:hover .tl-label { fill: #eef1f6; }
.tl-life { fill: rgba(255, 255, 255, 0.15); }

.tl-event { cursor: pointer; }
.tl-event circle, .tl-event rect { fill: #e0913f; }
.tl-event-name { fill: #d8dde7; font-size: 10px; opacity: 0; pointer-events: none; }
.tl-event:hover .tl-event-name,
.tl-event.tl-hot .tl-event-name { opacity: 1; }

.tl-dot { cursor: pointer; }
.tl-dot circle { stroke: #101117; stroke-width: 1; }
.tl-dot .tl-span { opacity: 0.55; }

.tl-guide { stroke: rgba(255, 255, 255, 0.16); stroke-width: 1; stroke-dasharray: 2 4; opacity: 0; }
.timeline.is-focus .tl-guide { opacity: 1; }

/* Hover leaves only the marks of one event lit, the way the graph leaves only
   a neighbourhood lit. */
.timeline.is-focus .tl-dot,
.timeline.is-focus .tl-event { opacity: 0.12; }
.timeline.is-focus .tl-dot.tl-hot,
.timeline.is-focus .tl-event.tl-hot { opacity: 1; }

.timeline.is-search .tl-dot,
.timeline.is-search .tl-row { opacity: 0.18; }
.timeline.is-search .tl-dot.is-hit,
.timeline.is-search .tl-row.is-hit { opacity: 1; }

/* Last, so a filtered-out link stays out even while another event is lit. */
.timeline .tl-dot.is-hidden { opacity: 0; pointer-events: none; }

.timeline-empty { margin: 1rem 0.4rem; font-size: 0.85rem; color: #8b93a2; }

/* The family tree: one absolutely positioned box per person over a single SVG
   of elbows. `family.json` owns every coordinate, so these rules only paint —
   nothing here decides where a box or a line sits. The canvas is wider than a
   phone, so it scrolls rather than shrinking the names, and `/js/tree.js` lets
   a mouse drag it the way a map pans and scales it between 40% and 250%: the
   grab cursor is the only hint that needs painting.
   `.tree-zoom` is what the scroller measures. The canvas keeps its own
   coordinates and is transformed as a whole, so the script writes the scaled
   size onto the wrapper (unzoomed, `max-content` is exact) and the scrollbars
   keep telling the truth. The toolbar is built by the script, because a button
   that zooms nothing is worse than no button at all. */
.tree-scroll { margin: 0.75rem 0 3rem; overflow: auto; padding-bottom: 0.75rem; }
.tree-scroll, .tree-node { cursor: grab; }
.tree-scroll.is-panning { cursor: grabbing; user-select: none; }
.tree-scroll.is-panning .tree-node { cursor: grabbing; }
.tree-zoom { width: max-content; margin: 0 auto; }
.tree-tools {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.3rem;
  margin: 2rem 0 0;
  font-family: ui-sans-serif, system-ui, sans-serif;
}
.tree-tools button {
  min-width: 1.9rem;
  padding: 0.25rem 0.5rem;
  font: inherit;
  font-size: 0.75rem;
  line-height: 1.2;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
}
.tree-tools button:hover:not(:disabled) { background: var(--wash); border-color: var(--person); }
.tree-tools button:focus-visible { outline: 2px solid var(--person); outline-offset: 2px; }
.tree-tools button:disabled { color: var(--line); cursor: default; }
.tree-zoom-level {
  min-width: 2.8rem;
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: var(--muted);
}
.tree { position: relative; margin: 0 auto; }
.tree-links { position: absolute; top: 0; left: 0; }
.tree-links path { fill: none; stroke: var(--line); stroke-width: 1.5; }
.tree-node {
  position: absolute;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.15rem;
  padding: 0 0.6rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--paper);
  line-height: 1.25;
  text-align: center;
  text-decoration: none;
}
.tree-node:hover { border-color: var(--person); background: var(--wash); }
.tree-node:focus-visible { outline: 2px solid var(--person); outline-offset: 2px; }
.tree-name { font-size: 0.78rem; font-weight: 600; color: var(--person); }
.tree-node:hover .tree-name { text-decoration: underline; }
.tree-years {
  font-family: ui-sans-serif, system-ui, sans-serif;
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
/* The drawn connector carries the relation, so the parent stays in the DOM for
   screen readers and out of the sighted reading order. */
.tree-child-of {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (max-width: 48rem) {
  .timeline { border-radius: 12px; padding: 0.35rem 0.35rem 0.15rem; }
  .view-switch button { padding: 0.2rem 0.55rem; }
  .timeline-toggle { font-size: 0.68rem; }
}

