:root{
  --paper:#f1f1ef; --ink:#1e2022; --ink-soft:#54585c; --ink-faint:#666b70;
  --etch:rgba(30,32,34,.5); --rule:rgba(30,32,34,.16); --rule-soft:rgba(30,32,34,.08);
  --route:#b0392c; --basin:rgba(176,57,44,.07);
  --r0s:var(--etch); --r1s:var(--etch); --r2s:var(--etch);
  --r0f:transparent; --r1f:transparent; --r2f:transparent;
  --spark:#b0392c;
  --serif:"Libre Caslon Text","Iowan Old Style",Georgia,serif;
  --sans:"Archivo","Helvetica Neue",Arial,sans-serif;
  --zone:clamp(200px,24vw,300px);
}
@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]){
  --paper:#191b1d; --ink:#e8e9ea; --ink-soft:#b4b7ba; --ink-faint:#95999d;
  --etch:rgba(232,233,234,.45); --rule:rgba(232,233,234,.15); --rule-soft:rgba(232,233,234,.07);
  --route:#e06a55; --basin:rgba(224,106,85,.08); --spark:#e06a55;
}}
:root[data-scheme="cyanotype"]{
  --paper:#14395f; --ink:#e9f1f8; --ink-soft:#c2d4e4; --ink-faint:#93aec7;
  --etch:rgba(233,241,248,.5); --rule:rgba(233,241,248,.18); --rule-soft:rgba(233,241,248,.09);
  --route:#ffffff; --basin:rgba(255,255,255,.08); --spark:#e3b23c;
  --r0s:var(--etch); --r1s:var(--etch); --r2s:var(--etch);
  --r0f:rgba(255,255,255,.025); --r1f:rgba(255,255,255,.04); --r2f:rgba(255,255,255,.055);
}
:root[data-scheme="bathy"]{
  --paper:#edf4f3; --ink:#14343c; --ink-soft:#47646c; --ink-faint:#567076;
  --etch:rgba(20,52,60,.45); --rule:rgba(20,52,60,.16); --rule-soft:rgba(20,52,60,.08);
  --route:#a62d62; --basin:rgba(23,94,124,.10); --spark:#a62d62;
  --r0s:rgba(23,94,124,.4); --r1s:rgba(23,94,124,.5); --r2s:rgba(23,94,124,.6);
  --r0f:rgba(23,94,124,.05); --r1f:rgba(23,94,124,.08); --r2f:rgba(23,94,124,.12);
}
@media (prefers-color-scheme:dark){ :root[data-scheme="bathy"]:not([data-theme="light"]){
  --paper:#0d181d; --ink:#dfe9ec; --ink-soft:#a8bcc2; --ink-faint:#7f959c;
  --etch:rgba(223,233,236,.42); --rule:rgba(223,233,236,.15); --rule-soft:rgba(223,233,236,.07);
  --route:#ee7fb4; --basin:rgba(107,178,214,.10); --spark:#ee7fb4;
  --r0s:rgba(107,178,214,.35); --r1s:rgba(107,178,214,.45); --r2s:rgba(107,178,214,.55);
  --r0f:rgba(107,178,214,.05); --r1f:rgba(107,178,214,.09); --r2f:rgba(107,178,214,.13);
}}
:root[data-scheme="thermal"]{
  --paper:#101012; --ink:#ece9e4; --ink-soft:#b8b4ad; --ink-faint:#918d85;
  --etch:rgba(236,233,228,.32); --rule:rgba(236,233,228,.14); --rule-soft:rgba(236,233,228,.07);
  --route:#9fd8e0; --basin:rgba(235,155,63,.08); --spark:#eb9b3f;
  --r0s:#9c3722; --r1s:#c65f22; --r2s:#eb9b3f;
  --r0f:rgba(156,55,34,.06); --r1f:rgba(198,95,34,.08); --r2f:rgba(235,155,63,.11);
}

*{ margin:0; padding:0; box-sizing:border-box; }
html{ font-size:17px; -webkit-text-size-adjust:100%; }
body{ background:var(--paper); color:var(--ink); font-family:var(--serif);
  line-height:1.62; -webkit-font-smoothing:antialiased; }
.plate{ max-width:1180px; margin:0 auto; padding:34px clamp(18px,4vw,54px) 90px; }
a{ color:inherit; }
a:focus-visible,button:focus-visible,input:focus-visible{ outline:2px solid var(--route); outline-offset:3px; }

/* masthead ---------------------------------------------------------------- */
.cartouche{ border:1px solid var(--rule); padding:30px 26px 26px; text-align:center; }
.cartouche .eyebrow{ font-family:var(--sans); font-size:11px; letter-spacing:.3em;
  text-transform:uppercase; color:var(--ink-faint); margin-bottom:14px; }
.cartouche h1{ font-size:clamp(26px,4.4vw,40px); font-weight:400; letter-spacing:.09em;
  text-transform:uppercase; line-height:1.14; }
.cartouche .dek{ font-style:italic; color:var(--ink-soft); max-width:44ch; margin:14px auto 0;
  font-size:16px; }
.cartouche hr{ border:0; border-top:1px solid var(--rule); width:120px; margin:20px auto; }
nav{ font-family:var(--sans); font-size:14px; display:flex; gap:22px; justify-content:center; flex-wrap:wrap; }
nav a{ text-decoration:none; color:var(--ink-soft); padding-bottom:3px; }
nav a:hover{ color:var(--ink); }
nav a[aria-current="page"]{ color:var(--route); border-bottom:1px solid var(--route); }

.schemes{ display:flex; gap:20px; margin:24px 0 0; font-family:var(--sans);
  font-size:11px; letter-spacing:.18em; text-transform:uppercase; flex-wrap:wrap; }
.schemes button{ background:none; border:0; color:var(--ink-faint); cursor:pointer;
  font:inherit; letter-spacing:inherit; padding:2px 0; }
.schemes button[aria-pressed="true"]{ color:var(--ink); border-bottom:1px solid var(--route); }

/* the elevation bench ----------------------------------------------------- */
.profile{ margin:24px 0 30px; }
.profile .bar{ display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  font-family:var(--sans); font-size:11px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink-faint); margin:0 0 10px; }
.profile input[type=range]{ flex:1 1 190px; min-width:150px; height:2px; -webkit-appearance:none;
  appearance:none; background:var(--rule); outline:none; }
.profile input[type=range]::-webkit-slider-thumb{ -webkit-appearance:none; appearance:none;
  width:11px; height:11px; border-radius:50%; background:var(--route); cursor:pointer; }
.profile input[type=range]::-moz-range-thumb{ width:11px; height:11px; border-radius:50%;
  background:var(--route); border:0; cursor:pointer; }
.profile .val{ font-variant-numeric:tabular-nums; color:var(--ink-soft); min-width:52px; }
.profile figure{ border-top:1px solid var(--rule); border-bottom:1px solid var(--rule); }
.profile canvas{ display:block; width:100%; height:250px; }
@media (max-width:860px){ .profile canvas{ height:200px; } }

/* timeline ---------------------------------------------------------------- */
.map{ position:relative; margin-top:14px; }
.map svg.terrain{ position:absolute; inset:0; width:var(--zone); height:100%; pointer-events:none; }
.route{ list-style:none; margin-left:var(--zone); }
.stop{ padding:26px 0 24px; border-top:1px solid var(--rule-soft); position:relative; }
.stop:first-child{ border-top:0; }
.stop .meta{ font-family:var(--sans); font-size:11px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--ink-faint); margin-bottom:7px; }
.stop h3{ font-size:20px; font-weight:400; line-height:1.28; }
.stop h3 a{ text-decoration:none; }
.stop h3 a:hover{ color:var(--route); }
.stop .au{ font-family:var(--sans); font-size:13.5px; color:var(--ink-soft); margin-top:5px; }
.stop blockquote{ font-style:italic; color:var(--ink-soft); margin-top:10px;
  padding-left:14px; border-left:1px solid var(--rule); font-size:15.5px; }
.stop blockquote cite{ display:block; font-style:normal; font-family:var(--sans);
  font-size:10.5px; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-faint); margin-top:7px; }
.chips{ margin-top:11px; display:flex; flex-wrap:wrap; gap:7px 14px;
  font-family:var(--sans); font-size:12.5px; }
.chips a{ color:var(--ink-soft); text-decoration:none; border-bottom:1px solid var(--rule); }
.chips a:hover{ color:var(--route); border-color:var(--route); }
.sessmark{ font-family:var(--sans); font-size:11px; letter-spacing:.24em; text-transform:uppercase;
  color:var(--ink-faint); padding:22px 0 4px; border-top:1px solid var(--rule); }

/* generic content --------------------------------------------------------- */
.head{ margin:30px 0 6px; }
.head .kicker{ font-family:var(--sans); font-size:11px; letter-spacing:.22em;
  text-transform:uppercase; color:var(--ink-faint); }
.head h2{ font-size:clamp(22px,3.2vw,31px); font-weight:400; line-height:1.2; margin-top:8px; }
.head .sub{ font-family:var(--sans); font-size:14px; color:var(--ink-soft); margin-top:8px; }
.cols{ display:grid; grid-template-columns:minmax(0,1fr); gap:34px; margin-top:26px; }
@media (min-width:900px){ .cols.two{ grid-template-columns:minmax(0,1.55fr) minmax(0,1fr); } }
h4.sec{ font-family:var(--sans); font-size:11px; letter-spacing:.22em; text-transform:uppercase;
  color:var(--ink-faint); font-weight:400; margin:26px 0 10px; padding-bottom:6px;
  border-bottom:1px solid var(--rule); }
.edge{ padding:14px 0; border-bottom:1px solid var(--rule-soft); }
.edge .rel{ font-family:var(--sans); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--route); }
.edge .to{ font-size:17px; }
.edge .to a{ text-decoration:none; border-bottom:1px solid var(--rule); }
.edge .note{ font-family:var(--sans); font-size:13px; color:var(--ink-soft); margin-top:3px; }
.passage{ margin-top:9px; font-size:15px; color:var(--ink-faint); line-height:1.6;
  border-left:1px solid var(--rule); padding-left:13px; }
.passage mark{ background:var(--basin); color:var(--ink); padding:1px 0; }
.passage .none{ font-family:var(--sans); font-size:12.5px; font-style:normal; }
.prov{ font-family:var(--sans); font-size:10.5px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink-faint); margin-top:7px; }
.empty{ font-family:var(--sans); font-size:13.5px; color:var(--ink-faint); font-style:normal;
  border:1px dashed var(--rule); padding:16px 18px; }

/* resources.html — one recommended talk per block, in reading order.
   --spark, not --route, for the author mark: --route is white in cyanotype. */
.res{ padding:16px 0 17px; border-bottom:1px solid var(--rule-soft); max-width:62ch; }
.res .rp{ font-family:var(--sans); font-size:11px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-faint); line-height:1.5; }
.res .rp a{ color:inherit; text-decoration:none; border-bottom:1px solid var(--rule-soft); }
.res .rp a:hover{ color:var(--route); border-color:var(--route); }
.res .rt{ font-size:19px; line-height:1.32; margin-top:7px; }
.res .rt a{ text-decoration:none; border-bottom:1px solid var(--rule); }
.res .rt a:hover{ color:var(--route); border-color:var(--route); }
.res .rs{ font-family:var(--sans); font-size:13.5px; color:var(--ink-soft);
  margin-top:7px; line-height:1.45; }
.res .rs .mark{ font-size:10.5px; letter-spacing:.15em; text-transform:uppercase;
  color:var(--spark); margin-left:10px; white-space:nowrap; }
.res .rv{ font-family:var(--sans); font-size:13px; color:var(--ink-faint);
  margin-top:3px; line-height:1.5; }
.res .prov{ margin-top:7px; letter-spacing:.11em; line-height:1.6; }
.head .grp{ margin-top:14px; display:flex; gap:8px; flex-wrap:wrap; }
/* an event: the occasion, then its talks in the order they were given */
.evt{ padding-top:4px; }
.evt + .evt{ margin-top:34px; }
.evt h3{ font-size:23px; line-height:1.24; margin-top:6px; font-weight:400; }
.evt .evwhen{ font-family:var(--sans); font-size:12.5px; letter-spacing:.04em;
  color:var(--ink-faint); margin-top:6px; margin-bottom:4px; }
/* one talk inside an event: its slot in the day, then the talk */
.etalk{ display:grid; grid-template-columns:5.5rem minmax(0,1fr); gap:0 14px;
  padding:13px 0; border-bottom:1px solid var(--rule-soft); align-items:baseline; }
.etalk .eslot{ font-family:var(--sans); font-size:11px; letter-spacing:.13em;
  text-transform:uppercase; color:var(--ink-faint); white-space:nowrap; }
.etalk .et{ font-size:16.5px; line-height:1.34; }
.etalk .et a{ text-decoration:none; border-bottom:1px solid var(--rule); }
.etalk .et a:hover{ color:var(--route); border-color:var(--route); }
.etalk .ew{ font-family:var(--sans); font-size:13px; color:var(--ink-soft);
  margin-top:5px; line-height:1.45; }
.etalk .epaper{ font-family:var(--sans); font-size:11px; letter-spacing:.13em;
  text-transform:uppercase; color:var(--spark); margin-top:6px; line-height:1.5; }
.etalk .epaper a{ color:inherit; text-decoration:none;
  border-bottom:1px solid var(--rule-soft); }
@media (max-width:560px){
  .etalk{ grid-template-columns:1fr; gap:0; }
  .etalk .eslot{ margin-bottom:5px; }
}
.tbl{ width:100%; border-collapse:collapse; font-family:var(--sans); font-size:13.5px; }
.tbl th{ text-align:left; font-weight:400; color:var(--ink-faint); font-size:11px;
  letter-spacing:.16em; text-transform:uppercase; padding:8px 10px 8px 0; border-bottom:1px solid var(--rule); }
.tbl td{ padding:8px 10px 8px 0; border-bottom:1px solid var(--rule-soft); vertical-align:top; }
.tbl a{ text-decoration:none; border-bottom:1px solid var(--rule); }
.grid{ display:grid; gap:8px 22px; grid-template-columns:repeat(auto-fill,minmax(210px,1fr)); }
.grid a{ font-family:var(--sans); font-size:13.5px; text-decoration:none; color:var(--ink-soft);
  padding:3px 0; display:flex; justify-content:space-between; gap:10px; }
.grid a:hover{ color:var(--route); }
.grid a .n{ color:var(--ink-faint); font-variant-numeric:tabular-nums; }
.grid a.dim{ opacity:.42; }
footer{ margin-top:64px; padding-top:18px; border-top:1px solid var(--rule);
  font-family:var(--sans); font-size:12px; color:var(--ink-faint);
  display:flex; justify-content:space-between; gap:16px; flex-wrap:wrap; }
code,pre{ font-family:ui-monospace,"SF Mono",Menlo,monospace; }
pre{ background:var(--rule-soft); padding:15px 17px; overflow-x:auto; font-size:13px; line-height:1.55; }
@media (prefers-reduced-motion:reduce){ *{ animation:none!important; transition:none!important; } }
svg.chord{ display:block; width:100%; max-width:880px; height:auto; margin:8px auto 30px; }

/* the map channel must not starve the text on small screens */
@media (max-width:900px){ :root{ --zone:86px; } }
@media (max-width:640px){
  :root{ --zone:0px; }
  .map svg.terrain{ display:none; }
  .route{ margin-left:0; }
  .cols.two{ grid-template-columns:minmax(0,1fr); }
}
.math{ overflow-x:auto; }
.math mjx-container[display="true"]{ margin:.7em 0; }
.thm{ border-left:2px solid var(--route); padding:12px 0 12px 16px; margin:16px 0; }
.thm .lbl{ font-family:var(--sans); font-size:10.5px; letter-spacing:.18em;
  text-transform:uppercase; color:var(--route); margin-bottom:6px; }
.thm .src{ font-family:var(--sans); font-size:11px; color:var(--ink-faint); margin-top:8px; }

/* bipartite map ----------------------------------------------------------- */
.rfilter{ display:flex; flex-wrap:wrap; gap:8px; margin:14px 0 6px; }
.rchip{ font-family:var(--sans); font-size:11px; letter-spacing:.12em; text-transform:uppercase;
  background:none; border:1px solid var(--rule); color:var(--ink-faint); padding:5px 11px;
  cursor:pointer; border-radius:0; }
.rchip[aria-pressed="true"]{ color:var(--ink); border-color:var(--route); }
.bipwrap{ display:grid; grid-template-columns:minmax(0,1fr); gap:22px; margin-top:12px; }
@media (min-width:1080px){ .bipwrap{ grid-template-columns:minmax(0,1fr) 300px; } }
.bipscroll{ overflow-x:auto; border-top:1px solid var(--rule); border-bottom:1px solid var(--rule); }
svg.bip{ display:block; width:100%; min-width:660px; height:auto; }
svg.bip .colhead{ font-family:var(--sans); font-size:10.5px; letter-spacing:.18em;
  text-transform:uppercase; fill:var(--ink-faint); }
svg.bip .lb{ font-family:var(--sans); font-size:12px; fill:var(--ink-soft); }
svg.bip .lb.sm{ font-size:11px; }
svg.bip .yr{ font-family:var(--sans); font-size:9.5px; fill:var(--ink-faint); }
svg.bip .dot{ fill:var(--route); opacity:.75; }
svg.bip .nd{ cursor:pointer; }
svg.bip .nd:focus{ outline:none; }
svg.bip .nd:focus-visible .lb{ fill:var(--route); text-decoration:underline; }
svg.bip .nd.hov .lb,svg.bip .nd:hover .lb{ fill:var(--route); }
svg.bip .nd.on .lb{ fill:var(--ink); }
svg.bip .nd.on .dot{ opacity:1; }
svg.bip .nd.off{ opacity:.26; }
svg.bip .wire{ fill:none; stroke:var(--route); stroke-width:1; opacity:.5; }
svg.bip .wire.r-introduces{ stroke-width:1.8; opacity:.9; }
svg.bip .wire.r-motivated-by{ stroke-dasharray:5 3; opacity:.7; }
svg.bip .wire.r-evaluates-with{ stroke-dasharray:1.5 3; opacity:.55; }
.bippanel{ font-family:var(--sans); font-size:13px; max-height:760px; overflow-y:auto;
  border-left:1px solid var(--rule); padding-left:18px; }
@media (max-width:1079px){ .bippanel{ border-left:0; padding-left:0;
  border-top:1px solid var(--rule); padding-top:14px; max-height:none; } }
.bippanel .pk{ font-size:10.5px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--ink-faint); }
.bippanel h3{ font-family:var(--serif); font-size:18px; font-weight:400; margin:6px 0 4px; line-height:1.3; }
.bippanel h3 a{ text-decoration:none; border-bottom:1px solid var(--rule); }
.bippanel .au{ color:var(--ink-soft); font-size:12.5px; }
.bippanel .rl{ font-size:10.5px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--route); margin:15px 0 5px; }

/* graph views ------------------------------------------------------------- */
.mbtn{ font-family:var(--sans); font-size:11px; letter-spacing:.14em; text-transform:uppercase;
  background:none; border:1px solid var(--rule); color:var(--ink-faint); padding:5px 12px;
  cursor:pointer; }
.mbtn[aria-pressed="true"]{ color:var(--ink); border-color:var(--route); }
.gvhost{ background:var(--paper); }

/* the semester chart: citation arcs over the reading order,
   concept territories on the ground */
svg.chart{ display:block; }
svg.chart .cap,svg.chart .fh{ font-family:var(--sans); font-size:10px; letter-spacing:.18em;
  text-transform:uppercase; fill:var(--ink-faint); }
svg.chart .arc{ fill:none; stroke:var(--etch); stroke-width:.9; opacity:.15; }
svg.chart .arc.pv{ opacity:.6; stroke-width:1.2; }
svg.chart .arc.out{ stroke:var(--spark); stroke-width:1.9; opacity:1; }
svg.chart .arc.in{ stroke:var(--ink); stroke-width:1.3; opacity:.8; stroke-dasharray:none; }
svg.chart .arc.out.pv{ opacity:.8; }
svg.chart .arc.in.pv{ opacity:.6; }
svg.chart .arc.dim{ opacity:.03; }
svg.chart .ccv{ fill:none; stroke:var(--route); stroke-width:1.1; opacity:.32; }
svg.chart .ccv.hot{ opacity:.95; stroke-width:1.8; }
svg.chart .ccv.dim{ opacity:.05; }
svg.chart .w{ fill:none; stroke:var(--route); stroke-width:1; opacity:.8; }
svg.chart .w.t-introduces{ stroke-width:1.9; opacity:.95; }
svg.chart .w.t-motivated-by{ stroke-dasharray:5 3; }
svg.chart .w.t-evaluates-with{ stroke-dasharray:1.5 3; opacity:.55; }
svg.chart .w.t-uses{ opacity:.55; }
svg.chart .w.pv{ opacity:.4; }
svg.chart .wv{ fill:none; stroke:var(--route); stroke-width:.7; opacity:.08; }
svg.chart .brk,svg.chart .fr{ fill:none; stroke:var(--rule); stroke-width:1; }
svg.chart .sn{ font-family:var(--sans); font-size:10px; letter-spacing:.14em;
  text-transform:uppercase; fill:var(--ink-soft); }
svg.chart .sd{ font-family:var(--sans); font-size:10px; fill:var(--ink-faint); }
svg.chart .pn,svg.chart .cn{ cursor:pointer; }
svg.chart .pn:focus,svg.chart .cn:focus{ outline:none; }
svg.chart .mk{ fill:var(--paper); stroke:var(--route); stroke-width:1.5; }
svg.chart .dot{ fill:var(--route); opacity:.8; }
svg.chart .pl,svg.chart .cl{ font-family:var(--sans); font-size:10.5px; fill:var(--ink-soft); }
svg.chart .pn:hover .pl,svg.chart .pn:focus-visible .pl,
svg.chart .cn:hover .cl,svg.chart .cn:focus-visible .cl{ fill:var(--route); }
svg.chart .pn.sel .mk{ fill:var(--route); }
svg.chart .cn.sel .dot{ opacity:1; stroke:var(--route); stroke-width:3.5; }
svg.chart .pn.sel .pl,svg.chart .cn.sel .cl{ fill:var(--ink); font-weight:500; }
svg.chart .pn.near .pl,svg.chart .cn.near .cl{ fill:var(--ink); }
svg.chart .pn.far,svg.chart .cn.far{ opacity:.16; }
svg.chart.focused .fh,svg.chart.focused .sd{ opacity:.55; }

/* the citation matrix: row cites column, reading order both ways */
svg.mx{ display:block; }
svg.mx .gl{ fill:none; stroke:var(--rule-soft); }
svg.mx .sl{ fill:none; stroke:var(--rule); }
svg.mx .dg{ fill:none; stroke:var(--rule-soft); stroke-dasharray:2 4; }
svg.mx .shade{ fill:var(--basin); pointer-events:none; }
svg.mx .axis{ font-family:var(--sans); font-size:10px; letter-spacing:.18em;
  text-transform:uppercase; fill:var(--ink-faint); }
svg.mx .ml{ cursor:pointer; }
svg.mx .ml:focus{ outline:none; }
svg.mx .mt{ font-family:var(--sans); font-size:10.5px; fill:var(--ink-soft); }
svg.mx .mn{ font-family:var(--sans); font-size:10px; fill:var(--ink-faint);
  font-variant-numeric:tabular-nums; }
svg.mx .ml:hover .mt,svg.mx .ml:focus-visible .mt{ fill:var(--route); }
svg.mx .ml.sel .mt{ fill:var(--ink); font-weight:500; }
svg.mx .ml.near .mt{ fill:var(--ink); }
svg.mx.focused .ml.far{ opacity:.3; }
svg.mx .cell{ cursor:pointer; }
svg.mx .cf{ fill:var(--route); opacity:.78; }
svg.mx .cell:hover .cf,svg.mx .cell.hot .cf{ opacity:1; }
svg.mx.focused .cell.dim .cf{ opacity:.1; }

/* the compass rose: one paper's neighbourhood on a ring */
.egowrap{ border:1px solid var(--rule); margin-top:10px; background:var(--paper);
  overflow-x:auto; }
svg.rose{ display:block; margin:0 auto; }
/* One line style per relation. Before this, extends, replaces, uses and
   `relates` all fell through to the base rule and drew identically -- and uses
   (134 edges) and extends (65) are the two commonest relations after citation,
   so the rose was least legible exactly where it was busiest. Paper-to-paper
   links stay --etch and paper-to-concept links stay --route, so the two halves
   of the neighbourhood never have to be told apart by dash pattern alone.
   The key under the rose is built from these same classes, so it cannot drift
   from what is actually drawn. */
svg.rose .sp{ fill:none; stroke:var(--route); stroke-width:1.3; opacity:.85; }
svg.rose .sp.t-introduces{ stroke-width:2.4; opacity:.95; }
svg.rose .sp.t-extends{ stroke-width:1.3; opacity:.85; }
svg.rose .sp.t-replaces{ stroke-width:1.6; opacity:.9; stroke-dasharray:7 2.5 1 2.5; }
svg.rose .sp.t-motivated-by{ stroke-width:1; opacity:.7; stroke-dasharray:5 3; }
svg.rose .sp.t-uses{ stroke-width:1; opacity:.3; }
svg.rose .sp.t-evaluates-with{ stroke-width:1; opacity:.5; stroke-dasharray:1.5 3; }
svg.rose .sp.t-acknowledges-limitation{ stroke-width:1.8; opacity:.8; stroke-dasharray:1 3; }
svg.rose .sp.t-relates{ stroke-width:1.4; opacity:.6; stroke-dasharray:3 3; }
svg.rose .sp.t-cites{ stroke:var(--etch); stroke-width:1; opacity:.75; stroke-dasharray:none; }
svg.rose .sp.t-cited-by{ stroke:var(--etch); stroke-width:1; opacity:.75; stroke-dasharray:4 2.5; }
svg.rose .sp.hot{ opacity:1; stroke-width:2.2; }
svg.rose.focused .sp.dim{ opacity:.12; }
svg.rose .ch{ fill:none; stroke:var(--etch); stroke-width:.8; opacity:.25; }
svg.rose .ch.t-relates{ stroke:var(--route); opacity:.5; stroke-width:1.2; }
svg.rose .ch.hot{ opacity:.9; stroke-width:1.5; }
svg.rose.focused .ch.dim{ opacity:.04; }
svg.rose .ctr{ fill:var(--route); }
svg.rose .ctl{ font-family:var(--sans); font-size:11px; fill:var(--ink); }
svg.rose .ri{ cursor:pointer; }
svg.rose .ri:focus{ outline:none; }
svg.rose .mk{ fill:var(--paper); stroke:var(--route); stroke-width:1.3; }
svg.rose .dot{ fill:var(--route); opacity:.8; }
svg.rose .rl{ font-family:var(--sans); font-size:11px; fill:var(--ink-soft); }
svg.rose .ri:hover .rl,svg.rose .ri:focus-visible .rl,
svg.rose .ri.hl .rl{ fill:var(--route); }

/* ---- the rose's key ----
   Each swatch is a real `svg.rose` carrying the same class as the spoke it
   stands for, so the key is drawn by the stylesheet that draws the picture.
   It lists only the relations this paper's rose actually contains. */
.rosekey{ display:flex; flex-wrap:wrap; gap:5px 15px; margin-top:8px; align-items:center; }
.rosekey .k{ display:inline-flex; align-items:center; gap:6px; }
.rosekey .k svg{ display:block; flex:none; overflow:visible; }
.rosekey .k b{ font-family:var(--sans); font-size:10.5px; font-weight:400;
  letter-spacing:.11em; text-transform:uppercase; color:var(--ink-faint); white-space:nowrap; }
.rosekey svg.rose .ch{ opacity:.55; stroke-width:1.1; }

/* restored bipartite view, now carrying intra-column arcs */
svg.bip2{ display:block; width:100%; min-width:640px; height:auto; }
svg.bip2 .bhead{ font-family:var(--sans); font-size:10.5px; letter-spacing:.18em;
  text-transform:uppercase; fill:var(--ink-faint); }
svg.bip2 .blab{ font-family:var(--sans); font-size:12px; fill:var(--ink-soft); }
svg.bip2 .blab.sm{ font-size:11px; }
svg.bip2 .bsub{ font-family:var(--sans); font-size:9.5px; fill:var(--ink-faint); }
svg.bip2 .bdot{ fill:var(--route); opacity:.8; }
svg.bip2 .bn{ cursor:pointer; }
svg.bip2 .bn:focus{ outline:none; }
svg.bip2 .bn:hover .blab,svg.bip2 .bn:focus-visible .blab{ fill:var(--route); }
svg.bip2 .bn.sel .blab{ fill:var(--ink); font-weight:500; }
svg.bip2 .bn.sel .bdot{ opacity:1; r:5; }
svg.bip2 .bn.near .blab{ fill:var(--ink); }
svg.bip2 .bn.far{ opacity:.24; }
/* ---- visit trail ----
   Nodes you have already been to, glowing behind you. --trail is set per node
   in network.js: 1 for the one you just left, decaying exponentially back
   through the last few. Placed after every .sel / .near / .far rule above so
   the cascade is plain rather than a specificity argument.

   The glow is --spark: gold in cyanotype, brick in survey, magenta in bathy,
   orange in thermal. Owner's call, and it survives the objection that first
   pushed it to --ink -- that --spark already means "this paper cites that one"
   on the arcs. What makes it work is that the trail is now a lit DISC and the
   arcs are thin LINES. When the glow was only a faint bloom the two were easy
   to confuse; a body is not a stroke, and form separates them where hue does
   not. The selected node stays --route and a solid fill, so all three marks
   differ in shape before they differ in colour. */
svg.chart .pn.trail,svg.chart .cn.trail,
svg.bip2 .bn.trail,svg.mx .ml.trail{
  filter:drop-shadow(0 0 calc(2px + 11px * var(--trail,0)) var(--spark))
         drop-shadow(0 0 calc(1px + 4px  * var(--trail,0)) var(--spark));
}
/* Every node already carries a transparent shape as its hit target. Lighting it
   gives the glow a body instead of only a bloom -- a bloom alone reads as
   "slightly brighter", which is not what you can pick out of a plate of ninety
   nodes at a glance. */
svg.chart .pn.trail .hit,svg.chart .cn.trail .hit,
svg.bip2 .bn.trail .hit,svg.mx .ml.trail .hit{
  fill:var(--spark); opacity:calc(.22 * var(--trail,0));
}
/* Isolating dims everything unrelated. A trail node has to climb back out of
   that, or the trail is invisible exactly when it is most useful. */
svg.chart .pn.trail.far,svg.chart .cn.trail.far{ opacity:calc(.16 + .72 * var(--trail,0)); }
svg.bip2 .bn.trail.far{ opacity:calc(.24 + .64 * var(--trail,0)); }
svg.mx.focused .ml.trail.far{ opacity:calc(.3 + .6 * var(--trail,0)); }

/* the mark itself, so the glow has something solid at its centre */
svg.chart .pn.trail .mk{ stroke:var(--spark); stroke-width:2.2; }
svg.chart .cn.trail .dot{ opacity:1; fill:var(--spark); stroke:var(--spark); stroke-width:2.5; }
svg.bip2 .bn.trail .bdot{ opacity:1; fill:var(--spark); }
svg.chart .pn.trail .pl,svg.chart .cn.trail .cl,
svg.bip2 .bn.trail .blab,svg.mx .ml.trail .mt{ fill:var(--ink-soft); }

/* The glow fades in rather than snapping, which is what makes it read as a
   trail rather than as a second selection. Line 172 turns this off wholesale
   under prefers-reduced-motion; the glow itself stays, only the easing goes. */
svg.chart .pn,svg.chart .cn,svg.bip2 .bn,svg.mx .ml{
  transition:filter .45s ease-out,opacity .45s ease-out;
}

svg.bip2 .bw{ fill:none; stroke:var(--route); stroke-width:1; opacity:.55; }
svg.bip2 .bw.t-cites{ stroke:var(--ink-faint); opacity:.75; stroke-width:1.1; }
svg.bip2 .bw.t-relates{ stroke-width:1.5; opacity:.85; }
svg.bip2 .bw.t-introduces{ stroke-width:1.9; opacity:.95; }
svg.bip2 .bw.t-motivated-by{ stroke-dasharray:5 3; }
svg.bip2 .bw.t-evaluates-with{ stroke-dasharray:1.5 3; opacity:.45; }

/* ===== network page: the graph gets the whole screen ===== */
body.netpage{ overflow:hidden; }
.netbar{ display:flex; align-items:center; gap:10px 16px; flex-wrap:wrap;
  padding:9px 16px; border-bottom:1px solid var(--rule); background:var(--paper); }
.netbar .home{ font-family:var(--serif); font-size:15px; text-decoration:none;
  border-bottom:1px solid var(--rule); white-space:nowrap; }
.netbar .grp{ display:flex; gap:6px; flex-wrap:wrap; }
.netbar .count{ font-family:var(--sans); font-size:10.5px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--ink-faint); margin-left:auto; white-space:nowrap; }
.netbar .mbtn,.netbar .rchip{ padding:4px 9px; font-size:10px; }
.netstage{ position:relative; width:100%; height:calc(100vh - var(--barh,92px));
  overflow:auto; }
.netstage .gvhost{ border:0; min-height:100%; }
body.netpage.bip svg.bip2{ min-width:920px; }
.netpanel{ position:fixed; top:var(--barh,92px); right:0; width:min(330px,86vw);
  height:calc(100vh - var(--barh,92px)); overflow-y:auto; background:var(--paper);
  border-left:1px solid var(--rule); padding:16px 18px 40px; font-family:var(--sans);
  font-size:13px; transform:translateX(100%); transition:transform .18s ease; z-index:6; }
.netpanel.open{ transform:none; }
@media (prefers-reduced-motion:reduce){ .netpanel{ transition:none; } }
.netpanel .pk{ font-size:10.5px; letter-spacing:.18em; text-transform:uppercase; color:var(--ink-faint); }
.netpanel h3{ font-family:var(--serif); font-size:19px; font-weight:400; margin:6px 0 4px; line-height:1.3; }
.netpanel h3 a{ text-decoration:none; border-bottom:1px solid var(--rule); }
.netpanel .au{ color:var(--ink-soft); font-size:12.5px; }
.netpanel .rl{ font-size:10.5px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--route); margin:15px 0 5px; }
.netpanel .close{ position:absolute; top:10px; right:12px; background:none; border:0;
  color:var(--ink-faint); font-size:20px; cursor:pointer; line-height:1; }
.nethint{ position:absolute; left:16px; bottom:14px; font-family:var(--sans); font-size:11px;
  color:var(--ink-faint); pointer-events:none; }
/* the chart and matrix are drawn at one SVG unit per screen pixel */
body.netpage svg.chart,body.netpage svg.mx{ margin:0 auto; }


/* theme swatches: colour is the label */
.themes{ position:fixed; right:14px; bottom:14px; z-index:20; display:flex;
  align-items:center; gap:7px; padding:6px 9px; background:var(--paper);
  border:1px solid var(--rule); border-radius:var(--radius,0); }
.themes .lbl{ font-family:var(--sans); font-size:9.5px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--ink-faint); margin-right:2px; }
.themes button{ width:17px; height:17px; padding:0; border-radius:50%; cursor:pointer;
  border:1px solid rgba(128,128,128,.45); position:relative; }
.themes button::after{ content:""; position:absolute; inset:4px; border-radius:50%; }
.themes button[aria-pressed="true"]{ outline:1.5px solid var(--ink); outline-offset:2px; }
.themes button:focus-visible{ outline:2px solid var(--ink); outline-offset:2px; }
@media (max-width:600px){ .themes{ right:8px; bottom:8px; } .themes .lbl{ display:none; } }

/* ---- experiments listing ---- */
.run{ padding:17px 0 18px; border-bottom:1px solid var(--rule-soft); max-width:64ch; }
.run .rt{ font-family:var(--serif); font-size:19px; line-height:1.35; margin:0; }
.run .rt a{ color:var(--ink); text-decoration:none; border-bottom:1px solid var(--rule); }
.run .rt a:hover{ border-bottom-color:var(--ink); }
.run .rn{ font-family:var(--sans); font-size:13px; line-height:1.6; color:var(--ink-soft);
  margin:7px 0 0; }
