/* ============================================================
   Layout stylesheet — the map-first shell (index.html).
   Loaded after style.css; restyles the shell, leaves every
   component's own look intact so versions compare fairly.
   ============================================================ */

.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}

/* ---------- 1. time stays on top ----------
   The year selector is the site's primary control, so the bar is
   generous: a large year, a full-width slider with a taller track
   and bigger grab handle, and readable era labels. Search was
   removed at the owner's request, which frees the whole middle
   column for the timeline. */
.v3 .timebar{
  position:sticky;top:0;z-index:60;
  background:rgba(13,19,33,.96);
  backdrop-filter:blur(9px);
  border-bottom:1px solid var(--line);
  padding:16px 0 14px;
}
.v3 .time-inner{
  display:grid;grid-template-columns:auto minmax(280px,1fr);
  align-items:center;gap:30px;
}
/* year and era on top, the view switch directly beneath them */
.v3 .time-col{display:flex;flex-direction:column;align-items:flex-start;gap:12px}

/* ---------- view switch: map / timeline / rulers ----------
   A segmented control: one bordered object with three joined cells, so it
   reads as "pick one of these" rather than three unrelated buttons. The
   active cell is filled gold — the strongest state available here, which
   matters because this control decides what the whole page below shows.

   Deliberately not .zbtn: those are the map's own zoom buttons, and a
   control that swaps the entire view should not look like one that pans
   within a single view. */
.v3 .view-switch{
  display:inline-flex;
  border:1px solid var(--line);border-radius:8px;
  overflow:hidden;background:var(--panel);
}
.v3 .view-switch .view-btn{
  background:none;border:0;border-right:1px solid var(--line);
  color:var(--ink-dim);
  font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.04em;
  padding:8px 16px;cursor:pointer;white-space:nowrap;
  transition:color .15s,background .15s;
}
.v3 .view-switch .view-btn:last-child{border-right:0}
.v3 .view-switch .view-btn:not(.on):hover{color:var(--gold)}
.v3 .view-switch .view-btn.on{background:var(--gold);color:var(--bg)}
.v3 .view-switch .view-btn:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}

/* ---------- panes swapped in under the year bar ----------
   Chart and rulers reuse the map box's footprint but not its class, because
   .map-shell carries a mobile aspect-ratio hack (padding-top:50%) meant only
   for the SVG map — applying it here would leave a blank gap above the
   chart/rulers content on small screens. */
/* One footprint for all three views.

   The map is locked to a 2:1 box, so its height is always half the content
   width. Timeline and Rulers had no floor at all, which meant the page grew
   and shrank every time you switched view, and shrank again between a
   three-ruler dynasty and a seventeen-ruler one. Giving the panes the same
   height the map computes for itself — half the content width, capped where
   the 1280px wrap stops growing — makes all three views one stable window.
   Taller content simply pushes past it. */
.v3 .view-pane{
  background:var(--panel);border:1px solid var(--line);border-radius:10px;
  padding:20px 22px;
  min-height:min(calc(50vw - 20px),620px);
}
.v3 .time-when{display:flex;align-items:baseline;gap:16px;white-space:nowrap}
.v3 .time-year{
  font-family:"Cormorant Garamond",Georgia,serif;
  font-size:86px;line-height:.88;color:var(--gold);font-weight:600;
  letter-spacing:.01em;
}
.v3 .time-era{display:flex;flex-direction:column;line-height:1.25}
.v3 .time-era .era-name{
  font-family:"Cormorant Garamond",Georgia,serif;
  font-size:27px;color:var(--ink);
}
.v3 .time-era .era-sub{font-size:14px;opacity:.6;letter-spacing:.02em}

.v3 .time-slider{position:relative;min-width:0;padding-top:2px}
.v3 .time-slider .mini-year{
  display:flex;justify-content:space-between;align-items:baseline;
  font-family:"IBM Plex Mono",monospace;font-size:13px;
  color:var(--gold);margin-bottom:4px;padding:0 2px;
}
.v3 .time-slider .mini-era{
  color:var(--ink-dim);font-family:"Cormorant Garamond",serif;
  font-size:15px;font-style:italic;
}
.v3 .time-slider .heat{height:11px;border-radius:6px;margin:0 2px 5px}
.v3 .time-slider input[type=range]{height:46px}
.v3 .time-slider input[type=range]::-webkit-slider-runnable-track{height:10px;border-radius:5px}
.v3 .time-slider input[type=range]::-webkit-slider-thumb{
  width:28px;height:28px;margin-top:-9px;border-width:4px;
}
.v3 .time-slider input[type=range]::-moz-range-track{height:10px;border-radius:5px}
.v3 .time-slider input[type=range]::-moz-range-thumb{width:24px;height:24px;border-width:4px}
/* the ruler under the slider: labelled years sit on a tall gold mark,
   unlabelled marks fill in between. Labels are widely spaced so they can
   never overlap — the fine granularity comes from the bare marks. */
.v3 .time-slider .ticks{
  height:32px;margin-top:2px;
  font-family:"IBM Plex Mono",monospace;
  border-top:1px solid rgba(212,169,92,.22);
  padding-top:0;
}
.v3 .time-slider .ticks .tk-min{
  position:absolute;top:0;width:1px;height:5px;
  transform:translateX(-50%);
  background:var(--gold);opacity:.4;
}
.v3 .time-slider .ticks .tk-maj{
  position:absolute;top:0;transform:translateX(-50%);
  padding-top:12px;line-height:1;white-space:nowrap;
  font-size:13px;font-weight:500;color:var(--gold);opacity:1;
  text-shadow:0 1px 3px rgba(13,19,33,.95);
}
.v3 .time-slider .ticks .tk-maj::before{
  content:"";position:absolute;left:50%;top:0;
  width:1.5px;height:9px;transform:translateX(-50%);
  background:var(--gold);opacity:.9;
}



/* ---------- 3. map is the main stage ---------- */
.v3 .mapstage{margin-bottom:6px}
.v3 .mapstage .map-shell{position:relative}
/* The map window is locked to the world view's 2:1. Even if a future
   viewBox is not 2:1, the box cannot change height and shove the page. */
.v3 .mapstage #worldMap{
  width:100%;aspect-ratio:2/1;height:auto;min-height:340px;
  cursor:crosshair;display:block;
}
@supports not (aspect-ratio:2/1){
  .v3 .mapstage .map-shell{position:relative;padding-top:50%}
  .v3 .mapstage #worldMap{position:absolute;inset:0;height:100%}
}
.v3 .map-pick{
  position:absolute;left:12px;top:12px;z-index:5;
  font-size:13px;color:var(--gold);
  background:rgba(13,19,33,.82);border:1px solid var(--line);
  border-radius:20px;padding:5px 13px;pointer-events:none;
  opacity:0;transition:opacity .25s;
}
.v3 .map-pick.pulse{opacity:1;animation:v3fade 2.4s ease forwards}
@keyframes v3fade{0%{opacity:0}12%{opacity:1}72%{opacity:1}100%{opacity:0}}
/* .map-caption removed with the paragraph under the map; its data credits
   moved to .data-credit in the footer, where the licence is still satisfied. */
.data-credit{margin-top:8px;text-align:center;font-size:11px;color:var(--ink-dim);opacity:.75}
.data-credit a{color:var(--ink-dim);text-decoration:underline}
.data-credit a:hover{color:var(--gold)}

/* ---------- 4. story below the map ---------- */
/* One column now. The 290px side rail held the year feed, the podcast
   catalogue and "Meanwhile"; all three have gone or moved, so the story
   takes the full width instead of leaving a permanent empty gutter. */
.v3 .storywrap{
  display:block;
  padding:18px 0 8px;
  border-top:1px solid var(--line);margin-top:16px;
}
.v3 .story-head{
  font-family:"Cormorant Garamond",Georgia,serif;
  font-size:27px;line-height:1.2;margin:0 0 10px;display:flex;
  align-items:baseline;gap:10px;flex-wrap:wrap;
}
.v3 .sh-place{color:var(--gold)}
.v3 .sh-year{font-size:16px;font-family:"IBM Plex Sans",sans-serif;opacity:.65}
.v3 .sh-hint{font-size:16px;font-family:"IBM Plex Sans",sans-serif;opacity:.55}
.v3 .story-rail{display:flex;flex-direction:column;gap:14px;position:sticky;top:132px}
.v3 .rail-block{border:1px solid var(--line);border-radius:12px;padding:11px 13px}
.v3 .rail-head{
  font-size:11.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--gold);margin-bottom:7px;
}
/* ---------- "Meanwhile around the world", read across ----------
   style.css already lays these out as five columns, one per continent —
   which is the point of the panel: the same year, seen in five places at
   once. This stylesheet had been overriding that to a single column, but
   only because the block was parked in the 290px side rail. It now sits
   full width below the story, so the original row layout applies again and
   the override is gone.

   The cards hang from a dashed rule with a short stub above each one, so
   the row reads as five branches off one moment in time. */
.v3 .mw-band{
  padding:18px 0 6px;border-top:1px solid var(--line);margin-top:4px;
}
.v3 .mw-band .rail-head{
  font-size:11.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--gold);margin-bottom:2px;
}
@media(max-width:900px){
  /* two per row rather than five; style.css already handles the columns */
  .v3 .mw-band{padding-top:14px}
}

/* The .angle-tabs / .angle-tab rules that sat here were dead: nothing in js/
   ever creates an element with either class, so they styled markup that has
   never existed. Removed rather than left to mislead the next reader. */
/* Flat, no boxes.

   These four sections used to be bordered cards with a gold left bar, sitting
   directly under a narrative block that had no background at all — and their
   headings were 19px serif while every other section label on the page is a
   10px mono capital. Two prose blocks, two completely different treatments,
   which is what made the card look like a jumble of fonts and shaded panels.

   Now: no border, no padding, no background. Sections are separated by their
   label and one hairline above the group. The label matches .fld b and .ms b
   in style.css, so every section heading in this card is finally the same
   thing. These rules live here rather than in style.css because this file
   loads second and .v3 .sp-angles .angle outranks a bare .angle — editing
   style.css alone has no effect on them. */
.v3 .sp-angles{
  display:grid;grid-template-columns:1fr;gap:20px;margin-top:16px;
  border-top:1px solid var(--line-faint);padding-top:15px;
}
.v3 .sp-angles .angle{
  border:none;border-radius:0;background:none;padding:0;margin:0;
  font-size:14.5px;line-height:1.65;
}
.v3 .sp-angles .angle > b{
  display:block;margin:0 0 6px;
  font-family:'IBM Plex Mono',monospace;font-size:10px;font-weight:500;
  letter-spacing:.16em;text-transform:uppercase;color:var(--gold);
}
/* two across once there is room for it */
@media(min-width:1250px){ .v3 .sp-angles{grid-template-columns:1fr 1fr;gap:20px 34px} }
.v3 #spotlight .spot.big{border-left:none;padding-left:0}

/* The listening column is uncapped in the data — a well-covered region in a
   well-covered century can return a dozen shows, which would stretch the
   picture row far past the pictures beside it. Cap the height and let the
   column scroll on its own instead. */
.v3 .sp-pods{max-height:340px;overflow:auto}
/* The year belongs in the heading.

   This used to be display:none, so the card read "Britain / UK" with no date
   anywhere in it except a 10px grey line further down. On a site whose whole
   premise is a year slider, the heading is exactly where the year should be. */
.v3 #spotlight .sp-yr{font-size:.55em;color:var(--gold);white-space:nowrap}

/* the territory panel becomes a secondary drawer under the map */
/* ---------- the polity, as a subtitle of its region ----------
   The region card IS the window. What the visitor clicked sits directly
   under the region heading as a subtitle with its own text, rather than in
   a second bordered box: a click on the Prussians should read
   "Poland & Baltics / Prussians", not open two windows saying nearly the
   same thing. */
/* Flat, like everything else in this card.

   This block kept the tinted background, 3px gold bar and asymmetric corners
   after the four sections below it lost theirs — so the card still had one
   shaded box in it, which was half the original complaint. It now sits on
   the page like the rest, separated by space and a hairline underneath. */
.v3 .sp-polity{
  margin:12px 0 4px;padding:0 0 14px;
  background:none;border:none;border-radius:0;
  border-bottom:1px solid var(--line-faint);
}
.v3 .sp-polity-name{
  font-family:"Cormorant Garamond",Georgia,serif;
  font-size:22px;line-height:1.15;color:var(--ink);
}
/* Gold, not grey: every other small mono label in this card is gold, and
   this one was the last holdout. */
.v3 .sp-polity-kind{
  font-family:'IBM Plex Mono',monospace;font-size:10px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--gold);margin-top:4px;
}
/* One body size for the whole card: the narrative, the four sections and
   this block were 14.5, 14.5 and 13.5px, with 13px grey notes inside it. */
.v3 .sp-polity-text{font-size:14.5px;line-height:1.65;margin-top:9px}
.v3 .sp-polity-text .md-note{color:var(--ink-dim);font-size:inherit}

/* ---------- extras kept out of the way ---------- */
.v3 .extras{padding:20px 0 8px;border-top:1px solid var(--line);margin-top:20px}
.v3 .extras summary{cursor:pointer;font-size:13.5px;color:var(--gold);padding:4px 0}
.v3 .extras[open] summary{margin-bottom:12px}

/* ---------- extras that stay open ----------
   Same divider line as .extras, but no <details>/<summary> fold: rulers &
   dynasties and the rating form are always visible under the line rather
   than needing a click to reveal. */
.v3 .extras-open{padding:20px 0 8px;border-top:1px solid var(--line);margin-top:20px}
.v3 .extras-open .extras-head{font-size:13.5px;color:var(--gold);padding:4px 0;margin:0 0 12px;font-weight:600}

/* ---------- rate & comment ----------
   A star row (five radios in reverse order + labels, so CSS alone can light
   up "this many and everything brighter" on hover/checked without JS), a
   comment box, and an optional reply address. rate.js handles the actual
   send; this is just the look. */
.rate-form{max-width:480px}
.rate-form .stars{display:flex;flex-direction:row-reverse;justify-content:flex-end;gap:2px;border:0;padding:0;margin:0 0 12px}
.rate-form .stars input{position:absolute;opacity:0;width:1px;height:1px}
.rate-form .stars label{font-size:30px;line-height:1;color:var(--line);cursor:pointer;transition:color .15s}
.rate-form .stars input:checked ~ label,
.rate-form .stars label:hover,
.rate-form .stars label:hover ~ label{color:var(--gold)}
.rate-form .stars input:focus-visible + label{outline:2px solid var(--gold);outline-offset:2px;border-radius:3px}
.rate-text,.rate-email{
  display:block;width:100%;box-sizing:border-box;background:var(--panel2);
  border:1px solid var(--line);color:var(--ink);font-family:'IBM Plex Sans',sans-serif;
  font-size:13.5px;border-radius:8px;padding:10px 12px;margin-bottom:10px;resize:vertical;
}
.rate-text:focus,.rate-email:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(228,184,92,.18)}
.rate-row{display:flex;align-items:center;gap:12px}
.rate-status{font-size:12.5px;color:var(--ink-dim)}
.rate-status.ok{color:var(--gold)}
.rate-status.err{color:#e08a7c}

/* ---------- the empire picker ----------
   Sized to its longest entry rather than to a round number. The widest
   string is the placeholder, "👑 Choose an empire or kingdom…" at 30
   characters, and a <select> clips rather than wrapping — so a box too
   narrow silently truncates instead of telling you anything is missing.

   The width is in ch, which is a measure of the font's own character
   width, so the box keeps fitting its text if the type size changes. The
   right padding clears the gold arrow, which is drawn as a background
   image and would otherwise sit on top of the last letters. */
.v3 #paneRulers{text-align:center}
.v3 #paneRulers .section-note{max-width:620px;margin-left:auto;margin-right:auto}
.v3 #dynSel{
  display:block;margin:14px auto 0;
  width:min(620px,100%);min-width:0;max-width:100%;
  font-size:14px;padding:13px 40px 13px 18px;
  text-align:center;text-overflow:ellipsis;
  background-position:right 16px center;
}
.v3 #dynSel:hover{border-color:var(--gold)}

/* The tree was boxed to 720px inside a pane nearly twice that wide, so a
   broad house scrolled sideways with empty pane on both sides of it. The
   pane is the limit now; .dtree-scroll still catches anything wider. */
.v3 #dynTree{max-width:none;margin:0 auto;text-align:left}
.v3 #dynTree .section-note,
.v3 #dynTree .house{max-width:820px;margin-left:auto;margin-right:auto}

/* ---------- the house window ----------
   Title, the span it actually covers, then a paragraph on who these people
   were and how they took power. 33 of the 44 houses had no text at all here
   before, so the box opened empty under its own name — "Wessex & the
   Anglo-Saxons" and nothing else. Left-aligned prose inside a centred pane,
   because centred paragraphs are hard to read. */
.v3 #dynTree .house{
  flex-direction:column;align-items:center;text-align:center;
  padding:16px 22px;border-left:1px solid var(--line);border-top:4px solid var(--gold);
}
.v3 .house-body{width:100%;min-width:0}
.v3 .house-meta{
  font-family:'IBM Plex Mono',monospace;font-size:10.5px;letter-spacing:.06em;
  color:var(--ink-dim);margin-top:3px;
}
.v3 .house-note{
  color:var(--ink);opacity:.82;font-size:13.5px;line-height:1.62;
  margin:9px auto 0;max-width:64ch;
}
.v3 .dyn-detail .dd-in{margin-left:auto;margin-right:auto;text-align:center}
.v3 .dyn-detail .rnote{margin-left:auto;margin-right:auto}
.v3 .dyn-detail .links{justify-content:center}

/* ---------- the key ----------
   Every mark on the chart explained in words, sitting above it. The tree got
   hard to read because it had grown a private vocabulary — dashed rings,
   lightning bolts, faded circles — that was never written down anywhere. */
.v3 .dlegend{
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;
  gap:9px 20px;max-width:820px;margin:14px auto 4px;
  padding:14px 18px;background:var(--panel2);
  border:1px solid var(--line);border-radius:12px;
}
.v3 .dlegend .dk{
  display:flex;align-items:center;gap:7px;
  font-size:11.5px;color:var(--ink-dim);line-height:1.4;
}
.v3 .dlegend i{flex:0 0 auto;font-style:normal}
.v3 .dlegend .k-ring{
  width:19px;height:19px;border-radius:50%;
  border:2px solid var(--gold);
}
.v3 .dlegend .k-ghost{
  width:19px;height:19px;border-radius:50%;
  border:2px solid var(--line-faint);opacity:.9;
}
.v3 .dlegend .k-solid{width:24px;border-top:1px solid var(--ink-dim)}
.v3 .dlegend .k-dash{width:24px;border-top:1px solid var(--line-faint)}
.v3 .dlegend .k-bolt{font-size:13px}

/* the family switch lives in the key, because that is where it is explained */
.v3 .dfam-btn{
  background:var(--panel);border:1px solid var(--line);color:var(--ink-dim);
  font-family:'IBM Plex Mono',monospace;font-size:11px;
  padding:7px 14px;border-radius:20px;cursor:pointer;
  transition:.15s;white-space:nowrap;
}
.v3 .dfam-btn:hover{border-color:var(--gold);color:var(--gold)}
.v3 .dfam-btn.on{background:var(--gold);border-color:var(--gold);color:var(--bg)}

/* ---------- the number in the line of succession ----------
   The single strongest aid to reading these charts: wherever the tree
   branches and the eye loses the thread, the numbers still run 1, 2, 3. */
.v3 .dtree .dnum{
  position:absolute;top:-5px;left:-7px;
  min-width:17px;height:17px;padding:0 3px;
  border-radius:9px;background:var(--gold);color:var(--bg);
  font-family:'IBM Plex Mono',monospace;font-size:10px;font-style:normal;
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 0 0 2px var(--panel);
}
.v3 .dtree .dav{position:relative;overflow:visible}

/* family, written out in the detail panel — always available, even with the
   chart in its clean rulers-only mode */
.v3 .dyn-detail .dd-fam{
  margin-top:10px;padding-top:9px;border-top:1px solid var(--line);
  text-align:left;
}
.v3 .dyn-detail .dd-fam-row{
  display:flex;gap:10px;font-size:12.5px;line-height:1.55;
  color:var(--ink);opacity:.85;margin-bottom:3px;
}
.v3 .dyn-detail .dd-fam-k{
  flex:0 0 66px;color:var(--ink-dim);
  font-family:'IBM Plex Mono',monospace;font-size:10px;
  letter-spacing:.06em;text-transform:uppercase;padding-top:3px;
}

/* reign length on the card, under the dates */
.v3 .dtree .dlen{
  font-family:'IBM Plex Mono',monospace;font-size:9px;
  color:var(--gold);opacity:.75;text-align:center;
}
/* and spelled out in the detail panel */
.v3 .dyn-detail .dd-len{
  font-family:'IBM Plex Mono',monospace;font-size:11px;
  color:var(--gold);margin:2px 0 4px;
}

@media(max-width:640px){
  .v3 #dynSel{width:100%;font-size:13px;padding:12px 34px 12px 14px}
}

/* ---------- what the Rulers view hides ----------
   Set by showView() in layout3.js.

   Everything in .storywrap answers one question — "what was happening in
   this PLACE at this year": the four region essays, the "This year" feed,
   the territory drawer whose empty state reads "Tap anywhere on the map",
   and the side rail of podcast links. The Rulers view is asking about a
   family instead, so none of it applies.

   Hiding those parts one by one left the block half-alive: the essays and
   the feed went, and the rail stayed behind as a lone podcast box floating
   beside the succession chart with nothing to sit next to. The whole block
   goes, and the tree takes the full width.

   Map and Timeline keep all of it — this is a per-view hide, not a removal. */
body.v3[data-view="rulers"] .storywrap,
/* "Meanwhile" moved out of the rail to run full width, which put it outside
   .storywrap — it still belongs to a place and a year, so it hides here too */
body.v3[data-view="rulers"] .mw-band{display:none}

/* ---------- succession tree ----------
   A top-down family chart: each ruler is a circle with the name and reign
   under it, children hang on a rank below, siblings sit side by side.

   The connectors are pure CSS on nested <ul>/<li> — no layout maths, no SVG
   overlay to keep in sync on resize. Each li draws half a horizontal bar to
   its left and right; the first child suppresses its left half and the last
   its right, which leaves exactly the bracket a family chart needs however
   many children there are.

   SOLID VERSUS DASHED IS A CLAIM ABOUT EVIDENCE
   Solid means the data says "son"/"daughter" — a direct child of the node
   above. Dashed means the tie is real but the intervening person is not in
   the dataset (grandson, nephew, "7th generation") or is not descent at all
   (cousin, marriage, "Palaiologos line"). The written relation always rides
   on the connector, so the reader never has to infer from the line alone. */
/* Generous vertical steps. The ranks were 22px apart, which made three
   generations look like one knot of circles; at 38px the eye can follow a
   single line down the page without losing it. */
.dtree-scroll{overflow-x:auto;padding:10px 0 16px}
.dtree{display:flex;flex-direction:column;align-items:center;min-width:min-content}
.dtree ul{display:flex;justify-content:center;padding:38px 0 0;margin:0;position:relative;list-style:none}
/* The top rank has nothing above it, so it draws no bracket — but the people
   on it may still be peers of one another (the four Rashidun caliphs), so they
   sit side by side with room between them rather than stacking. */
.dtree ul.droot{padding-top:4px;gap:18px}
.dtree li{
  list-style:none;position:relative;
  display:flex;flex-direction:column;align-items:center;
  padding:38px 14px 0;
}
.dtree ul.droot>li{padding-top:0}

/* the two halves of the horizontal bar above each child */
.dtree li::before,.dtree li::after{
  content:"";position:absolute;top:0;right:50%;
  width:50%;height:38px;
  border-top:1px solid var(--line);
}
.dtree li::after{right:auto;left:50%;border-top:1px solid var(--line);border-left:1px solid var(--line)}
.dtree li::before{border-right:0}
/* an only child needs just the straight drop, not a bracket */
.dtree li:only-child::before,.dtree li:only-child::after{display:none}
.dtree li:only-child{padding-top:38px}
.dtree li:only-child>.dpair::before{
  content:"";position:absolute;left:50%;top:-38px;height:38px;
  border-left:1px solid var(--line);
}
/* outer ends of the bracket carry no bar */
.dtree li:first-child::before,.dtree li:last-child::after{border-top:0}
.dtree li:last-child::before{border-right:1px solid var(--line);border-radius:0 6px 0 0}
.dtree li:first-child::after{border-radius:6px 0 0 0}
/* the drop from a parent into its children's bar */
.dtree ul ul::before{
  content:"";position:absolute;top:0;left:50%;width:0;height:38px;
  border-left:1px solid var(--line);
}
/* ---------- "the exact link is not in the data" ----------
   This used to be drawn with border-style:dashed. On a display at 125% or
   150% scaling the browser must fit a dash pattern into 1.25 device pixels;
   it rounds every segment up, and a 1px dashed line renders as chunky,
   uneven, brighter blocks — far heavier than the solid lines beside it.
   Solid 1px lines have no such problem, which is why only the dashed ones
   looked wrong.

   So the distinction is carried by WEIGHT instead of pattern: a certain link
   is drawn in the normal line colour, an uncertain one in a dimmer tint of
   it. Same meaning, and it renders identically at every zoom level. The
   written relation still rides on the connector, so the words remain the
   precise statement either way. */
.dtree li.dashed::before,.dtree li.dashed::after,
.dtree li.dashed:only-child>.dpair::before{border-color:var(--line-faint)}

/* ---------- a ruler and their consort ----------
   The pair is one unit: the bracket above and the drop below both centre on
   it, so the children's line falls from between the couple exactly as a
   family chart draws it. */
/* The cell is a column now: ruler, then the marriage caption, then the
   consorts. Column layout keeps the group symmetrical about the ruler, which
   is what makes the connectors above and below land on him. */
.dtree .dpair{position:relative;display:flex;flex-direction:column;align-items:center;gap:2px}
.dtree .dmarr{
  display:flex;align-items:center;gap:5px;margin-top:5px;
}
.dtree .dheart{color:var(--gold);font-size:12px;opacity:.8}

/* ---------- people who never ruled ----------
   Same card shape, drawn muted and inert, so the eye can separate those who
   actually held power from the family around them without reading a word. */
.dtree .dghost{cursor:default}
.dtree .dghost .dav{
  border-style:solid;border-color:var(--line-faint);
  color:var(--ink-dim);background:transparent;
  width:40px;height:40px;font-size:15px;
}
.dtree .dghost .dn{color:var(--ink-dim);font-weight:400;font-size:11px}
.dtree .dghost .dy{font-size:8.5px;opacity:.7;font-style:italic}
.dtree li.ghost>.dpair::before{border-color:var(--line-faint)}
.dtree .dsp .dav{border-color:var(--gold);opacity:.55}

/* ---------- the consorts, grouped and labelled ----------
   One heart, then the wives under a written caption. Without the caption the
   extra circles were unexplained; with a heart repeated before each one they
   read as marriages between the women rather than to the ruler. */
.dtree .dsp-label{
  font-family:'IBM Plex Mono',monospace;font-size:8.5px;letter-spacing:.04em;
  color:var(--gold);opacity:.75;white-space:nowrap;
}
.dtree .dsp-row{display:flex;align-items:flex-start;justify-content:center;gap:4px;margin-top:2px}
/* a founder's brothers and sisters, captioned under the ruler rather than
   bracketed to him across the width of his whole dynasty */
.dtree .dsib-label{
  font-family:'IBM Plex Mono',monospace;font-size:8.5px;letter-spacing:.04em;
  color:var(--ink-dim);opacity:.8;white-space:nowrap;margin-top:6px;
}
.dtree .dsib-row{display:flex;align-items:flex-start;justify-content:center;gap:4px;margin-top:2px}

/* ---------- a founder's parents, on the rank above ----------
   They used to be a line of text under the founder's card, which in a chart
   that reads downwards described the wrong generation entirely: "parents:
   Amyntas III & Eurydice I" sat directly above Alexander and was read as
   Alexander's parents. Now they are ordinary nodes with a line down to their
   son, and the chart says it without needing a caption at all. */
.dtree li.parents{padding-top:0}
.dtree li.parents>.dpair{opacity:.9}
/* Nothing sits above the parents, so they must draw no connector upward —
   otherwise a stub rises out of the top of the chart into blank space. */
.dtree li.parents::before,
.dtree li.parents::after,
.dtree li.parents>.dpair::before{display:none}
/* the parents are a couple, so they keep the side-by-side arrangement */
.dtree li.parents>.dpair{flex-direction:row;align-items:flex-start;gap:2px}
.dtree li.parents>.dpair>.dheart{align-self:center;margin-top:-14px}

/* the relation, written on the connector */
.dtree .drel{
  position:absolute;top:2px;left:50%;transform:translateX(-50%);
  font-family:'IBM Plex Mono',monospace;font-size:9px;letter-spacing:.04em;
  color:var(--ink-dim);background:var(--panel);
  padding:1px 6px;border-radius:10px;white-space:nowrap;max-width:150px;
  overflow:hidden;text-overflow:ellipsis;z-index:2;
}
/* No connector above the top rank, so nothing to hang a bracket or a floating
   label on: the relation becomes a plain caption above the circle. */
.dtree ul.droot>li::before,
.dtree ul.droot>li::after{display:none}
.dtree ul.droot>li>.drel{
  position:static;transform:none;display:inline-block;
  margin:0 0 6px;background:var(--panel2);
}

/* the ruler card itself */
.dtree .dcard{
  position:relative;display:flex;flex-direction:column;align-items:center;gap:3px;
  background:none;border:0;cursor:pointer;padding:4px 2px;width:112px;
  color:var(--ink);font-family:inherit;
}
.dtree .dav{
  width:52px;height:52px;border-radius:50%;
  background:var(--panel2);border:2px solid var(--gold);color:var(--gold);
  display:flex;align-items:center;justify-content:center;
  font-family:'Cormorant Garamond',serif;font-weight:700;font-size:19px;
  transition:transform .15s,box-shadow .15s;
}
.dtree .dcard:hover .dav{transform:scale(1.07)}
.dtree .dcard.on .dav{box-shadow:0 0 0 3px rgba(228,184,92,.35)}
.dtree .dn{font-size:12px;font-weight:600;line-height:1.25;text-align:center}
.dtree .dy{font-family:'IBM Plex Mono',monospace;font-size:9.5px;color:var(--ink-dim);text-align:center}
.dtree .dcard:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:8px}

/* a usurper/general/election starts a fresh stump */
.dbreak{
  display:flex;align-items:center;gap:8px;width:100%;
  margin:14px 0 2px;color:var(--ink-dim);
  font-family:'IBM Plex Mono',monospace;font-size:10px;
}
.dbreak::before,.dbreak::after{content:"";flex:1;border-top:1px solid var(--line)}
.dbreak span{white-space:nowrap}
/* still family, only a different branch — quieter than an outright break */
.dbreak.soft{opacity:.6;font-size:9.5px;margin:10px 0 2px}
.dbreak.soft::before,.dbreak.soft::after{border-top-color:var(--line-faint)}

/* detail for the selected ruler, under the tree */
.dyn-detail{min-height:10px}
.dyn-detail .dd-in{
  background:var(--panel2);border:1px solid var(--line);border-left:3px solid var(--gold);
  border-radius:12px;padding:12px 16px;margin-top:10px;max-width:680px;
}
.dyn-detail .dd-n{font-family:'Cormorant Garamond',serif;font-size:21px;color:var(--gold)}
.dyn-detail .dd-rel{font-size:12px;color:var(--ink-dim);margin:4px 0 6px}
/* .reign and .rnote used to be styled only under .ruler, which no longer exists */
.reign{background:none;border:none;color:var(--gold);font-family:'IBM Plex Mono',monospace;font-size:11.5px;cursor:pointer;padding:0;margin:3px 0;display:block;text-decoration:underline dotted}
.rnote{color:var(--ink-dim);font-size:12.5px;line-height:1.5;max-width:660px}

@media(max-width:640px){
  .dtree li{padding-left:4px;padding-right:4px}
  .dtree .dcard{width:88px}
  .dtree .dav{width:42px;height:42px;font-size:16px}
  .dtree .dn{font-size:11px}
  .dtree .drel{font-size:8.5px;max-width:104px}
}

/* ---------- responsive ---------- */
@media(max-width:1000px){
  .v3 .time-inner{grid-template-columns:auto 1fr;row-gap:10px;gap:18px}
  .v3 .time-year{font-size:64px}
  .v3 .time-era .era-name{font-size:22px}
  .v3 .storywrap{grid-template-columns:1fr}
  .v3 .story-rail{position:static}
}
@media(max-width:640px){
  .v3 .timebar{padding:12px 0 10px}
  .v3 .time-inner{grid-template-columns:1fr;gap:10px}
  .v3 .time-col{gap:9px;align-items:stretch}
  /* one column at this width, so the segments share it evenly */
  .v3 .view-switch{display:flex;width:100%}
  .v3 .view-switch .view-btn{flex:1 1 0;text-align:center;padding:9px 4px}
  .v3 .time-when{justify-content:space-between;gap:10px}
  .v3 .time-year{font-size:46px}
  .v3 .time-era .era-name{font-size:18px}
  .v3 .time-era .era-sub{font-size:12px}
  .v3 .time-slider input[type=range]{height:52px}
  .v3 .time-slider input[type=range]::-webkit-slider-thumb{width:32px;height:32px;margin-top:-11px}
  .v3 .time-slider .ticks{height:28px}
  .v3 .time-slider .ticks .tk-maj{font-size:11.5px}
  /* narrow bar: keep every second label so the text still cannot collide */
  .v3 .time-slider .ticks .tk-maj:nth-of-type(even){display:none}
  .v3 .story-head{font-size:22px}
  .v3 .mapstage #worldMap{min-height:240px}
}

/* ---------- podcast markers: headphone badge, zoom-compensated ----------
   Every dimension is set inline by podpins.js, scaled against the current
   viewBox so the badge keeps a constant apparent size at any zoom. */
.v3 .podpin{cursor:pointer}
.v3 .podpin .pp-hit{fill:transparent;stroke:none}
.v3 .podpin .pp-bg{
  fill:#0D1321;stroke:var(--gold);opacity:.9;
  transition:opacity .12s;pointer-events:none;
}
.v3 .podpin .pp-ico{pointer-events:none;dominant-baseline:auto}
.v3 .podpin:hover .pp-bg{opacity:1;fill:#1a2233}
.v3 .podpin.sel .pp-bg{opacity:1;fill:var(--gold)}

/* ---------- the episode popup, anchored to its pin ---------- */
.v3 .pod-pop{
  position:absolute;z-index:12;width:250px;
  transform:translate(-50%,-100%);
  background:rgba(13,19,33,.97);
  border:1px solid var(--gold);border-radius:12px;
  padding:11px 13px 12px;
  box-shadow:0 8px 26px rgba(0,0,0,.5);
  opacity:0;visibility:hidden;transition:opacity .14s;
}
.v3 .pod-pop.open{opacity:1;visibility:visible}
.v3 .pod-pop.below{transform:translate(-50%,0)}
.v3 .pod-pop::after{
  content:"";position:absolute;left:50%;bottom:-6px;
  width:9px;height:9px;margin-left:-5px;
  background:rgba(13,19,33,.97);
  border-right:1px solid var(--gold);border-bottom:1px solid var(--gold);
  transform:rotate(45deg);
}
.v3 .pod-pop.below::after{bottom:auto;top:-6px;transform:rotate(225deg)}
.v3 .pp-x{
  position:absolute;right:7px;top:6px;
  background:none;border:none;color:var(--ink);opacity:.5;
  font-size:13px;line-height:1;cursor:pointer;padding:3px 5px;
}
.v3 .pp-x:hover{opacity:1;color:var(--gold)}
.v3 .pp-show{
  font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--gold);opacity:.85;margin-bottom:4px;padding-right:18px;
}
.v3 .pp-title{
  font-family:"Cormorant Garamond",Georgia,serif;
  font-size:18px;line-height:1.22;color:var(--ink);margin-bottom:5px;
}
.v3 .pp-teaser{font-size:12.5px;line-height:1.5;opacity:.8}
.v3 .pp-foot{display:flex;align-items:center;gap:9px;margin-top:9px}
.v3 .pp-go{
  background:none;border:1px solid var(--line);border-radius:20px;
  padding:4px 11px;font:inherit;font-size:11.5px;
  font-family:"IBM Plex Mono",monospace;
  color:var(--gold);cursor:pointer;
}
.v3 .pp-go:hover{border-color:var(--gold)}
.v3 .pp-listen{font-size:12.5px;color:var(--gold);text-decoration:none;margin-left:auto}
.v3 .pp-listen:hover{text-decoration:underline}
@media(max-width:640px){
  .v3 .pod-pop{width:210px}
  .v3 .pp-title{font-size:16px}
}

/* ---------- map rendering quality ----------
   geometricPrecision stops the renderer approximating curves/edges for
   speed; non-scaling-stroke keeps outlines hairline-thin when the viewBox
   zooms, instead of thickening 4.6x and smothering the coastline detail. */
.v3 #worldMap{shape-rendering:geometricPrecision;text-rendering:optimizeLegibility}
.v3 #worldMap .land{
  vector-effect:non-scaling-stroke;stroke-width:.7;
  stroke-linejoin:round;stroke-linecap:round;
}
.v3 #worldMap .bpoly{
  vector-effect:non-scaling-stroke;stroke-width:.6;
  stroke-linejoin:round;
}
.v3 #worldMap .grat{display:none}
.v3 #worldMap.grid-on .grat{display:inline}
.v3 #worldMap .grat line{vector-effect:non-scaling-stroke}
.v3 #worldMap .emp,.v3 #worldMap #empLayer path{
  vector-effect:non-scaling-stroke;stroke-linejoin:round;
}

/* ---------- fill rule: holes must be holes ----------
   Each polity's outer boundary, its holes and its islands are concatenated
   into one path. SVG's default 'nonzero' rule decides fill by winding
   direction, which GeoJSON does not guarantee — so a ring can render solid
   where it should be hollow, producing bands of inverted colour. 'evenodd'
   fills a region when it is enclosed by an odd number of rings, which gives
   correct holes no matter which way each ring was wound. */
.v3 #worldMap .land,
.v3 #worldMap .bpoly,
.v3 #worldMap #empLayer path,
.v3 #worldMap .emp{fill-rule:evenodd}

/* ---------- 0. header banner ----------
   Sits above the sticky time bar and scrolls away with the page, so the map
   still reaches the top of the screen once the reader starts working.

   The whole picture is shown — no cropping in either direction. The artwork
   is 4:1 and reads chronologically left to right, ending in a line of type
   along the bottom, so anything trimmed from an edge costs content. Height is
   therefore left to follow the width, and the picture is capped and centred
   instead: past ~1700px the banner stops growing rather than filling a large
   monitor. No gradient over the foot either — the subtitle lives there. */
.v3 .hero{
  background:#0D1321;
  border-bottom:1px solid var(--line);
}
.v3 .hero picture{
  display:block;
  max-width:1700px;
  margin:0 auto;
}
.v3 .hero img{
  display:block;
  width:100%;
  height:auto;          /* full picture, never cropped */
}




/* ---------- the timeline handle ----------
   Koh-i-noor_after_1852.png, used as supplied. Background is already
   fully transparent, so no backdrop, rim or recolouring is applied.

   No transform / scale anywhere on this thumb, deliberately. The timebar
   above it uses backdrop-filter: blur(9px); animating a transform inside a
   backdrop-filtered, sticky element makes the browser re-rasterise the whole
   blurred layer every frame, which is what made the bar shiver and the page
   appear to shift while dragging. The handle is therefore a fixed size and
   the only hover feedback is the cursor, which costs no repaint.

   margin-top is -(thumb - track)/2 so the stone sits centred on the 10px
   track: -(38-10)/2 = -14, and -(45-10)/2 = -17.5 on small screens. */
.v3 .time-slider input[type=range]{height:48px;margin:0;display:block}
.v3 .time-slider input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  background-image:url("../img/kohinoor.png");
  background-size:contain;background-repeat:no-repeat;background-position:center;
  background-color:transparent;
  border:none;border-radius:0;box-shadow:none;
  width:38px;height:38px;margin-top:-14px;
  transform:none;transition:none;
  cursor:grab;
}
.v3 .time-slider input[type=range]:active::-webkit-slider-thumb{cursor:grabbing}
.v3 .time-slider input[type=range]::-moz-range-thumb{
  background-image:url("../img/kohinoor.png");
  background-size:contain;background-repeat:no-repeat;background-position:center;
  background-color:transparent;
  border:none;border-radius:0;box-shadow:none;
  width:38px;height:38px;
  transform:none;transition:none;
  cursor:grab;
}
.v3 .time-slider input[type=range]:active::-moz-range-thumb{cursor:grabbing}
.v3 .time-slider input[type=range]:focus-visible{outline:none}
.v3 .time-slider input[type=range]:focus-visible::-webkit-slider-thumb{
  outline:2px solid var(--gold);outline-offset:3px;
}
.v3 .time-slider input[type=range]:focus-visible::-moz-range-thumb{
  outline:2px solid var(--gold);outline-offset:3px;
}
/* reserve the row height up front so nothing below can be nudged when the
   handle image finishes decoding */
.v3 .time-slider{min-height:118px}
@media(max-width:640px){
  .v3 .time-slider input[type=range]{height:56px}
  .v3 .time-slider input[type=range]::-webkit-slider-thumb{width:45px;height:45px;margin-top:-17.5px}
  .v3 .time-slider input[type=range]::-moz-range-thumb{width:45px;height:45px}
  .v3 .time-slider{min-height:126px}
}


/* ---------- Buy Me a Coffee ----------
   The inline button script writes an <a> where its <script> tag sits, so it
   lands inside the footer. Give it room above and centre it; the widget
   carries its own colours from the data- attributes, so nothing here
   restyles the button itself. */
.bmc-slot{margin-top:18px;display:flex;justify-content:center}
.bmc-slot img{border-radius:6px}

/* ---------- who built this ----------
   A quiet line under the coffee button, not competing with it. Uses the
   footer's own muted colour so it reads as part of the small print. */
.site-credit{margin-top:14px;text-align:center;font-size:12px;color:var(--ink-dim)}
.site-credit a{color:var(--ink-dim);text-decoration:underline}
.site-credit a:hover{color:var(--ink)}

/* ---------- stop the timebar reflowing as the year changes ----------
   The real cause of the shake. .time-inner is a two-column grid whose first
   column is sized `auto`, so it measures its contents. app.js writes the year
   as Math.abs(y).toLocaleString(), which is "1" at one end of the slider and
   "3,000" at the other, and the era name swings from "Cold War" to "Bronze Age
   Collapse & Iron Age". Every year change therefore re-measured column one,
   which resized column two, which moved the slider track under the handle —
   so the stone appeared to judder and the whole line shifted with it.

   Fix: give the year and the era fixed boxes. The `auto` column then resolves
   to a constant and nothing downstream can move. Overflow stays visible, so
   even if a string is fractionally wider than its box it draws over the gap
   instead of pushing the layout. tabular-nums keeps the digits themselves from
   changing width as they tick. The era name is allowed two lines and always
   reserves both, so the bar cannot change height either. */
.v3 .time-year{
  width:228px;flex:0 0 228px;   /* grows with the 86px type — see judder note */
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;
}
.v3 .time-when{align-items:flex-start}
.v3 .time-era{width:240px;flex:0 0 240px}
.v3 .time-era .era-name{
  display:block;white-space:normal;
  min-height:2.5em;   /* two lines at line-height 1.25 — reserved always */
}
.v3 .time-slider .mini-year{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.v3 .time-slider .mini-year #miniYear{flex:0 0 auto}
.v3 .time-slider .mini-era{flex:0 1 auto;text-align:right}

@media(max-width:1000px){
  .v3 .time-year{width:168px;flex:0 0 168px}
  .v3 .time-era{width:210px;flex:0 0 210px}
}
@media(max-width:640px){
  .v3 .time-year{width:120px;flex:0 0 120px}
  .v3 .time-era{width:auto;flex:1 1 auto;max-width:62%}
  .v3 .time-era .era-name{min-height:2.5em}
}

/* The Rest Is History catalogue panel was removed from the page — a
   browsable index of one show's 721 episodes reads as promotion for that
   show rather than as reference. Its .trih / .tr-* rules matched nothing
   afterwards and went with it. */

/* ---------- everything drawn on the map scales with the zoom ----------
   Text and circles inside an SVG are measured in viewBox units, so zooming
   from the whole world (1000 units wide) to Europe (194 units) magnifies
   every label and dot by about 5x. app.js publishes the zoom factor as
   --mapk on the svg, and every rule below multiplies its ORIGINAL size from
   style.css by it, so nothing changes at world view and everything holds a
   constant on-screen size as you zoom in.

   Base sizes are copied from style.css deliberately — changing them here
   would resize the world view too, which is not what "dynamic sizing" means.

   Radii use the CSS `r` property, which overrides the r="" attribute the
   JS writes, so the markers shrink without touching the renderers. */

/* territory names */
.v3 #worldMap .blbl{
  font-size:calc(6.4px * var(--mapk,1));
  stroke-width:calc(1.9px * var(--mapk,1));
}
/* painted empire names */
.v3 #worldMap .emplbl{
  font-size:calc(10px * var(--mapk,1));
  stroke-width:calc(3px * var(--mapk,1));
}
.v3 #worldMap .emplbl.sm{
  font-size:calc(7px * var(--mapk,1));
  stroke-width:calc(2px * var(--mapk,1));
}
/* the selected region's own marker — this is the one that blew up most,
   because it is only ever drawn when you have zoomed in to look at it */
.v3 #worldMap .rmark text{
  font-size:calc(11px * var(--mapk,1));
  stroke-width:calc(3px * var(--mapk,1));
}
.v3 #worldMap .rmark circle:first-child{
  r:calc(7px * var(--mapk,1));
  stroke-width:calc(1.6px * var(--mapk,1));
}
.v3 #worldMap .rmark circle:last-of-type{r:calc(2.4px * var(--mapk,1))}
/* event markers */
.v3 #worldMap .evmark text{
  font-size:calc(9.5px * var(--mapk,1));
  stroke-width:calc(2.6px * var(--mapk,1));
}
.v3 #worldMap .evmark circle{
  r:calc(4.2px * var(--mapk,1));
  stroke-width:calc(1.4px * var(--mapk,1));
}
.v3 #worldMap .evmark:hover circle{r:calc(6px * var(--mapk,1))}
/* the small region anchor dots */
.v3 #worldMap .tanchor{r:calc(1.7px * var(--mapk,1))}
/* borders themselves already use non-scaling-stroke, so they need nothing */

/* ---------- podcast badges, now grouped by region ----------
   A badge sits beside the region's own name with a count, instead of one
   icon per episode scattered at its coordinates. The name is what makes the
   marker legible before it is clicked. */
.v3 #worldMap .pp-lbl{
  fill:#EAE3D0;font-family:"IBM Plex Sans",sans-serif;font-weight:500;
  paint-order:stroke;stroke:#0A0F1B;stroke-width:calc(2.4px * var(--mapk,1));
  stroke-linejoin:round;pointer-events:none;
}
.v3 #worldMap .podpin.sel .pp-lbl{fill:var(--gold)}
.v3 #worldMap .pp-n{
  fill:#0D1321;font-family:"IBM Plex Mono",monospace;font-weight:500;
  text-anchor:middle;pointer-events:none;
  paint-order:stroke;stroke:var(--gold);stroke-width:calc(3px * var(--mapk,1));
  stroke-linejoin:round;
}
/* popup now lists a whole region's episodes */
.v3 .pod-pop .pp-list{max-height:260px;overflow:auto;margin-top:2px}
.v3 .pod-pop .pp-item{padding:8px 0;border-top:1px solid var(--line)}
.v3 .pod-pop .pp-item:first-child{border-top:none;padding-top:4px}
.v3 .pod-pop .pp-meta{font-size:11px;opacity:.55;margin:2px 0 4px}
/* style.css shrinks territory names on narrow screens; keep that intent,
   since .v3 #worldMap .blbl would otherwise out-specify it */
@media(max-width:760px){
  .v3 #worldMap .blbl{
    font-size:calc(5.4px * var(--mapk,1));
    stroke-width:calc(1.6px * var(--mapk,1));
  }
}

/* ---------- regions that have essays: dotted outline + gold name ----------
   The outline is the real territory geometry from the year's own survey,
   stroked dotted, so it runs along political borders and coastlines. Fill
   is none — this sits over the painted territories without hiding them. */
.v3 #worldMap .rring path{
  fill:none;stroke:var(--gold);opacity:.55;
  stroke-linejoin:round;stroke-linecap:round;
}
.v3 #worldMap .rring text{
  fill:var(--gold);text-anchor:middle;
  font-family:"IBM Plex Sans",sans-serif;font-weight:500;
  paint-order:stroke;stroke:#0A0F1B;stroke-width:calc(2.4px * var(--mapk,1));
  stroke-linejoin:round;opacity:.92;
}
.v3 #worldMap .rring.sel path{opacity:.95;stroke-dasharray:none!important}
.v3 #worldMap .rring.sel text{opacity:1}
.v3 #worldMap .rring{pointer-events:none}

/* a territory whose region has essays: gold, so the correct historical name
   is itself the invitation to click. Cultural zones stay quieter. */
.v3 #worldMap .blbl.lead{fill:var(--gold);opacity:1}
.v3 #worldMap .blbl.cult{opacity:.72;font-weight:400}
.v3 #worldMap .blbl.lead.cult{opacity:.88}

/* ---------- the territory panel, rebuilt around the polity ---------- */
/* Three tiers in this panel and no more: body text, dimmer metadata lines,
   and the small gold mono label. They were 14 / 13 / 11.5 / 10.5px in four
   slightly different treatments — close enough to look like a mistake rather
   than a hierarchy. Rank is now carried by colour and weight, not by four
   sizes a couple of pixels apart. */
.v3 .md-desc{font-size:inherit;line-height:1.68;margin:2px 0 12px;color:var(--ink)}
.v3 .md-zone{
  font-family:'IBM Plex Mono',monospace;font-size:10px;
  letter-spacing:.16em;text-transform:uppercase;
  color:var(--gold);opacity:.8;margin-bottom:6px;
}
.v3 .md-line{font-size:13.5px;line-height:1.62;margin:7px 0;color:var(--ink-dim)}
.v3 .md-line b{color:var(--ink)}
.v3 .md-k{
  display:inline-block;min-width:62px;
  font-family:'IBM Plex Mono',monospace;font-size:10px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--gold);opacity:.75;
}
.v3 .md-line .chip{
  background:none;border:1px solid var(--line);border-radius:20px;
  padding:2px 9px;margin:2px 2px 2px 0;font:inherit;font-size:12px;
  color:var(--ink);cursor:pointer;
}
.v3 .md-line .chip:hover{border-color:var(--gold);color:var(--gold)}
