:root{
  --bg:#0b0d12; --bg2:#12151d; --panel:#161a24; --line:#232838;
  --ink:#e8eaf0; --dim:#9aa2b5; --faint:#6a7286;
  --accent:#e9c46a; --accent2:#6ab0f3; --alive:#7ee0a8; --death:#e07a7a;
  --serif:"Iowan Old Style",Georgia,"Times New Roman",serif;
  --sans:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
}
*{box-sizing:border-box}
html,body{margin:0}
body{
  background:radial-gradient(1200px 700px at 50% -10%,#161b28 0%,var(--bg) 60%) fixed;
  color:var(--ink); font-family:var(--sans); line-height:1.55;
  min-height:100vh; -webkit-font-smoothing:antialiased;
}
a{color:inherit}

/* top bar */
.topbar{display:flex; justify-content:space-between; align-items:center;
  padding:18px 26px; border-bottom:1px solid var(--line)}
.brand{font-family:var(--mono); letter-spacing:.22em; font-size:13px; text-decoration:none; color:var(--dim)}
.topbar nav a{color:var(--dim); text-decoration:none; font-size:14px}
.topbar nav a:hover{color:var(--ink)}

#app{max-width:820px; margin:0 auto; padding:0 22px}

/* hero */
#hero{padding:16vh 0 8vh; text-align:center}
.odds{font-family:var(--mono); color:var(--accent); letter-spacing:.04em; margin:0 0 6px; font-size:15px}
#hero h1{font-family:var(--serif); font-weight:500; font-size:clamp(40px,9vw,76px); margin:0 0 34px; line-height:1.02}
/* Descriptive subtext, standardized to match .stage-hint for legibility. */
.subtle{color:var(--dim); font-size:15px; line-height:1.5; max-width:560px; margin:22px auto 0; text-align:center}
/* The one claim that explains what the site is: lifted out of the surrounding gray. */
.subtle strong,.stage-hint strong{color:var(--ink); font-weight:600}

/* One rule for the whole page: if it is a pill — filled or outlined — it is a control,
   it lifts under the cursor, and it can be clicked. Nothing passive (the progress rail,
   chips, labels) may use that shape. */
button.primary,button{font:inherit}
button{cursor:pointer}
button:not(:disabled):hover{transform:translateY(-1px)}
button:not(:disabled):active{transform:translateY(0)}
button:focus-visible{outline:2px solid var(--accent2); outline-offset:3px}
button.primary{
  background:var(--accent); color:#20180a; border:0; border-radius:999px;
  padding:14px 30px; font-size:17px; font-weight:600; cursor:pointer;
  transition:transform .12s ease, box-shadow .2s ease; box-shadow:0 6px 30px -8px var(--accent);
}
button.primary:disabled{opacity:.45; cursor:default; transform:none; box-shadow:none}
.actions button:not(.primary){
  background:transparent; color:var(--dim); border:1px solid var(--line);
  border-radius:999px; padding:12px 20px; font-size:15px; cursor:pointer; transition:.15s;
}
.actions button:not(.primary):hover{color:var(--ink); border-color:var(--faint)}

/* stage */
#stage{padding:40px 0 20px}
.stage-visuals{display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-bottom:26px}
@media(max-width:620px){.stage-visuals{grid-template-columns:1fr}}
.panel{background:var(--panel); border:1px solid var(--line); border-radius:14px; padding:18px}
.panel-label{font-family:var(--mono); text-transform:uppercase; letter-spacing:.16em; font-size:11px; color:var(--faint); margin-bottom:12px}
.big-value{font-family:var(--serif); font-size:26px; margin-top:12px; min-height:1.2em}

/* timeline */
.tl-track{position:relative; height:8px; background:#0c0e14; border-radius:6px; overflow:hidden; border:1px solid var(--line)}
.tl-fill{position:absolute; inset:0 100% 0 0; background:linear-gradient(90deg,#2a3247,var(--accent2)); transition:right 1.4s cubic-bezier(.2,.7,.2,1)}
.tl-marker{position:absolute; top:-4px; width:3px; height:16px; background:var(--accent); left:0; transition:left 1.4s cubic-bezier(.2,.7,.2,1); box-shadow:0 0 12px var(--accent)}
.tl-scale{display:flex; justify-content:space-between; font-family:var(--mono); font-size:10px; color:var(--faint); margin-top:7px}

/* map */
#map-svg{width:100%; height:auto; display:block; background:#0c0e14; border-radius:8px; border:1px solid var(--line)}
.graticule{stroke:#182036; stroke-width:.4; fill:none}
.graticule.equator{stroke:#26314a; stroke-width:.5}
.landmass{fill:#232c40; stroke:#33405c; stroke-width:.3; stroke-linejoin:round}
.crosshair{stroke:var(--accent); stroke-width:.4; opacity:.4}
.crosshair.hop{stroke-width:.5; opacity:.6}
.pop-dot{fill:var(--accent2); opacity:.42}
.pop-layer{mix-blend-mode:screen}
.dot-pulse{fill:var(--accent)}
.dot-halo{fill:var(--accent); opacity:.3}
.dot{fill:#fff; stroke:var(--accent); stroke-width:1}

/* steps reveal */
#steps{list-style:none; margin:0; padding:0}
#steps li{
  border-left:2px solid var(--line); padding:10px 0 16px 18px; margin-left:6px;
  opacity:0; transform:translateY(8px); transition:opacity .5s ease, transform .5s ease;
}
#steps li.show{opacity:1; transform:none}
.step-title{font-family:var(--mono); font-size:11px; text-transform:uppercase; letter-spacing:.14em; color:var(--faint)}
.step-line{font-family:var(--serif); font-size:20px; margin:3px 0 0}
.chips{margin-top:7px; display:flex; flex-wrap:wrap; gap:6px}
.chip{font-family:var(--mono); font-size:11px; color:var(--accent2); text-decoration:none;
  border:1px solid var(--line); border-radius:999px; padding:2px 9px; background:#10141e}
.chip:hover{border-color:var(--accent2)}
.caveat{margin-top:8px; font-size:13px; color:var(--faint); font-style:italic; border-left:2px solid var(--line); padding-left:10px}

/* life */
#life{padding:20px 0 60px; animation:rise .6s ease}
@keyframes rise{from{opacity:0; transform:translateY(12px)}to{opacity:1;transform:none}}
#life-name{font-family:var(--serif); font-weight:500; font-size:clamp(30px,6vw,50px); margin:0 0 6px}
/* Generated illustration for a life. Square-ish (1024x942 sources), capped so it never
   dominates the story it accompanies. .is-empty is set by app.js when the library has no
   image for this life -- display:none beats the `hidden` clearing that revealStoryBody
   does, so an empty figure can never flash. */
#life-image{margin:0 0 22px; text-align:center}
#life-image.is-empty{display:none}
#life-image img{width:100%; max-width:340px; height:auto; aspect-ratio:1024/942;
  border-radius:12px; border:1px solid var(--line); background:var(--panel);
  display:block; margin:0 auto}
#life-image figcaption{font-size:11.5px; line-height:1.5; color:var(--faint);
  max-width:440px; margin:9px auto 0; text-align:center; font-style:italic}
.story{font-family:var(--serif); font-size:clamp(19px,2.6vw,23px); line-height:1.6; color:#eef0f6; margin:6px 0 26px}
/* Longer lives arrive as several <p> (see showStory); the first sits flush with the
   heading above it, and the rest are separated by a paragraph space. */
.story p{margin:0 0 0.85em}
.story p:last-child{margin-bottom:0}
/* Editorial note above the story: sans rather than serif, so it reads as apparatus
   around the story rather than as part of it. No left rule -- the typeface change
   already does that work, and the bar competed with the illustration below it. */
.disclaimer{font-family:var(--sans); font-size:16.5px; line-height:1.55; color:var(--ink);
  padding:2px 0; margin:16px 0 22px}
.stats{display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:12px; margin-bottom:26px}
.tile{background:var(--panel); border:1px solid var(--line); border-radius:12px; padding:13px 15px}
.tile .k{font-family:var(--mono); font-size:11.5px; text-transform:uppercase; letter-spacing:.1em; color:var(--dim)}
.tile .v{font-size:16px; margin-top:5px}
.tile-src{margin-top:8px; display:flex; flex-wrap:wrap; gap:4px; align-items:center}
.tile-src-label{font-family:var(--mono); font-size:9px; color:var(--faint); text-transform:uppercase; letter-spacing:.08em}
.tile-chip{font-family:var(--mono); font-size:9px; color:var(--faint); text-decoration:none;
  border:1px solid var(--line); border-radius:4px; padding:1px 5px; line-height:1.5; cursor:pointer}
.tile-chip:hover{color:var(--accent2); border-color:var(--accent2)}
.tile .v.alive{color:var(--alive)} .tile .v.death{color:var(--death)}

details#sources{border:1px solid var(--line); border-radius:12px; padding:6px 16px; background:var(--bg2); margin-bottom:26px}
details#sources summary{cursor:pointer; font-family:var(--mono); font-size:13px; letter-spacing:.08em; color:var(--dim); padding:8px 0}
#src-list{margin:6px 0 12px; padding-left:18px}
#src-list li{font-size:13px; color:var(--dim); margin-bottom:8px}
#src-list a{color:var(--accent2)}

.actions{display:flex; flex-wrap:wrap; gap:12px; align-items:center; justify-content:center}

/* wall / gallery */
.wall-main{padding:34px 22px 70px}
.wall-title{font-family:var(--serif); font-weight:500; font-size:clamp(30px,6vw,48px); margin:0}
.wall-sub{margin:4px 0 26px}
.wall-sub a{color:var(--accent2)}
.wall{list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(auto-fill,minmax(260px,1fr)); gap:14px}
.card{background:var(--panel); border:1px solid var(--line); border-radius:14px; transition:.15s}
.card:hover{border-color:var(--faint); transform:translateY(-2px)}
.card a{display:block; padding:16px 18px; text-decoration:none}
.card-head{display:flex; justify-content:space-between; align-items:baseline; gap:8px}
.card-name{font-family:var(--serif); font-size:21px}
.card-born{font-family:var(--mono); font-size:12px; color:var(--accent)}
.card-place{font-size:12px; color:var(--faint); margin:3px 0 8px}
.card-summary{font-size:14px; color:var(--dim); margin:0}
.empty{color:var(--faint)}
.empty a{color:var(--accent2)}

.footer{max-width:820px; margin:0 auto; padding:26px 22px 40px; color:var(--faint); font-size:12px; text-align:center; border-top:1px solid var(--line)}
[hidden]{display:none !important}

/* progress rail — dots on a connecting rail, and steps you have already played ARE
   clickable (they take you back to that stage).
   It used to be a row of bordered pills with a filled gold "active" one, i.e. the exact
   visual language of the buttons below it: user testing showed people trying to click
   the stage names — and expecting to land back on that stage. So the rail now says two
   things at once, in two different languages: the PILL (see the button rule above) means
   "an action you can take here"; the UNDERLINED LABEL means "a place you can go back to",
   the ordinary link affordance. A step with no underline is not clickable — either it is
   where you already are, or you have not played it yet. */
#progress{list-style:none; display:flex; gap:0; justify-content:center; align-items:center;
  margin:24px 0 10px; padding:0; flex-wrap:wrap; user-select:none}
#progress li{display:flex; align-items:center}
#progress li:not(:last-child)::after{content:""; width:clamp(14px,4vw,30px); height:1px;
  background:var(--line); margin:0 9px}
#progress .step{display:flex; align-items:center; gap:7px; margin:0; padding:5px 2px;
  background:none; border:0; font-family:var(--mono); font-size:11px; letter-spacing:.12em;
  text-transform:uppercase; color:var(--faint); cursor:default; transition:color .2s}
#progress .step::before{content:""; flex:none; width:7px; height:7px; border-radius:50%;
  border:1px solid var(--faint); background:transparent; transition:.2s}
#progress .step:disabled{opacity:1}   /* the state colours below say it, not a dimming */
#progress .step:hover{transform:none} /* it is not a pill, so it must not lift like one */
#progress .lbl{border-bottom:1px solid transparent; padding-bottom:1px; transition:.15s}
/* played: behind you, and you can go back to it */
#progress li.done .step{color:var(--dim)}
#progress li.done .step::before{background:var(--faint); border-color:var(--faint)}
/* where you are */
#progress li.active .step{color:var(--accent)}
#progress li.active .step::before{background:var(--accent); border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(233,196,106,.16)}
/* clickable — the underline is the whole affordance */
#progress li.nav .step{cursor:pointer; color:var(--dim)}
#progress li.nav .lbl{border-bottom-color:var(--faint)}
#progress li.nav .step:hover{color:var(--ink)}
#progress li.nav .step:hover .lbl{border-bottom-color:var(--accent)}

/* stages */
.stage{padding:26px 0 40px; animation:rise .5s ease}
.stage h2{font-family:var(--serif); font-weight:500; font-size:clamp(26px,5vw,40px); margin:8px 0 8px; text-align:center}
.stage-hint{color:var(--dim); font-size:15px; max-width:640px; margin:0 auto 22px; text-align:center; line-height:1.5}

.reveal-value{min-height:2.4em; text-align:center; font-size:16px; color:var(--ink); margin:18px 0 8px; line-height:1.5}
/* Reserve room for the full (up to two-line) life summary so the action button below
   keeps its vertical position when the result appears. */
#life-result{min-height:4.4em}
.reveal-value strong{font-family:var(--serif); font-weight:600; font-size:26px}
.reveal-value .sub{display:block; color:var(--faint); font-size:13px; margin-top:3px}
/* The head-count under the drawn year. Bigger and brighter than .sub -- it is a
   statement in its own right, not a footnote -- with the two figures that carry the
   meaning picked out. */
.reveal-value .alive-share{display:block; color:var(--dim); font-size:17px; margin-top:8px; line-height:1.45}
.reveal-value .alive-share b{color:var(--ink); font-weight:600}
/* Reserve the FULL settled height from the outset -- year line plus a head-count that
   wraps to two lines on a phone -- so revealing the caption never pushes the buttons
   below it down. The year is sized up to occupy that reserved space rather than leaving
   it blank. Same tactic as #life-result above. */
#when-result{min-height:6.6em}
#when-result strong{font-size:34px}
.reveal-value.is-death strong{color:var(--death)}
.reveal-value.is-alive strong{color:var(--alive)}
.reveal-value .life-cause{display:block; font-family:var(--serif); font-size:22px; margin-top:6px; color:var(--ink)}
/* The settled life summary: one continuous sentence, one font, neutral colour. */
/* Left-aligned in a fixed-width centered block so that, as the summary is built up
   segment by segment, already-written text never re-flows — new events just tack on
   at the end (wrapping downward when needed). */
.reveal-value .life-line{font-family:var(--serif); font-size:23px; line-height:1.45; color:var(--ink); text-align:left; max-width:640px; margin:0 auto}
/* The (disease-type) parenthetical matches the surrounding summary text. */
.life-cat{font-family:inherit; font-size:inherit; color:inherit; font-style:normal}

/* Slot-machine reveal of the drawn sex in the Life-stage heading, and the fade-in of
   the sex-specific odds once it settles. */
.sex-word{display:inline-block; min-width:2.6em; text-align:center; color:var(--accent); font-weight:700}
.sex-word.boy{color:var(--accent2)}   /* blue */
.sex-word.girl{color:#ea8fc4}         /* pink */
.sex-word.flip{animation:sexFlip .16s ease}
@keyframes sexFlip{0%{transform:translateY(-45%); opacity:.25}100%{transform:none; opacity:1}}
.sex-word.settled{animation:sexSettle .34s cubic-bezier(.2,.85,.25,1)}
@keyframes sexSettle{0%{transform:scale(1.35)}100%{transform:none}}
#demo-stats.reveal-in{animation:fadeUp .45s ease}
/* The story stage, revealed once the name roll settles (see rollName). */
.fade-in{animation:fadeUp .45s ease}
/* The name reveal reuses the sex roll's flip and settle, in the story heading. */
#life-name .name-roll{display:inline-block; min-width:5ch}
#life-name .name-roll.rolling{color:var(--accent)}
#life-name .name-roll.flip{animation:sexFlip .16s ease}
#life-name .name-roll.settled{animation:sexSettle .34s cubic-bezier(.2,.85,.25,1)}
@keyframes fadeUp{0%{opacity:0; transform:translateY(6px)}100%{opacity:1; transform:none}}

/* life-events timeline */
/* The timeline is the hero of the Life stage: it fills the column width and scales
   up with it (aspect-ratio gives it auto height instead of the old fixed 74px). */
#life-timeline{margin:22px 0 8px}
#tl-svg{width:100%; height:auto; aspect-ratio:360/84; display:block}
.tl-mark{transition:opacity .25s ease}

.stage-actions{display:flex; gap:12px; justify-content:center; align-items:center; margin-top:8px}
.ghost-next{background:transparent; color:var(--accent); border:1px solid var(--accent); border-radius:999px;
  padding:13px 26px; font-size:16px; font-weight:600; cursor:pointer; transition:.15s}
.ghost-next:hover{background:var(--accent); color:#20180a}
.again-btn{background:transparent; color:var(--dim); border:1px solid var(--line); border-radius:999px;
  padding:13px 20px; font-size:14px; cursor:pointer; transition:.15s}
.again-btn:hover{color:var(--ink); border-color:var(--faint)}
.again-btn:disabled{opacity:.5; cursor:default}

/* population graph */
#pop-graph{width:100%; height:150px; display:block}
.pop-area{fill:url(#g) ; fill:rgba(106,176,243,.14)}
.pop-line{fill:none; stroke:var(--accent2); stroke-width:1.4; vector-effect:non-scaling-stroke}
.scan{stroke:var(--accent); stroke-width:1.5; vector-effect:non-scaling-stroke; opacity:.8}
.scan.settled{opacity:1}
.graph-dot{fill:#fff; stroke:var(--accent); stroke-width:2; vector-effect:non-scaling-stroke}
.graph-grid{stroke:#1a2133; stroke-width:.5; vector-effect:non-scaling-stroke}
.graph-axis{position:relative; height:13px; margin-top:6px; font-family:var(--mono); font-size:10px; color:var(--faint)}
.graph-axis span{position:absolute; transform:translateX(-50%); white-space:nowrap}
.graph-axis-unit{font-family:var(--mono); font-size:9px; color:var(--faint); text-align:center; margin-top:3px; opacity:.7}

/* demography */
.demo{margin:6px 0 8px}
.demo-tiles{display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:12px; margin-bottom:18px}
.demo-tiles .tile{text-align:center}
.demo-tiles .v{font-family:var(--serif); font-size:24px; margin-top:6px}
.causes{background:var(--panel); border:1px solid var(--line); border-radius:12px; padding:14px 16px}
.causes .k{font-family:var(--mono); font-size:11.5px; text-transform:uppercase; letter-spacing:.1em; color:var(--dim); margin-bottom:12px}
#demo-stats > .k{font-family:var(--mono); font-size:11.5px; text-transform:uppercase; letter-spacing:.1em; color:var(--dim); margin:6px 0 12px}
.k-note{text-transform:none; letter-spacing:0; color:var(--faint); opacity:.8; font-style:italic}
.source-line{font-size:11px; color:var(--faint); margin:8px 0 2px; text-align:center; line-height:1.5}
/* A chart's sources sit inside the chart's panel, under a hairline: attribution for what
   is drawn above, rather than something belonging to the result revealed below. */
.panel .source-line{margin:12px 0 0; padding-top:9px; border-top:1px solid var(--line)}
/* A stat block's sources belong to the TILES ABOVE them, not to the heading below.
   The generic spacing put 18px above the source line and 6px below, so it read as a
   caption for the next section. Hug the grid it documents, then leave a clear break.
   Direct children only: the .causes panel keeps its own bordered, left-aligned rule. */
#demo-stats > .demo-tiles{margin-bottom:5px}
#demo-stats > .source-line{margin:0 0 30px}
.source-line a{color:var(--dim); text-decoration:none; border-bottom:1px dotted var(--line)}
.source-line a:hover{color:var(--accent2)}
.causes .source-line{text-align:left; margin-top:14px; padding-top:12px; border-top:1px solid var(--line)}
.cause{display:grid; grid-template-columns:1fr 120px 40px; align-items:center; gap:10px; margin:8px 0; font-size:14px}
.cause-name{color:var(--ink)}
.cause-track{background:#0c0e14; border-radius:6px; height:8px; overflow:hidden; border:1px solid var(--line)}
/* Neutral bars: these are just the odds for this era and place. Red is reserved for the
   one cause that actually took this life (.cause-hit below). */
.cause-bar{display:block; height:100%; background:linear-gradient(90deg,#31394a,#8892a6)}
.cause-pct{font-family:var(--mono); font-size:12px; color:var(--dim); text-align:right}
.cause-other .cause-name{color:var(--dim); font-style:italic}
.cause-other .cause-bar{background:var(--line)}
/* The one cause that actually took this life: a horizontal light-up sweep, settling
   into a steady highlight so it stays legible after the flash. */
.cause{position:relative; border-radius:6px; padding:2px 8px; margin-left:-8px; margin-right:-8px;
  transition:background .5s ease, box-shadow .5s ease}
.cause-hit{background:rgba(224,122,122,.14); box-shadow:inset 0 0 0 1px rgba(224,122,122,.35); animation:causeHit 1s ease}
.cause-hit .cause-name{color:#f2b8b8; font-weight:600}
.cause-hit .cause-bar{background:linear-gradient(90deg,#e07a7a,#ffd18f)}
.cause-hit .cause-pct{color:#f2b8b8}
@keyframes causeHit{
  0%{background:rgba(224,122,122,0)}
  35%{background:rgba(255,190,140,.45); box-shadow:inset 0 0 0 1px rgba(255,190,140,.7), 0 0 14px rgba(224,122,122,.4)}
  100%{background:rgba(224,122,122,.14)}
}
@media(max-width:520px){.cause{grid-template-columns:1fr 70px 34px}}


/* Year picker: the graph only becomes interactive in picking mode, so the cursor and
   the highlighted frame appear then and not before. */
#pop-graph.picking{cursor:ew-resize; touch-action:none}
#map-svg.picking{cursor:crosshair; touch-action:none}
#where-pick.on{color:var(--ink); border-color:var(--faint)}
/* Same reservation as #when-result: the head-count line must not push the
   buttons down when it appears. */
#where-result{min-height:6.6em}
#where-result strong{font-size:34px}
.panel.picking{box-shadow:0 0 0 1px var(--faint) inset; border-radius:10px}
#when-pick.on{color:var(--ink); border-color:var(--faint)}

/* A caveat under the famine odds: the chronology holds named famines only. */
.demo-note{color:var(--faint); font-size:12px; margin:4px 0 2px; text-align:center}
