/* ============================================================
   Period Piece — main stylesheet
   Illuminated-manuscript aesthetic: parchment ground, iron-gall
   brown ink, vermilion rubrication, gold leaf, lapis + verdigris.
   Design tokens live in the single :root block further down.
   ============================================================ */

/* ---- the three faces, served from here ---------------------------------
   These came from fonts.googleapis.com on every page load, which handed
   Google each visitor's address, user-agent and referer before the page had
   drawn anything — on a site that rejected an OSM basemap partly because it
   "sends every visitor's viewport to a tile server against the site's
   privacy posture" (§3.8). The privacy page is an inventory and said nothing
   about it, because there was nothing kept in the browser to inventory: the
   leak was the request itself.

   Self-hosted, so the page makes no third-party request at all. Two DNS
   lookups and two TLS handshakes leave the critical path with it.

   Only latin and latin-ext are carried. Cardo also ships greek, hebrew,
   gothic, runic and old-italic and nothing here uses them; the two strings
   that genuinely leave Latin — Bronenosets Potyomkin in Cyrillic, Red Cliff
   in Chinese — have no subset on offer for these families, so they fell back
   to a system face before and still do. `unicode-range` means a browser
   fetches only the subsets a page actually needs.

   Relative paths are correct here and only here: CSS resolves against the
   stylesheet's own location, which does not move (§3.5).

   The filename IS the version. Swapping a face means a new name, or the
   year-long cache in _headers will go on serving the old one. */
@font-face{font-family:'Cardo';font-style:italic;font-weight:400;font-display:swap;
  src:url(../fonts/cardo-400italic-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Cardo';font-style:italic;font-weight:400;font-display:swap;
  src:url(../fonts/cardo-400italic-latin-ext.woff2) format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Cardo';font-style:normal;font-weight:400;font-display:swap;
  src:url(../fonts/cardo-400-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Cardo';font-style:normal;font-weight:400;font-display:swap;
  src:url(../fonts/cardo-400-latin-ext.woff2) format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Cardo';font-style:normal;font-weight:700;font-display:swap;
  src:url(../fonts/cardo-700-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Cardo';font-style:normal;font-weight:700;font-display:swap;
  src:url(../fonts/cardo-700-latin-ext.woff2) format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'MedievalSharp';font-style:normal;font-weight:400;font-display:swap;
  src:url(../fonts/medievalsharp-400-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'MedievalSharp';font-style:normal;font-weight:400;font-display:swap;
  src:url(../fonts/medievalsharp-400-latin-ext.woff2) format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'UnifrakturMaguntia';font-style:normal;font-weight:400;font-display:swap;
  src:url(../fonts/unifrakturmaguntia-400-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}

*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{
  background:var(--paper);
  color:var(--ink);
  font-family:var(--body);
  background-image:
    radial-gradient(ellipse at 50% -10%, rgba(185,138,47,.14), transparent 55%),
    repeating-linear-gradient(0deg, transparent 0 3px, rgba(36,28,18,.018) 3px 4px);
  min-height:100vh;
}
a{color:var(--oxblood)}

/* ---------- Masthead ---------- */
header.masthead{
  border-bottom:3px double var(--ink);
  padding:2.4rem 1.5rem 1.6rem;
  text-align:center;position:relative;
}
.sprockets{
  position:absolute;top:0;left:0;right:0;height:16px;
  background:repeating-linear-gradient(90deg, var(--ink) 0 18px, transparent 18px 30px);
  opacity:.85;
}
.sprockets.bottom{top:auto;bottom:-1px;height:14px;opacity:.25}
/* Height and tile are set together below; both are yours to change. */
:root{ --rule-height:14px; --rule-foot-height:8px; }
.masthead h1{
  font-family:var(--display);
  font-size:clamp(2.2rem,6vw,4.4rem);
  letter-spacing:.06em;color:var(--oxblood);
  text-shadow:2px 2px 0 rgba(36,28,18,.15);margin-top:.6rem;
}
.masthead h1 a{color:inherit;text-decoration:none}
.masthead .tagline{
  font-family:var(--utility);text-transform:uppercase;
  letter-spacing:.28em;font-size:.78rem;color:var(--lake);margin-top:.5rem;
}
.masthead .rule-note{
  max-width:620px;margin:.9rem auto 0;
  font-size:.98rem;font-style:italic;color:rgba(36,28,18,.75);
}
.masthead .admin-link{
  position:absolute;top:1.2rem;right:1.2rem;
  font-family:var(--utility);text-transform:uppercase;letter-spacing:.16em;
  font-size:.66rem;color:var(--lake);text-decoration:none;
  border:1.5px solid var(--lake);padding:.3rem .6rem;
}
.masthead .admin-link:hover{background:var(--lake);color:var(--paper)}

/* ---------- Era bar ---------- */
.era-bar{display:flex;justify-content:center;gap:.6rem;flex-wrap:wrap;padding:1.6rem 1rem 0}
.era-btn{
  font-family:var(--utility);font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;
  background:var(--paper);color:var(--ink);border:2px solid var(--ink);
  padding:.5rem .9rem;cursor:pointer;display:inline-flex;align-items:center;gap:.5rem;
  transition:background .15s ease,color .15s ease,box-shadow .15s ease;
  box-shadow:3px 3px 0 rgba(36,28,18,.25);
}
.era-btn .dot{width:12px;height:12px;border:1.5px solid var(--ink);background:var(--era-c)}
.era-btn .range{opacity:.55;font-size:.62rem;letter-spacing:.08em}
.era-btn:hover,.era-btn:focus-visible{background:var(--paper-deep)}
.era-btn:focus-visible{outline:2px dashed var(--oxblood);outline-offset:3px}
.era-btn.zoomed{background:var(--era-c);color:var(--paper);box-shadow:1px 1px 0 rgba(36,28,18,.4)}
.era-btn.zoomed .dot{background:var(--paper)}
.era-btn.zoomed .range{opacity:.8}
.era-btn.dimmed{opacity:.35}
.era-hint{text-align:center;font-family:var(--utility);font-size:.64rem;letter-spacing:.2em;
  text-transform:uppercase;color:rgba(36,28,18,.5);margin-top:.7rem}

/* ---------- Era filter row (period/location) ---------- */
.filter-row{display:none;justify-content:center;gap:1.2rem;flex-wrap:wrap;align-items:center;padding:1.1rem 1rem 0}
.filter-row.show{display:flex}
.filter-group{display:flex;align-items:center;gap:.5rem}
.filter-group label{font-family:var(--utility);font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;color:rgba(36,28,18,.65)}
.filter-group select{
  font-family:var(--utility);font-size:.78rem;letter-spacing:.06em;
  background:var(--paper);color:var(--ink);border:2px solid var(--ink);
  padding:.4rem .6rem;cursor:pointer;box-shadow:2px 2px 0 rgba(36,28,18,.25);
}
.filter-group select:focus-visible{outline:2px dashed var(--oxblood);outline-offset:2px}
.clear-filters{
  font-family:var(--utility);font-size:.64rem;letter-spacing:.16em;text-transform:uppercase;
  background:none;border:none;border-bottom:2px solid var(--oxblood);color:var(--oxblood);cursor:pointer;padding:.2rem 0;
}

/* ---------- Timeline ---------- */
.timeline-wrap{padding:.4rem 0 0;position:relative}
.timeline-scroll{
  position:relative;
  overflow-x:auto;overflow-y:visible;padding:2.2rem 3rem .4rem;
  scrollbar-width:thin;scrollbar-color:var(--oxblood) var(--paper-deep);
}
.timeline{display:flex;align-items:flex-end;gap:0;min-width:100%;width:max-content;position:relative}
.timeline.zoomed{min-width:100%}
.tick{
  flex:1 0 46px;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;
  background:none;border:none;cursor:pointer;padding:0 2px;position:relative;
  font-family:var(--utility);color:var(--ink);
}
.tick .label{
  font-size:.68rem;letter-spacing:.06em;white-space:nowrap;opacity:0;
  transform:translateY(6px) scale(.85);transition:opacity .18s ease,transform .18s ease;
  margin-bottom:.45rem;background:var(--ink);color:var(--paper);padding:.2rem .5rem;border-radius:2px;pointer-events:none;
}
.tick .mark{width:3px;height:22px;background:var(--era-c,var(--ink));transition:height .18s ease,width .18s ease,opacity .18s ease}
.tick.has-films .mark::after{
  content:"";display:block;width:7px;height:7px;border-radius:50%;
  background:var(--era-c);border:1.5px solid var(--ink);transform:translate(-2.5px,-11px);
}
.timeline.zoomed .tick .label{opacity:.85;transform:none;background:none;color:var(--ink);font-size:.62rem}
.timeline.zoomed .tick:hover .label,.timeline.zoomed .tick.active .label{opacity:1;background:var(--era-c);color:var(--paper)}
.tick:hover .label,.tick:focus-visible .label,.tick.active .label{opacity:1;transform:translateY(0) scale(1)}
.tick:hover .mark,.tick:focus-visible .mark{height:38px;width:4px}
.tick.active .label{background:var(--era-c);color:var(--paper)}
.tick.active .mark{height:44px;width:5px}
.tick:focus-visible{outline:2px dashed var(--oxblood);outline-offset:4px}

/* ---------- Drop zone ---------- */
.drop-zone{position:relative;min-height:120px;padding:0 1.5rem 3rem}
.drop-line{width:3px;background:var(--era-c,var(--ink));height:64px;transform-origin:top;transform:scaleY(0);position:absolute;top:0}
.drop-line.drawn{transition:transform .45s cubic-bezier(.6,0,.2,1);transform:scaleY(1)}
.year-banner{text-align:center;padding-top:70px;opacity:0;transition:opacity .3s ease .25s}
.year-banner.show{opacity:1}
.year-banner h2{font-family:var(--display);font-size:clamp(1.6rem,4vw,2.6rem);color:var(--era-c,var(--ink));letter-spacing:.04em}
.year-banner .sub{font-family:var(--utility);text-transform:uppercase;letter-spacing:.24em;font-size:.72rem;color:rgba(36,28,18,.65);margin-top:.3rem}

/* ---------- Year controls (sort + type) ---------- */
.year-controls{display:flex;justify-content:center;gap:1.6rem;flex-wrap:wrap;align-items:center;margin-top:1.3rem}
.control-group{display:flex;align-items:center;gap:.5rem}
.control-group .clabel{font-family:var(--utility);font-size:.64rem;letter-spacing:.2em;text-transform:uppercase;color:rgba(36,28,18,.6)}
.seg{display:inline-flex;border:2px solid var(--ink);box-shadow:2px 2px 0 rgba(36,28,18,.22)}
.seg button{
  font-family:var(--utility);font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;
  background:var(--paper);color:var(--ink);border:none;border-right:2px solid var(--ink);
  padding:.42rem .7rem;cursor:pointer;display:inline-flex;align-items:center;gap:.3rem;
}
.seg button:last-child{border-right:none}
.seg button.on{background:var(--ink);color:var(--paper)}
.seg button:focus-visible{outline:2px dashed var(--oxblood);outline-offset:2px}
.seg button .dir{font-size:.8em;opacity:.85}

/* ---------- Shelf ---------- */
.shelf{display:flex;gap:1.6rem;justify-content:center;flex-wrap:wrap;padding:2rem 0 1rem;max-width:1160px;margin:0 auto}

/* ---------- Poster card (film / single episode) ---------- */
.poster-card{
  background:none;border:none;padding:0;cursor:pointer;width:172px;text-align:left;
  font-family:var(--body);color:var(--ink);opacity:0;transform:translateY(18px);
  transition:opacity .4s ease,transform .4s ease;
}
.poster-card.in{opacity:1;transform:translateY(0)}
.poster-card:focus-visible{outline:2px dashed var(--oxblood);outline-offset:4px}
.poster{
  width:172px;height:250px;border:3px solid var(--ink);box-shadow:5px 5px 0 rgba(36,28,18,.35);
  position:relative;overflow:hidden;transition:transform .18s ease,box-shadow .18s ease;background:var(--paper-deep);
}
.poster-card:hover .poster,.poster-card:focus-visible .poster{transform:translateY(-6px) rotate(-1deg);box-shadow:8px 10px 0 rgba(36,28,18,.3)}
.poster svg{display:block;width:100%;height:100%}
.poster img.tmdb{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .4s ease}
.poster img.tmdb.loaded{opacity:1}
.badge{
  position:absolute;top:8px;left:8px;font-family:var(--utility);font-size:.58rem;letter-spacing:.14em;text-transform:uppercase;
  background:var(--paper);border:1.5px solid var(--ink);padding:.15rem .4rem;z-index:2;
}
.badge.review{top:auto;bottom:8px;left:auto;right:8px;background:var(--gold);color:var(--ink)}
.poster-meta{margin-top:.6rem;width:172px}
.poster-meta .p-title{font-weight:600;font-size:.96rem;line-height:1.2}
.poster-meta .p-sub{font-family:var(--utility);font-size:.64rem;letter-spacing:.12em;text-transform:uppercase;color:rgba(36,28,18,.6);margin-top:.2rem}
.poster-meta .p-lb{font-family:var(--utility);font-size:.66rem;letter-spacing:.08em;color:var(--gold);margin-top:.25rem;display:flex;align-items:center;gap:.3rem}
.poster-meta .p-lb .lb-num{color:var(--ink);opacity:.7}
.salt-compact{display:flex;align-items:center;gap:.3rem;margin-top:.2rem}
.salt-compact .s-num{font-family:var(--utility);font-size:.62rem;letter-spacing:.06em;color:rgba(36,28,18,.72)}

/* ---------- Salt grains ---------- */
.salt-emblem{fill:var(--salt-ink);color:var(--salt-ink);display:inline-block;vertical-align:middle;flex:0 0 auto}

/* ---------- TV show group (collapsed stack) ---------- */
.show-stack-card{
  background:none;border:none;padding:0;cursor:pointer;width:172px;text-align:left;font-family:var(--body);color:var(--ink);
  opacity:0;transform:translateY(18px);transition:opacity .4s ease,transform .4s ease;
}
.show-stack-card.in{opacity:1;transform:translateY(0)}
.show-stack-card:focus-visible{outline:2px dashed var(--oxblood);outline-offset:4px}
.show-stack{position:relative;width:172px;height:250px}
.show-stack .mini{
  position:absolute;width:150px;height:220px;border:3px solid var(--ink);overflow:hidden;background:var(--paper-deep);
  box-shadow:4px 4px 0 rgba(36,28,18,.3);transition:transform .18s ease;
}
.show-stack .mini svg,.show-stack .mini img{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover}
.show-stack .mini img.tmdb{opacity:0;transition:opacity .4s ease}
.show-stack .mini img.tmdb.loaded{opacity:1}
.show-stack .mini.back.b0{top:2px;left:2px;transform:rotate(-9deg);z-index:1}
.show-stack .mini.back.b1{top:2px;left:22px;transform:rotate(8deg);z-index:2}
.show-stack .mini.front{top:16px;left:11px;transform:rotate(-2deg);z-index:3}
.show-stack-card:hover .mini.back.b0{transform:rotate(-13deg) translate(-7px,-3px)}
.show-stack-card:hover .mini.back.b1{transform:rotate(12deg) translate(7px,-3px)}
.show-stack-card:hover .mini.front{transform:rotate(-2deg) translateY(-4px)}
.show-stack .ep-count{
  position:absolute;top:8px;right:8px;z-index:4;font-family:var(--utility);font-size:.58rem;letter-spacing:.1em;text-transform:uppercase;
  background:var(--ink);color:var(--paper);padding:.15rem .4rem;
}
.show-title-tab{
  margin-top:.6rem;width:172px;display:inline-flex;align-items:center;justify-content:space-between;gap:.4rem;
  background:var(--era-c,var(--lake));color:var(--paper);border:2px solid var(--ink);
  font-family:var(--utility);font-size:.74rem;letter-spacing:.06em;padding:.4rem .55rem;cursor:pointer;
  box-shadow:3px 3px 0 rgba(36,28,18,.3);text-align:left;line-height:1.15;
}
.show-title-tab .chev{font-size:1rem}
.show-stack-card:hover .show-title-tab{background:var(--ink)}

/* ---------- TV show group (expanded panel) ---------- */
.show-panel{
  flex:1 1 100%;background:var(--era-c,var(--lake));border:3px solid var(--ink);
  box-shadow:6px 6px 0 rgba(36,28,18,.3);padding:1.3rem 1.3rem 0;
  opacity:0;transform:translateY(10px);transition:opacity .35s ease,transform .35s ease;
}
.show-panel.in{opacity:1;transform:translateY(0)}
.show-panel .panel-eps{display:flex;gap:1.4rem;flex-wrap:wrap;justify-content:center}
.show-panel .poster-meta .p-title,
.show-panel .poster-meta .p-sub,
.show-panel .poster-meta .p-lb .lb-num,
.show-panel .salt-compact .s-num{color:var(--paper)}
.show-panel .poster-meta .p-lb{color:var(--gold)}
.show-panel{--salt-ink:var(--paper)}
.show-close-tab{
  display:block;width:100%;margin:1.3rem 0 0;background:var(--ink);color:var(--paper);border:none;
  border-top:2px solid rgba(233,223,200,.4);
  font-family:var(--utility);font-size:.8rem;letter-spacing:.1em;text-transform:uppercase;
  padding:.8rem;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:.5rem;
}
.show-close-tab:hover{background:var(--oxblood-deep)}
.show-close-tab:focus-visible{outline:2px dashed var(--paper);outline-offset:-4px}

/* ---------- Empty state ---------- */
.empty-state{max-width:640px;margin:1.5rem auto 0;text-align:center;border:2px dashed rgba(36,28,18,.4);padding:2rem 1.5rem;background:rgba(233,223,200,.6)}
.empty-state p{font-style:italic;font-size:1.05rem;color:rgba(36,28,18,.8)}
.jump-row{display:flex;justify-content:center;gap:1.2rem;margin-top:1.2rem;flex-wrap:wrap}
.jump-btn{
  font-family:var(--utility);letter-spacing:.14em;text-transform:uppercase;font-size:.78rem;
  background:var(--ink);color:var(--paper);border:2px solid var(--ink);padding:.6rem 1.1rem;cursor:pointer;
  display:inline-flex;align-items:center;gap:.5rem;transition:background .15s ease,color .15s ease;
}
.jump-btn:hover,.jump-btn:focus-visible{background:var(--oxblood);border-color:var(--oxblood)}
.jump-btn:focus-visible{outline:2px dashed var(--oxblood);outline-offset:3px}
.jump-btn .arrow{font-size:1rem}

/* ---------- Intro ---------- */
.intro-hint{text-align:center;padding:3rem 1.5rem;font-style:italic;color:rgba(36,28,18,.6);font-size:1.05rem}
.intro-hint .big-arrow{display:block;font-size:1.8rem;color:var(--oxblood);font-style:normal;margin-bottom:.4rem;animation:bob 1.6s ease-in-out infinite}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}

/* ---------- Ratings (review page) ---------- */
.rating-block{margin-top:.9rem}
.rating-label{font-family:var(--utility);font-size:.62rem;letter-spacing:.22em;text-transform:uppercase;color:rgba(36,28,18,.6)}
.stars-wrap{position:relative;display:inline-block;font-size:1.35rem;letter-spacing:.12em;line-height:1;vertical-align:middle}
.stars-wrap .stars-bg{color:rgba(36,28,18,.25)}
.stars-wrap .stars-fg{color:var(--gold);position:absolute;inset:0;overflow:hidden;white-space:nowrap}
.rating-num{font-family:var(--utility);font-size:.86rem;color:var(--ink);margin-left:.5rem;vertical-align:middle}
.salt-row{display:flex;align-items:center;gap:.5rem;margin-top:.3rem}
.salt-note{font-size:.9rem;font-style:italic;color:rgba(36,28,18,.7);margin-top:.4rem;max-width:380px}

/* ---------- Review page ---------- */
.review-inner{max-width:720px;margin:0 auto;padding:2.5rem 1.5rem 4rem}
.back-btn{
  font-family:var(--utility);letter-spacing:.16em;text-transform:uppercase;font-size:.75rem;
  background:none;border:2px solid var(--ink);color:var(--ink);padding:.5rem 1rem;cursor:pointer;margin-bottom:2rem;
  display:inline-block;text-decoration:none;
}
.back-btn:hover{background:var(--ink);color:var(--paper)}
.review-head{display:flex;gap:1.6rem;align-items:flex-start;flex-wrap:wrap;border-bottom:3px double var(--ink);padding-bottom:1.6rem}
.review-head .poster{flex:0 0 150px;width:150px;height:218px}
.review-title{flex:1;min-width:240px}
.review-title h2{font-family:var(--display);font-size:clamp(1.6rem,4vw,2.4rem);color:var(--oxblood);line-height:1.1}
.review-title .rt-sub{font-family:var(--utility);text-transform:uppercase;letter-spacing:.2em;font-size:.72rem;color:var(--lake);margin-top:.5rem}
.review-body{padding-top:1.6rem;font-size:1.08rem;line-height:1.7}
.review-body p+p{margin-top:1rem}
/* A write-up is written in the same restricted HTML a Marginalia note is, so
   it can carry the same blocks. Matched to .post-body deliberately: one
   editor produces both, and two looks would say they were different kinds of
   writing when they are not. */
/* review.html's main is `.review-inner`, not a content page, so nothing here
   is competing with `.content-page h2` and (0,1,1) is enough. */
.review-body h2{font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.8rem;letter-spacing:.01em;margin:2.2rem 0 .6rem;
  border-bottom:2px solid var(--gold);padding-bottom:.25rem}
.review-body h3{font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.35rem;margin:1.8rem 0 .5rem}
.review-body h4{font-family:var(--utility);font-size:.82rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--lake);margin:1.4rem 0 .4rem}
.review-body blockquote{margin:1.3rem 0;padding:.2rem 0 .2rem 1.1rem;
  border-left:4px solid var(--gold);font-style:italic;color:rgba(59,42,23,.9)}
.review-body blockquote p{margin:0}
.review-body blockquote p+p{margin-top:.7rem}
.review-body ul,.review-body ol{margin:0 0 1rem 1.4rem}
.review-body li{margin-bottom:.3rem}
.review-body code{font-family:var(--utility);font-size:.9em;
  background:rgba(59,42,23,.07);padding:.05em .3em}
.review-body hr{border:0;border-top:2px solid var(--gold);opacity:.7;margin:1.6rem auto;width:40%}
.review-body u{text-decoration-thickness:1px;text-underline-offset:2px}
/* ---- citations ---------------------------------------------------------
   The marker is a rubricated numeral in the flow of the prose, the same red
   ink the salt emblems and the drop caps use. It is an anchor, so with no
   JavaScript it jumps to the Sources list; citations.js turns it into an
   inline disclosure. */
.ref-mark{text-decoration:none;color:var(--oxblood);padding:0 .05em}
.ref-mark sup{font-family:var(--utility);font-size:.62em;letter-spacing:.02em;
  padding:0 .12em;border-bottom:1px solid rgba(158,43,37,.4)}
.ref-mark:hover sup,.ref-mark.on sup{background:var(--gold-bright);border-bottom-color:var(--oxblood)}
.ref-mark:focus-visible{outline:2px solid var(--lake);outline-offset:2px}
/* A <span>, because this lives inside a <p> where a <div> is not allowed —
   display:block is what makes it push the rest of the paragraph down instead
   of opening a modal. */
.ref-panel{display:block;margin:.7rem 0;padding:.6rem .8rem;
  border-left:4px solid var(--oxblood);background:rgba(158,43,37,.05);
  font-size:.9rem;line-height:1.5}
.ref-panel[hidden]{display:none}
.ref-claim{display:block;font-style:italic}
.ref-source{display:block;font-family:var(--utility);font-size:.86em;margin-top:.3rem}
.ref-url{margin-left:.4rem;word-break:break-word}
.ref-note{display:block;font-size:.86em;opacity:.8;margin-top:.3rem}

/* The list at the foot: the whole apparatus as it reads with no scripts, and
   what every marker's href points at. */
.review-sources{margin-top:2rem;border-top:3px double var(--gold);padding-top:1rem}
.review-sources h3{font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.2rem;margin-bottom:.6rem}
.source-list{margin:0 0 0 1.4rem;padding:0;font-size:.94rem;line-height:1.5}
.source-list li{margin-bottom:.7rem;scroll-margin-top:1.5rem}
.src-claim{display:block;font-style:italic}
.src-source{display:block;font-family:var(--utility);font-size:.88em;margin-top:.2rem}
.src-note{display:block;font-size:.86em;opacity:.8;margin-top:.2rem}
.src-back{margin-left:.4rem;text-decoration:none}
/* Says which entry a reader arrived at, so they don't have to match the
   number up by eye. Cleared as soon as they move. */
.src-target{background:rgba(216,192,120,.28);outline:2px solid var(--gold);outline-offset:3px}
/* Absence, stated. The same posture as an unrated saltiness printed as
   unrated (§3.2) and a plot saying why it has no trend line (§3.7): a missing
   section reads as "no sources were needed", which is not the true claim. */
.sources-none{margin-top:1.6rem;font-family:var(--utility);font-size:.78rem;
  letter-spacing:.06em;color:rgba(59,42,23,.6);border-top:1px dashed rgba(59,42,23,.3);
  padding-top:.6rem}
.review-body .verdict{margin-top:1.8rem;border-left:5px solid var(--moss);background:rgba(51,96,66,.08);padding:1rem 1.2rem;font-style:italic}
.review-body .no-review{font-style:italic;color:rgba(36,28,18,.65)}

/* ---------- Review overlay (standalone build only) ---------- */
.review-overlay{position:fixed;inset:0;z-index:50;background:var(--paper);overflow-y:auto;display:none}
.review-overlay.open{display:block}

/* ---------- Toast ---------- */
.toast{
  position:fixed;left:50%;bottom:26px;transform:translateX(-50%) translateY(20px);
  background:var(--lake);color:var(--paper);font-family:var(--utility);letter-spacing:.1em;font-size:.8rem;text-transform:uppercase;
  padding:.7rem 1.3rem;border:2px solid var(--ink);opacity:0;pointer-events:none;transition:opacity .25s ease,transform .25s ease;z-index:60;
}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}

footer.site-foot{border-top:3px double var(--ink);margin-top:2rem;padding:1.6rem;text-align:center;font-family:var(--utility);font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;color:rgba(36,28,18,.55);line-height:2}
/* The nav now lays out two labelled groups rather than eleven links; the
   links themselves are laid out by the group. */
.foot-nav{display:flex;gap:.8rem 1.9rem;justify-content:center;align-items:baseline;flex-wrap:wrap;margin-bottom:1rem}
.foot-nav-group{display:flex;gap:1.6rem;justify-content:center;flex-wrap:wrap;align-items:baseline}
/* THE HAIRLINE BETWEEN THE CLUSTERS IS GONE. It was the visible half of the
   grouping the ARIA labels state, and it was the only half — which is why it
   mattered. Now that the paperwork is set in its own voice (see the colophon
   block: smaller, uppercase, tracked, ink rather than oxblood) the grouping is
   carried at every width, including below 520px where the rule was hidden by
   design and the two clusters read as one block of fourteen.

   What it cost was the centring. The rule was a ::before INSIDE the second
   group's flex box, so it added its width and its margin to that group's left
   and pushed the whole row off centre in a footer that is centred throughout.
   A device that says nothing the voice does not, and moves a row to say it. */
.foot-nav a{font-family:var(--utility);font-size:.74rem;letter-spacing:.16em;text-transform:uppercase;color:var(--lake);text-decoration:none;border-bottom:2px solid transparent;padding-bottom:.15rem}
.foot-nav a:hover,.foot-nav a:focus-visible{border-bottom-color:var(--oxblood);color:var(--oxblood)}
/* Metadata, not a second headline. WHAT IT LOOKS LIKE IS THE COLOPHON BLOCK'S
   — the rule that used to sit here was `opacity:.6`, which composited to
   2.44:1 at 10.88px, and every declaration in it is now set there instead.
   Leaving the dead pair behind would have left the failing spelling reading as
   the control, which is §3.22's `.sprockets{height:16px}` trap exactly. */

/* ---------- Logo image ---------- */
.masthead-logo{margin-top:.6rem;line-height:0}
.masthead-logo a{display:inline-block}
/* max-width, not just width: 82vw is measured against the viewport while the
   box it sits in is the masthead's content area, so any left padding — the
   bookmark asks for some on a phone — would otherwise push the wordmark past
   the right edge and give the whole page a horizontal scrollbar. */
.masthead-logo img{width:min(460px,82vw);max-width:100%;height:auto;display:block;margin:0 auto}

/* ---------- Content pages (About / Contact / Saltiness) ---------- */
.content-page{max-width:720px;margin:0 auto;padding:2.5rem 1.5rem 4rem}
.content-page h2{font-family:var(--display);color:var(--oxblood);font-size:clamp(1.6rem,4vw,2.3rem);margin-bottom:1.2rem}
.content-page h3{font-family:var(--utility);letter-spacing:.14em;text-transform:uppercase;font-size:.95rem;color:var(--lake);margin:1.8rem 0 .6rem}
/* THE SUB-HEADING HAD NO RULE AT ALL HERE, so it rendered as the browser's
   default <h4> — bold body text at roughly the size of a paragraph, which is
   not a heading, it is an emphasised sentence. The editor has offered it since
   the prose pages moved into the rich-text box; only the stylesheet had not
   caught up, and `.post-body h4` / `.review-body h4` had carried a rule the
   whole time (§4's "fixed on one surface and not the neighbour").

   A rank BELOW the h3 above it, and it has to say so without a colour: h3 is
   already the lake utility face, so going quieter in the same family would
   read as the same heading in a worse mood. Ink rather than lake, smaller,
   and the letter-spacing opened rather than the weight raised — a small caps
   line is read as a label, which is what a heading inside a section is. */
.content-page h4{font-family:var(--utility);letter-spacing:.1em;
  text-transform:uppercase;font-size:.82rem;font-weight:700;
  color:var(--ink);margin:1.3rem 0 .4rem}
.content-page p{font-size:1.08rem;line-height:1.75}
.content-page p+p{margin-top:1rem}
.content-page a{color:var(--oxblood)}
.salt-legend{list-style:none;margin:1.4rem 0;padding:0}
.salt-legend li{display:flex;gap:1rem;align-items:flex-start;padding:1rem 0;border-bottom:1px solid rgba(36,28,18,.15)}
.salt-legend li:last-child{border-bottom:none}
.salt-legend .emblem{flex:0 0 56px;height:56px;border:2px solid var(--ink);display:flex;align-items:center;justify-content:center;background:var(--paper-deep)}
.salt-legend .emblem .salt-emblem{width:36px;height:36px}
.salt-legend .tier-name{font-family:var(--display);font-size:1.15rem;color:var(--oxblood)}
.salt-legend .tier-level{font-family:var(--utility);font-size:.66rem;letter-spacing:.16em;text-transform:uppercase;color:rgba(36,28,18,.55);margin-left:.5rem}
.salt-legend .tier-blurb{font-size:1rem;line-height:1.6;margin-top:.2rem}
/* Level 0 is the absence of a verdict rather than the bottom of the scale
   (§3.2), so it is set apart from the five below it — a broken rule and the
   lake blue the site already uses for a thing that is stated rather than
   scored, never a tint over the emblem, which would read as a sixth tier in a
   quieter mood. The words say it too; this is the second carrier (§7). */
.salt-legend li.tier-unsalted{border-bottom-style:dashed}
.salt-legend li.tier-unsalted .tier-name{color:var(--lake)}
.salt-legend li.tier-unsalted .emblem{border-style:dashed}

/* ============================================================
   Page furniture — the widgets an infrastructure page places

   Every rule here is selected through its own widget class, and not for
   tidiness: these live inside `.content-page`, whose `.content-page p` is
   (0,1,1) and beats a bare class outright — the trap that rendered
   `.mini-note` at body size on five pages (§4). Winning on specificity rather
   than on file order also means moving this block cannot silently undo it.
   ============================================================ */
/* The editor's own opening line above a widget. Body size, because it IS body
   prose — what makes it a widget's rather than the page's is only that the
   words live in the widget registry. */
.widget-lede{margin:0 0 .6rem}

/* ---- how to read a Breakdown ---- */
.widget-breakdown{margin:1.6rem 0}
.wb-list{list-style:none;margin:1rem 0 .8rem;padding:0;
  border-top:2px solid var(--ink);border-bottom:2px solid var(--ink)}
.wb-item{display:grid;grid-template-columns:2.6rem 1fr;gap:.15rem .8rem;
  align-items:start;padding:.75rem .2rem;
  border-bottom:1px solid rgba(59,42,23,.16)}
.wb-item:last-child{border-bottom:none}
.wb-item:nth-child(odd){background:rgba(216,192,120,.10)}
/* Filled by saltiness.js once the art has arrived — empty in the stored HTML,
   exactly as the saltiness legend's <ul> is, so nothing here needs a build
   step to know what a drawing looks like. */
/* SIZED IN REM, NOT IN PER CENT. `svg{width:100%}` inside a box whose own
   width is being resolved is a cycle the browser breaks by falling back to the
   drawing's intrinsic contribution — so the box came out 28.25px wide inside a
   41.6px track, and an inline `width:…!important` on it changed nothing while
   `min-width` did. That is the tell §4 records: when neither an inline style
   nor !important can move a property, the reading is wrong rather than the
   cascade, and here the reading was of a size nothing had finished computing.
   A definite size on the drawing removes the cycle. */
.wb-icon{grid-row:1 / span 2;width:2.6rem;min-width:2.6rem;height:2.6rem;
  display:flex;align-items:center;justify-content:center;color:var(--oxblood)}
.wb-icon svg{width:2.6rem;height:2.6rem}
.content-page .wb-name{font-family:var(--display);font-size:1.15rem;
  color:var(--oxblood);line-height:1.2}
.content-page .wb-what{font-size:.98rem;line-height:1.55}
@media (max-width:480px){
  .wb-item{grid-template-columns:1.9rem 1fr;gap:.15rem .6rem}
  .wb-icon{width:1.9rem;min-width:1.9rem;height:1.9rem}
  .wb-icon svg{width:1.9rem;height:1.9rem}
}

/* ---- the three demonstrations ----
   A miniature of a control a reader has not met yet, drawn from the registries
   so it cannot go stale the way a screenshot would. The stage is INERT: the
   era chips are links into the timeline and everything else is plain markup,
   because a control that looked live and did nothing would be worse than a
   picture of one. */
.widget-demo{margin:1.6rem 0}
.wd-stage{border:2px solid var(--ink);background:var(--paper-deep);
  box-shadow:3px 3px 0 rgba(36,28,18,.18);
  padding:.9rem;margin:.9rem 0;
  /* A miniature is narrower than the rule it depicts, so anything that cannot
     wrap scrolls inside its own box rather than pushing the page sideways —
     the rule §4 records after chasing a documentElement.scrollWidth that was
     never an overflow at all. */
  overflow-x:auto}
/* The era bar's own rules apply; only the spacing is a miniature's. */
.wd-era-bar{display:flex;justify-content:flex-start;gap:.4rem;flex-wrap:wrap;padding:0}
/* The real bar's own size, not a smaller one. A first pass set .62rem and
   measured 9.92px, which is under anything worth setting a label at — and the
   point of a miniature is that a reader recognises the control when they meet
   it, which a shrunken copy works against. It wraps here exactly as the real
   bar wraps on a narrow screen. */
.content-page .wd-era{font-size:.72rem;padding:.4rem .7rem;gap:.4rem;
  text-decoration:none;color:var(--ink)}
.content-page .wd-era:hover{background:var(--paper)}
.wd-era .range{font-size:.62rem}

/* The thread menu, at rest with one tab pulled. */
.wd-threads{padding:0;background:none;border:0;box-shadow:none;overflow:visible}
.wd-threads .threads-book{margin:0}
.wd-thread-tabs{justify-content:flex-start;padding:.5rem .6rem .45rem}
.wd-thread-tab{cursor:default;max-width:150px}
.wd-thread-tab:hover{transform:none}
.wd-thread-leaf{padding:.7rem .8rem;align-items:flex-start}
.content-page .wd-thread-leaf .th-name{font-size:.8rem}
.content-page .wd-thread-leaf .th-desc{font-size:.92rem;margin:.25rem 0 0}

/* The compare bands. One row per period: a letter, a name, the span, and the
   band itself drawn where it falls across the three. */
.wd-compare{display:flex;flex-direction:column;gap:.55rem}
.wd-band{position:relative;display:grid;
  grid-template-columns:1.5rem minmax(0,1fr) auto;gap:.1rem .55rem;
  align-items:center;padding-bottom:.5rem}
.wd-band-key{grid-row:1 / span 2;justify-self:start;font-family:var(--utility);
  font-weight:700;font-size:.8rem;color:var(--paper);background:var(--wd-c);
  border:2px solid var(--ink);width:1.5rem;height:1.5rem;
  display:grid;place-items:center;line-height:1}
.content-page .wd-band-name{font-family:var(--utility);font-size:.8rem;
  letter-spacing:.04em;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.content-page .wd-band-span{font-family:var(--utility);font-size:.68rem;
  color:rgba(59,42,23,.72);white-space:nowrap;font-variant-numeric:tabular-nums}
/* The rule the bands are drawn on. Its own grid cell rather than an ::after on
   the row, so the fill's percentage is a share of the RULE — measured against
   the whole row it would slide every band left by the width of the letter and
   the name. */
.wd-band-track{grid-column:2 / -1;grid-row:2;position:relative;
  height:4px;background:rgba(59,42,23,.16)}
.wd-band-fill{position:absolute;top:0;height:100%;background:var(--wd-c)}
/* The three compare colours are the timeline's own A/B/C, so a reader who has
   used the real control recognises the pairing.

   THE NAMES ARE THIS WIDGET'S OWN and deliberately not the timeline's. They
   were `.cmp-a`/`.cmp-b`/`.cmp-c`, which are the compare RULES drawn over the
   year ticks — and `.cmp-b{color:var(--moss);border-top-style:dashed}` reached
   every band here, so each row took its text colour from a control it is not
   and two of the three grew a 3px rule across the whole widget (a border-style
   with no width still draws, at the initial `medium`). The markup was correct
   and only the paint was wrong, which is the one thing no source check sees —
   §4 records `pa-row` silently re-laying a whole <table> the same way. */
.wd-band.wd-band-a{--wd-c:#A81E24}
.wd-band.wd-band-b{--wd-c:#0A6459}
.wd-band.wd-band-c{--wd-c:#2A4FB5}
@media (max-width:480px){
  .content-page .wd-band-span{font-size:.62rem}
}


/* ---- three more demonstrations ----
   Standing in a year, narrowing Browse down, and one place inside another.
   They share `.widget-demo` and `.wd-stage` with the three above, so a reader
   meets one kind of box rather than four — and every class below is this
   widget's own rather than borrowed from the control it depicts. The compare
   bands took `.cmp-a` from the timeline and each row then wore a rule drawn
   for something else (§4); a miniature is the one place where borrowing a
   neighbour's name is most tempting and least visible when it bites. */

/* The standpoint slider. A rule with the years the archive actually holds
   marked on it, a fill up to the standpoint, and a marker where the thumb
   would be. Every part is inert — this is a picture of a control, and the
   sentence underneath is what it is for. */
.wd-hist-say{display:flex;align-items:baseline;gap:.5rem;margin:0 0 .55rem}
.content-page .wd-hist-label{font-family:var(--utility);font-size:.72rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink)}
.content-page .wd-hist-year{font-family:var(--display);font-size:1.5rem;
  line-height:1;color:var(--oxblood)}
/* `position:relative` on the rule and not on the row, so a notch's percentage
   is a share of the RULE — measured against the row it would slide every mark
   by the width of anything beside it, which is the mistake the compare bands
   were built to avoid one block up. */
.wd-hist-rule{position:relative;display:block;height:10px;
  background:rgba(59,42,23,.16);border:1px solid rgba(59,42,23,.32)}
.wd-hist-fill{position:absolute;left:0;top:0;bottom:0;background:rgba(158,43,37,.28)}
.wd-hist-notch{position:absolute;top:-3px;width:1px;height:16px;
  background:rgba(59,42,23,.55)}
/* The marker, centred on its own year rather than starting at it. */
.wd-hist-thumb{position:absolute;top:-5px;width:9px;height:20px;
  margin-left:-4.5px;background:var(--oxblood);border:2px solid var(--ink)}
.wd-hist-ends{display:flex;justify-content:space-between;margin:.5rem 0 0}
.content-page .wd-hist-ends span{font-family:var(--utility);font-size:.68rem;
  color:rgba(59,42,23,.78);font-variant-numeric:tabular-nums}
.content-page .wd-hist-count{font-family:var(--body);font-size:.95rem;
  line-height:1.5;margin:.6rem 0 0}

/* What Browse narrows by. A definition list in all but name — the facet and
   how far it reaches — so it reads as a list of controls rather than as a
   table of numbers. `auto-fit`, because nine short rows in one column is a
   ladder and in two is a control panel, which is what it is a picture of. */
.wd-facets{list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));
  gap:.1rem .9rem}
.wd-facet{display:flex;align-items:baseline;gap:.5rem;min-width:0;
  padding:.3rem 0;border-bottom:1px solid rgba(59,42,23,.14)}
.content-page .wd-facet-name{font-family:var(--utility);font-size:.74rem;
  letter-spacing:.08em;text-transform:uppercase;color:var(--lake);
  flex:0 0 5.5rem}
/* `min-width:0` as well as the flex basis: a flex item's automatic minimum is
   its content's intrinsic width, so the longer phrases would refuse to wrap
   and push the second column off the stage (§4, five times over). */
.content-page .wd-facet-has{font-family:var(--body);font-size:.92rem;
  line-height:1.4;min-width:0;color:var(--ink)}
.wd-browse-take{display:flex;flex-wrap:wrap;align-items:baseline;gap:.55rem;
  margin:.9rem 0 0;padding-top:.75rem;border-top:2px solid var(--ink)}
/* The switch as Browse draws it — filled oxblood, so a reader who has pressed
   it there recognises it here. An <a>, so it is underlined on hover like every
   other link rather than pretending to be a button that does nothing. */
.content-page .wd-switch{font-family:var(--utility);font-size:.78rem;
  letter-spacing:.04em;background:var(--oxblood);color:var(--paper);
  border:2px solid var(--ink);padding:.3rem .7rem;text-decoration:none;
  box-shadow:2px 2px 0 rgba(36,28,18,.25)}
.content-page .wd-switch:hover{text-decoration:underline}
.content-page .wd-switch-says{font-family:var(--body);font-size:.92rem;
  line-height:1.45;min-width:0;flex:1 1 14rem}

/* One place inside another. Indented lists rather than a drawn tree: the
   nesting IS the fact, and a set of connector rules would be decoration over
   something the indent already says. */
.wd-place-tree,.wd-place-kids{list-style:none;margin:0;padding:0}
.wd-place-kids{margin-left:1rem;padding-left:.8rem;
  border-left:2px solid rgba(59,42,23,.22)}
.wd-place{padding:.3rem 0}
.wd-place-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:.2rem .55rem}
.content-page .wd-place-name{font-family:var(--body);font-weight:700;
  font-size:1rem;color:#2F5436;text-decoration:none}
.content-page .wd-place-name:hover{text-decoration:underline}
/* Verdigris, because a place is verdigris everywhere else on the site
   (§3.11l3) — and `--moss` is a border weight that does not clear 4.5:1 on
   parchment, so the type takes the darker green `.rail-locations` and `.syl-dl`
   already carry. Reusing that value rather than inventing a near-miss of it,
   which is how two spellings of one pigment start. */
.content-page .wd-place-tier{font-family:var(--utility);font-size:.64rem;
  letter-spacing:.08em;text-transform:uppercase;color:var(--paper);
  background:#2F5436;padding:.05rem .35rem}
.content-page .wd-place-span{font-family:var(--utility);font-size:.7rem;
  color:rgba(59,42,23,.78);font-variant-numeric:tabular-nums}
.content-page .wd-place-inside{font-family:var(--utility);font-size:.7rem;
  color:var(--lake)}
/* In the row rather than under it, which is where /locations puts them and
   which is most of what keeps eleven places to a readable height. */
.wd-place .era-ribbons{flex:0 0 auto}
@media (max-width:480px){
  .wd-facets{grid-template-columns:1fr}
  .content-page .wd-facet-name{flex-basis:4.6rem}
  .wd-place-kids{margin-left:.45rem;padding-left:.55rem}
}

/* ---- anniversaries falling this year ----
   Drawn as a CANON TABLE, which is not decoration. The Eusebian tables at the
   front of a gospel book are the manuscript tradition's answer to exactly this
   shape — several short parallel lists, unreadable stacked and perfectly
   legible under an arcade — and the historiography panel already borrows the
   same form (§3.10e2). One bay per anniversary: a rubric under the arch, the
   year on the impost, and the titles ruled beneath it.

   THE DEVICES ARE THE ARCADE'S OWN and the class names are not. `.hist-col`,
   `.hist-rubric` and `.hc-list` are the timeline panel's, nine rules of them
   scoped through `.hist-panel`, and §3.11i3's rule is that a second control
   sharing a neighbour's DECLARATIONS must not share its NAMES — §4 records
   `pa-row` silently re-laying a whole <table> because the name was already
   spoken for. These also sit inside a `.content-page`, where those rules would
   meet a different cascade from the one they were measured in.

   Every text rule is selected through `.widget-anniv`, because `.content-page
   p` and `.content-page li` are both (0,1,1) and beat a bare class outright —
   the trap that rendered `.mini-note` at body size on five pages (§4). Winning
   on specificity rather than on file order also means moving this block cannot
   silently undo it.

   The section itself ships `hidden` and stays hidden in a year where nothing
   falls, so nothing here needs a state for "empty": there is no empty. */
.widget-anniv{margin:2.2rem 0;padding:1.1rem 0;
  border-top:3px double var(--gold);border-bottom:3px double var(--gold)}
.widget-anniv h3{margin-top:0}
/* The generated sentence: what the table is, and whether it is all of what
   falls this year. It is the live region, so it is also what a reader who
   cannot see the arcade is told when the button draws another set. */
.content-page .widget-anniv .anniv-line{font-size:1rem;line-height:1.5;
  margin:.8rem 0 .8rem;color:rgba(59,42,23,.86)}
/* THE ARCADE. `auto-fit` rather than a fixed three: the bay count is the
   artifact's and a year may fall short of it, and a bay left as a stub beside
   two full ones reads as a column that failed to draw. A single bay stretching
   the measure is a plate, which is the honest degradation. */
.widget-anniv .anniv-arcade{display:grid;
  grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));
  gap:.8rem;margin:0 0 .9rem;
  /* STRETCH, not start. An arcade whose bays are three different heights is
     not an arcade — one anniversary routinely holds one title where its
     neighbour holds three. */
  align-items:stretch}
/* THE BAY WEARS THE ERA of the year it counts back to. `--bay-c` is written
   inline from the artifact (anniversaries.js), the way every other era colour
   on this site is written; the declaration here is the fallback for a year the
   archive has no era for, and for anything reading this file with no bay in
   front of it. */
.widget-anniv .anniv-bay{--bay-c:var(--ink);
  min-width:0;display:flex;flex-direction:column;
  border:2px solid var(--bay-c);background:var(--paper);
  /* The arch. Shallow: a semicircle over a column this wide is a doorway, and
     what is wanted is the suggestion of one. */
  border-radius:1.5rem 1.5rem 3px 3px;
  box-shadow:2px 2px 0 rgba(59,42,23,.16);overflow:hidden}
/* THE HEAD OF THE BAY. The round number is the whole point of an anniversary
   and it used to be .64rem of small caps — smaller than the titles underneath
   it. It is drawn as the initial a scribe would have illuminated instead: a
   gold-ruled cartouche standing on the lozenge trellis that fills the spandrel
   of every arcaded page of the period.

   THE TRELLIS IS TWO REPEATING GRADIENTS, no image and no library (§3.1), and
   it is GOLD ON A TINT OF THE ERA rather than on the era colour itself. That
   is the measurement, not a preference: parchment on the eight era colours
   comes out 3.84 (Ancient World), 4.36 (Revolutionary) and 4.38 (Medieval),
   all under AA, so nothing small is ever set on one of them at full strength.
   Ink on a 26% tint measures 6.6–7.8 at every era. §3.11l2 records --moss
   failing the same way one rail over.

   The flat `background` first and the tint second is the subgrid arrangement
   (§3.10): a browser without color-mix keeps the paper-deep band this widget
   has always drawn — no colour, which is a real loss, and never a transparent
   head, which was the bug. */
.content-page .widget-anniv .anniv-head{margin:0;
  padding:.5rem .5rem .44rem;display:flex;justify-content:center;
  background:var(--paper-deep);
  background:
    repeating-linear-gradient(45deg, rgba(185,138,47,.30) 0 1px, transparent 1px 9px),
    repeating-linear-gradient(-45deg, rgba(185,138,47,.30) 0 1px, transparent 1px 9px),
    color-mix(in srgb, var(--bay-c) 26%, var(--paper));
  border-bottom:2px solid var(--bay-c)}
/* A CARTOUCHE AND NOT A ROUNDEL, because the number does not fit in a circle.
   The archive reaches 3,000,000 BCE, so in 2050 a bay here reads 3,002,050
   years — nine characters, 106px against a 45px roundel. A pill that keeps a
   roundel's proportions until the figure needs more never clips, and the two
   short cases (50, 100) still draw as a disc. */
.widget-anniv .anniv-cart{display:inline-flex;flex-direction:column;
  align-items:center;justify-content:center;
  min-width:3.1rem;max-width:100%;min-height:2.5rem;padding:.1rem .5rem;
  border:2px solid var(--gold);border-radius:999px;
  background:var(--paper);box-shadow:0 0 0 2px var(--bay-c);text-align:center}
/* Rubricated: --oxblood is what :root already calls vermilion rubric red, and
   it measures 5.65 on parchment. The UTILITY face, not the display one —
   §3.9c4's rule is that only the year is blackletter, and two blackletter
   things in one small bay is neither of them standing out. */
.content-page .widget-anniv .ac-n{font-family:var(--utility);font-size:1.25rem;
  line-height:1;color:var(--oxblood);font-variant-numeric:tabular-nums;
  letter-spacing:.02em}
.content-page .widget-anniv .ac-u{font-family:var(--utility);font-size:.52rem;
  letter-spacing:.13em;text-transform:uppercase;color:rgba(59,42,23,.8);
  margin-top:.06rem}
/* The gold impost the column springs from, carrying the year it counts back
   to. THE ONE THING IN THE DISPLAY FACE: `--display` is blackletter, right for
   a year and a thing a reader decodes rather than reads once it is a phrase,
   which is §3.11i3's finding about the review plate's own span. */
.content-page .widget-anniv .anniv-year-line{margin:0;padding:.4rem .5rem .34rem;
  text-align:center;border-bottom:1px solid rgba(59,42,23,.18);
  border-bottom-color:color-mix(in srgb, var(--bay-c) 45%, transparent)}
/* THE ERA IN WORDS. The frame's colour reinforces a fact the bay states here
   rather than carrying it alone (§7) — and it is the line that tells a reader
   meeting the arcade for the first time what the colours mean. Ink at the .78
   .mini-note already settled on, never the era colour: as small text on
   parchment three of the seven fail AA (§3.11l2's finding, one rail over). */
.content-page .widget-anniv .anniv-era{display:block;margin-top:.1rem;
  font-family:var(--utility);font-size:.58rem;letter-spacing:.12em;
  text-transform:uppercase;color:rgba(59,42,23,.78)}
.content-page .widget-anniv .anniv-year{font-family:var(--display);
  font-size:1.25rem;line-height:1.1;white-space:nowrap;
  border-bottom:1px solid rgba(216,192,120,.8);text-decoration:none}
.content-page .widget-anniv .anniv-year:hover,
.content-page .widget-anniv .anniv-year:focus-visible{
  border-bottom-color:var(--oxblood)}
/* Ruled rows with the ordinal in the margin, which is what a canon table is.
   `list-style:decimal` rather than a CSS counter, so a bay holding one title
   still numbers it and nothing depends on where the row sits. */
.widget-anniv .anniv-titles{list-style:decimal;margin:0;
  padding:.25rem 0 .3rem 2rem}
.widget-anniv .anniv-titles li::marker{color:#6A4E0F;font-family:var(--utility);
  font-size:.62rem;font-variant-numeric:tabular-nums}
.content-page .widget-anniv .anniv-titles li{margin:0;
  padding:.22rem .55rem .22rem .1rem;
  font-family:var(--utility);font-size:.8rem;line-height:1.35;min-width:0}
/* Alternate ruling, the way a table of this kind is banded so the eye holds a
   line across it. Faint: a guide, not a stripe. */
.widget-anniv .anniv-titles li:nth-child(odd){background:rgba(185,138,47,.10);
  background:color-mix(in srgb, var(--bay-c) 11%, transparent)}
.content-page .widget-anniv .anniv-titles a{text-decoration:none;
  border-bottom:1px solid rgba(216,192,120,.7);overflow-wrap:anywhere}
.content-page .widget-anniv .anniv-titles a:hover,
.content-page .widget-anniv .anniv-titles a:focus-visible{
  border-bottom-color:var(--oxblood)}
/* THE SITE'S OWN .btn, AT THE SITE'S OWN SIZE, with no override of its type
   or its padding. A first pass shrank it to .7rem and measured 114×31 against
   the 147×34 every other button on this page draws — a smaller target for no
   reason anybody chose, which is the demonstration widgets' own finding about
   their era chips one block up ("the real bar's own size, not a smaller one").
   Only the spacing around it belongs to this section. */
.anniv-more-wrap{margin:.2rem 0 .9rem}
@media (max-width:480px){
  /* Two bays at a phone's width rather than three stubs: a bay narrower than
     its own rubric is not a column. */
  .widget-anniv .anniv-arcade{grid-template-columns:repeat(auto-fit,minmax(8.5rem,1fr));
    gap:.6rem}
  .content-page .widget-anniv .anniv-year{font-size:1.1rem}
  .widget-anniv .anniv-titles{padding-left:1.7rem}
}
@media print{ .widget-anniv .anniv-more-wrap{display:none} }

/* ---------- Admin ---------- */
.admin-wrap{max-width:960px;margin:0 auto;padding:2rem 1.5rem 5rem}
.admin-wrap h2{font-family:var(--display);color:var(--oxblood);margin:2.2rem 0 1rem;font-size:1.6rem}
.admin-wrap h3{font-family:var(--utility);letter-spacing:.14em;text-transform:uppercase;font-size:.9rem;margin:1.4rem 0 .6rem;color:var(--lake)}
/* The bar stacks three captioned clusters; each cluster lays out its own
   buttons. The caption is what makes the grouping visible — see admin.html
   for why it is a word rather than a rule between the clusters. */
.admin-tabs{display:flex;flex-direction:column;gap:.55rem;margin-bottom:1rem;border-bottom:3px double var(--ink);padding-bottom:1rem}
.admin-tab-cluster{display:flex;align-items:baseline;gap:.7rem}
.admin-tab-legend{font-family:var(--utility);font-size:.62rem;letter-spacing:.16em;text-transform:uppercase;
  opacity:.55;flex:0 0 5.2rem;text-align:right}
.admin-tab-group{display:flex;gap:.5rem;flex-wrap:wrap;flex:1 1 auto}
.admin-tabs button{font-family:var(--utility);letter-spacing:.12em;text-transform:uppercase;font-size:.74rem;background:var(--paper);border:2px solid var(--ink);padding:.5rem .9rem;cursor:pointer;box-shadow:3px 3px 0 rgba(36,28,18,.22)}
.admin-tabs button.on{background:var(--ink);color:var(--paper)}
/* Gold, not oxblood: the badge sits on paper AND on a selected tab's dark
   ground, and an oxblood count on an oxblood tab is the invisible-label
   failure the footer's proceed button already had. */
.tab-badge{display:inline-block;margin-left:.45rem;padding:0 .4rem;border:1px solid currentColor;border-radius:.75rem;font-size:.66rem;letter-spacing:.06em}
.tab-badge.blocking{background:var(--gold);color:var(--ink);border-color:var(--ink)}
/* Narrow: the caption sits above its own cluster rather than stealing a fifth
   of the row from the buttons it labels. */
@media (max-width:640px){
  .admin-tab-cluster{flex-direction:column;align-items:stretch;gap:.25rem}
  .admin-tab-legend{flex:0 0 auto;text-align:left}
}
.admin-panel{display:none}
.admin-panel.on{display:block}
.field{display:flex;flex-direction:column;gap:.25rem;margin-bottom:.7rem}
.field label{font-family:var(--utility);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:rgba(36,28,18,.7)}
/* The same exclusion as the width rule below, and for the same reason: a
   border and .55rem of padding are for a box somebody types into. Ticks
   escaped this one only by sitting outside a `.field`. */
.field input:not([type=checkbox]):not([type=radio]),.field select,.field textarea{
  font-family:var(--body);font-size:1rem;padding:.55rem .7rem;border:2px solid var(--ink);background:#F5EFE0;color:var(--ink);
}
.field textarea{min-height:100px;resize:vertical}
/* Tighter and DARKER. Measured composited on the admin's own paper, the old
   .6 alpha at 12.48px came out at 4.04:1 — under AA on the one line of every
   field that explains what the field is for. .78 is the figure `.mini-note`
   already settled on for the same complaint (§4). The line-height is what
   buys the space: a three-line hint under twenty fields is most of a screen. */
.field .hint{font-size:.74rem;line-height:1.4;font-style:italic;color:rgba(36,28,18,.78)}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
.btn{font-family:var(--utility);letter-spacing:.14em;text-transform:uppercase;font-size:.78rem;background:var(--ink);color:var(--paper);border:2px solid var(--ink);padding:.6rem 1.1rem;cursor:pointer}
.btn.secondary{background:var(--paper);color:var(--ink)}
.btn.danger{background:var(--oxblood)}
.btn+.btn{margin-left:.6rem}
.admin-list{border:2px solid var(--ink);max-height:280px;overflow-y:auto;background:#F5EFE0;margin-bottom:1rem}
.admin-list .row{display:flex;justify-content:space-between;align-items:center;gap:1rem;padding:.5rem .8rem;border-bottom:1px solid rgba(36,28,18,.15);cursor:pointer}
.admin-list .row:hover{background:var(--paper-deep)}
.admin-list .row .meta{font-family:var(--utility);font-size:.66rem;letter-spacing:.08em;text-transform:uppercase;color:rgba(36,28,18,.55)}
.salt-picker{display:flex;gap:.4rem;align-items:center;flex-wrap:wrap}
.salt-picker button{background:var(--paper);border:2px solid rgba(36,28,18,.25);cursor:pointer;padding:.25rem;line-height:0}
.salt-picker button.salt-opt{opacity:.5;transition:opacity .12s ease,border-color .12s ease}
.salt-picker button.salt-opt:hover{opacity:.85}
.salt-picker button.salt-opt.on{opacity:1;border-color:var(--ink);box-shadow:2px 2px 0 rgba(36,28,18,.25)}
.export-box{border:3px double var(--ink);padding:1.2rem;margin-top:1.5rem;background:rgba(51,96,66,.06)}
.export-box p{font-size:.95rem;margin-bottom:.8rem}
/* THE EXPORT PANEL, IN THREE GROUPS. Thirteen buttons in one undifferentiated
   run meant the one an editor wants is found by reading every label — and they
   are not the same kind of thing: the whole working copy, the files a publish
   would write, and the catalogue you read before you take it. A rule above each
   heading rather than a box around each group, because three boxes inside a box
   is a panel arguing with itself about where its own edges are. */
.export-group{margin-top:1.1rem;padding-top:.9rem;border-top:1px solid rgba(59,42,23,.28)}
.export-group:first-of-type{margin-top:.2rem;padding-top:0;border-top:none}
.export-group h4{font-family:var(--utility);font-size:.78rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink);margin:0 0 .3rem}
.export-group .mini-note{margin:0 0 .6rem;max-width:44rem}
/* The buttons wrap rather than reaching for a grid: they are ten labels of
   wildly different lengths, and a track list sized for the longest leaves the
   short ones swimming. */
.export-line{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem}
.export-line .btn{margin:0}
.ep-editor{border:2px solid var(--ink);padding:1rem;margin:.8rem 0;background:#F5EFE0}
.ep-editor .field-row{grid-template-columns:1fr 1fr 1fr}

/* ---- the entry forms, as a book of sections ---------------------------
   The film and episode editors were 3,780px and 3,023px of one-field-per-row
   stacking, measured in a browser — four screens between the title box and
   the Save button, on the two panels an editor spends the day in. The
   Locations tab does far more on a fraction of that, and the whole of the
   difference is arrangement: group, pack across the column, and put the
   occasional things behind a summary.

   `<details>` for the grouping, the way the Locations tree and the year adder
   already do it: the keyboard, the ARIA and the disclosure marker come free,
   and there is no open-state flag of ours to fall out of step (§3.11a). The
   summary carries a note saying what is inside, so a shut section is never a
   question about whether anything is in there — the rule /locations' own group
   disclosure follows by keeping its count on the summary. */
.form-sec{border:2px solid rgba(36,28,18,.4);background:var(--paper);margin:0 0 .55rem}
.form-sec > summary{
  cursor:pointer;padding:.42rem .7rem;background:rgba(216,192,120,.18);
  font-family:var(--utility);font-size:.7rem;letter-spacing:.12em;text-transform:uppercase;
  display:flex;gap:.6rem;align-items:baseline;flex-wrap:wrap;
}
.form-sec > summary:hover{background:rgba(216,192,120,.34)}
.form-sec[open] > summary{border-bottom:1px solid rgba(36,28,18,.28)}
.fs-title{font-weight:700}
/* The note is prose about the section, not more of its label — so it takes the
   body face and drops the tracking, the way a `.meta` line does beside a row. */
.fs-note{font-family:var(--body);font-size:.8rem;font-style:italic;
  letter-spacing:0;text-transform:none;color:rgba(36,28,18,.78)}
.form-sec-body{padding:.65rem .75rem .15rem}

/* Short fields, packed across the admin's own width. `auto-fit` rather than a
   hand-counted three, because that column is one width on a laptop and another
   on a wide screen and a fixed count would be wrong at one of them.

   `min-width:0` on BOTH the track and the item: a grid item's own default width
   is its content's intrinsic width, so `minmax(0,…)` on the track is not enough
   on its own — §4 records that same trap four times over, twice in this admin. */
.form-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(15rem,100%),1fr));
  gap:0 1rem;align-items:start}
/* A PAIR is two, not "as many as fit". On the widened column an auto-fit
   floor of 22rem gives three tracks and a two-item row then leaves a third of
   the section empty beside it — which reads as a control that failed to draw
   rather than as a deliberate pair. It collapses to one below the width where
   two tag inputs stop being usable side by side. */
.form-grid.pair{grid-template-columns:repeat(2,minmax(0,1fr))}
@media (max-width:44rem){ .form-grid.pair{grid-template-columns:minmax(0,1fr)} }
.form-grid > *{min-width:0}
.form-grid .field{margin-bottom:.5rem;min-width:0}
/* A TICK IS NOT A TEXT BOX, and `width:100%` on one is what actually deleted
   the inspiration checkbox. This rule is written for the things an editor
   types into; a checkbox took the full width of its containing block, and with
   the shrink rule that used to reach it as well it collapsed to nothing and
   left a bare line of text that still toggled when clicked. Every other tick
   on these forms escaped only by sitting OUTSIDE a `.field` — which is luck,
   not a rule, so the exclusion is written here where the next one is covered
   by it rather than patched onto whichever component notices next (§4's
   "fixed on one surface and not the neighbour"). A radio goes with it: the
   tier and flag groups are one nesting away from the same fate. */
.form-grid .field input:not([type=checkbox]):not([type=radio]),
.form-grid .field select,.form-grid .field textarea{
  width:100%;box-sizing:border-box}

/* The span control, the circa tick and the year adder stack beside the "Set in"
   list rather than under it: all three are decisions about the same field, and
   the multi-select is tall enough to hold them all in the space beside it. */
.span-stack{display:flex;flex-direction:column;gap:.35rem;min-width:0}
.span-stack .span-field{margin:0}

/* Save and Delete, kept on screen. Sticky rather than fixed, so the bar belongs
   to the form and leaves with it — a sticky box can only travel inside its own
   containing block, which is what makes this safe (§3.7a). */
.form-actions{position:sticky;bottom:0;z-index:3;display:flex;gap:.6rem;flex-wrap:wrap;
  margin-top:.6rem;padding:.6rem 0;background:var(--paper);
  border-top:2px solid var(--ink);box-shadow:0 -6px 10px -8px rgba(36,28,18,.5)}
/* `.btn+.btn` adds a left margin that the gap already provides. */
.form-actions .btn+.btn{margin-left:0}
.ep-editor .form-actions{background:#F5EFE0}
/* ---- the small italic caption, and why its size is declared apart ---------
   `.mini-note` is (0,1,0) and `.content-page p` is (0,1,1), so on every page
   whose main is a content page the size lost and the caption rendered at BODY
   size — measured at 17.92px against the intended 13.12px, on the statistics
   page (14 of them), /locations, a series page, a filmography and a period
   page. Review pages were right by accident: review.html's main is not a
   content page, so nothing outranked the class.

   That is the same trap §3.9c records for `.proceed-btn` and §4 for
   `.bd-caption`, and it had been patched one caption at a time —
   `.content-page .browse-note` below is a survivor of that. Fixing the class
   itself is what stops the next one needing its own line.

   ONLY THE SIZE IS RAISED, and that is deliberate: `.content-page p` sets no
   colour, so lifting the whole block to (0,2,0) would have made this rule beat
   the contrast override further down the file (`.mini-note{color:rgba(59,42,23,.78)}`,
   the accessibility pass) and quietly undo it inside every content page. The
   size is the one declaration that loses, so the size is the one that moves.

   It stays HERE, early, so a component modifier later in the file — the
   `.browse-note` above — still wins on file order at equal specificity, which
   is the ordinary base-then-modifier layering rather than an accident. */
.mini-note{font-style:italic;color:rgba(36,28,18,.6);margin:.4rem 0 1rem}
.mini-note,.content-page .mini-note{font-size:.82rem}

/* "No period found under that name." A record page that finds no record says
   so, and that sentence is the WHOLE of the page rather than a caption under
   something — so it is prose, at prose size, the way review.html's own
   `.no-review` already is. All three of these were `.mini-note`, and they read
   correctly only because `.content-page p` was outranking that class and
   accidentally sizing them as body text; the fix above would have left them at
   13px grey italic, alone on the page.

   It needs the same two-selector treatment as `.mini-note` above, which it did
   NOT get first time round: written as a bare class it was outranked by
   `.content-page p` in its turn and rendered at 17.92px — right by accident on
   a content page and 16px on a review, which is the whole disease. Declared at
   both specificities it is the same size wherever it lands, so it does not
   depend on whether a given page's main is a content page, which is exactly
   the difference that hid all of this in the first place. */
.page-miss,.content-page .page-miss{font-size:1.05rem;line-height:1.7;margin:1.4rem 0}

@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
  .drop-line.drawn{transform:scaleY(1)}
}
@media (max-width:640px){
  .timeline-scroll{padding:2.2rem 1.2rem .4rem}
  .poster-card,.show-stack-card{width:140px}
  .poster,.show-stack{width:140px;height:204px}
  .poster-meta,.show-title-tab{width:140px}
  .field-row{grid-template-columns:1fr}
  .ep-editor .field-row{grid-template-columns:1fr}
}

/* ---------- Cookie consent banner ---------- */
.cookie-banner{
  position:fixed;left:50%;bottom:18px;transform:translateX(-50%) translateY(140%);
  width:min(680px,calc(100% - 24px));z-index:70;
  background:var(--paper);border:2px solid var(--ink);box-shadow:5px 5px 0 rgba(36,28,18,.28);
  padding:1rem 1.1rem;display:flex;gap:1rem;align-items:center;flex-wrap:wrap;
  transition:transform .3s cubic-bezier(.6,0,.2,1);
}
.cookie-banner.show{transform:translateX(-50%) translateY(0)}
.cookie-banner p{font-size:.92rem;line-height:1.5;flex:1 1 300px;margin:0}
.cookie-banner a{color:var(--oxblood)}
.cookie-actions{display:flex;gap:.6rem;flex:0 0 auto}
.cookie-actions .btn{padding:.5rem .9rem;font-size:.72rem}
@media (prefers-reduced-motion:reduce){ .cookie-banner{transition:none} }
@media (max-width:520px){ .cookie-actions{flex:1 1 100%} .cookie-actions .btn{flex:1} }

/* ---------- "Proceed to the Timeline" -----------------------------------
   The way out of Start Here, and the one deliberately grand control on the
   site: a rubricated plate with a gold rule under it, sized like the end of
   a chapter rather than like a form button. It is an <a>, so everything a
   link can do it still does — middle-click, new tab, crawl.

   The flourishes are decoration and are marked aria-hidden or carried on
   ::before/::after, so a screen reader hears "Ready? Proceed to the
   Timeline" and nothing else. */
.proceed-wrap{margin:2.6rem 0 1rem;text-align:center}
/* Selected through .proceed-wrap on purpose. `.content-page a{color:oxblood}`
   is (0,1,1) and a bare `.proceed-btn` is (0,1,0), so the page's link colour
   won and the label rendered oxblood on oxblood — invisible. Winning on
   specificity rather than on file order means moving this block cannot
   silently break it again. */
.proceed-wrap .proceed-btn{
  display:inline-flex;align-items:baseline;gap:.7rem;
  padding:.9rem 2rem;text-decoration:none;
  color:var(--paper);background:var(--oxblood);
  border:2px solid var(--ink);box-shadow:4px 4px 0 var(--gold);
  position:relative;transition:transform .12s, box-shadow .12s;
}
/* Gold hairlines just inside the border, the way a rubric is boxed. */
.proceed-wrap .proceed-btn::before{
  content:"";position:absolute;inset:4px;border:1px solid var(--gold-bright);
  opacity:.65;pointer-events:none;
}
.proceed-wrap .proceed-btn:hover,.proceed-wrap .proceed-btn:focus-visible{
  transform:translate(-2px,-2px);box-shadow:6px 6px 0 var(--gold);
}
.proceed-wrap .proceed-btn:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--gold)}
.proceed-wrap .proceed-btn:focus-visible{outline:3px solid var(--lake);outline-offset:3px}
.proceed-main{font-family:var(--display);font-size:1.5rem;line-height:1.1}
.proceed-arrow{font-size:1.2rem;line-height:1}
.proceed-wrap .proceed-btn:hover .proceed-arrow{transform:translateX(3px)}
.proceed-arrow{display:inline-block;transition:transform .12s}
@media (prefers-reduced-motion:reduce){
  .proceed-wrap .proceed-btn,.proceed-arrow{transition:none}
  .proceed-wrap .proceed-btn:hover,.proceed-wrap .proceed-btn:focus-visible{transform:none}
  .proceed-wrap .proceed-btn:hover .proceed-arrow{transform:none}
}
@media (max-width:480px){
  .proceed-wrap .proceed-btn{flex-direction:column;align-items:center;gap:.2rem;padding:.9rem 1.4rem;width:100%}
  .proceed-main{font-size:1.25rem}
}
@media print{ .proceed-wrap{display:none} }

/* ---------- The glossary ------------------------------------------------
   A reference page: 128 short entries, alphabetical, filtered by kind. The
   whole list is pre-rendered, so everything below styles markup that is
   already there rather than markup a script builds. */
.gl-count{margin:.8rem 0 .4rem}
.gl-filter{display:flex;flex-wrap:wrap;gap:.3rem;margin:.6rem 0}
.gl-filter button{font-family:var(--utility);font-size:.72rem;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--gold);
  padding:.22rem .6rem;display:inline-flex;align-items:baseline;gap:.35rem}
.gl-filter button.on{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.gl-n{font-size:.85em;opacity:.7}
.gl-filter button.on .gl-n{opacity:.85}
.gl-jump{display:flex;flex-wrap:wrap;gap:.15rem;margin:.5rem 0 1.2rem;
  border-top:1px dashed rgba(59,42,23,.3);border-bottom:1px dashed rgba(59,42,23,.3);
  padding:.4rem 0}
.gl-jump a{font-family:var(--utility);font-size:.8rem;text-decoration:none;
  padding:.1rem .35rem;color:var(--lake)}
.gl-jump a:hover{background:var(--gold-bright);color:var(--ink)}
.gl-letter{font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.6rem;margin:1.6rem 0 .5rem;border-bottom:2px solid var(--gold);line-height:1}
.gl-list{margin:0}
.gl-entry{padding:.55rem 0;border-bottom:1px solid rgba(59,42,23,.14);scroll-margin-top:1.5rem}
.gl-entry dt{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap}
.gl-term{font-family:var(--body);font-weight:700;font-size:1.05rem}
/* Named in words, never left to a colour (§7) — the tint is a second signal,
   not the only one. */
.gl-kind{font-family:var(--utility);font-size:.62rem;letter-spacing:.1em;
  text-transform:uppercase;border:1.5px solid currentColor;padding:0 .3rem;color:var(--lake)}
.gl-kind-concept{color:var(--oxblood)}
.gl-kind-era{color:var(--moss)}
.gl-entry dd{margin:.2rem 0 0}
/* A gloss may run to several paragraphs (§3.11c2 took the depth cap off, and
   the renderer now honours a blank line). The gap is on the paragraph rather
   than a `gap` on the parent, because the meta and the links below are siblings
   in the same <dd> and a parent gap would space those too. */
.gl-gloss{font-size:.96rem;line-height:1.5;margin:0}
.gl-gloss + .gl-gloss{margin-top:.55rem}
.gl-meta{font-family:var(--utility);font-size:.72rem;opacity:.75;margin-top:.15rem}
.gl-links{margin-top:.2rem;display:flex;flex-wrap:wrap;gap:.8rem}
.gl-more{font-family:var(--utility);font-size:.74rem}
.gl-target{background:rgba(216,192,120,.28);outline:2px solid var(--gold);outline-offset:3px}
.gl-empty{font-style:italic;opacity:.7;margin-top:1rem}
.gl-pager{margin-top:1.2rem}
/* The plate down to the ledger. It borrows .proceed-wrap/.proceed-btn whole
   (§3.9c), so all that is left here is the spacing — this one sits under a
   search box rather than at the foot of a page of prose — and the arrow's
   direction, which travels down the page instead of away from it. */
.gl-tothe{margin:1.4rem 0 .6rem}
.gx-tothe{margin:1.4rem 0 .6rem}
/* THE ONE PLATE ON THE SITE THAT IS NOT OXBLOOD, and the difference means
   something: the other two lead further into the same kind of writing, and
   this leads to a second kind — a sentence pinned to a year rather than a note
   with a page. Selected through .proceed-wrap so it beats the shared rule on
   specificity rather than on file order, which is the trap §3.9c records for
   .proceed-btn itself. Paper on --moss measures 4.71:1 composited, clear of AA
   at any size; the gold rules and the ink border are the plate's own and are
   untouched, so it is unmistakably the same object in a different colour. */
.proceed-wrap .proceed-btn.proceed-green{background:var(--moss)}
.proceed-wrap .proceed-btn:hover .proceed-arrow-down{transform:translateY(3px)}
@media (prefers-reduced-motion:reduce){
  .proceed-wrap .proceed-btn:hover .proceed-arrow-down{transform:none}
}

/* ---------- The Book of Citations ---------------------------------------
   Every sourced claim in the archive, below the index it shares a page with.
   A glossary says what the site MEANS by a word; this says what it KNOWS.

   Every rule here is selected through .book-of-citations, and that is not
   decoration: this page is a .content-page, whose `.content-page p` is
   (0,1,1) and beats a bare class outright — the trap that rendered
   .mini-note at body size on five pages and .bd-caption on a sixth. Winning
   on specificity rather than on file order also means moving this block
   cannot silently undo it. */
.book-of-citations{margin-top:2.4rem;border-top:2px solid var(--ink);padding-top:1rem}
.book-of-citations h2{font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.6rem;margin:0 0 .3rem;line-height:1.1}
.book-of-citations .boc-count{margin:.2rem 0 .8rem}
.book-of-citations .boc-none{margin:.6rem 0}
.boc-list{list-style:none;margin:0;padding:0;counter-reset:boc}
.boc-entry{position:relative;padding:.7rem 0 .7rem 2.2rem;
  border-bottom:1px solid rgba(59,42,23,.14)}
/* The number is ordinal within this list and nothing else — it is NOT the
   footnote number the review prints, which follows that review's own prose
   (§3.10c) and would be a different figure beside the same claim. It restates
   what the <ol> already carries, which is why replacing the default marker
   with a counter loses nothing: the element is still an ordered list and
   still announced as one. */
.boc-entry::before{counter-increment:boc;content:counter(boc);
  position:absolute;left:0;top:.75rem;font-family:var(--utility);font-size:.72rem;
  color:var(--lake);opacity:.75}
/* THE SECOND SELECTOR IS THE CITATION EMBED, and it shares these rules rather
   than restating them. PP.citationRowHTML is one row on three surfaces now —
   the ledger, a period page's slice of it, and a claim pulled into a Marginalia
   note — and the row is precisely the part a reader compares between them
   (§3.3). A post is inside a .content-page too, so the embed needs the same
   (0,2,0) for the same reason the ledger does. */
.book-of-citations .boc-claim,.embed-citation .boc-claim{font-family:var(--body);
  font-size:1rem;line-height:1.5;margin:0}
.book-of-citations .boc-source,.embed-citation .boc-source{font-family:var(--utility);
  font-size:.78rem;margin:.25rem 0 0;display:flex;flex-wrap:wrap;gap:.5rem;align-items:baseline}
.boc-url{font-family:var(--utility);font-size:.74rem;word-break:break-all}
.book-of-citations .boc-note,.embed-citation .boc-note{font-size:.85rem;font-style:italic;
  opacity:.8;margin:.25rem 0 0}
.book-of-citations .boc-from,.embed-citation .boc-from{font-family:var(--utility);
  font-size:.74rem;margin:.35rem 0 0;display:flex;flex-wrap:wrap;gap:.5rem;align-items:baseline}
.boc-sub{opacity:.7}
@media (max-width:480px){
  .boc-entry{padding-left:1.7rem}
}

/* ---------- The Book of Glosses -----------------------------------------
   Every gloss in the archive, below the notes it shares a page with. A note
   argues; a gloss annotates — and unlike a note it has no page, so the row
   carries the sentence itself and links to the year it is pinned to.

   Every text rule is selected through .gloss-ledger, for the reason the Book
   of Citations' own are: this page is a .content-page, whose `.content-page p`
   is (0,1,1) and beats a bare class outright (§4). Its own `gx-` prefix rather
   than the ledger's `boc-`, because two lists reachable by one selector is how
   a check that means one starts counting both (§3.11i3). */
.gloss-ledger{margin-top:2.4rem;border-top:2px solid var(--ink);padding-top:1rem}
.gloss-ledger h2{font-family:var(--display);font-weight:400;color:var(--moss);
  font-size:1.6rem;margin:0 0 .3rem;line-height:1.1}
.gloss-ledger .gx-count{margin:.2rem 0 .8rem}
.gx-list{list-style:none;margin:0;padding:0;counter-reset:gx}
/* The manicule is the mark that says GLOSS (§3.10g) and it is drawn here as
   the rubricated ordinal a scribe would have put in the margin — the number is
   ordinal within this list and says nothing about anything else, which is why
   replacing the default marker loses nothing: the element is still an <ol>. */
.gx-entry{position:relative;padding:.7rem 0 .7rem 2.2rem;
  border-left:3px solid var(--moss);
  border-bottom:1px solid rgba(59,42,23,.14)}
.gx-entry::before{counter-increment:gx;content:counter(gx);
  position:absolute;left:.6rem;top:.78rem;font-family:var(--utility);font-size:.72rem;
  color:var(--moss);opacity:.85}
.gloss-ledger .gx-text{font-family:var(--body);font-size:1rem;line-height:1.5;margin:0}
.gloss-ledger .gx-src{font-family:var(--utility);font-size:.78rem;
  margin:.3rem 0 0;display:flex;flex-wrap:wrap;gap:.5rem;align-items:baseline}
/* `.78` on the COLOUR and never `opacity`: opacity fades ink toward the paper
   at exactly the sizes least able to afford it, and this is the smallest
   string in the block (§4). Measured composited on parchment at 5.73:1. */
.gloss-ledger .gx-date{color:rgba(59,42,23,.78);margin-left:auto}
.gx-sep{color:rgba(59,42,23,.5)}
@media (max-width:480px){
  .gx-entry{padding-left:1.7rem}
  .gx-entry::before{left:.4rem}
  .gloss-ledger .gx-date{margin-left:0;flex-basis:100%}
}

/* ---------- one claim, pulled into a note ----------
   The frame is this embed's and the row is the ledger's, which is the same
   split PP.saltSpreadHTML makes between a series page and a period page.
   Rubricated on the left the way a gloss is (§3.10g): a sourced claim dropped
   into an argument is an appeal to the record, and it should read as one rather
   than as another grey box.

   NO ORDINAL. The ledger numbers its rows because it is a list somebody is
   reading down; here there is one claim and a "1" beside it is a count of the
   list it is not in — the same reason §3.11c3 refuses to print the footnote
   number in the ledger, one direction over. */
/* `.embed.embed-citation`, NOT `.embed-citation`. Both are (0,1,0) and
   `.embed{margin:1.6rem 0;padding:0}` sits LATER in this file, so it won on
   file order and zeroed the padding — the rubric sat hard against the claim
   with nothing between the two, and the block's left edge landed exactly on
   the prose column's, so the red rule read as spilling out of it. Nothing
   errored and the markup was right; only the geometry was wrong, which is the
   one thing no source check can see (§4).

   Winning on SPECIFICITY rather than on file order is what stops moving either
   block silently undoing it again — §3.9c's lesson about `.proceed-btn`, and
   the same fix the Book of Citations' own rules already carry. */
.embed.embed-citation{margin:1.3rem 0;padding:.1rem 0 .1rem .9rem;
  border-left:3px solid var(--oxblood)}
/* The ledger's <ol> inside a post body picks up `.post-body ol`'s reading
   indent — 1.4rem of margin-left that `.boc-list{margin:0}` cannot beat at
   (0,1,0). Measured: the claim started 39px right of its own rubric, which
   reads as the rule belonging to something else. Same family as the padding
   above, one element in. */
.embed-citation .boc-list{counter-reset:none;margin:0;padding:0;list-style:none}
.embed-citation .boc-entry{padding:0;border-bottom:0}
.embed-citation .boc-entry::before{content:none}
.embed-citation figcaption{font-family:var(--utility);font-size:.72rem;line-height:1.5;
  margin:.5rem 0 0;color:rgba(59,42,23,.8)}
.embed-citation figcaption a{color:var(--oxblood);text-decoration:none;
  border-bottom:1px solid rgba(216,192,120,.7)}
.embed-citation figcaption a:hover,.embed-citation figcaption a:focus-visible{
  border-color:var(--oxblood)}

/* ---------- The inline gloss ----------
   A "?" beside a term, added by glossary-tip.js only where a gloss exists —
   so a term the glossary does not cover is left exactly as it was. */
.gl-ask{font-family:var(--utility);font-size:.66rem;line-height:1;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:1.5px solid currentColor;
  border-radius:50%;width:1.15rem;height:1.15rem;padding:0;margin-left:.3rem;
  vertical-align:.1em}
.gl-ask:hover,.gl-ask.on{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.gl-ask:focus-visible{outline:2px solid var(--lake);outline-offset:2px}
/* A <span> set to block, because these sit inside headings and list items
   where a <div> would be illegal — the same constraint the citation panel
   has. */
.gl-tip-panel{display:block;margin:.4rem 0;padding:.5rem .7rem;
  border-left:4px solid var(--lake);background:rgba(39,75,142,.06);
  font-family:var(--body);font-size:.85rem;line-height:1.45;font-weight:400;
  text-transform:none;letter-spacing:normal}
.gl-tip-gloss{display:block}
.gl-tip-meta{display:block;font-family:var(--utility);font-size:.72rem;opacity:.75;margin-top:.2rem}
.gl-tip-more{display:inline-block;font-family:var(--utility);font-size:.72rem;margin-top:.25rem}

/* ---------- the genre note ----------
   The inline gloss's own mark at a CONTROL rather than at a term, and its own
   names sharing the gloss's declarations. glossary-tip.js closes by querying
   `.gl-ask[aria-expanded="true"]` and removing `.gl-tip-panel`, so borrowing
   either name would let one control half-close the other — the aria cleared on
   a panel it cannot remove (§4's "a class name already spoken for", caught
   before it bit). Two names, one look, the way .orig-title and .orig-lang
   already sit together. */
.gn-ask,.sn-ask{font-family:var(--utility);font-size:.66rem;line-height:1;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:1.5px solid currentColor;
  border-radius:50%;width:1.15rem;height:1.15rem;padding:0;margin-left:.3rem;
  vertical-align:.1em;flex:0 0 auto}
.gn-ask:hover,.gn-ask.on,.sn-ask:hover,.sn-ask.on{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.gn-ask:focus-visible,.sn-ask:focus-visible{outline:2px solid var(--lake);outline-offset:2px}
/* THE MARK SAYS WHETHER THE READING IS ON, so a reader who has never opened the
   panel can still see that the names have been changed. Filled in the moss
   green the site already uses for a chosen state, and the accessible name says
   it in words — colour is never the only carrier (§7). */
.gn-ask.grouped{background:var(--moss);color:var(--paper);border-color:var(--ink)}
.gn-host,.sn-host{position:relative;display:inline-flex;align-items:center}
/* The genre control is a SPAN of its own rather than a wrapping label, because
   the panel carries a checkbox and a label inside a label is invalid — and
   costs the select its accessible name while the panel is open. The `for`
   attribute does the associating instead. */
.browse-filters .ba-genre{display:inline-flex;align-items:center}
/* A <span> set to block, for the reason the gloss's panel is one: these sit
   inside <label> and <h4>, where a <div> would be illegal. */
/* THE LEFT MARGIN IS THE GAP BESIDE THE "?", not indentation. In flow the
   panel's parent is a flex row (.stat-head on the statistics page), so the
   panel becomes a flex item sitting immediately beside the mark — measured at
   zero, the ruled edge hard against the button's own circle, which reads as
   the two being one object. */
.gn-panel,.sn-panel{display:block;margin:.45rem 0 .45rem .5rem;padding:.55rem .7rem;max-width:26rem;
  border-left:4px solid var(--lake);background:rgba(39,75,142,.06);
  font-family:var(--body);font-size:.85rem;line-height:1.45;font-weight:400;
  text-transform:none;letter-spacing:normal;color:var(--ink);
  white-space:normal;text-align:left}
/* IN FLOW BY DEFAULT, and floated out of it on Browse only. The three places
   this control appears want opposite things and neither rule is right for both:
   the historiography bay is `overflow:hidden` (it is an arch with a clipped
   corner), so an absolutely-positioned panel there would simply be cut off —
   while Browse's filter strip is a wrapping flex row, where an in-flow panel
   becomes a flex item and shoves the other controls around. So the default
   flows, and the one container that cannot take it gets the popover. */
.browse-filters .gn-panel{position:absolute;top:100%;left:0;z-index:40;
  width:min(24rem, calc(100vw - 2.5rem));margin:.35rem 0 0;
  background:var(--paper);border:1px solid var(--ink);border-left-width:4px;
  box-shadow:2px 2px 0 rgba(59,42,23,.2)}
.gn-say,.sn-say{display:block}
.gn-check{display:flex;align-items:flex-start;gap:.45rem;margin-top:.5rem;
  font-family:var(--utility);font-size:.78rem;cursor:pointer}
.gn-check input{margin:.15rem 0 0;accent-color:var(--moss);flex:0 0 auto;cursor:pointer}

/* admin: the glossary's hand-written half */
.gl-gauge.over{color:var(--oxblood);font-weight:700}

/* ---------- The bookmark ----------------------------------------------
   A vermilion ribbon hanging into the top-left corner of every page, holding
   the four ways in. It is a <details>, so the open/shut state, the keyboard
   and the ARIA all belong to the browser; the CSS only has to make a
   <summary> look like a ribbon.

   The ribbon face is assets/art/bookmark.svg — swap the file and it just
   works, the same deal border-rule.svg and drollery.svg offer. The label sits
   on top of it in HTML rather than in the drawing, so a translated or
   re-worded bookmark doesn't need the art redrawn. Keep the middle of the
   artwork quiet if you replace it. */
.pp-bookmark{
  position:fixed;top:0;left:max(.6rem,2vw);z-index:65;
  font-family:var(--utility);
}
.bm-tab{
  /* Both are needed: Firefox honours list-style, WebKit its own pseudo. */
  list-style:none;cursor:pointer;
  width:46px;height:132px;
  background:url(../art/bookmark.svg) top left / 46px 132px no-repeat;
  filter:drop-shadow(3px 3px 0 rgba(36,28,18,.25));
  display:grid;place-items:center;
  padding:34px 0 26px;
}
.bm-tab::-webkit-details-marker{display:none}
.bm-tab:hover{filter:drop-shadow(3px 3px 0 rgba(36,28,18,.45))}
.bm-tab:focus-visible{outline:3px solid var(--lake);outline-offset:2px}
.bm-tab-text{
  writing-mode:vertical-rl;
  color:var(--paper);font-size:.62rem;letter-spacing:.1em;
  text-transform:uppercase;white-space:nowrap;
}
.bm-panel{
  position:absolute;top:0;left:54px;
  width:min(20rem,calc(100vw - 5rem));
  background:var(--paper);border:2px solid var(--ink);
  box-shadow:5px 5px 0 rgba(36,28,18,.28);
  padding:.85rem .95rem .95rem;
}
/* Shown on a first visit only, and it explains why the panel opened itself —
   an unexplained open panel reads as a bug rather than a welcome. */
.bm-hail{
  font-family:var(--body);font-size:.84rem;font-style:italic;line-height:1.45;
  border-left:3px solid var(--gold);padding-left:.55rem;margin-bottom:.7rem;
}
.bm-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.35rem}
/* One appearance for the two links and the two buttons: what a row DOES is
   the reader's business, what element it happens to be is not. */
.bm-go{
  display:block;width:100%;text-align:left;cursor:pointer;font:inherit;
  background:var(--paper);border:2px solid var(--ink);padding:.45rem .6rem;
  color:var(--ink);text-decoration:none;
}
.bm-go:hover,.bm-go:focus-visible{background:var(--gold-bright)}
.bm-go[disabled]{opacity:.55;cursor:default;background:var(--paper)}
.bm-what{display:block;font-family:var(--utility);font-size:.84rem;color:var(--oxblood)}
.bm-why{display:block;font-family:var(--body);font-size:.75rem;line-height:1.35;opacity:.78;margin-top:.1rem}
.bm-said{font-family:var(--body);font-size:.78rem;line-height:1.4;color:var(--oxblood);margin-top:.55rem}
.bm-said:empty{display:none}
/* Below this the panel would hang off the right edge, so it drops under the
   ribbon instead of sitting beside it. */
@media (max-width:560px){
  .pp-bookmark{left:.5rem}
  .bm-tab{width:40px;height:112px;background-size:40px 112px;padding:28px 0 22px}
  .bm-panel{left:0;top:120px;width:calc(100vw - 1.6rem)}
  /* A ribbon clipped into a page displaces what is under it. The masthead is
     centred inside its own padding, so widening the left side carries the
     tagline and the logo clear of the ribbon — on a phone there is no empty
     left margin for it to hang in, and letting it sit on the wordmark is the
     one thing it must not do.

     WIDENED ON BOTH SIDES, AND THAT IS THE WHOLE POINT. It used to pad the
     left alone, which cleared the ribbon and bought the clearance by pushing
     everything centred inside it to the right: measured at 375px, the tagline
     and the wordmark both sat 16.9px right of the page's own centre, on a
     masthead whose every element is centred and which is read against a
     centred rule, a centred standfirst and a centred footer. Symmetric padding
     clears the ribbon by exactly as much and keeps the content where the rest
     of the page says it should be.

     What it costs is 3.6rem of content width on a phone, which the wordmark
     gives up — and that is a second gain rather than a price, since the image
     is capped at `max-width:100%` and had been running out to the very edge of
     the screen on the side the padding did not defend. */
  header.masthead{padding-left:3.6rem;padding-right:3.6rem}
}


/* ============================================================
   Design tokens + illuminated-manuscript styling
   ============================================================ */
/* ============================================================
   Period Piece — "Illuminated Manuscript" theme
   Layered AFTER main.css. Parchment ground, iron-gall brown ink,
   vermilion rubrication, gold leaf, lapis + verdigris accents,
   blackletter display. Saltiness renders as red marginal glosses,
   and a bas-de-page drollery (knights vs. a medieval film crew)
   runs along the foot of every page.
   ============================================================ */
:root{
  --paper:#E9E0C9;              /* parchment (cooled, less yellow) */
  --paper-deep:#DCD0B4;
  --ink:#3B2A17;               /* iron-gall brown ink */
  --oxblood:#9E2B25;           /* vermilion rubric red */
  --oxblood-deep:#7E1E1A;
  --lake:#274B8E;              /* ultramarine (lapis) */
  --lake-deep:#1C3868;
  --moss:#3E6B45;              /* verdigris green */
  --murex:#6A3D9A;             /* Tyrian purple — the genre facet (§3.11l3) */
  --murex-text:#57307E;        /* the same pigment, darkened for type on parchment */
  --gold:#B98A2F;              /* gold leaf */
  --gold-bright:#D8C078;       /* muted highlight (less yellow) */
  --salt-ink:#9E2B25;          /* saltiness = red marginalia */
  --display:'UnifrakturMaguntia','MedievalSharp',serif;
  --body:'Cardo','EB Garamond',Georgia,serif;
  --utility:'MedievalSharp','Cardo',serif;
}

/* ---- parchment ground: mottled, faintly ruled, and with a tooth ----------
   THE FIBRE IS THE TOP LAYER AND IT IS DELIBERATELY ALMOST NOTHING. Measured,
   it moves the ground from #E9E0C9 to #E5DBC4 at its darkest — two points of
   luminance, which costs the tightest string on the site 0.25 of its 5.65:1 and
   leaves every one of the 46 ratios in the working notes clearing AA with room.

   That restraint is the whole design rather than timidity. A photographic paper
   at full strength reads beautifully and turns `--paper` from a value into a
   RANGE, and AA then has to hold against its darkest pixel: on a scan with a
   vignette and a crease the quiet `.78` text goes to 3.82:1 and the oxblood
   rubrics to 3.09:1, and the SAME string passes at the top of the page and
   fails at the bottom, which no static measurement can express. The strength
   lives in the art file, and there is a check on it.

   It is also a TILE rather than a photograph: 180px, seamless, ~1 KB. A full
   scan would be several hundred KB on every page above the fold, which is the
   weight §6c spent eighteen art files removing. Swap `paper-grain.svg` for a
   real scan if you want one — keep it tileable, and keep it this faint. */
body{
  color:var(--ink);
  background:
    url(../art/paper-grain.svg) repeat,
    radial-gradient(120% 70% at 20% 0%, rgba(158,43,37,.05), transparent 55%),
    radial-gradient(120% 90% at 90% 30%, rgba(39,75,142,.05), transparent 55%),
    radial-gradient(140% 120% at 50% 110%, rgba(59,42,23,.14), transparent 60%),
    repeating-linear-gradient(0deg, transparent 0 29px, rgba(59,42,23,.05) 29px 30px),
    var(--paper);
  background-attachment:fixed;
}
/* Ink on paper needs no picture of paper — and the print block already says so
   for the whole stack (`body{background:#fff !important}`), which resets the
   image layers with it. A second rule here saying the same thing is the kind of
   duplicate that eventually disagrees with the first. */
a{color:var(--oxblood)}

/* ---- ornamental rules where the film-sprockets were ---- */
/* ---- masthead banner: a tileable illuminated band ----------------------
   The band is an editable SVG that repeats horizontally:
     assets/art/border-rule.svg       the main rule
     assets/art/border-rule-foot.svg  the quieter one under the masthead
   Redraw either file to change the banner — keep the viewBox so it still
   tiles, and adjust --rule-height / --rule-foot-height if you change the
   tile's proportions. */
.sprockets{
  height:var(--rule-height);opacity:1;
  background:url(../art/border-rule.svg) repeat-x left center;
  background-size:auto 100%;
  border:none;
}
.sprockets::after{content:none}
.sprockets.bottom{
  height:var(--rule-foot-height);opacity:1;
  background:url(../art/border-rule-foot.svg) repeat-x left center;
  background-size:auto 100%;
}

/* ---- masthead ---- */
header.masthead{border-bottom:0px double var(--gold);background:linear-gradient(180deg, rgba(216,192,120,.10), transparent)}
.masthead .tagline{color:var(--oxblood);font-family:var(--utility);letter-spacing:.18em}
.masthead .rule-note{font-family:var(--body);font-size:1.05rem}
.masthead .admin-link{color:var(--oxblood);border-color:var(--oxblood);font-family:var(--utility)}
.masthead .admin-link:hover{background:var(--oxblood);color:var(--paper)}
.masthead-logo img{filter:drop-shadow(0 1px 0 rgba(59,42,23,.25))}

/* ---- era bar: rubricated chapter tabs ---- */
.era-btn{
  font-family:var(--utility);letter-spacing:.06em;text-transform:none;font-size:.9rem;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--gold);
  box-shadow:2px 2px 0 rgba(59,42,23,.3);
}
.era-btn .dot{border-color:var(--ink)}
.era-btn .range{font-family:var(--body);opacity:.6}
.era-btn:hover,.era-btn:focus-visible{background:var(--paper-deep)}
.era-btn.zoomed{background:var(--oxblood);color:var(--paper);border-color:var(--gold)}
.era-btn.zoomed .dot{background:var(--gold)}
.era-hint{font-family:var(--utility);color:var(--ink);opacity:.6;letter-spacing:.12em;text-transform:none}

/* ---- filters + controls ---- */
.filter-group label,.control-group .clabel{font-family:var(--utility);color:var(--ink);text-transform:none;letter-spacing:.08em}
.filter-group select,.seg button{font-family:var(--utility);background:var(--paper);color:var(--ink);border-color:var(--ink)}
.seg button.on{background:var(--oxblood);color:var(--paper)}
.clear-filters{font-family:var(--utility);color:var(--oxblood);border-bottom-color:var(--oxblood);text-transform:none}

/* ---- timeline: era-coloured segments (each tick's underline is its era) ---- */
.timeline{box-shadow:0 3px 0 var(--gold)}
.tick{font-family:var(--utility);color:var(--ink);border-bottom:4px solid var(--era-c,var(--ink))}
.tick .mark{background:var(--era-c,var(--oxblood))}
.tick .label{background:var(--ink);color:var(--paper);border-radius:2px}
.tick.has-films .mark::after{background:var(--paper);border-color:var(--ink)}
.timeline.zoomed .tick .label{background:none;color:var(--ink)}
.timeline.zoomed .tick:hover .label,.timeline.zoomed .tick.active .label{background:var(--era-c);color:var(--paper)}
.tick.active .mark{background:var(--era-c)}
.tick.active{border-bottom-width:7px}

/* ---- drop zone: illuminated headings ---- */
.year-banner h2{font-family:var(--display);color:var(--oxblood);font-weight:400;letter-spacing:.02em;text-shadow:1px 1px 0 rgba(216,192,120,.5)}
.year-banner .sub{font-family:var(--utility);color:var(--ink);text-transform:none;letter-spacing:.1em}
.intro-hint{font-family:var(--body);color:rgba(59,42,23,.7)}
.intro-hint .big-arrow{color:var(--oxblood)}

/* ---- poster cards as manuscript miniatures ---- */
.poster{
  border:3px solid var(--ink);
  box-shadow:0 0 0 3px var(--gold), 4px 4px 0 rgba(59,42,23,.35);
  background:var(--paper-deep);
}
.poster-card:hover .poster,.poster-card:focus-visible .poster{box-shadow:0 0 0 3px var(--gold-bright), 6px 8px 0 rgba(59,42,23,.3)}
.badge{font-family:var(--utility);background:var(--paper);border-color:var(--ink);color:var(--ink);text-transform:none;letter-spacing:.04em}
.badge.review{background:var(--gold);color:var(--ink);border-color:var(--ink)}
.poster-meta .p-title{font-family:var(--body);font-weight:700}
.poster-meta .p-sub{font-family:var(--utility);color:rgba(59,42,23,.65);text-transform:none;letter-spacing:.04em}
.poster-meta .p-lb{font-family:var(--utility);color:var(--gold)}
.poster-meta .p-lb .lb-num{color:rgba(59,42,23,.6)}

/* ---- saltiness = red marginal gloss ---- */
.salt-compact{color:var(--oxblood)}
.salt-compact .s-num{font-family:var(--utility);color:var(--oxblood);font-style:italic}

/* ---- TV grouping ---- */
.show-stack .mini{border:2px solid var(--ink);box-shadow:0 0 0 2px var(--gold),3px 3px 0 rgba(59,42,23,.3)}
.show-title-tab{font-family:var(--body);font-weight:700;font-size:1rem;letter-spacing:.01em;background:var(--oxblood);color:var(--paper);border:2px solid var(--gold)}
.show-stack .ep-count{font-family:var(--utility);background:var(--ink);color:var(--paper)}
.show-panel{border:2px solid var(--gold);box-shadow:0 0 0 2px var(--ink),4px 4px 0 rgba(59,42,23,.3)}
.show-close-tab{font-family:var(--utility);background:var(--ink);color:var(--paper)}
.show-close-tab:hover{background:var(--oxblood)}

/* ---- empty state + jump ---- */
.empty-state{border-color:var(--gold);background:rgba(216,192,120,.08)}
.empty-state p{font-family:var(--body);color:rgba(59,42,23,.8)}
.jump-btn{font-family:var(--utility);background:var(--paper);border:2px solid var(--ink);color:var(--oxblood);text-transform:none}
.jump-btn:hover,.jump-btn:focus-visible{background:var(--oxblood);color:var(--paper);border-color:var(--gold)}

/* ---- ratings on the review page ---- */
.rating-label{font-family:var(--utility);color:rgba(59,42,23,.7);text-transform:none;letter-spacing:.12em}
.stars-wrap .stars-fg{color:var(--gold)}
.rating-num{font-family:var(--utility);color:var(--ink)}

/* ---- review page: illuminated + marginal gloss ---- */
.back-btn{font-family:var(--utility);border:2px solid var(--oxblood);color:var(--oxblood);text-transform:none}
.back-btn:hover{background:var(--oxblood);color:var(--paper)}
.review-head{border-bottom:3px double var(--gold)}
.review-title h2{font-family:var(--display);color:var(--oxblood);font-weight:400;letter-spacing:.01em}
.review-title .rt-sub{font-family:var(--utility);color:var(--ink);text-transform:none;letter-spacing:.08em}
.review-body{font-family:var(--body);font-size:1.14rem}
/* The illuminated capital, and it is opt-in. This was `p:first-of-type`,
   which selects per PARENT — so every container holding a paragraph got one,
   including the glossary's 128 glosses, a statistics caption reading "81
   titles shown", the figure stat "2 titles in the archive", a post's byline
   and, on 92 review pages, the note saying no write-up exists yet. The class
   is stamped by PP.markLede on the opening paragraph of a body of prose and
   nowhere else; matching it here means the flourish cannot wander again by
   somebody nesting a paragraph. */
.lede::first-letter{
  font-family:var(--display);font-size:3.4em;line-height:.8;float:left;
  color:var(--oxblood);margin:.05em .12em 0 0;
  text-shadow:2px 2px 0 var(--gold-bright);
}
.review-body .verdict{font-family:var(--body);border-left:5px solid var(--gold);background:rgba(216,192,120,.12)}
.review-body .verdict strong{font-family:var(--utility);color:var(--oxblood);letter-spacing:.04em}
/* the saltiness note becomes a red scribal gloss with a manicule */
.salt-note{
  font-family:var(--body);font-style:italic;color:var(--oxblood);
  border-left:3px solid var(--oxblood);background:rgba(158,43,37,.06);
  padding:.5rem .8rem .5rem 2rem;position:relative;max-width:none;
}
.salt-note::before{content:"\261E";position:absolute;left:.5rem;top:.45rem;font-style:normal;color:var(--oxblood);font-size:1.1rem}

/* ---- content pages + legend ---- */
.content-page h2{font-family:var(--display);color:var(--oxblood);font-weight:400}
.content-page h3{font-family:var(--utility);color:var(--lake);text-transform:none;letter-spacing:.06em}
.content-page p,.content-page li{font-family:var(--body);font-size:1.12rem}
.salt-legend .emblem{border-color:var(--ink);box-shadow:0 0 0 2px var(--gold)}
.salt-legend .tier-name{font-family:var(--display);color:var(--oxblood);font-weight:400}
.salt-legend .tier-level{font-family:var(--utility);text-transform:none}
.salt-legend .tier-blurb{font-family:var(--body)}

/* ---- toast + cookie banner ---- */
.toast{font-family:var(--utility);background:var(--oxblood);color:var(--paper);border-color:var(--gold);text-transform:none}
.cookie-banner{background:var(--paper);border:2px solid var(--ink);box-shadow:0 0 0 2px var(--gold),4px 4px 0 rgba(59,42,23,.3)}
.cookie-banner p{font-family:var(--body)}
.cookie-actions .btn{font-family:var(--utility);text-transform:none}

/* ---- footer: the colophon, and the bas-de-page drollery --------------------

   The page used to stop dead. The footer was transparent, so the body's own
   ruled sheet ran straight through it; four lines of text sat at one size in
   one colour (10.88px MedievalSharp at .75 ink, measured, all four); and after
   the last of them came 16px of padding and the document edge. Nothing closed
   it, and nothing in it was a different KIND of thing from anything else in
   it, which is the whole of why it read as rows of plain text buttons.

   Five devices close it, and every one is CSS over art the tree already
   carries — §6c is a section about not putting weight on every page, and the
   two illumination files that would have suited this are 485 KB and 1.1 MB.

     the ground      a wash down to --paper-deep, so the block is a panel
                     rather than more page. It arrives at --foot-seat, the foot
                     of the drollery's own mound, so the figures stand ON the
                     deepened ground instead of floating above a list.
     the seat        a soft ellipse under that mound. A hairline there would be
                     a third rule competing with the two real ones; a shadow is
                     what standing on something actually looks like.
     the foot rule   border-rule-foot.svg tiled along the bottom edge. The site
                     has always owned a drawn foot rule and spent it under the
                     MASTHEAD (§3.22 — .sprockets.bottom measures 805px up from
                     the page bottom to prove it). Same file, already fetched
                     by CSS on every page, finally at a foot.
     the index panel the nav gets §3.9c4's lozenge trellis — two repeating
                     gradients, no image — so it reads as an illuminated index
                     in a language a reader has met on /start and /trivia.
     the finis       a rubricated lozenge under the last line, so the page ends
                     on a device rather than on an attribution sentence.

   TWO NUMBERS DRIVE THE REST. --foot-art-h is the drollery's slot and
   --foot-seat is its base; the padding, the ground's stop and the seat are all
   derived, so the phone block sets two values rather than six. */
footer.site-foot{
  --foot-art-h:150px;
  --foot-seat:164px;           /* the 14px top offset plus the slot */
  --foot-rule-h:12px;
  font-family:var(--utility);color:rgba(59,42,23,.75);text-transform:none;letter-spacing:.06em;
  /* The gold double rule measured 2.37:1 on parchment, under the 3:1 §3.9c4
     sets for a non-text component — the footer's only structural line was the
     faintest thing in it. --gold-text is the same pigment darkened, which is
     what that token exists for, and it clears the bar comfortably. */
  border-top:3px double var(--gold-text);position:relative;
  padding-top:calc(var(--foot-seat) + .5rem);
  padding-bottom:calc(var(--foot-rule-h) + 1.5rem);
  /* First layer is topmost: the seat lies over the ground, and the terminal
     rule over both. THE SEAT'S 26% IS A RADIUS, NOT A WIDTH — the first pass
     said 56%, which spans 112% of the footer, so the shadow reached far past
     the figures on both sides and read as a drop shadow on the whole block
     rather than as ground under their feet. The drawing is 634px in a 1170px
     footer, so half of that is what the radius wants to be. A browser dropping any one of these keeps the others —
     there is no state here in which the footer loses its ground and keeps a
     shadow of a mound that is no longer standing on anything. */
  background:
    radial-gradient(26% 14px at 50% var(--foot-seat), rgba(59,42,23,.11), transparent 70%),
    url(../art/border-rule-foot.svg) repeat-x left bottom / auto var(--foot-rule-h),
    linear-gradient(180deg,
      rgba(220,208,180,0)   0,
      rgba(220,208,180,.62) calc(var(--foot-seat) * .58),
      var(--paper-deep)     var(--foot-seat));
}
footer.site-foot::before{
  content:"";position:absolute;top:14px;left:0;right:0;height:var(--foot-art-h);
  /* A PNG, not an SVG wrapper like the other three: an SVG loaded as a CSS
     background is an image document and may not fetch an external href, so a
     wrapper here would paint nothing at all. Rendered at 2x its slot.

     `contain` + `bottom` rather than `auto <h>` + `top`, and BOTH halves are
     load-bearing. The drawing is 1268x300, so in its 104px phone slot it is
     439.6px wide and a 375px viewport was amputating 32.3px from each side —
     the spearman's spear and the cameraman's back, on every phone. `contain`
     fits it to whichever axis is tighter, which on any screen wider than the
     drawing is still exactly `auto <h>`; `bottom` then keeps the mound's foot
     on --foot-seat at every width, which is where the ground arrives. */
  background:url(../art/drollery.png) center bottom / contain no-repeat;
}
/* THE PAGE ENDS ON A DEVICE. ::after is free because the terminal rule is a
   background layer on the footer itself rather than a pseudo-element — and it
   has to be, since a tiled rule and a centred ornament are not the same box.
   Drawn, never a glyph: a rotated square costs nothing, and a ❦ would be read
   aloud, which is a decoration announcing itself (§7). */
footer.site-foot::after{
  content:"";display:block;width:9px;height:9px;margin:1.2rem auto .1rem;
  background:var(--oxblood);border:1px solid var(--gold);transform:rotate(45deg);
  box-shadow:0 0 0 2px rgba(185,138,47,.22);
}

/* ---- the index panel ---- */
/* Fourteen identical words in two rows became a band: the arcade's own trellis
   on a tint, ruled top and bottom in gold. Bounded rather than full bleed, so
   it reads as a panel set on the colophon rather than as a third rule; and the
   trellis is at .14 because it sits behind type, where §3.9c4's own spandrel
   does not. */
.foot-nav{
  max-width:58rem;margin:0 auto 1.15rem;padding:.95rem 1.2rem .85rem;
  /* The bounding rules are --gold-text rather than --gold: on the deepened
     ground full gold measures 2.04:1, so the rules that bound the panel were
     fainter than the trellis inside it. The darker pigment comes out at 3.87,
     clear of the 3:1 §3.9c4 sets for a non-text component. */
  border-top:1px solid var(--gold-text);
  border-bottom:1px solid var(--gold-text);
  /* .11 on a 13px pitch. At .14/11px it read as pattern rather than texture
     behind the links on a phone, where the panel is at its narrowest and the
     diagonals are least broken up by the words sitting on them. */
  background:
    repeating-linear-gradient(45deg,  rgba(185,138,47,.11) 0 1px, transparent 1px 13px),
    repeating-linear-gradient(-45deg, rgba(185,138,47,.11) 0 1px, transparent 1px 13px);
}
.foot-nav a{font-family:var(--utility);color:var(--oxblood);text-transform:none;letter-spacing:.06em}
.foot-nav a:hover,.foot-nav a:focus-visible{color:var(--oxblood-deep);border-bottom-color:var(--gold)}
/* TWO DIFFERENT KINDS OF THING: ways into the archive, and the paperwork. The
   hairline said so and is hidden below 520px by design (§3.11e) — so on a
   phone the grouping was carried by NOTHING, and "Terms" read exactly like
   "Browse" in one undifferentiated block of fourteen. The voice carries it at
   every width, and the two groups' aria-labels already state it in words, so
   neither colour nor size is doing this alone (§7). */
.foot-nav-group + .foot-nav-group{gap:1.25rem}
.foot-nav-group + .foot-nav-group a{
  font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;color:rgba(59,42,23,.86);
}
.foot-nav-group + .foot-nav-group a:hover,
.foot-nav-group + .foot-nav-group a:focus-visible{color:var(--oxblood)}

/* ---- the colophon: three ranks where there was one voice ---- */
/* The stamp was `opacity:.6` over ink already at .75, compositing to 2.44:1 at
   10.88px — §4 has a row on exactly this, and the alpha belongs on the COLOUR
   where it can be read off and measured rather than on opacity, which fades
   ink toward the paper at the sizes least able to afford it. It is also the
   most manuscript-ish sentence on the site — the date a scribe finished the
   book — so it is set in the body face rather than faded into the paper, with
   a rubric lozenge before it. `content:""` draws a shape and announces
   nothing. */
/* RUBRICATED, NOT MARKED. It carried a small oxblood lozenge before it, which
   was the second rhombus on the page — the finis under the colophon is the
   other, and a device used twice within four lines is a device that has
   stopped meaning anything. So the line is rubricated instead, which is what a
   scribe does to the sentence that matters rather than hanging an ornament off
   it, and the rank is carried by the colour it is written in.

   MedievalSharp and NOT the blackletter --display: §3.9c4 settles that the
   display face is for a YEAR, a thing a reader decodes rather than reads, and
   this is a phrase. Oxblood measures 4.86:1 on the deepened ground at 13.44px,
   which is the rubric red every other one on the site sits at. */
.foot-updated{
  opacity:1;color:var(--oxblood);
  font-family:var(--utility);font-size:.84rem;letter-spacing:.06em;
  line-height:1.7;margin:0 0 .5rem;
}
.foot-credit{color:rgba(59,42,23,.92);font-size:.8rem;letter-spacing:.1em;line-height:1.8}
/* The longest line and the one a reader needs least: a rank below the name it
   sits under, and measured so it does not run the width of a wide screen. */
.foot-sources{
  color:rgba(59,42,23,.78);font-size:.66rem;letter-spacing:.05em;line-height:1.75;
  max-width:46rem;margin:.1rem auto 0;
}

/* ---- admin (kept legible) ---- */
.admin-wrap h2{font-family:var(--display);color:var(--oxblood);font-weight:400}
.admin-wrap h3{font-family:var(--utility);color:var(--lake);text-transform:none}
.admin-tabs button,.btn{font-family:var(--utility);text-transform:none}
.admin-tabs button.on{background:var(--oxblood);color:var(--paper)}
.btn{background:var(--oxblood);color:var(--paper);border-color:var(--gold)}
.btn.secondary{background:var(--paper);color:var(--ink)}

@media (max-width:640px){
  /* Two numbers. The padding, the ground's stop and the seat all derive from
     them, and `contain` means the drawing no longer needs a size of its own. */
  footer.site-foot{--foot-art-h:104px;--foot-seat:118px}
  .foot-nav{padding:.75rem .5rem .65rem;margin-bottom:.9rem;gap:.45rem 1rem}
  .foot-nav-group{gap:.45rem 1.05rem}
  /* The uppercase and the tracking are what make the paperwork a different
     voice, and on a 375px screen they are also what pushed "Terms" onto a
     line of its own. The voice survives a tighter setting; an orphan does
     not survive being looked at. */
  .foot-nav-group + .foot-nav-group a{letter-spacing:.1em}
}

/* ---- knight-and-snail drollery in the empty-year state ---- */
.empty-drollery{display:flex;justify-content:center;margin-bottom:.8rem}
.empty-drollery svg{width:210px;height:auto}

/* ============================================================
   Finder (search + surprise), sort caption, focus, search flash
   ============================================================ */
/* `flex-wrap:wrap` is load-bearing, not tidying. The copy-view read-out is
   `flex:1 1 100%` so it takes a line of its own — but a basis of 100% in a
   NON-wrapping row is not a line break, it is simply an enormous flex item.
   It ate 788px of a 1180px row, crushed the search box from 440 to 122 and
   shoved the whole group off centre. */
.finder{max-width:1180px;margin:1rem auto .6rem;padding:0 1rem;display:flex;
  flex-wrap:wrap;justify-content:center;gap:.6rem;align-items:flex-start}
.search-box{position:relative;flex:1 1 auto;max-width:440px}
#searchInput{width:100%;font-family:var(--utility);font-size:.95rem;color:var(--ink);
  background:var(--paper);border:2px solid var(--ink);border-radius:0;padding:.5rem .7rem;
  box-shadow:2px 2px 0 rgba(59,42,23,.22)}
#searchInput::placeholder{color:rgba(59,42,23,.55)}
#searchInput:focus{outline:none;border-color:var(--oxblood);box-shadow:2px 2px 0 var(--gold)}
.search-results{position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:60;list-style:none;
  margin:0;padding:0;background:var(--paper);border:2px solid var(--ink);
  box-shadow:4px 4px 0 rgba(59,42,23,.28);display:none;max-height:340px;overflow:auto}
.search-results.open{display:block}
.sr-item{display:flex;justify-content:space-between;align-items:baseline;gap:.7rem;
  padding:.5rem .7rem;cursor:pointer;border-bottom:1px solid rgba(59,42,23,.16)}
.sr-item:last-child{border-bottom:none}
.sr-item.active,.sr-item:hover{background:var(--oxblood);color:var(--paper)}
.sr-title,.sr-year{font-family:var(--body);font-weight:700}
.sr-kind{font-family:var(--utility);font-size:.72rem;opacity:.7;white-space:nowrap}
.sr-item.active .sr-kind{opacity:.9}
.surprise-btn{flex:0 0 auto;font-family:var(--utility);font-size:.85rem;color:var(--paper);
  background:var(--oxblood);border:2px solid var(--gold);padding:.5rem .95rem;cursor:pointer;
  box-shadow:2px 2px 0 rgba(59,42,23,.3)}
.surprise-btn:hover{background:var(--oxblood-deep)}

/* Copy view. A quieter sibling of Surprise me: that one is the invitation,
   this one is the way out with what you found. Outlined rather than filled so
   the two do not compete for the same click. */
.copy-view-btn{flex:0 0 auto;font-family:var(--utility);font-size:.85rem;
  color:var(--oxblood);background:var(--paper);border:2px solid var(--oxblood);
  padding:.5rem .95rem;cursor:pointer;box-shadow:2px 2px 0 rgba(59,42,23,.18)}
.copy-view-btn:hover{background:var(--oxblood);color:var(--paper)}
/* The read-out takes the whole next line: it names the era, the filters and
   the threads that were captured, and wedged beside the buttons it would
   either be truncated or push them apart on every copy.
   Hidden while empty, so the resting row costs nothing — this sits directly
   above the rule, and reserving a permanent blank line here would undo part
   of the work done to get the timeline onto a phone's first screen. */
.finder .copy-said{flex:1 1 100%;text-align:center;font-family:var(--utility);
  font-size:.72rem;color:var(--lake);letter-spacing:.03em}
.finder .copy-said:empty{display:none}
@media print{ .copy-view-btn,.finder .copy-said{display:none} }

.sort-caption{font-family:var(--utility);font-size:.78rem;color:var(--oxblood);opacity:.85;margin:.15rem 0 0;letter-spacing:.02em}

/* keyboard focus visibility */
.tick:focus-visible,.era-btn:focus-visible,.seg button:focus-visible,.jump-btn:focus-visible,
.poster-card:focus-visible,.show-stack-card:focus-visible,.surprise-btn:focus-visible,
.foot-nav a:focus-visible,.back-btn:focus-visible,.clear-filters:focus-visible{
  outline:3px solid var(--gold);outline-offset:2px}

/* search-jump highlight */
.poster-card.flash,.show-stack-card.flash{animation:pp-flash 1.5s ease}
@keyframes pp-flash{
  0%,100%{outline:0 solid transparent;outline-offset:2px}
  25%,65%{outline:3px solid var(--oxblood);outline-offset:3px}
}
@media (prefers-reduced-motion:reduce){ .poster-card.flash,.show-stack-card.flash{animation:none;outline:3px solid var(--oxblood);outline-offset:3px} }
@media (max-width:640px){ .finder{flex-wrap:wrap} .search-box{max-width:none;flex:1 1 100%} }

/* ============================================================
   Admin: validation badge, TMDB autofill, validation report
   ============================================================ */
.admin-statusbar{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap;max-width:900px;margin:0 auto .4rem;padding:0 1rem}
.admin-statusbar .mini-note{margin:0}
.val-badge{font-family:var(--utility);font-size:.76rem;border:2px solid var(--ink);background:var(--paper);color:var(--ink);
  padding:.22rem .6rem;cursor:pointer;letter-spacing:.02em}
.val-badge:empty{display:none}
.val-badge.ok{border-color:var(--moss);color:var(--moss)}
.val-badge.warn{border-color:var(--gold);color:#8a6a1f}
.val-badge.err{border-color:var(--oxblood);background:var(--oxblood);color:var(--paper)}

/* --- admin: the command palette (Ctrl/Cmd+K) ---------------------------
   A shortcut nobody can see is a shortcut nobody uses, so the same thing is
   also a button in the status bar. */
.palette-btn{font-family:var(--utility);font-size:.74rem;background:var(--paper);color:var(--ink);
  border:2px solid var(--ink);padding:.22rem .6rem;cursor:pointer;display:flex;align-items:center;gap:.4rem}
.palette-btn kbd{font-family:var(--utility);font-size:.66rem;border:1px solid rgba(36,28,18,.4);
  border-radius:3px;padding:0 .25rem;opacity:.75}
.palette-scrim{position:fixed;inset:0;background:rgba(36,28,18,.45);z-index:80;display:flex;
  align-items:flex-start;justify-content:center;padding:8vh 1rem 1rem}
.palette{width:min(680px,100%);background:var(--paper);border:2px solid var(--ink);
  box-shadow:6px 6px 0 rgba(36,28,18,.3);display:flex;flex-direction:column;max-height:78vh}
.palette input{font-family:var(--body);font-size:1.05rem;padding:.7rem .9rem;border:none;
  border-bottom:2px solid var(--ink);background:var(--paper);color:var(--ink);width:100%}
.palette input:focus{outline:3px solid var(--gold);outline-offset:-3px}
.palette-hint{font-family:var(--utility);font-size:.7rem;letter-spacing:.06em;opacity:.6;
  margin:0;padding:.45rem .9rem;border-top:1px solid rgba(36,28,18,.2)}
.palette-list{overflow-y:auto}
.palette-list button{display:flex;width:100%;gap:.8rem;align-items:baseline;text-align:left;
  background:none;border:none;border-bottom:1px solid rgba(36,28,18,.14);
  padding:.5rem .9rem;cursor:pointer;font-family:var(--body);font-size:.95rem}
.palette-list button:hover{background:rgba(216,192,120,.25)}
.palette-list button.sel{background:rgba(216,192,120,.4);box-shadow:inset 4px 0 0 var(--oxblood)}
.palette-kind{font-family:var(--utility);font-size:.64rem;letter-spacing:.1em;text-transform:uppercase;
  opacity:.65;flex:0 0 8.5rem}
.palette-label{min-width:0;overflow-wrap:anywhere}
.palette-sub{font-family:var(--utility);font-size:.7rem;opacity:.6;margin-left:auto;padding-left:.8rem;
  text-align:right;flex:0 0 auto}

.val-report{margin-top:.6rem}
.val-list{margin:.4rem 0 0;padding-left:1.2rem;font-family:var(--utility);font-size:.82rem;line-height:1.5}
.val-list.err li{color:var(--oxblood)}
.val-list.warn li{color:#8a6a1f}

.tmdb-lookup{margin:.1rem 0 .8rem}
/* A bare button dropped straight into a form carries no margin of its own —
   every other block in there is a `.field`, which has one. So "Fetch
   Letterboxd rating" sat flush against the uppercase label of whatever field
   came next, which reads as the two overlapping. `.tmdb-lookup` above already
   solved this for itself; this is the same fact for the buttons beside it. */
#filmForm>.btn,#epForm>.btn,#showBox>.btn{margin-bottom:.9rem}
/* The state line and its button are one row, centred on each other rather
   than sitting on a shared text baseline — a bordered button baseline-aligned
   against a sentence hangs below it. Wraps to two lines rather than
   overflowing when the sentence is long or the column narrow. */
.poster-field{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap}
.pf-state{font-family:var(--body);font-size:.9rem;flex:1 1 16rem;min-width:0}
.poster-field .btn{flex:0 0 auto}
.tmdb-results{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.5rem}
.tmdb-hit{display:flex;gap:.5rem;align-items:center;text-align:left;background:var(--paper);
  border:2px solid var(--ink);padding:.35rem;cursor:pointer;width:230px}
.tmdb-hit:hover{background:var(--paper-deep)}
.tmdb-hit img,.tmdb-hit .noimg{width:40px;height:60px;object-fit:cover;border:1px solid var(--ink);flex:0 0 auto}
.tmdb-hit .noimg{background:var(--paper-deep);display:inline-block}
.tmdb-hit .th-meta{display:flex;flex-direction:column;min-width:0}
.tmdb-hit .th-title{font-family:var(--body);font-weight:700;font-size:.85rem;line-height:1.15}
.tmdb-hit .th-sub{font-family:var(--utility);font-size:.7rem;opacity:.7}

.export-box .btn{margin:.3rem .4rem .3rem 0}

/* ---- Admin: add-a-year widget ---- */
.year-adder{margin:.4rem 0 .9rem;border:2px dashed var(--ink);padding:.5rem .75rem;background:rgba(59,42,23,.05)}
.year-adder summary{font-family:var(--utility);cursor:pointer;color:var(--oxblood);letter-spacing:.02em}
.year-adder[open] summary{margin-bottom:.5rem}
.year-adder-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.5rem .8rem}
.year-adder .field label{font-size:.72rem}
/* What the control says about its own press. Selected through .year-adder so
   it wins on specificity rather than on file order — a bare .mini-note is
   (0,1,0) and loses to .content-page p, which is the trap §4 records. A
   refusal is marked by the rule down its left as well as by the colour (§7),
   since a colour is not a message. */
.year-adder .ya-say{margin:.5rem 0 0;font-family:var(--utility);font-size:.82rem;color:var(--ink)}
.year-adder .ya-refused{color:var(--oxblood);border-left:3px solid var(--oxblood);padding-left:.5rem}
@media (max-width:560px){ .year-adder-grid{grid-template-columns:1fr} }

/* ---- Admin: the episode runtime pull ----
   The box and its button on one line, with what the press did underneath.
   .ya-say is borrowed rather than renamed: it is the same thing — a control
   answering for its own press where the editor is looking (§6f) — and it is
   selected through .ep-runtime-pull for the specificity reason above. */
.ep-runtime{display:flex;gap:.5rem;align-items:flex-start;flex-wrap:wrap}
.ep-runtime input{flex:1 1 8rem;min-width:0}
.ep-runtime-pull{flex:1 1 12rem;display:flex;flex-direction:column;align-items:flex-start}
.ep-runtime-pull .btn{margin:0}
.ep-runtime-pull .ya-say{margin:.35rem 0 0;font-family:var(--utility);font-size:.82rem;color:var(--ink)}

/* multi-year (flashback / spans several years) badge, bottom-left of a card */
.badge.multi{top:auto;bottom:8px;left:8px;right:auto;background:var(--paper);color:var(--ink);border-color:var(--ink);letter-spacing:.06em}

/* ============================================================
   Browse / rankings page, related links, 404
   ============================================================ */
.browse-tabs{display:flex;flex-wrap:wrap;gap:.4rem;margin:1.2rem 0 .8rem}
.browse-tabs button{font-family:var(--utility);font-size:.82rem;background:var(--paper);color:var(--oxblood);
  border:2px solid var(--gold);padding:.35rem .8rem;cursor:pointer;box-shadow:2px 2px 0 rgba(59,42,23,.22)}
.browse-tabs button.on{background:var(--oxblood);color:var(--paper);border-color:var(--gold)}
/* The arrow sits on the chosen measure only, and it is the one thing on the
   button that says WHICH WAY — the fill says only that this is the measure in
   force (§3.7b). It is `aria-hidden`, so the accessible name carries the
   direction in words and this is purely the sighted shortcut to it. */
.browse-tabs button:active{transform:translate(2px,2px);box-shadow:none}
.browse-filters{display:flex;flex-wrap:wrap;gap:.9rem;align-items:center;margin:.4rem 0 1rem;
  font-family:var(--utility);font-size:.8rem}
.browse-filters select{font-family:var(--utility);background:var(--paper);color:var(--ink);
  border:2px solid var(--ink);padding:.25rem .4rem;margin-left:.3rem}
.browse-count{margin-left:auto;color:var(--oxblood)}
/* The bundle control. A checkbox among selects, so it needs the baseline the
   `select` rule above gives its neighbours — without it the box sat on the
   text baseline and the label rode high against the dropdowns beside it.
   Disabled says why through the label's own `title`; the dimming is the
   second carrier, never the only one (§7). */
.browse-filters .ba-check{display:inline-flex;align-items:center;gap:.4rem;cursor:pointer}
.browse-filters .ba-check input{accent-color:var(--oxblood);margin:0}
.browse-filters .ba-check input:disabled{cursor:default}
.browse-filters .ba-check input:disabled + span{opacity:.5}

/* ---- the advanced panel ----------------------------------------------------
   Six selects behind a <details>, so the era chips and the search box are what
   the page opens with. Styled as the spread's own box is (.bd-box), because
   they are the same device doing the same job on the same page and two looks
   would say they were different kinds of thing. */
.browse-adv{border:2px solid var(--ink);background:var(--paper);
  box-shadow:2px 2px 0 rgba(59,42,23,.18);margin:.4rem 0 .8rem}
/* NOT `display:flex`. Changing a summary's display drops its disclosure
   triangle, and a box with no marker does not read as one that opens — which
   is the whole job of a control that starts shut. The two spans are inline and
   spaced by a margin instead, exactly as the spread's summary is. */
.ba-summary{cursor:pointer;padding:.45rem .8rem;font-family:var(--utility);
  font-size:.74rem;color:rgba(59,42,23,.85);list-style-position:outside}
.ba-summary::-webkit-details-marker{color:var(--oxblood)}
.ba-summary:hover{background:rgba(216,192,120,.18)}
.ba-summary:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.browse-adv[open] .ba-summary{border-bottom:1px solid rgba(59,42,23,.22)}
.ba-head{letter-spacing:.04em;text-transform:uppercase}
/* How many filters are on, so a collapsed panel never hides one. The words are
   on the summary's accessible name; this is the sighted half (§7). */
.ba-n{color:var(--oxblood);margin-left:.6rem}
.ba-n:empty{display:none}
/* The margin the row carried while it was the whole block sits on the details
   now, or the panel opens with a gap above its first control. */
.browse-adv .browse-filters{margin:.6rem .8rem .7rem}
/* The count and the timeline link, outside the disclosure: how many titles are
   showing is the answer to what the reader just did, never something to open a
   panel for. */
.browse-meta{display:flex;flex-wrap:wrap;align-items:center;gap:.9rem;
  margin:.4rem 0 1rem;font-family:var(--utility);font-size:.8rem;min-height:1.4rem}
@media print{ .browse-adv{display:none} }
.browse-list{display:flex;flex-direction:column;border-top:2px solid var(--ink)}
.browse-row{display:flex;align-items:center;gap:.8rem;padding:.6rem .4rem;text-decoration:none;color:var(--ink);
  border-bottom:1px solid rgba(59,42,23,.22)}
.browse-row:hover,.browse-row:focus-visible{background:rgba(216,192,120,.18)}
.br-rank{font-family:var(--display);font-size:1.1rem;color:var(--gold);width:2.2rem;text-align:right;flex:0 0 auto}
.br-main{display:flex;flex-direction:column;min-width:0;flex:1 1 auto}
/* A WRAPPING FLEX ROW, and the gap is the whole point. The name, the era
   ribbons and the write-up chip used to be inline content spaced by margins,
   and a margin is something a narrow breakpoint can zero: at 400px the chip's
   `margin-left:0` — added to stop it squeezing the title — put it flush
   against the ribbon, so a green chip beside a green ribbon read as one
   merged blob. Measured: a gap of exactly 0px.

   `gap` cannot be collapsed by a neighbour's margin and does not need one, so
   the two can never touch again; `flex-wrap` means the chip drops to its own
   line when the width runs out instead of crushing the name. */
.br-title{display:flex;align-items:center;flex-wrap:wrap;gap:.15rem .4rem;
  font-family:var(--body);font-weight:700;font-size:1.02rem;min-width:0}
.br-name{min-width:0;overflow-wrap:anywhere}
.br-sub{font-family:var(--utility);font-size:.74rem;opacity:.72}
.br-salt{flex:0 0 auto}
.br-rating{font-family:var(--utility);font-size:.95rem;color:var(--ink);flex:0 0 auto;min-width:3.2rem;text-align:right}
.br-rating small{opacity:.55;font-size:.7em}
/* How long it runs, on the row. Set back from the two figures beside it — a
   runtime is a fact about the thing rather than a judgement of it, and the
   saltiness and the rating are what this list exists to rank by. Tabular
   numerals so the column reads down as a column. */
.br-runtime{font-family:var(--utility);font-size:.8rem;color:rgba(59,42,23,.78);
  flex:0 0 auto;min-width:3.6rem;text-align:right;white-space:nowrap;
  font-variant-numeric:tabular-nums}
/* An absent rating, matching the em dash /locations prints for the same
   reason: 0.0 is not a low score, it is no score (§3.2). */
.br-none{opacity:.45}
/* How much of a review there is. Drawn only where there IS one — four rows in
   five carry no write-up, so a chip saying so would be wallpaper (§3.10c). The
   two states differ in fill as well as in wording, and the wording is the part
   that carries it (§7). */
/* No margins on either: the title row's `gap` owns the spacing, so there is
   nothing for a breakpoint to zero (see .br-title). */
.br-depth{font-family:var(--utility);font-size:.6rem;letter-spacing:.05em;
  text-transform:uppercase;padding:0 .3rem;flex:0 0 auto;
  border:1px solid currentColor;white-space:nowrap}
.br-depth.is-full{color:var(--paper);background:var(--moss);border-color:var(--moss)}
.br-depth.is-partial{color:var(--moss);background:transparent}
/* /figures: the person behind a character rather than a portrayal (§3.9).
   A different hue from the write-up chips because it answers a different
   question, and the word carries it either way (§7). */
.br-depth.is-inspired{color:var(--lake);background:transparent;border-color:var(--lake)}
/* The residual, on the trend view only. Set apart from the rest of the sub so
   the ranking's reason does not read as part of the title's description. */
.br-defy{color:var(--oxblood);opacity:.95}
@media (max-width:560px){ .br-rank{width:1.6rem} .browse-count{margin-left:0;flex:1 1 100%} }

/* ---- the saltiness spread of whatever is on screen -------------------------
   A ranked list says what is at the top and nothing about the distribution it
   came out of, so a reader who has narrowed to one period cannot tell a salty
   corner of the archive from an ordinary one. Six columns say it before a row
   is read.

   Every column prints its own count, so the bar heights reinforce a number
   that is already there rather than being the only way to read it (§7); the
   strip as a whole carries the breakdown in words as its accessible name. */
.browse-dist{border:2px solid var(--ink);background:var(--paper);
  margin:0 0 1rem;box-shadow:3px 3px 0 rgba(59,42,23,.16)}
/* A <details>, so minimising costs no script and the keyboard and ARIA come
   free (§3.11a). The SUMMARY carries the caption, so a collapsed strip still
   says what it was holding rather than becoming an unlabelled twisty. */
.bd-summary{cursor:pointer;padding:.5rem .8rem;font-family:var(--utility);
  font-size:.72rem;color:rgba(59,42,23,.85);list-style-position:outside}
.bd-summary::-webkit-details-marker{color:var(--oxblood)}
.bd-summary:hover{background:rgba(216,192,120,.18)}
.bd-box[open] .bd-summary{border-bottom:1px solid rgba(59,42,23,.22)}
.bd-body{padding:.5rem .8rem .6rem}
/* The switch sits in the BODY, never in the summary: a button inside a
   <summary> toggles the disclosure, so a metric control there would collapse
   the very strip it had just redrawn. */
.bd-switch{display:flex;gap:.3rem;margin:0 0 .45rem}
.bd-switch button{font-family:var(--utility);font-size:.68rem;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:1.5px solid var(--gold);
  padding:.15rem .5rem}
.bd-switch button.on{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
/* The two label rows are a fixed 1.15rem each, so the bar track is this
   height minus 2.3rem — the plot has to be tall enough that what is left is
   still a chart. */
.bd-plot{display:flex;align-items:flex-end;gap:.5rem;height:5.4rem}
/* A GRID, not a flex column, and that is the whole of the arithmetic working.
   As a flex column the bar was a flex ITEM with a percentage height, so it
   resolved against a box the label and the tier number were also competing
   for and then shrank to fit — 8 titles and 4 titles both came out 34px, which
   is a bar chart that is not one. The middle track is `1fr` of a plot with a
   definite height, so a percentage inside it means what it says.

   THE OUTER ROWS ARE FIXED, NOT `auto`, AND THAT IS THE SECOND HALF OF THE
   SAME LESSON. Every column is its OWN grid, so `auto` rows are sized by that
   column's own content — and an empty tick label collapses its row to 0px,
   handing that column a taller `1fr` track than its neighbours. Measured on
   the rating spread, whose half-star bands were drawn unlabelled: the labelled
   columns got a 20.8px track and the unlabelled ones 38.7px, so 51 titles came
   out 21px and 24 titles came out 18px. Bars on two different scales, side by
   side, in the same chart.

   Fixed outer rows make the bar track identical in every column BY
   CONSTRUCTION, whatever any label happens to contain. */
.bd-col{display:grid;grid-template-rows:1.15rem 1fr 1.15rem;justify-items:center;
  flex:1 1 0;min-width:0;height:100%}
/* EXPLICIT ROWS, because a column with no bar has only two children and
   auto-placement would put its tick in the bar's row — floating the label of
   every empty band a row above its neighbours'. Naming the row means the
   geometry cannot depend on how many children a column happens to have. */
.bd-n{grid-row:1;font-family:var(--utility);font-size:.7rem;color:var(--oxblood);line-height:1.15rem}
/* min-height so a tier holding one title is still a mark rather than nothing.
   A tier holding NONE is drawn no bar at all — the renderer omits the element
   rather than sizing it to zero, because a 2px minimum would make "none" and
   "one" the same picture, and those are the two the eye most needs to tell
   apart at the ends of a filtered range. */
.bd-bar{grid-row:2;width:100%;align-self:end;background:var(--oxblood);border:1px solid var(--ink);
  border-bottom:0;min-height:2px}
.bd-t{grid-row:3;font-family:var(--utility);font-size:.7rem;opacity:.7;line-height:1.15rem}
/* Unrated is not a sixth tier and is not drawn as one: separated by a rule and
   filled differently, because 0 means "not yet judged" (§3.2). */
.bd-unrated{flex:0 0 2.2rem;border-left:1px dashed rgba(59,42,23,.45);padding-left:.4rem}
.bd-unrated .bd-bar{background:repeating-linear-gradient(45deg,
  rgba(59,42,23,.35) 0 3px, transparent 3px 6px)}
/* The caption moved INTO the summary, so a collapsed strip still says what it
   is holding. It keeps its own size rule for the reason the old `.bd-caption`
   needed one: `.content-page p` is (0,1,1) and beat a bare class, rendering it
   at body size — measured at 17.92px, wrapping one sentence onto five lines
   and standing taller than the plot it described (§3.9c, §4). A <summary> is
   not a <p>, so it escapes that particular selector, but `.browse-note` beside
   it does not — hence the wrapper there. */
.content-page .browse-note{font-size:.8rem;line-height:1.6;margin:0 0 1rem}

/* ---- why nothing matched ---------------------------------------------------
   Naming the dead end is not the same as offering a way out of it (§3.11a2).
   Each button is a filter measured to bring titles back, and says how many. */
.browse-empty{padding:1rem .4rem}
.be-fixes{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.6rem}
.be-fix{display:inline-flex;align-items:baseline;gap:.45rem;cursor:pointer;
  font-family:var(--utility);font-size:.78rem;background:var(--paper);color:var(--oxblood);
  border:2px solid var(--gold);padding:.35rem .7rem;box-shadow:2px 2px 0 rgba(59,42,23,.22)}
.be-fix:hover{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.be-fix:active{transform:translate(2px,2px);box-shadow:none}
.be-n{opacity:.7;font-size:.9em}
.be-all{border-color:var(--ink)}

/* ---- the syllabus: the same list drawn as a plan ---------------------------
   A second rendering of what browse.js has already filtered, sorted and
   bundled, so this block styles the SAME rows in a different shape and adds no
   filtering of its own.

   EVERY TEXT RULE IS SELECTED THROUGH `.syl-list` OR `.browse-page`, because
   `.content-page p` and `.content-page li` are both (0,1,1) and beat a bare
   class outright — the trap that rendered `.mini-note` at body size on five
   pages (§4). Winning on specificity rather than on file order means moving
   this block cannot silently undo it. */
.browse-format{display:inline-flex}
.syl-switch{font-family:var(--utility);font-size:.78rem;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--gold);
  padding:.35rem .8rem;box-shadow:2px 2px 0 rgba(59,42,23,.22)}
.syl-switch:hover{background:var(--paper-deep)}
.syl-switch.on{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.syl-switch:active{transform:translate(2px,2px);box-shadow:none}
.syl-switch:focus-visible{outline:3px solid var(--gold);outline-offset:2px}

/* The ranked mode rules its rows off one another and needs the top border;
   the plan is a numbered run of plates and would read as a table with a stray
   line above it. */
.browse-list.is-syllabus{display:block;border-top:none}

.browse-page .syl-lede{font-family:var(--utility);font-size:.82rem;line-height:1.6;
  color:rgba(59,42,23,.78);margin:.2rem 0 1rem;max-width:44rem}

/* `list-style:decimal` and a styled ::marker rather than a counter of ours,
   which is the canon table's own answer to this (§3.10e2) and §3.11c3's rule
   for the ledger: the numbering then honours the <ol>'s own `start` and
   carries across a page turn for free, where a CSS counter only increments
   for elements that generate a box and would restart at 1 on page two —
   reading as a second, shorter plan. */
.syl-list{list-style:decimal;padding:0 0 0 2.6rem;margin:0}
.syl-list li::marker{color:var(--gold-text);font-family:var(--display);
  font-size:1.1rem;font-variant-numeric:tabular-nums}
.browse-page .syl-item{font-size:1rem;padding:.9rem 0;
  border-bottom:1px solid rgba(59,42,23,.2)}
.browse-page .syl-item:first-child{border-top:2px solid var(--ink)}
.syl-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:.15rem .5rem}
.browse-page .syl-title{font-family:var(--body);font-weight:700;font-size:1.1rem;
  color:var(--oxblood);text-decoration:none;overflow-wrap:anywhere}
.browse-page .syl-title:hover,.browse-page .syl-title:focus-visible{text-decoration:underline}
.browse-page .syl-when{font-family:var(--utility);font-size:.76rem;color:rgba(59,42,23,.78)}
.browse-page .syl-facts{font-family:var(--utility);font-size:.76rem;
  color:rgba(59,42,23,.78);margin-top:.15rem}
.browse-page .syl-facts .rating-none{font-size:1em}

/* The caveat: the emblem and the tier's own sentence side by side. It wraps to
   two lines on a narrow screen rather than clipping, because the sentence is
   the point of the row and a truncated one is worse than a taller plate. */
.syl-caveat{display:flex;flex-wrap:wrap;align-items:baseline;gap:.2rem .6rem;margin-top:.45rem}
.syl-caveat .salt-compact{flex:0 0 auto}
.browse-page .syl-blurb{font-family:var(--body);font-size:.92rem;line-height:1.5;
  color:var(--ink);flex:1 1 16rem;min-width:0}

/* The four facets a watchlist is taken away for. One wrapping run rather than
   four fixed lines: at a hundred steps a line apiece is most of the page, and
   these are reference rather than the step's own claim — so they are set back
   and the labels do the separating. */
.syl-tags{display:flex;flex-wrap:wrap;gap:.1rem .9rem;margin-top:.4rem}
.syl-tag-group{display:inline}
.browse-page .syl-tag-label{font-family:var(--utility);font-size:.64rem;
  letter-spacing:.06em;text-transform:uppercase;color:rgba(59,42,23,.78);
  margin-right:.35rem}
.browse-page .syl-tag{font-family:var(--utility);font-size:.74rem;color:var(--ink)}

/* Taking it away. Its own line under the lede, because it is about the whole
   plan rather than about any step in it. */
.syl-get{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;margin:0 0 1rem}
/* #2F5436 and not --moss, which is a BORDER weight: §3.11l2 records it failing
   as type on parchment, and `.rail-locations` already carries this darker green
   for exactly that reason. Reusing that value rather than inventing a near-miss
   of it, which is how two spellings of one pigment start. */
.syl-dl{font-family:var(--utility);font-size:.78rem;cursor:pointer;
  background:var(--paper);color:#2F5436;border:2px solid var(--moss);
  padding:.35rem .8rem;box-shadow:2px 2px 0 rgba(59,42,23,.22)}
.syl-dl:hover{background:var(--moss);color:var(--paper)}
.syl-dl:active{transform:translate(2px,2px);box-shadow:none}
.syl-dl:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.browse-page .syl-said{font-family:var(--utility);font-size:.74rem;
  color:rgba(59,42,23,.78)}
.browse-page .syl-said:empty{display:none}

.browse-page .syl-more{font-family:var(--utility);font-size:.74rem;margin-top:.35rem}
.browse-page .syl-more a{color:#2F5436;text-decoration:none;
  border-bottom:1px solid rgba(62,107,69,.5)}
.browse-page .syl-more a:hover{color:var(--paper);background:var(--moss)}

/* What to read behind it. Its own classes sharing the reading list's LOOK and
   not its names: `.pd-book` and `.fg-book` are the period and filmography
   rows, and two lists reachable by one selector is how a check that means one
   starts counting both (§3.11i3, and §4 records `pa-row` re-laying a whole
   table because a name was already spoken for). */
.syl-books{margin-top:.5rem;border-left:2px solid var(--gold);padding-left:.7rem}
/* The `.78` ink every small label on this site settled on, NOT --gold-text:
   that variable measures exactly 4.50:1 on parchment, which clears AA with no
   margin at all and is uncomfortable at .7rem — the canon table hit the same
   wall and darkened its own marker to #6A4E0F (5.89:1) rather than use it at
   .62rem. Reusing the established ink beats adding a second spelling of that
   hex, and the gold accent is already carried by the border beside it; the
   words say what the list is either way (§7). Measured at 5.73:1. */
.browse-page .syl-books-head{display:block;font-family:var(--utility);font-size:.7rem;
  letter-spacing:.05em;text-transform:uppercase;color:rgba(59,42,23,.78)}
.syl-book-list{list-style:none;padding:0;margin:.2rem 0 0}
.browse-page .syl-book{font-size:.9rem;line-height:1.45;padding:0;border:none;display:block}
.browse-page .syl-bk-title{font-family:var(--body);font-style:italic}
.browse-page .syl-bk-who{font-family:var(--utility);font-size:.74rem;
  color:rgba(59,42,23,.78);margin-left:.4rem}

@media (max-width:520px){
  /* A narrower gutter rather than none: at this width 2.6rem is most of the
     room the title has to wrap in, and the marker still has to sit outside
     the plate for the numbering to read as a sequence. */
  .syl-list{padding-left:1.7rem}
}

/* Paper has no toggle, and a plan is exactly the thing somebody wants on it —
   so the switch goes and the items stay, each one whole. The rest of this
   page's print furniture (the sort bar, the advanced panel, the chips, the
   masthead and the foot nav) is already stripped by the main print block. */
@media print{
  /* Paper has no toggle and no file dialogue. */
  .browse-format,.syl-get{display:none}
  .syl-item{break-inside:avoid;page-break-inside:avoid}
  .syl-list li::marker{color:#000}
  .syl-books{border-left-color:#000}
  .browse-page .syl-books-head,.browse-page .syl-bk-who,
  .browse-page .syl-when,.browse-page .syl-facts,.browse-page .syl-lede,
  .browse-page .syl-tag-label,.browse-page .syl-tag{color:#000}
  .browse-page .syl-more a{color:#000;border-bottom-color:#000}
}

.related{margin-top:2rem;border-top:3px double var(--gold);padding-top:1rem}
.related h3{font-family:var(--utility);color:var(--lake);text-transform:none;letter-spacing:.06em;margin-bottom:.5rem}
.related ul{list-style:none;padding:0;margin:0}
.related li{display:flex;align-items:baseline;gap:.6rem;padding:.35rem 0;border-bottom:1px solid rgba(59,42,23,.18)}
.related li a{font-family:var(--body);font-weight:700;color:var(--oxblood);flex:1 1 auto}
.related .rel-sub{font-family:var(--utility);font-size:.72rem;opacity:.7}
.related .rel-more{margin-top:.6rem;font-family:var(--utility);font-size:.8rem}

/* Along the timeline, at the foot of a review. Two columns where both exist
   and one full-width where only one does — at the ends of the archive there
   is no opposite direction, and a half-width plate beside a gap reads as
   something that failed to load. `1fr` on an auto-fit track would stretch a
   lone card; `minmax` with only one child does the same thing on purpose. */
.timeline-nav{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,15rem),1fr));
  gap:.9rem;margin-top:2rem;border-top:3px double var(--gold);padding-top:1.2rem}
.tn-btn{display:flex;flex-direction:column;gap:.15rem;padding:.7rem .9rem;
  border:2px solid var(--ink);background:rgba(233,223,200,.5);color:inherit;text-decoration:none}
/* The later card sits right and reads right, so the pair mirrors the
   direction it is describing rather than only naming it. */
.tn-next{text-align:right}
.tn-btn:hover,.tn-btn:focus-visible{background:var(--paper);border-color:var(--oxblood)}
.tn-btn:focus-visible{outline:2px dashed var(--oxblood);outline-offset:3px}
.tn-dir{font-family:var(--utility);font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--oxblood)}
.tn-when{font-family:var(--utility);font-size:.72rem;opacity:.75}
.tn-title{font-family:var(--body);font-weight:700;line-height:1.3}
@media (max-width:520px){
  /* One column, so the mirrored alignment has nothing left to mirror. */
  .tn-next{text-align:left}
}

.notfound{text-align:center}
/* A floated drop cap and centred text cannot both be had: the initial goes to
   the left edge of the 720px column while the rest of the line stays in the
   middle, leaving the capital stranded halfway across the page. Raised rather
   than dropped here — the flourish survives, sitting on the line it belongs
   to. This is the only centred content page; everywhere else keeps the drop. */
.notfound .lede::first-letter{
  float:none;font-size:2.1em;line-height:1;margin:0;vertical-align:-.08em;
}
.notfound-art{display:flex;justify-content:center;margin:1rem 0}
.notfound-art svg{width:260px;height:auto}

/* ============================================================
   Accessibility pass + admin dashboard / card preview
   ============================================================ */
/* readable gold for TEXT on parchment (the leaf gold is decorative only) */
:root{ --gold-text:#7F5F14; }

.skip-link{position:absolute;left:-9999px;top:0;z-index:200;background:var(--oxblood);color:var(--paper);
  font-family:var(--utility);padding:.6rem 1rem;border:2px solid var(--gold);text-decoration:none}
.skip-link:focus{left:.5rem;top:.5rem}
main:focus{outline:none}

.timeline-wrap:focus-visible{outline:3px solid var(--gold);outline-offset:3px}

/* contrast: these were gold or low-opacity on parchment */
.br-rank{color:var(--gold-text)}
.mini-note{opacity:1;color:rgba(59,42,23,.78)}
.poster-meta .p-sub{color:rgba(59,42,23,.78)}
.sr-kind{opacity:.85}
.era-hint{opacity:.8}
.tick.has-films .mark::after{border-color:var(--ink)}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important;scroll-behavior:auto !important}
}

/* --- admin: needs-attention dashboard --- */
.attn-group{border:2px solid var(--ink);background:var(--paper);margin:.6rem 0;padding:.5rem .75rem}
.attn-group summary{font-family:var(--utility);cursor:pointer;color:var(--ink)}
.attn-count{display:inline-block;min-width:1.8rem;text-align:center;background:var(--oxblood);color:var(--paper);
  padding:.05rem .35rem;margin-right:.4rem;font-family:var(--utility)}
/* "12 of 110" — how much of the group is on screen against how much the
   backlog holds. The denominator is set back so the number an editor is about
   to work through reads first, but it stays inside the same plate: two plates
   would read as two counts of two different things. */
.attn-of{opacity:.7;font-size:.85em}
.attn-list{list-style:none;margin:.6rem 0 0;padding:0}
.attn-list li{display:flex;align-items:baseline;gap:.6rem;padding:.25rem 0;border-bottom:1px solid rgba(59,42,23,.16)}
.attn-list button{background:none;border:none;padding:0;cursor:pointer;text-align:left;
  font-family:var(--body);font-weight:700;color:var(--oxblood);text-decoration:underline}
.attn-kind{font-family:var(--utility);font-size:.7rem;opacity:.75;margin-left:auto}
/* The editor's own flag note. It sits after the title and before the kind,
   which keeps `margin-left:auto` on .attn-kind doing its job, and it clips
   rather than pushing the row wide — a grid does not clip what overflows it
   and neither does a flex item without this (§4, three times now). The whole
   note is on the cell's own title attribute. */
.attn-note{font-family:var(--body);font-style:italic;font-size:.82rem;color:var(--ink);
  opacity:.85;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* A row that reports something with nowhere to jump to. It reads as text rather
   than as the underlined button every other row carries, because a control that
   goes nowhere when pressed is worse than no control (§3.11f2). It still clips,
   for the reason .attn-note does — a flex item does not clip on its own. */
.attn-plain{font-family:var(--body);font-weight:700;color:var(--ink);
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The one row in this panel that carries its own fix. The gap is a single word
   wide, so the box goes where the noticing happens rather than costing a jump
   to another tab (§6f's argument for a control answering for itself). It sits
   before .attn-kind, which carries margin-left:auto and has to stay last. */
.attn-name{flex:0 1 12rem;min-width:6rem;font-family:var(--body);font-size:.85rem;
  padding:.2rem .4rem;border:1px solid var(--ink);background:var(--paper);
  color:var(--ink)}
.attn-name:focus-visible{outline:2px dashed var(--gold);outline-offset:1px}

/* --- admin: the three hand-raised flags ---
   ONE place the three colours are written down. The JS table carries the id
   and the label and no colour at all, so this is not a second copy of the
   palette — it is the only one, and a check asserts every id has a rule here.
   Each is the palette's own: oxblood, verdigris (--moss) and ultramarine
   (--lake), all three of which already carry text on parchment.
   Colour is never the only carrier: the group's name says the colour in
   words, the swatch is aria-hidden, and each row prints its reason. */
.af-oxblood{--af:var(--oxblood)}
.af-verdigris{--af:var(--moss)}
.af-blue{--af:var(--lake)}
.attn-manual-head{font-family:var(--utility);margin:1.4rem 0 .2rem;
  border-top:2px solid var(--ink);padding-top:.7rem}
.attn-group.attn-manual{border-color:var(--af);box-shadow:inset 4px 0 0 var(--af)}
.attn-group.attn-manual .attn-count{background:var(--af)}
/* FOR INFORMATION — drawn quieter than a task, because it is not one. The
   border is broken rather than tinted: a wash would read as a state somebody
   has to clear, where a dashed rule is the manuscript's own way of marking
   something provisional (§3.11i3's own reasoning, at the size of a panel).
   The count plate loses the oxblood for the same reason — that red is the
   colour of outstanding work everywhere else on this page, and a number
   wearing it is a number an editor tries to drive to nought.
   Measured composited on the admin's paper: the count plate 6.94:1, and the
   broken rule 3.5:1 against the ground — above the 3:1 a non-text component
   owes, and deliberately no more than that. */
.attn-info-head{border-top-style:dashed}
.attn-group.attn-info{border-style:dashed;border-color:rgba(36,28,18,.55)}
.attn-group.attn-info .attn-count{background:rgba(36,28,18,.78)}
.attn-swatch{display:inline-block;width:.7rem;height:.7rem;margin-right:.4rem;
  background:var(--af);border:1px solid var(--ink);vertical-align:baseline}
/* The flag control on the film and episode forms. */
.admin-flag-set{display:flex;flex-wrap:wrap;gap:.5rem 1rem}
.af-opt{display:inline-flex;align-items:center;gap:.35rem;font-family:var(--utility);
  font-size:.85rem;cursor:pointer}
.af-opt .af-swatch{display:inline-block;width:.85rem;height:.85rem;
  background:var(--af,transparent);border:1px solid var(--ink)}
/* Unflagged has no colour, so its swatch is hatched rather than filled — an
   empty square reads as "none" where a parchment-filled one reads as a fourth
   colour nobody can name. Its own class rather than a :not() over the others,
   so adding a colour cannot silently restyle it. */
.af-none .af-swatch{background:repeating-linear-gradient(
  45deg,transparent,transparent 3px,rgba(59,42,23,.35) 3px,rgba(59,42,23,.35) 4px)}
/* The pip on a bulk-edit row. */
.bl-flag{color:var(--af);font-size:.8rem}

/* The publication control on the film and episode forms. What it says about
   its own state, where the editor is looking (§6f) — the alpha is on the
   COLOUR rather than on `opacity`, which fades ink toward the paper at exactly
   the sizes least able to afford it (§4). Selected through .field so it beats
   `.content-page p` on specificity rather than on file order, this stylesheet's
   standing lesson. */
.field .ul-say{margin:.35rem 0 0;font-family:var(--utility);font-size:.82rem;
  color:rgba(59,42,23,.78)}
/* Held back: marked by a rule down the left as well as by the colour, because
   a colour is not a message. */
.field .ul-say.ul-on{color:var(--oxblood);border-left:3px solid var(--oxblood);
  padding-left:.5rem}
/* The bulk lock's own note, one field down (§6d3). The publication note's
   arrangement and deliberately the lake blue rather than the oxblood: taking an
   entry off the site is a decision readers feel and this one is not, so the two
   states of the same section must not shout equally loudly. */
.field .bl-say{margin:.35rem 0 0;font-family:var(--utility);font-size:.82rem;
  color:rgba(59,42,23,.78)}
.field .bl-say.bl-on{color:var(--lake);border-left:3px solid var(--lake);
  padding-left:.5rem}

/* --- admin: filmographies --- */
.fig-admin-list{max-height:26rem;overflow-y:auto;border:2px solid var(--ink);
  background:var(--paper);margin:.6rem 0}
.fig-admin-row{width:100%;text-align:left;background:none;border:none;
  border-bottom:1px solid rgba(59,42,23,.16);cursor:pointer;font:inherit}
.fig-admin-row:hover{background:rgba(216,192,120,.2)}
.fig-admin-row.on{background:rgba(216,192,120,.38);box-shadow:inset 4px 0 0 var(--oxblood)}
/* A missing summary is marked with a bullet AND spelled out in the row's own
   sub-line, so the flag is never carried by the mark alone. */
.fig-gap{color:var(--oxblood);font-size:1.2rem;line-height:1}
/* And the opposite claim, which is a different KIND of thing and so carries a
   different glyph as well as a different colour (§7): the bullet is a gap an
   editor owes the archive, this half-square is a diptych and says a comparison
   has been made. Verdigris, the site's own colour for the affirmative mark, and
   the sub-line spells it out in words either way. */
.fig-has{color:#2F5436;font-size:1rem;line-height:1;margin-right:.35rem}
/* What the rename says about its own press, scoped through .fig-rename for
   the reason .year-adder scopes the same class: a bare .mini-note is (0,1,0)
   and loses to .content-page p, so it wins on SPECIFICITY rather than on file
   order and moving the block cannot silently undo it (§4). .ya-say is
   borrowed rather than renamed because it is the same thing — a control
   answering for its own press where the editor is looking (§6f) — which is
   the call .ep-runtime-pull already made; a refusal is marked by the rule
   down its left as well as by the colour, since a colour is not a message. */
.fig-rename{margin:.2rem 0 .8rem}
.fig-rename .ya-say{margin:.5rem 0 0;font-family:var(--utility);font-size:.82rem;color:var(--ink)}
.fig-rename .ya-refused{color:var(--oxblood);border-left:3px solid var(--oxblood);padding-left:.5rem}
.check-line{display:block;margin:.15rem 0 .5rem}

/* --- admin: the traffic read-out ---
   One figure worth reading across the room, and ranked lists under it drawn
   with the site's own bar idiom. The number is never the only carrier: the
   label beside it says what it counts and the note under it says what it does
   NOT count, because "page loads" and "visitors" are different claims and only
   one of them is true here (§7, §3.7). */
.traffic-tile{border:2px solid var(--ink);background:rgba(216,192,120,.14);
  padding:.7rem .9rem;margin:.6rem 0}
.traffic-tile .tt-n{font-family:var(--display);font-size:2.2rem;line-height:1;
  color:var(--oxblood);margin-right:.5rem}
.traffic-tile .tt-label{font-family:var(--utility);font-size:.8rem;
  letter-spacing:.06em;text-transform:uppercase}
.traffic-tile .mini-note{margin:.35rem 0 0}
/* The bar is scaled to every row in its own block, never to the slice drawn
   (§3.7b) — and the count is printed beside it, so the drawing reinforces a
   figure the row already states rather than carrying it alone.

   THE BAR SITS IN A TRACK OF ITS OWN, and that is not decoration. It was a
   bare flex item at `width:N%` with `max-width:30%`, and a percentage on a
   flex item resolves against the LINE, not against the space the bar is
   allowed — so every row drew at its true share of the whole row and the
   longest one was then clipped by the max-width. Measured: 412 drew 265px and
   96 drew 204px, a four-fold difference rendered as a third. A bar chart
   drawing numbers that are not the numbers is §4's standing lesson about
   percentages inside flex, and no source check can see it.

   A track with a definite basis is what makes `width:N%` mean what it says. */
.traffic-list .tl-name{flex:0 1 auto;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;max-width:55%}
.traffic-list .tl-track{flex:0 0 30%;min-width:0;align-self:center;
  height:.55rem;background:rgba(59,42,23,.08)}
.traffic-list .tl-bar{display:block;height:100%;background:var(--lake);
  border:1px solid var(--ink);box-sizing:border-box}

/* --- admin: reader feedback queue --- */
.reader-inbox{margin-top:.6rem}
/* A flagged tally has crossed the threshold. It is also the only row with a
   count printed beside it and its group is open by default, so the colour is
   emphasis rather than the thing that tells you. */
.attn-hot{opacity:1;font-weight:700;color:var(--oxblood)}
.attn-reset{font-size:.68rem;padding:.15rem .5rem;margin:0 0 0 .6rem;flex:none}
.attn-list .attn-reset{text-decoration:none;font-family:var(--utility)}
.sg-queue{list-style:none;margin:.6rem 0 0;padding:0}
.sg-queue li{border:1px solid rgba(59,42,23,.3);background:rgba(59,42,23,.03);
  padding:.5rem .6rem;margin-bottom:.5rem}
.sgq-head{display:flex;align-items:baseline;gap:.6rem}
.sgq-entry{background:none;border:none;padding:0;cursor:pointer;text-align:left;
  font-family:var(--body);font-weight:700;color:var(--oxblood);text-decoration:underline}
.sgq-body{white-space:pre-wrap;margin:.4rem 0;font-size:.92rem}
.sgq-foot{display:flex;align-items:center;justify-content:space-between;gap:.6rem}

/* --- admin: live poster-card preview --- */
.card-preview{margin:1rem 0;padding:.75rem;border:2px dashed var(--ink);background:rgba(59,42,23,.04);
  display:inline-block}
.cp-label{font-family:var(--utility);font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--oxblood);margin-bottom:.5rem}
.cp-host .poster-card{pointer-events:none}

/* --- admin: autosave / draft state --- */
.undo-btn{font-family:var(--utility);font-size:.74rem;background:var(--paper);color:var(--ink);
  border:2px solid var(--ink);padding:.2rem .55rem;cursor:pointer}
.undo-btn:disabled{opacity:.4;cursor:default}
.draft-state{font-family:var(--utility);font-size:.74rem;color:rgba(59,42,23,.7)}
.draft-state.unsaved{color:var(--oxblood)}
.draft-banner{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap;
  background:var(--gold);color:var(--ink);border-bottom:3px solid var(--ink);
  padding:.7rem 1rem;font-family:var(--utility);font-size:.85rem}
.draft-banner .btn{margin:0}

/* ============================================================
   Historical figures: review section, filmography page, tag inputs
   ============================================================ */
.figures{margin-top:2rem;border-top:3px double var(--gold);padding-top:1rem}
.figures h3{font-family:var(--utility);color:var(--lake);text-transform:none;letter-spacing:.06em;margin-bottom:.6rem}
.figure-list{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:.45rem}
.figure-list li{margin:0}
.figure-list a{display:inline-block;font-family:var(--body);font-weight:700;color:var(--oxblood);
  background:rgba(216,192,120,.18);border:2px solid var(--gold);padding:.25rem .6rem;text-decoration:none}
.figure-list a:hover,.figure-list a:focus-visible{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.figure-pager{display:flex;align-items:center;gap:.8rem;margin-top:.8rem;font-family:var(--utility);font-size:.8rem}
.figure-pager button{font-family:var(--utility);font-size:.78rem;background:var(--paper);color:var(--oxblood);
  border:2px solid var(--gold);padding:.25rem .7rem;cursor:pointer}
.figure-pager button:disabled{opacity:.4;cursor:default}
.fig-count{color:rgba(59,42,23,.78)}

.figure-head{display:flex;gap:1.6rem;align-items:flex-start;flex-wrap:wrap;
  border-bottom:3px double var(--gold);padding-bottom:1.4rem;margin-bottom:1rem}
.figure-portrait{flex:0 0 150px;width:150px}
.figure-portrait svg{width:150px;height:auto;border:3px solid var(--ink);box-shadow:0 0 0 3px var(--gold),4px 4px 0 rgba(59,42,23,.3);display:block}
.figure-title{flex:1 1 320px;min-width:0}
.figure-title h2{font-family:var(--display);color:var(--oxblood);font-weight:400}
.ft-sub{font-family:var(--utility);color:rgba(59,42,23,.78);font-size:.85rem;margin-bottom:.8rem}
/* Who they were, in a sentence, and when they lived. */
.fig-dates{font-family:var(--utility);font-size:.72rem;letter-spacing:.04em;margin:0 0 .5rem;
  display:flex;gap:.5rem;align-items:baseline}
.fd-label{text-transform:uppercase;color:var(--lake);opacity:.8}
.fd-value{color:var(--ink)}
.fig-summary{font-family:var(--body);font-size:1rem;line-height:1.55;max-width:44rem;
  margin:0 0 .9rem;padding-left:.8rem;border-left:3px solid var(--gold)}

/* How much of a life the archive covers. The headline is the figure; the note
   under it carries the denominator and what was excluded, because a bare
   "12 years of a 63 year life" invites a reading the data can't support. */
.fig-life{border:2px solid var(--ink);background:rgba(216,192,120,.14);
  padding:.7rem .9rem;margin:0 0 1.2rem;max-width:44rem;
  box-shadow:3px 3px 0 rgba(59,42,23,.2)}
/* The headline and the share, opposite ends of one row. `gap` and `wrap` so a
   long headline at a phone width drops the share to its own line rather than
   squeezing the phrase it qualifies; `min-width:0` because a flex item's
   automatic minimum is its content's intrinsic width, which for a headline of
   this size is wider than a narrow column (§4, the fixed-track family). */
.fl-head{display:flex;flex-wrap:wrap;align-items:baseline;
  justify-content:space-between;gap:.4rem .9rem}
/* SELECTED THROUGH `.fig-life`, and that is not tidiness — it is the fix for a
   bug that was already here. `figure.html`'s main is a `.content-page`, whose
   `.content-page p,.content-page li{font-family:var(--body);font-size:1.12rem}`
   is (0,1,1) and beat a bare `.fl-big` at (0,1,0) outright: the headline of
   this box has been rendering at 17.92px in Cardo rather than at 1.45rem in
   the display face since the box was written. §4 records the identical failure
   for `.mini-note` on five pages and for `.proceed-btn` rendering oxblood on
   oxblood. Measured in a browser, before and after — not read off the
   declaration, which was right the whole time.

   Winning on SPECIFICITY rather than on file order is what stops moving either
   block silently undoing it again. */
.fig-life .fl-big{font-family:var(--display);font-size:1.45rem;line-height:1.2;
  color:var(--oxblood);margin:0;flex:1 1 auto;min-width:0}
/* The headline's own oxblood, at the headline's own size: it is the same
   claim said as a number, so a second colour would say it was a second kind
   of thing. Measured composited on parchment at 5.65:1. */
/* `margin-left:auto` as well as the row's space-between: at a phone width the
   headline wraps and the share drops to a line of its own, where space-between
   has nothing to space and would leave it at the LEFT margin — a stray "9.6%"
   under a sentence rather than the far end of the claim it qualifies.
   Measured at 375px. */
.fig-life .fl-share{font-family:var(--display);font-size:1.45rem;line-height:1.2;
  color:var(--oxblood);margin:0 0 0 auto;flex:0 0 auto;white-space:nowrap}
/* The same (0,1,1) it sits under, and the same measurement: this was rendering
   at 17.92px in the body face too, which is why the box read as three lines of
   prose rather than as a headline with a caption. `opacity` is left as it was
   — .78 on a .7rem string composites to 5.73:1 on parchment, which is the
   figure §4 settled on for `.mini-note` — but the SIZE has to win first. */
.fig-life .fl-note{font-family:var(--utility);font-size:.7rem;opacity:.78;
  margin:.4rem 0 0;line-height:1.5}

.fig-stats{display:flex;flex-wrap:wrap;gap:.8rem}
.fig-stat{border:2px solid var(--ink);background:rgba(216,192,120,.14);padding:.5rem .7rem;min-width:120px}
.fs-big{font-family:var(--display);font-size:1.7rem;color:var(--oxblood);line-height:1}
.fs-big small{font-size:.5em;opacity:.65}
.fs-label{font-family:var(--utility);font-size:.72rem;letter-spacing:.04em;margin-top:.15rem}
.fs-sub{font-family:var(--body);font-size:.78rem;opacity:.75;font-style:italic}

/* ---- three sections a credit table cannot state --------------------------
   figure.html is a `.content-page`, whose `.content-page p` and
   `.content-page li` are BOTH (0,1,1) and beat a bare class — the trap §3.9c
   records for `.proceed-btn` and §4 for `.mini-note`, which rendered at body
   size on five page types because the class was losing. Every rule here is
   selected through its section, so it wins on specificity rather than on file
   order and moving the block cannot undo it.

   The prefixes are `fse-`, `fx-` and `fc-`. NOT `fs-`, which is the stat
   cell's three rules above: §4 records a class reused for a second meaning
   inside one component going red the first time an entry carried one field
   without the other, and `pa-row` silently re-laying a whole <table>. */

/* FIRST AND LAST ON SCREEN. The strip above draws the axis a filmography is
   filed by; this is the other one, so it reads as a pair with an arrow between
   rather than as two statistics. */
.fig-screen{margin:0 0 1.2rem;max-width:44rem}
.fig-screen h2{font-family:var(--display);font-weight:400;font-size:1.15rem;
  color:var(--oxblood);margin:0 0 .5rem}
.fse-ends{display:flex;align-items:center;flex-wrap:wrap;gap:.5rem .9rem}
.fig-screen .fse-end{border:2px solid var(--ink);background:rgba(216,192,120,.14);
  padding:.45rem .7rem;min-width:0;flex:1 1 12rem;
  display:flex;flex-direction:column;gap:.1rem}
.fig-screen .fse-end-label{font-family:var(--utility);font-size:.62rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--lake)}
.fig-screen .fse-end-title{font-family:var(--body);font-weight:700;font-size:1rem;
  color:var(--oxblood);text-decoration:none;overflow-wrap:anywhere;
  border-bottom:1px solid rgba(216,192,120,.8)}
.fig-screen .fse-end-title:hover,.fig-screen .fse-end-title:focus-visible{
  border-color:var(--oxblood)}
.fig-screen .fse-end-year{font-family:var(--display);font-size:1.3rem;
  color:var(--ink);line-height:1}
/* Decoration: the direction is in the two labels and the distance is written
   out in the note beneath (§7). It collapses at the wrap, where "→" between
   two stacked boxes points at nothing. */
.fse-arrow{font-size:1.4rem;color:var(--gold);flex:0 0 auto}
@media (max-width:520px){ .fse-arrow{display:none} }

/* TREATED MOST AND LEAST FAITHFULLY. Two ends of one filmography, so the two
   plates are deliberately identical in weight — a bigger one would be reading
   a verdict into whichever end it was. */
.fig-extremes{margin:1.6rem 0}
.fig-extremes h2{font-family:var(--display);font-weight:400;font-size:1.15rem;
  color:var(--oxblood);margin:0 0 .5rem}
.fx-ends{display:flex;flex-wrap:wrap;gap:.7rem}
.fig-extremes .fx-end{flex:1 1 14rem;min-width:0;border:2px solid var(--ink);
  padding:.5rem .7rem;display:flex;flex-direction:column;gap:.15rem;
  background:rgba(216,192,120,.14)}
/* The tint reinforces the label and never replaces it: both plates name which
   end they are, in words, and the tier is spelled out under the emblem (§7). */
.fig-extremes .fx-end.is-low{border-left:5px solid var(--moss,#3f6b46)}
.fig-extremes .fx-end.is-high{border-left:5px solid var(--oxblood)}
.fig-extremes .fx-label{font-family:var(--utility);font-size:.62rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--lake)}
.fig-extremes .fx-title{font-family:var(--body);font-weight:700;font-size:1rem;
  color:var(--oxblood);text-decoration:none;overflow-wrap:anywhere;
  border-bottom:1px solid rgba(216,192,120,.8)}
.fig-extremes .fx-title:hover,.fig-extremes .fx-title:focus-visible{
  border-color:var(--oxblood)}
/* The emblem's own top margin is for a stacked card; here it is already in a
   column with its own gap. */
.fig-extremes .fx-salt .salt-compact{margin-top:0}
.fig-extremes .fx-tier{font-family:var(--utility);font-size:.68rem;opacity:.75}

.period-tags{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:.4rem}
.period-tags a{display:inline-block;font-family:var(--utility);font-size:.8rem;color:var(--ink);
  border:2px solid var(--ink);padding:.2rem .55rem;text-decoration:none;background:var(--paper)}
.period-tags a:hover{background:var(--ink);color:var(--paper)}
/* How many of the person's titles carry this tag. Shown only above one, so a
   rail of singletons stays quiet; the rail's own note explains the number. */
.tag-count{display:inline-block;margin-left:.4rem;padding:0 .3rem;font-size:.72em;
  background:var(--ink);color:var(--paper)}
.period-tags a:hover .tag-count{background:var(--paper);color:var(--ink)}

/* --- the appearance strip: when this person is depicted ---
   Era colours are the era bar's, so a reader who learnt them on the timeline
   needs no second lesson. The scale is linear across THIS person's span, not
   the archive's — on the archive's, every Napoleon mark would land inside two
   pixels. A wide span still bunches, which is the honest picture; the written
   year list below is the part that actually reads, and it is not optional. */
.fig-strip{margin:0 0 1.2rem}
.st-head{font-family:var(--utility);font-size:.72rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--lake);margin:0 0 .45rem}
.st-rail{position:relative;height:26px;border:2px solid var(--ink);background:var(--paper);
  box-shadow:3px 3px 0 rgba(59,42,23,.2);margin-bottom:.55rem}
.st-bands{position:absolute;inset:0;opacity:.3}
.st-band{position:absolute;top:0;bottom:0}
/* The bands span the whole rail; the marks sit in an inset track. The
   earliest year is always at 0% and the latest at 100%, so most strips put
   two marks hard against the ends — clearing half a mark was enough to stop
   them overhanging the border but left them touching it. This is a real
   margin, so a two-mark strip reads as marks on a rail rather than as two
   things wedged into its corners. */
.st-marks{position:absolute;top:0;bottom:0;left:14px;right:14px}
/* A tick, not a dot: a rule is read along its length, and a vertical stroke
   says "this year" far more precisely than a square centred on it. The <a>
   stays a comfortable target; the visible tick is drawn inside it. */
.st-mark{position:absolute;top:0;bottom:0;width:16px;margin-left:-8px;display:block}
.st-mark::before{content:"";position:absolute;left:50%;top:50%;
  width:3px;height:15px;margin:-7.5px 0 0 -1.5px;
  background:var(--era-c);box-shadow:0 0 0 1px rgba(36,28,18,.6)}
/* Growing to the rail's full height on hover keeps the cue in the same
   vocabulary as the tick itself. */
.st-mark:hover::before,.st-mark:focus-visible::before{height:100%;top:0;margin-top:0;
  box-shadow:0 0 0 1px var(--oxblood)}
.st-mark:focus-visible{outline:2px dashed var(--oxblood);outline-offset:1px}
.st-mark:hover,.st-mark:focus-visible{z-index:2}
.st-years{font-family:var(--utility);font-size:.78rem;margin:0;line-height:1.7}
.st-years a{color:var(--oxblood);text-decoration:none;border-bottom:1px solid rgba(158,43,37,.4)}
.st-years a:hover{background:var(--oxblood);color:var(--paper)}
.st-sep{opacity:.45;padding:0 .1rem}

/* --- appeared alongside --- */
.al-list{list-style:none;margin:0;padding:0}
.al-list li{display:grid;grid-template-columns:1fr auto;gap:0 .7rem;align-items:baseline;
  padding:.35rem 0;border-bottom:1px solid rgba(59,42,23,.16)}
.al-name{font-family:var(--body);font-weight:700;color:var(--oxblood)}
/* The percentage is emphasis, never the whole story — the detail line beneath
   spells out both denominators in words. */
.al-share{font-family:var(--display);font-size:1.25rem;color:var(--oxblood);
  line-height:1;justify-self:end}
.al-share small{font-size:.55em;opacity:.65}
.al-detail{grid-column:1 / -1;font-family:var(--utility);font-size:.7rem;opacity:.75}

/* --- admin tag input --- */
.tag-field{margin-top:.2rem}
.tag-entry{display:flex;gap:.4rem;align-items:center}
/* `min-width:0`, because a flex item's automatic minimum is its content's
   intrinsic width and an <input>'s is its default `size` — about 268px. So
   the box refused to shrink and the Add button beside it hung out of the
   field: 340px of row inside a 300px column at 375px wide. Pre-existing and
   13px at the old full-bleed width; the section padding made it visible.
   §4's fixed-track family, in its flexbox spelling.

   THE CHILD COMBINATOR IS LOAD-BEARING, and it was missing. A bare
   `.tag-entry input` also matches the CHECKBOX inside the inspiration
   label, which is a flex item of that label — so `min-width:0` against
   the default `flex-shrink:1` let it collapse to zero width in the narrow
   figures column and the control vanished, leaving a bare line of text
   that still toggled when clicked. The fix for the text box reaching its
   neighbour is §4's "fixed on one surface and not the neighbour" read
   backwards: not a fix left undone, but one applied where it was never
   wanted. The checkbox is pinned as well, so the day something nests a
   second input here it cannot happen again. */
.tag-entry > input{flex:1 1 auto;min-width:0}
.tag-inspired-toggle input{flex:0 0 auto;width:auto}
.tag-entry .btn{margin:0;flex:0 0 auto}
.tag-hint{font-family:var(--utility);font-size:.76rem;margin-top:.3rem;min-height:1.1em;color:rgba(59,42,23,.8)}
.tag-hint .th-warn{color:var(--oxblood)}
.tag-hint button{font-family:var(--utility);font-size:.76rem;background:none;border:none;padding:0 .15rem;
  cursor:pointer;text-decoration:underline;color:var(--oxblood)}
.tag-chips{list-style:none;padding:0;margin:.4rem 0 0;display:flex;flex-wrap:wrap;gap:.35rem}
.tag-chip{display:inline-flex;align-items:center;gap:.35rem;border:2px solid var(--ink);background:var(--paper);
  padding:.15rem .35rem .15rem .5rem;font-family:var(--body);font-size:.85rem}
.tag-chip.primary{border-color:var(--oxblood);background:rgba(158,43,37,.08)}
.tc-badge{font-family:var(--utility);font-size:.62rem;letter-spacing:.08em;text-transform:uppercase;
  background:var(--oxblood);color:var(--paper);padding:.05rem .3rem}
.tc-primary{font-family:var(--utility);font-size:.66rem;background:none;border:none;cursor:pointer;
  color:var(--lake);text-decoration:underline;padding:0}
.tc-remove{background:none;border:none;cursor:pointer;font-size:1rem;line-height:1;color:var(--oxblood);padding:0 .1rem}
.tag-empty{font-family:var(--utility);font-size:.76rem;opacity:.7}
@media (max-width:560px){ .figure-portrait{flex:0 0 110px;width:110px} .figure-portrait svg{width:110px} }

/* --- circa marker + temporal distance stats --- */
.badge.circa{top:auto;bottom:34px;left:8px;right:auto;background:var(--lake);color:var(--paper);border-color:var(--ink)}
/* ---------- a title the archive cannot place exactly (§3.11i3) -------------
   THE SAME CORNER AS `.badge.multi`, which it can never share: the validator
   refuses a span on a title carrying more than one set-in year, so the two are
   exclusive by construction rather than by luck. `circa` sits above both and
   CAN coincide — an uncertain date inside an unspecific decade is two separate
   admissions and each keeps its own chip. */
/* FILLED, not a pale chip. It sat on paper with a thin purple rule, which made
   it read as one more neutral label on a card that already carries several —
   the review star, the New mark and `multi`'s own "↺ 2 yrs" are all paper on
   ink, and a year-shaped label among them disappears into the run. Filled in
   the facet's purple it is unmistakably its own thing, the way `.badge.circa`
   is filled lake. The broken outline survives on the paper side, so the chip
   still says "provisional" as well as "genre-purple". */
.badge.span{top:auto;bottom:8px;left:8px;right:auto;
  background:var(--murex);color:var(--paper);
  border:1.5px dashed var(--paper);box-shadow:0 0 0 1.5px var(--ink)}
/* THE BROKEN RULE IS THE CARD'S OWN MARK, and it carries more weight now that
   the shelf is no longer split (§3.11i3). Three pixels rather than two, because
   at two it read as a focus ring at a glance; dashed and inset rather than
   tinted, since a wash over the poster would fight the artwork and read as a
   hover state, where a broken rule around it is the manuscript's own way of
   marking something provisional.

   Drawn on the POSTER rather than the whole card so the meta text under it
   stays plain ink — except the title, which takes the facet colour: a reader
   scanning a shelf reads titles, and that is where the difference is cheapest
   to notice. */
.span-card .poster{outline:3px dashed var(--murex);outline-offset:-3px}
.span-card .show-stack .mini.front{outline:3px dashed var(--murex);outline-offset:-3px}
.span-card .p-title{color:var(--murex-text)}
/* And a broken rule under the card, so the mark survives a poster the outline
   happens to sit badly on — a dark image, or one whose own border is busy. */
.span-card{padding-bottom:.45rem;border-bottom:2px dashed rgba(106,61,154,.5)}
/* The legend under the shelf. A swatch, the sentence, then the "?" — the
   swatch is aria-hidden because the words beside it say the same thing (§7). */
/* CENTRED. It is a legend for the shelf above it rather than a line of prose
   belonging to the left margin — the shelf itself centres, and a caption
   hanging off the left edge of a centred run of cards reads as something that
   failed to line up. */
.span-legend{display:flex;align-items:center;justify-content:center;
  flex-wrap:wrap;gap:.45rem;text-align:center;
  margin:1rem 0 .2rem;font-family:var(--utility);font-size:.78rem;
  letter-spacing:.04em;color:var(--murex-text)}
.span-legend .sl-swatch{flex:0 0 auto;width:1.5rem;height:1rem;
  border:2px dashed var(--murex);background:rgba(106,61,154,.08)}
.span-legend .sl-why{display:inline-flex;align-items:center}
/* The review page's plate, when the title will not name a year. `.span-note` is
   `.circa-note`'s neighbour and deliberately not its class: a check asserts the
   circa marker is absent where nothing is flagged, and sharing the name would
   make "carries a span" answer that question too (§4's class reused for a
   second meaning). */
.span-note{display:inline-block;margin-left:.5rem;font-family:var(--utility);font-size:.72rem;
  color:var(--murex-text);border:1.5px dashed var(--murex);padding:.05rem .4rem;vertical-align:middle}
/* Newly added. TOP-RIGHT: the top-left corner belongs to the lettered marks
   — compare’s A/B/C and a pulled thread’s badges, which are the same corner
   because the two modes are mutually exclusive and can never both be on. New
   is the only mark that can coincide with either, so it moves out of their
   way. The word does the work; the colour is emphasis. */
.badge.new{top:8px;right:8px;left:auto;bottom:auto;
  background:var(--moss);color:var(--paper);border-color:var(--ink)}
.show-stack .badge.new{top:6px;right:6px;left:auto;z-index:4}
.circa-note{display:inline-block;margin-left:.5rem;font-family:var(--utility);font-size:.72rem;
  color:var(--lake);border:1.5px dashed var(--lake);padding:.05rem .4rem;vertical-align:middle}
.distance-stats{display:flex;flex-wrap:wrap;gap:.8rem;margin:1rem 0 0}
.dist-stat{border:2px solid var(--ink);background:rgba(39,75,142,.08);padding:.5rem .8rem;min-width:150px;flex:1 1 auto;max-width:280px}
.ds-big{font-family:var(--display);font-size:1.5rem;color:var(--lake);line-height:1.05}
.ds-label{font-family:var(--utility);font-size:.74rem;letter-spacing:.03em;margin-top:.15rem}
.ds-sub{font-family:var(--body);font-size:.78rem;opacity:.75;font-style:italic;margin-top:.1rem}
.check-field{display:flex;align-items:center;gap:.45rem;flex-wrap:wrap;margin:.6rem 0;
  font-family:var(--utility);font-size:.85rem;cursor:pointer}
.check-field .cf-hint{flex:1 1 100%;font-size:.74rem;opacity:.75;margin-left:1.6rem}
/* admin: the span control on the film and episode forms.
   Set inside a tinted box with a purple rule down the left, so the two year
   pickers plainly belong to the checkbox above them rather than reading as two
   more fields in the run. `.span-say` is selected THROUGH .span-field so it
   wins on specificity rather than on file order — a bare .mini-note is (0,1,0)
   and loses, which is the trap §4 records for the year adder's own note. */
.span-field{margin:.4rem 0 .9rem;border-left:4px solid var(--murex);
  background:rgba(106,61,154,.06);padding:.5rem .8rem}
.span-field .check-field{margin:.1rem 0}
.span-field .span-body[hidden]{display:none}
.span-field .span-say{font-family:var(--body);font-size:.82rem;font-style:italic;
  color:var(--murex-text);opacity:1;margin-top:.3rem;min-height:1.2em}

/* ============================================================
   Statistics page
   ============================================================ */
.stats-page .glance{display:flex;flex-wrap:wrap;gap:.6rem;margin:1.2rem 0 1.6rem}
.glance-cell{flex:1 1 110px;border:2px solid var(--ink);background:rgba(216,192,120,.14);padding:.6rem .5rem;text-align:center}
.gc-big{font-family:var(--display);font-size:1.6rem;color:var(--oxblood);line-height:1}
.gc-label{font-family:var(--utility);font-size:.7rem;letter-spacing:.03em;margin-top:.2rem;opacity:.85}

/* ---- the page's own contents bar ----
   Fourteen sections over roughly 10,500px, and no way to move between them.
   It sticks under the top of the viewport so it is reachable from anywhere
   down the page, and scrolls sideways rather than wrapping to three rows —
   the same treatment the era bar gets on a phone, for the same reason. */
.stats-nav{
  position:sticky;top:0;z-index:5;
  margin:1rem 0 1.4rem;padding:.45rem 0;
  background:var(--paper);
  border-top:2px solid var(--ink);border-bottom:2px solid var(--ink);
}
.stats-nav ul{
  display:flex;gap:.3rem;list-style:none;margin:0;padding:0 .2rem;
  overflow-x:auto;scrollbar-width:thin;scrollbar-color:var(--gold) transparent;
  -webkit-overflow-scrolling:touch;
}
.stats-nav li{flex:0 0 auto}
.stats-nav a{
  display:block;text-decoration:none;white-space:nowrap;
  font-family:var(--utility);font-size:.68rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink);padding:.3rem .55rem;border:1.5px solid transparent;
}
.stats-nav a:hover,.stats-nav a:focus-visible{border-color:var(--gold);background:rgba(216,192,120,.18)}
/* The reader's place is marked by a filled chip AND kept as a real border, so
   it does not rest on colour alone (§7). */
.stats-nav a.on{background:var(--oxblood);color:var(--paper);border-color:var(--oxblood)}
/* Anchors must clear the sticky bar, or a jump lands with the heading behind
   it. The bar measures 52px, so this leaves about 20px of air — and it matches
   the top inset wireStatsNav gives the observer, so the section the bar marks
   is the section a jump actually lands on. */
.stat-block,.stats-page .glance{scroll-margin-top:4.5rem}
@media print{ .stats-nav{display:none} }

/* ---- …and the same contents as a right-hand sidebar, where there is room ----
   Fourteen items across the top of a wide screen is a strip of small caps the
   eye has to scan sideways, and it costs the page 52px of height at every
   scroll position. Down the right-hand margin the same list is a column: all
   fourteen visible at once, in reading order, in space the 720px measure was
   not using anyway.

   The layout is a grid and the NAV never moves in the source (§ the comment in
   stats-page.js). Below this width nothing here applies and the bar above is
   what renders — a 190px sidebar on a phone is not a smaller sidebar, it is a
   ruined column, and the horizontal strip is already tuned for that case.

   1024px is where the content column, the gap and the sidebar all fit without
   squeezing the measure: 720 + 40 + 190 plus the page's own padding. */
@media (min-width:1024px){
  .stats-page{max-width:1040px}
  /* The prose keeps its measure even though the page got wider. A 1,000px
     line of running text is not an improvement on a 720px one. */
  .stats-page > h1,.stats-page > .lede{max-width:44rem}

  .stats-layout{display:grid;grid-template-columns:minmax(0,1fr) 190px;gap:0 2.5rem}
  /* min-width:0 or a wide table or SVG inside a block pushes the grid column
     past its share and the sidebar off the page. A grid item's default
     min-width is auto, which is its content's intrinsic width. */
  .stats-body{grid-column:1;grid-row:1;min-width:0}

  .stats-nav{
    grid-column:2;grid-row:1;
    /* The nav STRETCHES to the row's full height — that is deliberate, and it
       is what gives the list something to be sticky inside. A sticky box can
       only travel within its containing block, so a nav shrunk to its own
       content would have nowhere to go and would scroll away with the page. */
    position:static;z-index:auto;
    margin:0;padding:0;background:none;border-top:none;border-bottom:none;
  }
  .stats-nav ul{
    position:sticky;top:1.2rem;
    display:block;padding:.1rem 0 .1rem .9rem;
    border-left:2px solid var(--ink);
    /* Fourteen items clear a normal viewport, but not a short laptop one, and
       a list that simply overflows loses its last entries with nothing saying
       so. It scrolls, and wireStatsNav keeps the marked link inside it. */
    max-height:calc(100vh - 2.4rem);
    overflow-x:visible;overflow-y:auto;
  }
  .stats-nav li{flex:none}
  .stats-nav a{
    /* Wrapping, not nowrap: "Cite & data" over two lines is fine in a column
       and a clipped label is not. */
    white-space:normal;padding:.32rem .5rem;line-height:1.35;
  }
  /* No bar overhead in this layout, so a jump wants a little air rather than a
     bar's worth of it. Still clear of the observer's -72px trigger line, so
     the section a jump lands on is the section the nav then marks. */
  .stat-block,.stats-page .glance{scroll-margin-top:1.5rem}
}

.stat-block{margin:2rem 0;border-top:3px double var(--gold);padding-top:1rem}
.stat-head{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;flex-wrap:wrap}
.stat-head h2{font-family:var(--display);font-weight:400;color:var(--oxblood);font-size:1.35rem}
.stat-sort{display:flex;gap:.3rem;flex-wrap:wrap}
.stat-sort button{font-family:var(--utility);font-size:.72rem;background:var(--paper);color:var(--oxblood);
  border:2px solid var(--gold);padding:.2rem .55rem;cursor:pointer}
.stat-sort button.on{background:var(--oxblood);color:var(--paper)}
/* Which way the chosen measure runs. The arrow is aria-hidden and the button's
   accessible name says it in words instead — an arrow is not a direction to a
   screen reader, and the fill alone says which button is chosen, never which
   way it points. */
.ss-dir{font-weight:700;letter-spacing:0}

/* --- screen time by era ---
   A coverage read-out rather than a ranked table, so it is bars in timeline
   order rather than rows with a rank in the margin. A GRID, and every cell
   clips: §4 records a fixed track painting over its neighbour three separate
   times, and `min-width:0` is the half that is easy to miss — a grid item's
   default width is its content's intrinsic width, so `minmax(0,…)` on the track
   is not enough on its own. */
.screen-bars{margin:.7rem 0 .3rem}
.sb-row{display:grid;
  grid-template-columns:minmax(0,9rem) minmax(0,1fr) minmax(0,4.2rem) minmax(0,7rem) minmax(0,3.6rem);
  gap:.6rem;align-items:center;padding:.3rem .2rem;
  border-bottom:1px solid rgba(59,42,23,.14)}
.sb-row>*{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sb-era{font-family:var(--body);font-weight:700;font-size:.9rem}
.sb-bar{position:relative;height:.85rem;background:var(--paper-deep);
  border:1px solid rgba(59,42,23,.25);overflow:hidden}
.sb-fill{position:absolute;left:0;top:0;bottom:0}
.sb-time{font-family:var(--utility);font-size:.85rem;text-align:right;
  font-variant-numeric:tabular-nums}
.sb-n,.sb-avg{font-family:var(--utility);font-size:.7rem;color:rgba(59,42,23,.78);
  font-variant-numeric:tabular-nums}
.sb-avg{text-align:right}
@media (max-width:640px){
  /* The bar and the two set-back figures drop under the era and its total: at
     this width five tracks is not a row, it is a squeeze. */
  .sb-row{grid-template-columns:minmax(0,1fr) minmax(0,4.2rem);gap:.25rem .6rem}
  .sb-bar{grid-column:1 / -1;order:3}
  .sb-n{order:4}
  .sb-avg{order:5;text-align:left}
}

.rank-table{margin-top:.7rem}
/* The paged ranked tables — languages and genres, the two that grow with every
   TMDB pull rather than with anybody's writing. The count line sits between the
   rows and the pager because it describes the slice the pager just turned to,
   and it is `role="status"` so a page turn is announced rather than only seen. */
.stats-page .rank-count{margin:.5rem 0 .2rem;text-align:right}
.rank-table+.rank-count+.list-pager{margin:.1rem 0 .3rem}
/* A GRID, NOT A FLEX ROW, and that is what makes the bars line up. Every cell
   here was a flex item and the last one — the saltiness emblem — was
   `flex:0 0 auto`, so its width was whatever its own text happened to be:
   "Salt Carthage · 5/5" against "Unsalted" is about sixty pixels of
   difference. The two growing items beside it (`flex:1 1 30%` on the label and
   on the bar) then split whatever was left, which differed per row — so every
   bar began and ended at a different x down the table, and the comparison the
   bars exist to make could not be read off them.

   It was invisible while the archive was fully salted, because every row then
   printed the same shape of emblem; unsalting it made the widths diverge and
   the misalignment came with them. The markup was right throughout and only
   the geometry was wrong, which is the one thing no source check sees (§4).

   Fixed tracks for the three cells whose content varies and can afford to be
   clipped, `1fr` shares for the label and the bar. `minmax(0,…)` on both of
   those because a grid item's automatic minimum is its content's intrinsic
   width, which for a long language name is wider than the track (§4, the
   fixed-track family). Its two neighbours on this page — `.credit-row` and
   `.sb-row` — are already grids, and for this exact reason. */
.rank-row{display:grid;
  grid-template-columns:1.8rem minmax(0,1fr) minmax(70px,1fr) 3.4rem minmax(0,7.6rem);
  align-items:center;column-gap:.6rem;padding:.35rem 0;
  border-bottom:1px solid rgba(59,42,23,.18)}
.rr-rank{font-family:var(--display);color:var(--gold-text);text-align:right}
.rr-label{font-family:var(--body);font-weight:700;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rr-label a{color:var(--ink);text-decoration:none;border-bottom:1px dotted var(--gold)}
.rr-label a:hover{color:var(--oxblood)}
.rr-bar{position:relative;height:1.15rem;background:rgba(59,42,23,.1);min-width:0}
.rr-fill{position:absolute;inset:0 auto 0 0;opacity:.85}
.rr-count{position:absolute;right:.35rem;top:50%;transform:translateY(-50%);font-family:var(--utility);font-size:.7rem;color:var(--ink)}
.rr-num{font-family:var(--utility);font-size:.9rem;text-align:right;white-space:nowrap}
.rr-num small{opacity:.55;font-size:.7em}
/* The emblem clips rather than sizing its own column: a rare long tier name
   must not move every bar in the table (§3.2a measured the same trade one row
   over, where a wrapped cell grew its row past every neighbour). The whole
   tier is in the emblem's own accessible name either way. */
.rr-salt{min-width:0;overflow:hidden}
.rr-salt .salt-compact{margin-top:0;flex-wrap:nowrap}
.rr-salt .s-num{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.heatmap{margin-top:.8rem}
.heat-era{margin-bottom:1.1rem}
.heat-era-head{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;margin-bottom:.35rem}
.he-dot{width:.7rem;height:.7rem;border:2px solid var(--ink);display:inline-block;flex:0 0 auto}
.he-name{font-family:var(--utility);font-size:.9rem}
.he-total{font-family:var(--utility);font-size:.72rem;opacity:.75;margin-left:auto}
.heat-grid{display:flex;flex-wrap:wrap;gap:3px}
.heat-cell{position:relative;width:52px;height:44px;display:flex;flex-direction:column;align-items:center;
  justify-content:center;border:2px solid var(--ink);text-decoration:none;color:var(--ink);
  background-color:color-mix(in srgb, var(--heat) calc(var(--op) * 100%), var(--paper));
  background-image:none}
.heat-cell.empty{border-style:dashed;border-color:rgba(59,42,23,.35);background:var(--paper)}
.heat-cell:hover,.heat-cell:focus-visible{outline:3px solid var(--gold);outline-offset:1px}
.hc-year{font-family:var(--utility);font-size:.62rem;line-height:1}
.hc-n{font-family:var(--display);font-size:1rem;line-height:1.1}
.heat-cell.empty .hc-year{opacity:.5}

.stat-champion{margin:.8rem 0;border:2px solid var(--oxblood);background:rgba(158,43,37,.07);padding:.8rem 1rem}
.sc-big{font-family:var(--display);font-size:1.8rem;color:var(--oxblood);line-height:1.05}
.sc-sub{font-family:var(--body);font-size:.88rem;opacity:.85;margin-top:.2rem}
.top-list{margin:.6rem 0 0;padding-left:1.4rem}
.top-list li{display:flex;align-items:baseline;gap:.9rem;padding:.35rem 0;
  border-bottom:1px solid rgba(59,42,23,.15);font-family:var(--body)}
.top-list li a{color:var(--oxblood)}
/* The count sits in its own column. It used to float, which collided with the
   row below as soon as an entry grew a second line of grouped place names. */
.tl-n{font-family:var(--utility);font-size:.8rem;opacity:.8;
  flex:0 0 auto;align-self:flex-start;padding-top:.1rem;white-space:nowrap}
.tl-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:.1rem}
@media (max-width:560px){
  .rank-row{grid-template-columns:1.6rem minmax(0,1.4fr) minmax(60px,1fr) 3.2rem minmax(0,5.6rem)}
  .heat-cell{width:44px;height:40px}
}

/* ============================================================
   Print — review pages and filmographies
   Parchment gradients, drolleries and navigation are ink-wasting
   noise on paper. Strip the furniture, keep the substance, and
   spell out where links point since they can't be clicked.
   ============================================================ */
@media print {
  :root{
    --paper:#fff; --paper-deep:#fff; --ink:#000;
    --oxblood:#6b1a16; --lake:#1d3865; --gold:#6b5214; --gold-bright:#6b5214;
    --gold-text:#6b5214; --salt-ink:#6b1a16;
  }
  *{ -webkit-print-color-adjust:exact; print-color-adjust:exact; box-shadow:none !important }
  body{ background:#fff !important; color:#000; font-size:11pt }

  /* furniture that means nothing on paper */
  .sprockets, .admin-link, .cookie-banner, .skip-link, .toast, .pp-bookmark,
  .back-btn, .figure-pager, .browse-tabs, .stat-sort, .finder,
  /* Paper has no clipboard, and a contents of anchors leads nowhere on it. */
  .copy-link, .copy-said, .post-toc,
  /* Paper has no disclosure either. The inline panels stay shut — the numbers
     in the prose and the Sources list at the foot are exactly the footnote
     apparatus print already has a convention for, and printing both would say
     everything twice. */
  .ref-panel,
  /* Nor does paper have a tooltip, a filter or a jump rail. */
  .gn-ask, .gn-panel, .sn-ask, .sn-panel,
  .gl-ask, .gl-tip-panel, .gl-filter, .gl-jump,
  .era-bar, .era-hint, .filter-row, .timeline-wrap, .controls,
  .foot-nav, footer.site-foot::before, .review-overlay,
  .empty-drollery, .notfound-art { display:none !important }

  header.masthead{ border-bottom:1pt solid #000; padding:0 0 .4rem; margin-bottom:.8rem;
    background:none !important }
  .masthead .tagline{ font-size:8pt; letter-spacing:.1em }
  .masthead-logo img, .masthead-logo svg{ width:180px !important; max-width:40% }

  main{ max-width:none; padding:0 }
  a{ color:#000; text-decoration:none }

  /* review page */
  .review-head{ page-break-inside:avoid; border-bottom:1pt solid #000 }
  .review-head .poster{ flex:0 0 110px; width:110px; height:160px }
  .review-title h2{ font-size:20pt }
  .review-body{ font-size:11pt; line-height:1.45 }
  .review-sources{ page-break-inside:avoid; font-size:9pt }
  .src-back{ display:none }
  .review-body .verdict{ page-break-inside:avoid; background:none; border-left:2pt solid #000 }
  .salt-note{ page-break-inside:avoid; background:none; border-left:2pt solid var(--oxblood) }
  .distance-stats, .fig-stats{ page-break-inside:avoid }
  .dist-stat, .fig-stat, .glance-cell{ border:.75pt solid #000; background:none !important }

  /* figures + related: print every entry, not just the first page */
  .figures, .related{ page-break-inside:avoid; border-top:1pt solid #000 }
  .figure-list a{ background:none; border:.75pt solid #000; color:#000 }
  .figure-list.print-all li{ display:inline-block }

  /* filmography page */
  .figure-head{ page-break-inside:avoid; border-bottom:1pt solid #000 }
  .figure-portrait{ flex:0 0 110px; width:110px }
  .figure-portrait svg{ width:110px }
  .browse-list{ border-top:.75pt solid #000 }
  .browse-row{ page-break-inside:avoid; border-bottom:.5pt solid #999; padding:.25rem 0 }
  .br-rating, .br-salt{ color:#000 }
  /* The spread survives printing because it is a fact about the list beneath
     it; the buttons that offer a way out of an empty one do not, since there
     is nothing to press on paper. */
  .browse-dist{ page-break-inside:avoid; border:.75pt solid #000; box-shadow:none }
  .bd-bar{ background:#000 !important; border-color:#000 }
  .bd-n, .bd-summary{ color:#000 }
  /* Printed open whatever the reader left it as: paper has no disclosure. */
  .bd-body{ display:block !important }
  .bd-switch{ display:none }
  .be-fixes{ display:none }
  .br-depth.is-full{ color:#000; background:none; border-color:#000 }
  .br-depth.is-partial{ color:#000 }
  /* A ribbon is pure colour, so on a monochrome print it says nothing the row
     does not already say in words — the years are printed beside it (§7). */
  .era-ribbons{ display:none }
  .period-tags a{ border:.75pt solid #000 }

  /* show where links actually go */
  .review-body a[href^="http"]::after,
  .related a::after, .figure-list a::after, .period-tags a::after{
    content:" (" attr(href) ")"; font-size:8pt; color:#444; word-break:break-all;
  }
  .related a[href^="review.html"]::after, .figure-list a[href^="figure.html"]::after,
  .period-tags a::after{ content:"" }

  footer.site-foot{ padding-top:.6rem !important; padding-bottom:.6rem !important;
    border-top:1pt solid #000; background:none !important;
    font-size:8pt; page-break-inside:avoid }
  /* The drollery, the finis and the trellis panel are ornament: ink on paper
     needs none of them, and a tiled gold rule prints as a grey smear. */
  footer.site-foot::before, footer.site-foot::after{ content:none !important }
}

/* ============================================================
   Era tools: Compare bands + Pull Threads tab markers
   ============================================================ */
.era-tools{display:flex;justify-content:space-between;gap:1rem;max-width:1180px;margin:.6rem auto 0;padding:0 1rem}
.tool-btn{font-family:var(--utility);font-size:.85rem;background:var(--paper);color:var(--oxblood);
  border:2px solid var(--gold);padding:.35rem .9rem;cursor:pointer;box-shadow:2px 2px 0 rgba(59,42,23,.25)}
.tool-btn:hover{background:var(--paper-deep)}
.tool-btn.on{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}

.compare-panel{display:flex;justify-content:center;align-items:center;gap:1.2rem;flex-wrap:wrap;
  max-width:1180px;margin:.7rem auto 0;padding:.7rem 1rem;border:2px dashed var(--ink);background:rgba(59,42,23,.04)}
.compare-panel label{font-family:var(--utility);font-size:.82rem;display:flex;align-items:center;gap:.4rem}
.compare-panel select{font-family:var(--utility);background:var(--paper);color:var(--ink);border:2px solid var(--ink);padding:.25rem .4rem;max-width:260px}

/* Comparison overlay: one absolutely-positioned layer covering the tick row,
   so bands and labels share a coordinate space. Labels sit clear of the year
   text — A above, B below — styled as illuminated ribbon banners. */
.timeline{position:relative}
.timeline.comparing{padding-top:30px;padding-bottom:30px}
.cmp-layer{position:absolute;pointer-events:none;z-index:1}

/* ---- three periods, three lanes, and nothing overlapping -----------------
   THE BANDS WERE TALL BOXES AND HAD ALREADY COLLAPSED TO HAIRLINES, which is
   most of what the confusion was. `drawBands` measured the timeline BEFORE
   adding `.comparing`, so the overlay was sized to the UNPADDED tick row —
   53.2px, measured — while every band asked for `top:57px; bottom:30px` inside
   it. That is a content box of minus thirty-four pixels, clamped to its own
   3px top border: three stray rules floating above the year numbers with no
   box, no sides and no relationship to the ticks. Staggering their tops five
   pixels apart, which is what the pass before this one did, made three
   hairlines where there had been one.

   SO THEY ARE LANES NOW, DELIBERATELY: one horizontal rule per slot with a
   serif at each end, stacked, never overlapping. Overlap was the whole
   difficulty — three boxes covering nearly the same years cannot show three
   pairs of boundaries on one line, however they are staggered — and a lane per
   period removes it rather than decorating around it. A rule with end serifs
   is how an extent is drawn on a plan, and it is close to what the collapsed
   bands accidentally already looked like.

   ONE LANE PER SLOT, not one per period actually drawn: choosing C must not
   move A's rule. That costs ten pixels of rail when fewer than three are
   compared and buys a vertical position that always means the same slot —
   which is what lets the stripes on the ticks below use the same three lanes
   in the same order.

   EACH RULE IS ITS OWN PATTERN: solid, dashed, dotted. The colour carries the
   pairing with the banner and the tick stripes, and the pattern carries it
   again for a reader who cannot tell the three apart — the same reason the
   banner has a letter on it (§3.10e, §7). THE SERIFS STAY SOLID whatever the
   rule's pattern, because a boundary drawn in dots is a boundary a reader has
   to guess at. And there is no background: the tint belongs on the ticks,
   where it says which YEARS are in the period rather than only how far it
   reaches. Positions come from `placeLabels`, which is the one place that
   knows how deep the banner rail ended up. */
.cmp-band{position:absolute;height:0;border-top:3px solid currentColor}
.cmp-band::before,.cmp-band::after{content:"";position:absolute;top:-3px;
  width:3px;height:8px;background:currentColor}
.cmp-band::before{left:0}
.cmp-band::after{right:0}
.cmp-a{color:var(--lake)}
.cmp-b{color:var(--moss);border-top-style:dashed}
.cmp-c{color:var(--oxblood);border-top-style:dotted}

/* ---- and the tick row holds still while something is pinned to it --------
   THE ROW'S HEIGHT WAS NOT A STABLE MEASUREMENT, which is the other half of
   the report — opening a year left every banner and rule sitting clear of the
   years they describe. `.timeline` is `align-items:flex-end`, so the row is as
   tall as its tallest tick and every tick hangs from the bottom; the mark then
   grows from 22px to 38px on hover and to 44px when a year is open, with the
   bottom border going 4px to 7px alongside it. Measured at 1280px: hovering a
   tick pushes the whole row down 16px and opening a year pushes it down 24.
   The overlay is anchored to the rail, which does not move.

   REDRAWING THE OVERLAY ON SELECTION WOULD FIX THE REPORT AND NOT THE FAULT:
   the row moves on HOVER too, so the rules would have to chase the pointer. So
   the row stops moving instead, and only while something is drawn against it —
   `.comparing` is already on the element for exactly the span of time this has
   to hold. Selection and focus still read through the mark's WIDTH, the filled
   label pill and the thicker rule under the tick, which are three of the four
   carriers they always had; the fourth is suspended while an overlay depends
   on the row, and nothing outside comparison changes at all.

   It is also what lets `placeLabels` position everything from `pad` alone:
   with the row frozen, the tick's own top edge is exactly `padding-top` below
   the timeline's. Measured at 57px against a 57px pad.

   AND THE TICK RESERVES A STRIP FOR ITS STRIPES, which is the one thing the
   first pass at this got wrong by looking right in the numbers. The stripes are
   drawn at the top of the tick's own box and the year's text began at that very
   pixel, so three lanes of colour landed BEHIND the top half of every year
   number and the row read as a run of labels sitting on a coloured bar — which
   is the slab this change set out to remove, moved twelve pixels. The strip is
   `--cmp-stripe` deep per slot and the padding is the same number times the
   same three lanes, so the stripes cannot grow into the text. */
.timeline.comparing{--cmp-stripe:4px}
.timeline.comparing .tick{padding-top:calc(var(--cmp-stripe) * 3);border-bottom-width:7px}
.timeline.comparing .tick:hover .mark,
.timeline.comparing .tick:focus-visible .mark,
.timeline.comparing .tick.active .mark{height:22px}

/* the banner itself: parchment ribbon with a rubricated slot letter */
.cmp-label{position:absolute;display:inline-flex;align-items:baseline;gap:.4rem;height:24px;box-sizing:border-box;
  font-family:var(--utility);font-size:.7rem;line-height:1.2;white-space:nowrap;
  padding:.18rem .5rem;background:var(--paper);border:2px solid currentColor;
  box-shadow:2px 2px 0 rgba(59,42,23,.25);pointer-events:none;max-width:none}
/* `top` and the stem's height are set by placeLabels, which packs the banners
   into as many rows as their widths actually need. Three fixed rails could
   not separate three periods covering the same years — see timeline-ui.js. */
.cmp-label-a{color:var(--lake)}
.cmp-label-c{color:var(--oxblood)}
.cmp-label-b{color:var(--moss)}
.timeline.comparing{padding-top:56px}
/* a stem joining each banner down to the band it labels */
.cmp-label::after{content:"";position:absolute;left:var(--tick-x,50%);width:2px;
  top:100%;height:var(--cmp-stem,3px);background:currentColor;opacity:.8}
.cmp-label .cb-tag{font-family:var(--display);font-size:1.05em;font-weight:400;
  color:var(--paper);background:currentColor;padding:0 .3rem;border-radius:2px}
.cmp-label-a .cb-tag{background:var(--lake)}
.cmp-label-b .cb-tag{background:var(--moss)}
.cmp-label-c .cb-tag{background:var(--oxblood)}
.cmp-label .cb-name{font-weight:700;color:var(--ink);letter-spacing:.01em}
.cmp-label .cb-range{color:var(--ink);opacity:.7;font-size:.92em}

/* ---- a tick inside more than one compared period ------------------------
   THE TINTS COMPOSE NOW RATHER THAN OVERRIDING EACH OTHER, and that was the
   whole bug. Three rules each set the `background` SHORTHAND at one
   specificity, so a year inside two periods drew whichever rule came last in
   the file and the other period's tint was simply gone — `.tick.in-cmp-c` sat
   above the other two, so red lost to both of them. Only ONE pair had an
   overlap rule at all (a+b, split top and bottom), which is exactly why the
   first two colours looked as though they worked and the third never did.

   Seven rules would cover three slots and fifteen would cover four, which is
   §4's hand-listing trap in a stylesheet. So each slot lights ITS OWN THIRD of
   the tick through a custom property, and one rule draws all three layers:
   an unset slot resolves to `transparent` and paints nothing. A year in one
   period gets one stripe, in all three gets three, and a fourth slot would be
   one property and one more layer rather than eight new combinations.

   THEY SIT IN A STRIP OF THEIR OWN AT THE TOP OF THE TICK, in the lanes the
   rules above them use and in the same order. They were thirds of the tick's
   WHOLE height, which put a wash of colour behind the year number — a year
   inside all three periods was tinted from its label to its mark — so the row
   read as a coloured slab and the rules above it read as unrelated to it. One
   `--cmp-stripe` a lane, in the padding the comparing tick reserves for them
   and directly under the lowest serif, says which of the three lanes this year
   belongs to and leaves the year legible. The depth and the reservation are the
   same number: see `.timeline.comparing .tick` above.

   THE COLOURS ARE THE PALETTE'S OWN, not three rgba triples spelling it again:
   a stripe is the same colour as its rule, which is the strongest pairing
   available and one fewer transcription of `--lake` to fall out of step (§4).
   The stripes are the reinforcement rather than the carrier either way — the
   rules above them draw each period's own boundaries, and the banner names it
   with a letter (§7). */
.tick.in-cmp-a{--cmp-t-a:var(--lake)}
.tick.in-cmp-b{--cmp-t-b:var(--moss)}
.tick.in-cmp-c{--cmp-t-c:var(--oxblood)}
.tick.in-cmp-a,.tick.in-cmp-b,.tick.in-cmp-c{
  background-image:
    linear-gradient(var(--cmp-t-a,transparent),var(--cmp-t-a,transparent)),
    linear-gradient(var(--cmp-t-b,transparent),var(--cmp-t-b,transparent)),
    linear-gradient(var(--cmp-t-c,transparent),var(--cmp-t-c,transparent));
  background-repeat:no-repeat;
  background-size:100% var(--cmp-stripe,4px);
  background-position:0 0,0 var(--cmp-stripe,4px),0 calc(var(--cmp-stripe,4px) * 2)}

/* thread tabs, drawn like the leather tab markers sewn into a manuscript */
/* ============================================================
   Historiography — the archive as it stood in a given year

   Drawn as a CANON TABLE. The Eusebian tables at the front of a gospel book
   are the manuscript tradition's answer to exactly this problem: several
   parallel columns of small repetitive data, which is unreadable as a slab and
   perfectly legible under an arcade. Three arched bays — who directed, who
   broadcast, in what language — over a ruled measure with the year on it.

   The restraint is deliberate. No interlace, no drawn capitals, no gold leaf
   beyond the rules: the devices borrowed are the ones that do WORK — an arch
   to separate columns, a rubric to head one, alternating ruled rows to hold a
   reader's eye across a line, and numerals in the margin. Everything else
   would be costume.
   ============================================================ */
.hist-panel{max-width:1180px;margin:.7rem auto 0;padding:.75rem .9rem .85rem;
  border:2px solid var(--ink);background:var(--paper);
  /* Two rules rather than one: an ink frame with a gold fillet inside it, which
     is how a page of this kind is ruled. Drawn with an inset shadow so it costs
     no extra element and no layout. */
  box-shadow:inset 0 0 0 2px var(--paper), inset 0 0 0 3px rgba(185,138,47,.55),
             3px 3px 0 rgba(59,42,23,.22)}

/* ---- the head: the year, and what the control is doing ---- */
.hist-head{display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:.2rem .95rem;align-items:start}
/* The rubricated numeral, in a ruled plate. A manuscript puts the number that
   governs a column in a box of its own at its head, and this is the number
   governing everything below it. */
.hist-year{grid-column:1;display:flex;flex-direction:column;align-items:center;
  border:2px solid var(--ink);background:var(--paper-deep);
  padding:.25rem .7rem .3rem;box-shadow:2px 2px 0 rgba(59,42,23,.2);cursor:pointer}
.hy-label{font-family:var(--utility);font-size:.56rem;letter-spacing:.18em;
  text-transform:uppercase;color:rgba(59,42,23,.8)}
.hy-value{font-family:var(--display);font-size:2rem;line-height:1.05;
  color:var(--oxblood);font-variant-numeric:tabular-nums}
/* THE EXPLANATION, at reading size and at the site's own measure. A reader who
   drags this without being told reads the result as the archive rather than as
   a slice of it, which is the failure §3.7 exists to refuse. */
.hist-lede{grid-column:2;font-family:var(--body);font-size:.92rem;line-height:1.5;
  max-width:44rem;margin:0}

/* ---- the ruled measure ---- */
.hist-slider{display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:.5rem .9rem;align-items:center;margin-top:.55rem}
.hist-rule{position:relative;min-width:0}
/* The notches, drawn rather than left to the browser: styling the track
   suppresses its own rendering of the datalist, and the notches are the half of
   this control that says it is a ruler. Behind the input, so the marker rides
   over them. */
.hist-notches{position:absolute;left:0;right:0;top:.52rem;height:1.05rem;
  pointer-events:none}
.hist-notches span{position:absolute;top:0;width:1px;height:100%;
  background:rgba(59,42,23,.38);transform:translateX(-.5px)}
.hist-range{-webkit-appearance:none;appearance:none;width:100%;
  background:transparent;margin:0;height:2.1rem;display:block;cursor:pointer}
.hist-range:focus{outline:none}
.hist-range:focus-visible{outline:2px dashed var(--gold);outline-offset:3px}
/* The rule itself: parchment, ink-edged, with the stretch BEHIND the marker
   laid in gold. `--hist-pct` is set by the client, because there is no CSS
   expression for "as far as the thumb" and that one number is the only part of
   this drawing the stylesheet cannot work out for itself. */
.hist-range::-webkit-slider-runnable-track{height:10px;border:2px solid var(--ink);
  background:linear-gradient(90deg,var(--gold-bright) 0 var(--hist-pct,100%),
    var(--paper-deep) var(--hist-pct,100%) 100%)}
.hist-range::-moz-range-track{height:10px;border:2px solid var(--ink);
  background:linear-gradient(90deg,var(--gold-bright) 0 var(--hist-pct,100%),
    var(--paper-deep) var(--hist-pct,100%) 100%)}
/* The marker a scribe would leave in a margin: a tall oxblood tab, ink-edged.
   Bigger than the rule is thick, so it is a comfortable target as well as an
   obvious one. */
.hist-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;
  width:.85rem;height:1.6rem;margin-top:-.53rem;border:2px solid var(--ink);
  background:var(--oxblood);box-shadow:1px 1px 0 rgba(59,42,23,.4);cursor:grab}
.hist-range::-moz-range-thumb{width:.85rem;height:1.6rem;border:2px solid var(--ink);
  border-radius:0;background:var(--oxblood);
  box-shadow:1px 1px 0 rgba(59,42,23,.4);cursor:grab}
.hist-range:active::-webkit-slider-thumb{cursor:grabbing;background:var(--oxblood-deep)}
.hist-range:active::-moz-range-thumb{cursor:grabbing;background:var(--oxblood-deep)}
.hist-ends{display:flex;justify-content:space-between;margin-top:-.3rem;
  font-family:var(--utility);font-size:.6rem;color:rgba(59,42,23,.78);
  font-variant-numeric:tabular-nums}
.hist-panel .hist-slider .clear-filters{grid-column:2;white-space:nowrap}
.hist-count{font-family:var(--utility);font-size:.72rem;line-height:1.45;
  margin:.45rem 0 0;color:rgba(59,42,23,.85);max-width:52rem}

/* ---- Standpoint Compare: a second rule under the first ----
   Drawn as the SAME instrument in a quieter hand. It is the same measure asking
   the same question at another year, so a differently-shaped control would say
   the two were different kinds of thing — which is the mistake §3.10g records
   about the gloss block borrowing a menu's furniture, read from the other side.
   What separates them is weight, not shape: a slimmer rule, a verdigris marker
   against the primary's oxblood, and the label reading "Against" rather than
   "Standing in". */
.hist-cmp-toggle{display:inline-flex;align-items:center;gap:.45rem;
  margin-top:.6rem;font-family:var(--utility);font-size:.7rem;
  color:rgba(59,42,23,.85);cursor:pointer}
.hist-cmp-toggle input{width:.95rem;height:.95rem;accent-color:var(--moss);
  cursor:pointer;flex:0 0 auto}
.hist-slider-a{margin-top:.3rem;grid-template-columns:auto minmax(0,1fr)}
.hist-year-a{display:flex;flex-direction:column;gap:.05rem;min-width:4.6rem}
/* Smaller than the primary output, and that difference is the whole hierarchy
   of the panel: the year you are standing in is the subject, and the year you
   are holding it against is the qualifier. */
.hist-year-a .hy-label{font-size:.56rem}
.hist-year-a .hy-value{font-size:1.25rem;color:var(--moss-deep,#2A5340)}
/* Its own fill percentage, because there is no CSS expression for "as far as
   the thumb" and two sliders means two numbers the client has to hand over. */
.hist-range-a{height:1.7rem}
.hist-range-a::-webkit-slider-runnable-track{height:7px;
  background:linear-gradient(90deg,var(--moss) 0 var(--hist-pct-a,0%),
    var(--paper-deep) var(--hist-pct-a,0%) 100%)}
.hist-range-a::-moz-range-track{height:7px;
  background:linear-gradient(90deg,var(--moss) 0 var(--hist-pct-a,0%),
    var(--paper-deep) var(--hist-pct-a,0%) 100%)}
.hist-range-a::-webkit-slider-thumb{width:.7rem;height:1.25rem;margin-top:-.42rem;
  background:var(--moss)}
.hist-range-a::-moz-range-thumb{width:.7rem;height:1.25rem;background:var(--moss)}
.hist-range-a:active::-webkit-slider-thumb{background:var(--moss-deep,#2A5340)}
.hist-range-a:active::-moz-range-thumb{background:var(--moss-deep,#2A5340)}
.hist-slider-a .hist-notches{top:.34rem;height:.85rem}

/* ---- the arcade: three bays ----
   Directors, networks, languages. The third is what the right-hand half of the
   panel was empty for, and it is a third reading of one question rather than an
   appendix to the other two — so it gets a bay of its own rather than a
   disclosure underneath them. */
.hist-detail{display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr) minmax(0,1.05fr);
  gap:.75rem;margin-top:.7rem;
  /* STRETCH, not start. An arcade whose bays are three different heights is
     not an arcade — and the middle one runs short whenever the archive holds
     no television for the years on the rule, which is most of them before the
     1950s. Equal bays with the colophon pinned to the foot of each reads as a
     column that happens to be short rather than as a layout that has slipped. */
  align-items:stretch}
/* FOUR bays while a second standpoint is chosen — the arcade gains an arch
   rather than wrapping one underneath the others, which would read as a bay
   that had come loose. Selected through .hist-panel so it wins on SPECIFICITY
   (0,2,0) rather than on file order, and the two media queries below are raised
   to match: §4 records a bare class losing this argument three separate times,
   and a rule that depends on where the block sits breaks silently when it
   moves. */
.hist-panel .hist-detail-cmp{grid-template-columns:repeat(4,minmax(0,1fr))}
.hist-col{min-width:0;display:flex;flex-direction:column;
  border:2px solid var(--ink);background:var(--paper);
  /* The arch. A shallow one: a semicircle over a 20rem column is a doorway,
     and what is wanted is the suggestion of one. */
  border-radius:1.5rem 1.5rem 3px 3px;
  box-shadow:2px 2px 0 rgba(59,42,23,.16);overflow:hidden}
/* The rubric under the arch, and the gold impost the column springs from. */
.hist-rubric{margin:0;padding:.4rem .7rem .32rem;text-align:center;
  background:var(--paper-deep);border-bottom:2px solid var(--gold);
  font-family:var(--utility);font-size:.62rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--oxblood);font-weight:400}
/* Ruled rows with the ordinal in the margin, which is what a canon table is.
   `list-style:decimal` rather than a CSS counter, so the numbering honours the
   <ol>'s own `start` and carries across a page turn for free — a counter would
   restart at 1 on page two and read as a second, shorter list. */
.hc-list{list-style:decimal;margin:0;padding:.15rem 0 .15rem 2.2rem}
.hc-list li::marker{color:#6A4E0F;font-family:var(--utility);
  font-size:.62rem;font-variant-numeric:tabular-nums}
.hc-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.5rem;
  align-items:baseline;padding:.19rem .6rem .19rem .15rem;
  font-family:var(--utility);font-size:.74rem;line-height:1.3}
/* Alternate ruling, the way a table of this kind is banded so the eye holds a
   line across it. Faint: it is a guide, not a stripe. */
.hc-list li:nth-child(odd){background:rgba(185,138,47,.10)}
.hc-list a{color:var(--oxblood);text-decoration:none;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hc-list a:hover,.hc-list a:focus-visible{color:var(--oxblood-deep);
  text-decoration:underline;text-underline-offset:2px}
.hc-n{color:rgba(59,42,23,.78);font-size:.64rem;white-space:nowrap;
  font-variant-numeric:tabular-nums}
.hc-pager{margin:.35rem 0 .1rem;justify-content:center}
/* The colophon at the foot of a column: what it holds, in the same voice the
   rest of the site closes a list with. */
.hist-panel .hc-note{margin:auto 0 0;padding:.3rem .6rem .4rem;text-align:center;
  font-size:.62rem;line-height:1.4;border-top:1px solid rgba(59,42,23,.18)}
.hist-panel .hc-none{margin:0;padding:.7rem .6rem;text-align:center;font-size:.7rem}

/* ---- the roundel ---- */
.hl-chart{display:flex;flex-direction:column;align-items:center;gap:.45rem;
  padding:.6rem .5rem .1rem}
.hl-pie{width:8.2rem;height:8.2rem;flex:0 0 auto}
.hl-key{list-style:none;margin:0;padding:0 .3rem;width:100%;min-width:0}
.hl-key li{display:grid;grid-template-columns:.7rem minmax(0,1fr) auto;gap:.4rem;
  align-items:baseline;font-family:var(--utility);font-size:.7rem;
  padding:.1rem 0;border-bottom:1px solid rgba(59,42,23,.12)}
.hl-key li:last-child{border-bottom:none}
.hl-swatch{width:.7rem;height:.7rem;border:1.5px solid var(--ink);align-self:center}
.hl-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hl-n{color:rgba(59,42,23,.78);font-size:.64rem;white-space:nowrap;
  font-variant-numeric:tabular-nums}
/* The legend rows are links on the statistics page and plain text inside the
   timeline's panel — that page has somewhere to send a reader and the compact
   panel has not. Only a REAL language is ever a link: the gathered row stands
   for several codes at once, so there is no single filter it could open. */
.hl-name a{color:var(--oxblood);text-decoration:none}
.hl-name a:hover,.hl-name a:focus-visible{text-decoration:underline;
  text-underline-offset:2px}

/* --- what the roundel counts: Language or Genre ---
   Two buttons under the rubric, sitting on the gold impost the column springs
   from — the bay's own heading control rather than something floating in the
   chart. The chosen one is filled AND the rubric above changes with it ("Made
   in" against "Filed under"), so the fill reinforces a fact the heading already
   states rather than carrying it alone (§7). */
.hist-facet{display:flex;gap:0;border-bottom:1px solid rgba(59,42,23,.18);
  background:var(--paper-deep)}
.hist-facet button{flex:1 1 0;min-width:0;border:none;background:none;
  padding:.28rem .3rem;cursor:pointer;font-family:var(--utility);
  font-size:.6rem;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(59,42,23,.7)}
.hist-facet button+button{border-left:1px solid rgba(59,42,23,.18)}
.hist-facet button:hover{color:var(--oxblood)}
.hist-facet button.on{background:var(--paper);color:var(--oxblood);font-weight:700;
  box-shadow:inset 0 -2px 0 var(--oxblood)}
.hist-facet button:focus-visible{outline:2px dashed var(--gold);outline-offset:-2px}

/* --- the same roundel, on the statistics page ---
   Side by side rather than stacked: this page is wide where the panel it came
   from is narrow, and a disc with a column of seven languages under it would
   leave the right-hand half of a stats block empty. It sits UNDER the ranked
   table inside the same section, because the two are readings of one question
   and a heading between them would say they were two. */
.lang-roundel{border-top:1px solid rgba(59,42,23,.18);margin-top:.8rem;
  padding-top:.6rem}
.lang-roundel .hl-chart{flex-direction:row;align-items:center;
  justify-content:flex-start;gap:1.6rem;flex-wrap:wrap;padding:.2rem 0}
.lang-roundel .hl-pie{width:9.5rem;height:9.5rem}
.lang-roundel .hl-key{flex:1 1 18rem;width:auto;padding:0}
.lang-roundel .hl-key li{font-size:.78rem;padding:.15rem 0}
@media (max-width:560px){
  .lang-roundel .hl-chart{flex-direction:column;align-items:center;gap:.6rem}
  .lang-roundel .hl-key{width:100%;flex:1 1 auto}
}

/* The fourth bay, and the added-names disclosure inside the first two. Both are
   Standpoint Compare's, and both draw NOTHING unless a second year is chosen —
   an empty bay apologising for a mode nobody turned on is the wallpaper §3.10c
   refuses. */
.hist-new{margin:.1rem .45rem .35rem;font-family:var(--utility);font-size:.66rem}
.hist-new>summary{cursor:pointer;color:var(--moss-deep,#2A5340);
  padding:.2rem 0;list-style-position:inside}
.hist-new>summary:focus-visible{outline:2px dashed var(--gold);outline-offset:2px}
.hist-new-list{list-style:none;margin:.15rem 0 0;padding:0}
.hist-new-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.4rem;
  align-items:baseline;padding:.12rem .2rem;line-height:1.3;
  border-bottom:1px solid rgba(59,42,23,.1)}
.hist-new-list li:last-child{border-bottom:none}
/* The one string in this panel that states a change rather than a state, so it
   is set apart from the colophon above it rather than reading as more of it. */
.hist-delta{border-top:1px solid rgba(59,42,23,.18);color:var(--moss-deep,#2A5340)}

@media (max-width:900px){
  /* Two bays, then the roundel across the foot: three columns of this width
     stop being an arcade and start being a squeeze. In compare mode the fourth
     bay simply joins the flow — two-up is still an arcade at four bays. */
  .hist-panel .hist-detail,
  .hist-panel .hist-detail-cmp{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .hist-langs{grid-column:1 / -1}
  .hl-chart{flex-direction:row;justify-content:center;gap:1.2rem;flex-wrap:wrap}
  .hl-key{width:auto;flex:1 1 14rem}
}
@media (max-width:560px){
  .hist-head{grid-template-columns:minmax(0,1fr);gap:.5rem}
  .hist-year{flex-direction:row;align-items:baseline;gap:.6rem;align-self:start}
  .hy-value{font-size:1.6rem}
  .hist-lede{grid-column:1}
  .hist-slider{grid-template-columns:minmax(0,1fr)}
  .hist-panel .hist-slider .clear-filters{grid-column:1;justify-self:start}
  .hist-slider-a{grid-template-columns:minmax(0,1fr)}
  .hist-panel .hist-detail,
  .hist-panel .hist-detail-cmp{grid-template-columns:minmax(0,1fr)}
  .hl-chart{flex-direction:column}
  .hl-key{width:100%}
}

.threads-panel{max-width:1180px;margin:.7rem auto 0;padding:0 1rem}

/* Register tabs sewn into the fore-edge of a codex: a stitched leather ledge
   above the page block. Muted parchment/vellum tones rather than gold leaf,
   which was reading as a wall of yellow. */
.threads-book{position:relative;border:2px solid var(--ink);background:var(--paper);
  box-shadow:3px 3px 0 rgba(59,42,23,.22)}
.threads-book::before{content:"";position:absolute;left:0;right:0;top:0;height:5px;
  background:repeating-linear-gradient(90deg,var(--ink) 0 6px,transparent 6px 13px);opacity:.35}
/* CENTRED, because the rows are RAGGED and nothing can make them even. A tab is
   as wide as its thread's name plus the year, so a wrapped row fills whatever it
   fills: measured on the timeline's sixteen, the first row left 181px unused and
   the last left 834px, all of it on the right. Flush left, that reads as a
   column that has run out rather than as a row of tabs.
   Centring cannot make the rows equal and does not try: it spreads each row's
   slack to both ends, so a short last row sits under the middle of the ones
   above it instead of hanging off the left edge. Shared with the period page's
   own book (§3.11l2), which has the same variable widths for the same reason. */
.thread-tabs{display:flex;flex-wrap:wrap;gap:.4rem .35rem;align-items:flex-end;
  justify-content:center;padding:.75rem 1rem .6rem;max-height:none}
.thread-tab{position:relative;font-family:var(--utility);font-size:.76rem;line-height:1.15;
  cursor:pointer;color:var(--ink);background:linear-gradient(180deg,#DCCFB2 0%,#CFC0A0 100%);
  border:2px solid var(--ink);border-bottom-width:1px;
  padding:.42rem .7rem .3rem;border-radius:9px 9px 0 0;
  box-shadow:inset 0 2px 0 rgba(255,255,255,.35), 2px -1px 0 rgba(59,42,23,.18);
  max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  transform:translateY(0);transition:transform .12s ease, background .12s ease}
/* the stitch that holds the tab to the leaf */
.thread-tab::before{content:"";position:absolute;left:50%;top:3px;transform:translateX(-50%);
  width:14px;height:2px;background:rgba(59,42,23,.45);
  box-shadow:0 3px 0 rgba(59,42,23,.25)}
/* the shadow where the tab meets the page block */
.thread-tab::after{content:"";position:absolute;left:.35rem;right:.35rem;bottom:-1px;height:2px;
  background:rgba(59,42,23,.3)}
.thread-tab:hover{background:linear-gradient(180deg,#E6DCC2 0%,#D8CBAB 100%);transform:translateY(-2px)}
.thread-tab:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
/* A pulled tab wears the colour it was assigned, which is the same colour its
   badge carries on every matching poster. --th-c is set inline from
   PP.THREAD_COLOURS, in selection order. */
.thread-tab.on{background:var(--th-c,var(--oxblood));
  color:var(--paper);border-color:var(--ink);transform:translateY(-3px);
  box-shadow:inset 0 2px 0 rgba(255,255,255,.18), 2px -2px 0 rgba(59,42,23,.3)}
.thread-tab.on::before{background:rgba(233,224,201,.6);box-shadow:0 3px 0 rgba(233,224,201,.3)}
.thread-tab.on::after{background:var(--th-c,var(--oxblood))}
.thread-tab:disabled{opacity:.4;cursor:default;transform:none}
.thread-tab:disabled:hover{background:linear-gradient(180deg,#DCCFB2 0%,#CFC0A0 100%);transform:none}
/* The letter, so a tab and its badges are read as the same thing without
   having to match a colour. */
.tt-letter{display:inline-block;font-weight:700;margin-right:.35rem;
  border:1.5px solid currentColor;padding:0 .22rem;line-height:1.1}
/* The earliest year the thread reaches, because the list is in that order and
   an order nobody can see is not an order. */
.tt-from{margin-left:.45rem;opacity:.6;font-size:.9em}
.thread-tab.on .tt-from{opacity:.8}
/* the leaf the tabs are sewn into
   THE PAPER IS SHARED AND THE LAYOUT IS NOT. The period page sews the same
   tabs into the same leaf (§3.11l2), so the texture, the rule above it and the
   padding are one declaration — a second copy is where the two would drift at
   the one thing a reader carries between the pages, which is what the furniture
   looks like. What differs is what sits on it: the timeline puts a hint and its
   controls in a row, and the period page stacks one thread's prose. */
.thread-leaf,.pdt-leaf{border-top:2px solid var(--ink);background:
  repeating-linear-gradient(0deg,transparent 0 15px,rgba(59,42,23,.06) 15px 16px),
  var(--paper-deep);
  padding:.5rem .8rem}
.thread-leaf{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}
.thread-hint{font-family:var(--utility);font-size:.74rem;color:rgba(59,42,23,.8);
  flex:1 1 22rem;min-width:0}
/* Three states, three jobs: an instruction, a definition, a legend. */
.th-idle{display:block}
.th-one{display:block}
.th-one .th-name{display:inline-block;font-size:.86rem;color:var(--th-c);font-weight:700}
/* 44rem, THE SITE'S OWN MEASURE (§3.7a), not 60ch. At this font size 60ch came
   out at 452px — the descriptor wrapped to three lines and stopped short of the
   viewport's midpoint while 538px of the leaf sat empty to its right, so the
   panel was taller than it needed to be and looked like a narrow column in a
   wide box. 44rem is 704px and is what every other run of prose on the site is
   set to; wider than that is not an improvement on it, which is the whole
   reason the measure exists. */
.th-one .th-desc{display:block;font-family:var(--body);font-size:.92rem;line-height:1.5;
  color:var(--ink);margin:.25rem 0 .2rem;max-width:44rem}
/* The stand-in, on the timeline's own definition panel — see .pdt-unwritten for
   why the alpha is on the colour and not on `opacity`. */
.th-one .th-unwritten{font-style:italic;color:rgba(59,42,23,.78)}
.th-one .th-count{display:block;opacity:.75}
.th-head{display:block;font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--lake);margin-bottom:.35rem}
.th-legend{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}
.th-legend li{display:grid;grid-template-columns:1.5rem 1fr;gap:.1rem .5rem;align-items:baseline}
/* The letter is what ties a legend row to a badge on a poster. Colour
   reinforces it; it never carries the meaning alone (§7). */
.th-key{grid-row:1 / span 2;justify-self:start;font-weight:700;font-size:.8rem;
  color:var(--paper);background:var(--th-c);border:2px solid var(--ink);
  width:1.5rem;height:1.5rem;display:grid;place-items:center;line-height:1}
.th-legend .th-name{font-size:.82rem;font-weight:700;color:var(--th-c)}
/* The same measure, for the same reason — a legend of six threads stacks six of
   these, so a narrow one costs six times over. */
.th-legend .th-desc{grid-column:2;font-family:var(--body);font-size:.86rem;
  line-height:1.45;color:var(--ink);opacity:.9;max-width:44rem}
.th-clear{flex:0 0 auto;align-self:flex-start}

/* The badge a poster wears for each pulled thread it belongs to. Stacked,
   because a title can sit in several at once. */
/* The same corner compare’s initials use, and deliberately so: a reader
   never sees both at once, so one position can mean "which of the things you
   selected is this". Matching .slot-marks exactly. */
.th-badges{position:absolute;top:8px;left:8px;display:flex;gap:3px;z-index:3}
.show-stack .th-badges{top:6px;left:6px;z-index:4}
.th-badge{font-family:var(--utility);font-size:.68rem;line-height:1;font-weight:700;
  color:var(--paper);background:var(--th-c);border:2px solid var(--ink);
  width:1.15rem;height:1.15rem;display:grid;place-items:center;
  box-shadow:1px 1px 0 rgba(59,42,23,.35)}
.thread-pager{display:flex;align-items:center;gap:.6rem;font-family:var(--utility);font-size:.75rem}
.thread-pager button{font-family:var(--utility);background:var(--paper);color:var(--oxblood);
  border:2px solid var(--ink);padding:.1rem .55rem;cursor:pointer}
.thread-pager button:disabled{opacity:.4;cursor:default}

/* threads on a review page */
.threads{margin-top:1.6rem;border-top:3px double var(--gold);padding-top:1rem}
.threads h3{font-family:var(--utility);color:var(--moss);text-transform:none;letter-spacing:.06em;margin-bottom:.5rem}
.thread-list{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:.4rem}
.thread-list a{display:inline-block;font-family:var(--utility);font-size:.82rem;color:var(--ink);
  background:var(--paper);border:2px solid var(--moss);padding:.2rem .6rem;text-decoration:none;border-radius:7px 7px 0 0}
.thread-list a:hover{background:var(--moss);color:var(--paper)}
@media (max-width:640px){ .era-tools{flex-wrap:wrap} .compare-panel select{max-width:100%} }
@media print{ .era-tools,.compare-panel,.threads-panel{display:none !important} }

/* admin: period boundary capture */
.bounds-ask{display:inline-flex;align-items:center;gap:.2rem;flex-wrap:wrap}
.bound-in{width:5.5rem;font-family:var(--utility);font-size:.78rem;background:var(--paper);
  color:var(--ink);border:2px solid var(--ink);padding:.1rem .3rem}

/* The hidden attribute must beat the display rules above it. */
[hidden]{display:none !important}

/* unrated: no aggregate score recorded yet — §3.2's rule one column across
   from saltiness, and it had no drawing of its own at all. Five cells printed
   an em dash and three printed "0.0/5"; a dash reads as "not applicable" where
   the claim is that nobody has scored this, so it is a word now.

   THE ALPHA IS ON THE COLOUR, NEVER ON opacity. These strings are the smallest
   on their rows, and opacity fades ink toward the paper at exactly the sizes
   that can least afford it (§4) — which is what `.br-none{opacity:.45}` and
   `.lp-none` were doing to the dash they replace. rgba(59,42,23,.78) is the
   ratio .mini-note settled on after the same measurement.

   `em`, not `rem`: this sits inside six different cells at six different
   sizes, and a fixed size would be larger than the figure it stands in for in
   the narrow ones and smaller in the wide. */
.rating-none{font-style:italic;color:rgba(59,42,23,.78);font-size:.86em;
  font-variant-numeric:normal;letter-spacing:0;white-space:normal}
/* The reason, on the one surface with room for it: the review page, where this
   sits under a label already naming the source. Every other caller draws the
   word alone. */
.rating-none .rn-why{font-size:.9em}

/* The poster card loses the gold star rather than drawing one beside a nought,
   so it must lose the gold with it. (0,3,0) to beat `.poster-meta .p-lb`'s own
   colour on SPECIFICITY rather than on file order (§3.9c). */
.poster-meta .p-lb.unrated{color:rgba(59,42,23,.78);font-style:italic}
.poster-meta .p-lb.unrated .lb-num{color:rgba(59,42,23,.6);font-style:normal}

/* unsalted: no verdict recorded yet */
.salt-compact.unsalted,.salt-row.unsalted{opacity:.72;font-style:italic}
.salt-compact.unsalted .salt-emblem,.salt-row.unsalted .salt-emblem{opacity:.7}
.salt-opt[title="Unsalted"]{border-style:dashed}

/* ============================================================
   MOBILE — touch ergonomics and small-screen layout
   ============================================================ */

/* ---- 1. the horizontal timeline inside a vertical page ---- */
.timeline-scroll{
  -webkit-overflow-scrolling:touch;          /* momentum on iOS */
  overscroll-behavior-x:contain;             /* a swipe can't bounce the page */
  scroll-snap-type:x proximity;              /* ticks settle instead of drifting */
  scroll-padding-inline:1rem;
}
.tick{scroll-snap-align:center}
/* an edge fade tells you there is more timeline off-screen */
.timeline-wrap::before,.timeline-wrap::after{
  content:"";position:absolute;top:0;bottom:0;width:26px;pointer-events:none;z-index:2}
.timeline-wrap::before{left:0;background:linear-gradient(90deg,var(--paper),rgba(233,224,201,0))}
.timeline-wrap::after{right:0;background:linear-gradient(270deg,var(--paper),rgba(233,224,201,0))}

@media (hover:none) and (pointer:coarse){
  /* WCAG 2.5.5 / HIG: ~44px in BOTH directions, not just width */
  .tick{flex:1 0 52px;min-height:48px;padding-bottom:.35rem}
  .tick .mark{min-height:14px}
  .era-btn,.seg button,.tool-btn,.jump-btn,.browse-tabs button,
  .stat-sort button,.thread-tab,.figure-pager button,.thread-pager button,
  .be-fix{min-height:44px}
  .filter-group select,#searchInput,.browse-filters select{min-height:44px}
  .tc-remove,.tc-primary{min-width:36px;min-height:36px}
  /* the grey flash on tap is jarring against parchment */
  a,button,select,input,summary,.poster-card,.show-stack-card,.tick,.heat-cell{
    -webkit-tap-highlight-color:rgba(158,43,37,.14)}
}

/* ---- 2. layout at phone widths ---- */
@media (max-width:640px){
  /* Getting the rule onto the first screen. Measured at 375x812, the timeline
     — the entire point of the site — began at 869px, so a phone visitor met a
     masthead, a standfirst and a full-width era button per row — seven of
     them then, eight now — and had to scroll before seeing a single year.

     The era bar was 358px of that: each button is 190–250px wide, so exactly
     one fits per row and every one of them wraps. It becomes a sideways strip —
     the same gesture the rule underneath already asks for — which costs about
     55px. The masthead gives up some padding and the standfirst some size.
     Together that lifts the rule to roughly 480px: above the fold on a 812px
     screen, and still above it on a 667px one. */
  header.masthead{padding-top:1.4rem;padding-bottom:1rem}
  .masthead-logo{margin-top:.35rem}
  .masthead .rule-note{font-size:.86rem;line-height:1.45;margin-top:.55rem}

  .era-bar{
    flex-wrap:nowrap;justify-content:flex-start;
    overflow-x:auto;
    /* The buttons carry a 3px offset shadow and a 3px-offset focus outline,
       and an overflow-x container clips vertically as well. The padding is
       what keeps both of those inside it. */
    padding:1rem .9rem .7rem;gap:.45rem;
    scroll-snap-type:x proximity;
    /* Deliberately NOT scroll-behavior:smooth. syncEraButtons repositions the
       strip by assigning scrollLeft, and smooth scrolling of a nested overflow
       container is unreliable — measured in a browser here, both
       scrollTo({behavior:'smooth'}) and a plain assignment under
       scroll-behavior:smooth left scrollLeft at 0, while the same assignment
       without it scrolled correctly. An instant reposition is also the honest
       response to a tap: the reader asked for this era, now. */
    scrollbar-width:thin;scrollbar-color:var(--oxblood) var(--paper-deep);
    -webkit-overflow-scrolling:touch;
  }
  .era-btn{flex:0 0 auto;scroll-snap-align:center}
  .era-hint{margin-top:.4rem}

  .timeline-scroll{padding:1.6rem .75rem .4rem}   /* was 3rem each side */
  .timeline-wrap::before,.timeline-wrap::after{width:16px}

  /* poster shelf: a real grid that fills the screen instead of two fixed
     columns with dead space. Card width now matches the sizes hint. */
  .shelf{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));
    gap:1rem .8rem;padding:1.2rem .75rem 1rem;justify-content:start}
  .poster-card,.show-stack-card{width:100%}
  .poster{width:100%;height:auto;aspect-ratio:172/250}
  .poster img.tmdb{width:100%;height:100%;object-fit:cover}
  .poster-meta{width:100%}

  /* review page stacks rather than squeezing a 150px poster beside prose */
  .review-head{flex-direction:column;align-items:flex-start;gap:.9rem}
  .review-head .poster{flex:0 0 auto;width:132px;height:192px}
  .review-title h2{font-size:1.6rem;line-height:1.15}
  .review-body{font-size:1.05rem}
  .distance-stats,.fig-stats{gap:.5rem}
  .dist-stat,.fig-stat{min-width:0;flex:1 1 46%}
  .figure-head{flex-direction:column}

  /* browse / filmography rows at ~360px: rank and bar were crushing the title */
  .browse-row{flex-wrap:wrap;gap:.35rem .5rem;padding:.55rem .2rem}
  .br-rank{width:1.4rem;font-size:.95rem}
  /* THE TITLE TAKES THE WHOLE FIRST LINE, so the three figures wrap together
     onto the second. With `flex:1 1 auto` the runtime was narrow enough to fit
     beside the title while the saltiness and the rating wrapped — three figures
     of one kind split across two lines for no reason a reader could see. */
  .br-main{flex:1 1 100%;min-width:0}
  .br-title{font-size:.95rem;white-space:normal}
  .br-sub{font-size:.7rem}
  /* At this width the three figures drop onto their own line under the title,
     in reading order: how long, how salty, how well rated. The runtime leads
     because it is the plainest fact of the three, and `margin-left` on the
     saltiness is what used to open that gap — it moves here so the runtime is
     what sits against the left edge. */
  .br-runtime{order:2;min-width:auto}
  .br-salt{order:3;margin-left:1.2rem}
  .br-rating{order:4;margin-left:auto;min-width:auto}
  /* The chip wraps onto its own line rather than squeezing the title — which
     is `flex-wrap` on .br-title doing it, NOT a zeroed margin. Zeroing the
     margin was the first attempt and it is what put the chip flush against
     the era ribbon; the row's `gap` now cannot be collapsed at any width.
     The strip loses a little height — six columns still read at 360px because
     each carries its number above the bar. */
  .bd-plot{height:4.6rem;gap:.35rem}
  .bd-unrated{flex:0 0 1.8rem;padding-left:.3rem}
  .be-fix{flex:1 1 100%;justify-content:space-between}

  .glance-cell{flex:1 1 calc(50% - .3rem)}
  /* The label takes a line of its own and the three measures share the one
     under it — the same two-row shape `.credit-row` drops to at this width,
     spelled as explicit tracks rather than as `order` on wrapped flex items so
     the bars still start at one x down the column. */
  .rank-row{grid-template-columns:1.6rem minmax(60px,1fr) 3.2rem minmax(0,6.4rem);
    row-gap:.2rem;padding:.45rem 0}
  .rr-rank{grid-column:1;grid-row:1}
  .rr-label{grid-column:2 / -1;grid-row:1;white-space:normal;text-overflow:clip}
  .rr-bar{grid-column:2;grid-row:2}
  .rr-num{grid-column:3;grid-row:2}
  .rr-salt{grid-column:4;grid-row:2}
}

@media (max-width:400px){
  .shelf{grid-template-columns:repeat(auto-fill,minmax(118px,1fr));gap:.8rem .6rem}
  /* 88vw is a VIEWPORT measure and the box it sits in is the masthead's
     content area, which the bookmark block pads in from both edges on a phone
     — a vw cap cannot see that, and the wordmark ran out to the very edge of
     the screen. Whichever of the two is smaller keeps it inside its box.

     With the padding symmetric again the 100% half is always the binding one,
     so this reads as belt to that brace rather than as the thing doing the
     work. It is kept because the two are not the same claim: one is about the
     screen and one is about the box, and the day the padding changes again it
     is the box that will still be right. */
  .masthead-logo img,.masthead-logo svg{max-width:min(88vw,100%)}
  .cmp-label{font-size:.6rem}
}

/* ---- 3. notched devices: keep fixed UI clear of the home indicator ---- */
.cookie-banner{
  bottom:calc(18px + env(safe-area-inset-bottom,0px));
  padding-left:calc(1.1rem + env(safe-area-inset-left,0px));
  padding-right:calc(1.1rem + env(safe-area-inset-right,0px));
}
.toast{bottom:calc(1.2rem + env(safe-area-inset-bottom,0px))}
body{padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}
footer.site-foot{padding-bottom:calc(var(--foot-rule-h) + 1.5rem + env(safe-area-inset-bottom,0px))}

/* Font payload: below 641px utility text falls back to Cardo, which is
   already loaded — one fewer family on the phone, no change on desktop.
   This used to be a media-scoped <link> in every page; now that the faces
   are declared here, no rule references MedievalSharp at this width and the
   browser simply never asks for it. Same saving, one fewer place to keep in
   step. */
@media (max-width:640px){
  :root{ --utility:'Cardo',Georgia,serif; }
  .era-btn,.seg button,.badge,.p-sub,.tick,.browse-tabs button{letter-spacing:.02em}
}


/* --- admin: periods editor ---------------------------------------------
   Rows are a grid so the name, span, count and buttons keep their own
   columns instead of wrapping into each other. Inputs here sit outside a
   .field wrapper, so they need their own styling. */
.period-table{margin-top:1.2rem;border-top:2px solid var(--ink)}
/* Six cells: name, span, title count, the has-a-page flag, Save, Delete.
   Every one of them clips, and `min-width:0` with it — a grid item's default
   width is its content's intrinsic width, so `minmax(0,…)` on the track is not
   enough on its own, and a track does not clip what overflows it. That trap is
   in §4 three times over. */
.period-row{
  display:grid;
  grid-template-columns:minmax(180px,1.6fr) auto minmax(5.5rem,auto) auto auto auto;
  align-items:center;column-gap:.9rem;row-gap:.5rem;
  padding:1rem .5rem;border-bottom:1px solid rgba(59,42,23,.25);
}
.period-row > *{min-width:0}
.period-row + .period-row{border-top:none}
/* The row the command palette sent you to. This panel lists every period at
   once and has no selection of its own, so without a mark a jump would leave
   the editor scanning forty-seven rows for the name they had just typed. The
   gold rule carries it as well as the tint (§7). */
.period-row.on{background:rgba(198,160,58,.13);box-shadow:inset 3px 0 0 var(--gold)}
.period-row input{
  font-family:var(--body);font-size:.95rem;padding:.45rem .6rem;
  border:2px solid var(--ink);background:#F5EFE0;color:var(--ink);width:100%;
}
.period-row input:focus{outline:none;border-color:var(--oxblood);box-shadow:2px 2px 0 var(--gold)}
.pr-span{display:inline-flex;align-items:center;gap:.4rem;white-space:nowrap;
  font-family:var(--utility);font-size:.9rem}
.pr-year{width:6.5rem;flex:0 0 6.5rem}
.pr-count{font-family:var(--utility);font-size:.75rem;opacity:.8;text-align:right;white-space:nowrap}
.period-row .btn{margin:0;white-space:nowrap;padding:.45rem .8rem;font-size:.78rem}
.period-row .btn.danger{background:var(--paper);color:var(--oxblood);border-color:var(--oxblood)}
.period-row .btn.danger:hover{background:var(--oxblood);color:var(--paper)}
.pr-warn{font-family:var(--utility);font-size:.75rem;color:var(--oxblood);
  padding:.15rem .5rem .9rem;border-bottom:1px solid rgba(59,42,23,.12)}
.pr-warn:empty{display:none}
/* The row above is a line of boundaries; this is prose, so it goes under it
   rather than in it. Shorter than the thread form's box because most periods
   will never carry one and 48 tall boxes would be the panel. */
.period-desc{padding:0 .5rem 1rem;border-bottom:1px solid rgba(59,42,23,.25);
  margin-top:-.4rem}
.period-desc .field{margin:0}
.period-desc textarea{min-height:3.4rem}
@media (max-width:820px){
  .period-row{grid-template-columns:1fr 1fr;row-gap:.6rem}
  .period-row .pr-name{grid-column:1 / -1}
  .pr-span{grid-column:1 / -1}
  .pr-count{grid-column:1 / -1;text-align:left}
}

/* --- statistics: director / network credit lists ------------------------
   A grid, so the name column can flex while rank, count, rating and the
   saltiness emblem hold steady columns down the list. */
.credit-list{margin-top:.8rem;border-top:2px solid var(--ink)}
.credit-row{
  display:grid;
  grid-template-columns:2.2rem minmax(0,1fr) 5.5rem 3.4rem minmax(6.5rem,auto);
  align-items:center;column-gap:.9rem;
  padding:.6rem .3rem;border-bottom:1px solid rgba(59,42,23,.2);
}
.credit-row:nth-child(odd){background:rgba(216,192,120,.10)}
.cr-rank{font-family:var(--display);font-size:1.15rem;color:var(--gold-text);text-align:right}
.cr-name{font-family:var(--body);font-weight:700;font-size:1rem;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cr-count{font-family:var(--utility);font-size:.75rem;opacity:.8;white-space:nowrap}
.cr-rating{font-family:var(--utility);font-size:.95rem;text-align:right;white-space:nowrap}
.cr-rating small{opacity:.55;font-size:.7em}
.cr-salt .salt-compact{margin-top:0}
.credit-pager{display:flex;align-items:center;justify-content:flex-end;gap:.7rem;
  margin-top:.7rem;font-family:var(--utility);font-size:.78rem}
.credit-pager button{font-family:var(--utility);font-size:.78rem;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--gold);
  padding:.35rem .85rem;box-shadow:2px 2px 0 rgba(59,42,23,.22)}
.credit-pager button:hover:not(:disabled){background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.credit-pager button:disabled{opacity:.4;cursor:default;box-shadow:none}
.cp-count{color:rgba(59,42,23,.8);margin-right:auto}
@media (max-width:640px){
  .credit-row{grid-template-columns:1.8rem minmax(0,1fr) 3.2rem;row-gap:.25rem;padding:.55rem .25rem}
  .cr-name{grid-column:2 / -1;white-space:normal}
  .cr-count{grid-column:2}
  .cr-rating{grid-column:3;text-align:right}
  .cr-salt{grid-column:2 / -1}
  .credit-pager{justify-content:space-between}
}

/* --- recommended reading --- */
.reading{margin-top:1.8rem;border-top:3px double var(--gold);padding-top:1rem}
.reading h3{font-family:var(--utility);color:var(--lake);text-transform:none;
  letter-spacing:.06em;margin-bottom:.6rem}
.reading-list{list-style:none;padding:0;margin:0}
.reading-list li{display:flex;flex-direction:column;gap:.1rem;padding:.5rem 0 .5rem 1.6rem;
  border-bottom:1px solid rgba(59,42,23,.18);position:relative}
.reading-list li::before{content:"\1F4D6";position:absolute;left:0;top:.55rem;
  font-size:.85rem;opacity:.55;filter:grayscale(1)}
.reading-list li:last-child{border-bottom:none}
.bk-title{font-family:var(--body);font-weight:700;font-style:italic;color:var(--ink)}
.bk-meta{font-family:var(--utility);font-size:.76rem;color:rgba(59,42,23,.78)}

/* --- admin: recommended reading editor --- */
.book-ask{margin:.5rem 0;padding:.7rem .8rem;border:2px dashed var(--ink);
  background:rgba(59,42,23,.05)}
.book-ask:empty{display:none;padding:0;border:none}
.ba-title{display:block;font-family:var(--body);font-weight:700;margin-bottom:.5rem}
.book-ask-grid{display:grid;grid-template-columns:2fr 1fr;gap:.8rem}
.book-ask .btn{margin:.2rem .4rem .2rem 0}
.book-chips{list-style:none;padding:0;margin:.5rem 0 0;display:flex;flex-direction:column;gap:.35rem}
.book-chip{display:flex;align-items:baseline;gap:.6rem;border:2px solid var(--ink);
  background:var(--paper);padding:.35rem .5rem}
.bc-title{font-family:var(--body);font-weight:700;font-style:italic;flex:1 1 auto;min-width:0}
.bc-meta{font-family:var(--utility);font-size:.74rem;opacity:.8;white-space:nowrap}
/* WHAT THE SOURCES ALREADY SAY. A citation names a WORK, and the reading list
   wants a title, an author and a year — so an editor who has just sourced six
   claims was retyping most of six books. These are suggestions and are drawn as
   suggestions: a dashed rule rather than the solid border a stored book carries,
   so a row that is IN the list and a row that is merely on offer can never be
   read as the same thing. Nothing here is a chip until somebody presses Use and
   confirms the author. */
.book-suggest{margin:.5rem 0 0}
.book-suggest:empty{display:none}
.bs-head{margin:0 0 .4rem}
.bs-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.3rem}
.bs-row{display:flex;align-items:baseline;gap:.6rem;border:2px dashed rgba(59,42,23,.5);
  background:rgba(59,42,23,.04);padding:.3rem .5rem}
.bs-title{font-family:var(--body);font-weight:700;font-style:italic;flex:1 1 auto;min-width:0}
.bs-meta{font-family:var(--utility);font-size:.74rem;color:rgba(36,28,18,.78);
  flex:0 1 auto;min-width:0}
.bs-use{flex:0 0 auto;margin:0}
@media (max-width:560px){ .book-ask-grid{grid-template-columns:1fr} }

/* --- admin: the comparisons editor (§3.12g) ---
   The reading editor's furniture one control over — the dashed sub-panel, the
   bordered chips, the same remove button — because it is the same KIND of
   thing: a list of small records edited one at a time (§3.10g's borrowing
   test). What it does not share is the SHAPE of the sub-panel, which holds two
   sides rather than two boxes. */
.cmp-ask{margin:.5rem 0;padding:.8rem .9rem;border:2px dashed var(--ink);
  background:rgba(59,42,23,.05)}
.cmp-ask:empty{display:none;padding:0;border:none}
.cmp-ask .btn{margin:.2rem .4rem .2rem 0}
.cmp-ask-head{font-family:var(--body);font-weight:700;margin:0 0 .6rem}
/* The two sides sit level so an editor reads them as a pair rather than as one
   long form — and they stack below the admin column's own breakpoint, where two
   columns of six fields each is neither. */
/* The two sides STRETCH to one height. One carries an attribution block and the
   other a picker, so they are never the same length on their own — and two
   bordered boxes of different heights side by side read as a layout that has
   slipped rather than as a pair (§3.10e2's arcade, at the size of a form). The
   shorter one simply has room at the foot, which is where the still shelf grows
   into anyway. */
.cmp-sides{display:grid;grid-template-columns:1fr 1fr;gap:1rem;
  margin:.6rem 0 .8rem}
.cmp-side{min-width:0;border:2px solid rgba(59,42,23,.3);padding:.6rem .7rem;
  background:var(--paper)}
.cmp-side-title{font-family:var(--utility);font-size:.72rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--oxblood);margin:0 0 .5rem}
.cmp-srcpick{display:flex;flex-wrap:wrap;gap:.2rem 1rem;margin-bottom:.5rem}
.cmp-radio{display:inline-flex;align-items:center;gap:.3rem;
  font-family:var(--utility);font-size:.76rem}
.cmp-attrib{border-top:1px solid rgba(59,42,23,.2);margin-top:.5rem;padding-top:.5rem}
/* ON WHAT BASIS (§3.12g6) — STACKED, unlike the source row above it, and not
   only to tell the two apart: these labels are whole clauses rather than
   two-word names, and a wrapping flex row would break one of them mid-phrase
   with the radio stranded on the line above. */
.cmp-usepick{display:flex;flex-direction:column;gap:.15rem;margin-bottom:.5rem}
/* WHERE THE FIGURE CAME FROM (§3.2b) — three controls that are one decision, so
   they are one block rather than three cells scattered across the grid. The
   inner fields lose their bottom margin: stacked at .7rem each they made a
   single rating taller than the four boxes beside it. */
.rating-field .field{margin-bottom:.35rem}
.rating-field .field:last-child{margin-bottom:0}
/* READ-ONLY under IMDb, because the box beside it is what writes the figure —
   two editable boxes for one number is two sources of truth at the size of a
   form. It has to LOOK inert or an editor types into it and wonders why
   nothing happens. */
.rating-field input[readonly]{background:rgba(59,42,23,.10);
  color:rgba(36,28,18,.78);cursor:not-allowed}
/* The crop preview (§3.12g4). AT THE REAL RATIO the page draws — 4:3, the same
   `aspect-ratio` .or-side img carries — because a preview at any other shape
   would have an editor lining up a crop that is not the one a reader gets. */
.cmp-crop{margin:0}
.cmp-crop[hidden]{display:none}
.cmp-crop-box{width:100%;max-width:16rem;aspect-ratio:4/3;border:2px solid var(--ink);
  background:rgba(59,42,23,.12);overflow:hidden}
.cmp-crop-box img{width:100%;height:100%;display:block}
/* Full width under the frame, so the travel of the slider reads as the travel
   of the crop rather than as an unrelated control beside it. */
.cmp-crop-range{display:block;width:100%;max-width:16rem;margin:.4rem 0 .3rem}
.cmp-crop-range:disabled{opacity:.45}
/* Who the pair is about. A wrapping row rather than a column: the roster is
   usually two or three names and a column of three checkboxes spends a third of
   the sub-panel's height saying so. */
/* Two rows, one control (§3.12g7): who the pair is about, and which thread it
   speaks to. Their own class names sharing one set of declarations rather than
   one name doing both — §3.11i3's rule, and here it is load-bearing on the
   checking side: a check that means "every figure the entry names is offered"
   must not start counting the thread ticks too. */
.cmp-figs,.cmp-threads{display:flex;flex-wrap:wrap;gap:.25rem 1rem}
.cmp-figs-one,.cmp-threads-one{display:inline-flex;align-items:center;gap:.3rem;
  font-family:var(--utility);font-size:.78rem}
/* The picker's own shelf. `object-fit:cover` on a fixed box, so twelve stills
   of different proportions read as one row to scan rather than a ragged edge. */
.cmp-shelf{display:flex;flex-wrap:wrap;gap:.4rem;margin:.5rem 0 0}
.cmp-thumb{padding:0;border:2px solid rgba(59,42,23,.3);background:none;
  cursor:pointer;line-height:0}
.cmp-thumb img{width:88px;height:50px;object-fit:cover;display:block}
.cmp-thumb.on{border-color:var(--oxblood);box-shadow:0 0 0 2px rgba(158,43,37,.3)}
/* What the rest of the programme has already compared. Tinted apart from the
   chips below, because these are OFFERS rather than things this episode holds —
   a reader glancing at the panel must not read a suggestion as a saved pair. */
.cmp-sug{margin:.5rem 0 0}
.cmp-sug:empty{display:none}
.cmp-sug-row{display:flex;align-items:baseline;gap:.6rem;padding:.3rem .5rem;
  border:2px dashed rgba(59,42,23,.35);background:rgba(216,192,120,.14);
  margin-top:.3rem}
.cs-subject{font-family:var(--body);font-weight:700;flex:0 1 auto;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cs-meta{font-family:var(--utility);font-size:.72rem;color:rgba(36,28,18,.78);
  flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cmp-rows{list-style:none;padding:0;margin:.5rem 0 0;display:flex;
  flex-direction:column;gap:.35rem}
/* min-width:0 on the flexible cell, because a grid or flex item's automatic
   minimum is its content's intrinsic width — §4 records that trap five times,
   twice on an admin list row. The meta cell clips; its full text is on `title`. */
.cmp-chip{display:flex;align-items:baseline;gap:.6rem;border:2px solid var(--ink);
  background:var(--paper);padding:.35rem .5rem}
.cc-subject{font-family:var(--body);font-weight:700;flex:0 1 auto;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cc-meta{font-family:var(--utility);font-size:.72rem;color:rgba(36,28,18,.78);
  flex:1 1 auto;min-width:0;overflow:hidden}
/* A pair that will not publish says so on itself, in the tone the rest of the
   admin uses for a refusal. */
.cc-bad{color:var(--oxblood);font-style:italic}
.cc-edit{background:none;border:none;cursor:pointer;font-family:var(--utility);
  font-size:.72rem;color:var(--lake);text-decoration:underline;padding:0 .2rem}
/* Selected through .cmp-say so it beats a bare .mini-note on specificity rather
   than on file order — this stylesheet's standing lesson (§4). */
.cmp-say.cmp-refused{color:var(--oxblood);border-left:3px solid var(--oxblood);
  padding-left:.5rem}
@media (max-width:900px){ .cmp-sides{grid-template-columns:1fr} }

/* --- statistics: cite & download --- */
.cite-block .btn{margin:.2rem 0 .6rem}
.cite-forms{border-top:2px solid var(--ink)}
.cite-row{display:grid;grid-template-columns:5.5rem minmax(0,1fr) 4.5rem;
  align-items:start;column-gap:.9rem;padding:.7rem .3rem;
  border-bottom:1px solid rgba(59,42,23,.2)}
.cite-style{font-family:var(--utility);font-size:.72rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--lake);padding-top:.15rem}
.cite-text{font-family:var(--body);font-size:.88rem;line-height:1.45;word-break:break-word}
.cite-text em{font-style:italic}
.cite-copy{font-family:var(--utility);font-size:.74rem;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--gold);
  padding:.25rem .5rem;box-shadow:2px 2px 0 rgba(59,42,23,.22)}
.cite-copy:hover{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
@media (max-width:640px){
  .cite-row{grid-template-columns:1fr auto;row-gap:.35rem}
  .cite-text{grid-column:1 / -1}
}


/* --- review: credit colophon (Directed by / Aired on) --- */
.credit-plate{display:flex;align-items:baseline;gap:.7rem;margin:1.3rem 0 .4rem;
  padding:.5rem .9rem;background:rgba(216,192,120,.16);
  border-left:5px solid var(--gold);
  border-top:1px solid rgba(59,42,23,.2);border-bottom:1px solid rgba(59,42,23,.2)}
.credit-plate .cp-label{font-family:var(--utility);font-size:.68rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--lake);flex:0 0 auto}
.credit-plate .cp-rule{flex:0 0 auto;width:16px;height:1px;background:var(--gold);align-self:center}
.credit-plate .cp-value{font-family:var(--display);font-size:1.3rem;font-weight:400;
  color:var(--oxblood);line-height:1.25}
@media (max-width:640px){
  .credit-plate{flex-wrap:wrap;gap:.2rem .5rem;padding:.45rem .7rem}
  .credit-plate .cp-rule{display:none}
  .credit-plate .cp-value{font-size:1.15rem;flex:1 1 100%}
}

/* --- admin periods: keep the action buttons inside their own row --- */
.period-row .btn{
  align-self:center;margin:0;padding:.4rem .75rem;font-size:.76rem;line-height:1.1;
  box-shadow:2px 2px 0 rgba(59,42,23,.22);
}
.period-row .btn:active{box-shadow:1px 1px 0 rgba(59,42,23,.22)}

/* --- browse: jump from a period filter to the timeline --- */
/* Verdigris rather than oxblood: this sits among oxblood links and filter
   controls, and the base `a{color:var(--oxblood)}` was winning often enough
   to leave oxblood text on an oxblood ground. The `a.` prefix raises the
   specificity so the light text always holds. */
a.see-timeline,.see-timeline{
  display:inline-block;font-family:var(--utility);font-size:.78rem;
  text-decoration:none;color:#F2EFE4;background:var(--moss);
  border:2px solid var(--ink);padding:.35rem .8rem;
  box-shadow:2px 2px 0 rgba(59,42,23,.28);white-space:nowrap}
a.see-timeline:hover,a.see-timeline:focus-visible{
  color:#FFFFFF;background:#2F5436;border-color:var(--gold)}
a.see-timeline:focus-visible{outline:3px solid var(--gold);outline-offset:2px}

/* --- saltiness range filter --- */
.salt-range-dash{font-family:var(--utility);font-size:.74rem;opacity:.75;margin:0 .1rem}
.browse-filters select[id$="SaltMin"],.browse-filters select[id$="SaltMax"]{min-width:5.2rem}
.filter-group select[id^="saltFilter"]{min-width:5rem}

/* --- compare mode: the analytical panel under the timeline --- */
.compare-analysis{max-width:1180px;margin:1rem auto 0;padding:0 1rem}
.cmp-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:1rem}
.cmp-col{border:2px solid var(--ink);background:var(--paper);
  box-shadow:3px 3px 0 rgba(59,42,23,.2);display:flex;flex-direction:column}
.cmp-col header{display:flex;align-items:baseline;gap:.45rem;flex-wrap:wrap;
  padding:.55rem .7rem;border-bottom:2px solid var(--ink)}
.cc-tag{font-family:var(--display);font-size:1.05rem;color:var(--paper);
  background:var(--ink);padding:0 .35rem;border-radius:2px;line-height:1.4}
.cmp-col-a .cc-tag{background:var(--lake)}
.cmp-col-b .cc-tag{background:var(--moss)}
.cmp-col-c .cc-tag{background:var(--oxblood)}
.cc-name{font-family:var(--body);font-weight:700;flex:1 1 auto;min-width:0}
.cc-range{font-family:var(--utility);font-size:.72rem;opacity:.75;white-space:nowrap}
.cc-stats{display:flex;gap:.9rem;flex-wrap:wrap;padding:.5rem .7rem;
  font-family:var(--utility);font-size:.76rem;background:rgba(216,192,120,.14);
  border-bottom:1px solid rgba(59,42,23,.2)}
.cc-stats strong{font-family:var(--display);font-size:1.05rem;color:var(--oxblood)}
.cc-note{font-family:var(--utility);font-size:.7rem;opacity:.75;padding:.35rem .7rem 0;margin:0}
.cc-list{list-style:none;margin:0;padding:.3rem .7rem .6rem;max-height:280px;overflow:auto}
.cc-list li{display:flex;align-items:baseline;gap:.4rem;padding:.28rem 0;
  border-bottom:1px solid rgba(59,42,23,.14)}
.cc-list li:last-child{border-bottom:none}
.cc-list a{font-family:var(--body);color:var(--ink);text-decoration:none;flex:1 1 auto;min-width:0}
.cc-list a:hover{color:var(--oxblood);text-decoration:underline}
.cc-shared{color:var(--gold-text);flex:0 0 auto}
.cc-nums{font-family:var(--utility);font-size:.7rem;opacity:.78;white-space:nowrap;flex:0 0 auto}
.cc-empty{font-family:var(--utility);font-size:.78rem;opacity:.75;padding:.6rem .7rem;margin:0}
@media (max-width:640px){ .cmp-cols{grid-template-columns:1fr} .cc-list{max-height:220px} }

/* --- admin: bulk edit --- */
.bulk-controls .btn{margin:.3rem .4rem .3rem 0}
.bulk-count{font-family:var(--utility);font-size:.78rem;opacity:.85;margin-left:.4rem}
.bulk-list{margin-top:1rem;border:2px solid var(--ink);background:var(--paper)}
.bulk-head{padding:.5rem .7rem;border-bottom:2px solid var(--ink);
  background:rgba(216,192,120,.16)}
.bulk-all{display:inline-flex;align-items:center;gap:.4rem;
  font-family:var(--utility);font-size:.8rem;cursor:pointer}
.bulk-rows{max-height:420px;overflow:auto}
/* The sub column was a FIXED 7rem with `white-space:nowrap` and no clipping,
   which held "Film · 2004" and nothing longer. Adding "· matched Trojan War"
   to it overflowed the track and painted straight over the tags beside it —
   a grid track does not clip what overflows it, which is the trap §4 already
   records about the timeline embed's label column, walked into a second time.

   So it is a flexible share now and it CLIPS. `min-width:0` is the half that
   is easy to miss: a grid item's default is `auto`, its content's intrinsic
   width, so `minmax(0,…)` on the track is not enough on its own. The full
   text stays reachable through the cell's own `title`. */
/* The fifth track is the saltiness the bulk setter writes. It is `minmax(0,…)`
   like its neighbours and NOT a fixed width: the longest emblem this can hold
   is "Salt Carthage · 5/5", and a fixed track sized for that would not shrink
   on a narrow panel while a track sized for "Grain · 1/5" would be painted
   straight over by the other one — a grid track does not clip what overflows
   it, which is the trap §4 records four times, twice on this very row. */
.bulk-row{display:grid;
  grid-template-columns:1.4rem minmax(0,2fr) minmax(0,1.6fr) minmax(0,1.4fr) minmax(0,8rem);
  align-items:center;column-gap:.7rem;padding:.4rem .7rem;cursor:pointer;
  border-bottom:1px solid rgba(59,42,23,.16)}
.bulk-row:nth-child(odd){background:rgba(216,192,120,.09)}
.bulk-row:hover{background:rgba(158,43,37,.07)}
.bl-title,.bl-sub,.bl-tags,.bl-salt{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* The emblem is drawn for a shelf card, where it sits under a poster with room
   around it; here it is one cell of a line, so the top margin goes — the same
   local re-fit `.cr-salt` and `.pdt-salt` already make for their own contexts.
   The TYPE is left at the size it is everywhere else on the site: the widest
   emblem ("Salt Carthage · 5/5") measures 120px, so the track is 8rem to leave
   it slack rather than the type being shrunk to fit a narrower one. It is a
   number an editor reads before a press that overwrites verdicts, and §4 is a
   list of contrast and legibility failures found at exactly these sizes. */
.bl-salt .salt-compact{margin-top:0;gap:.2rem}
/* A PROGRAMME'S HEADING, and its episodes nested under it. The tint and the
   rule above it are what stop a run of ten episodes reading as ten unrelated
   rows.

   THE INDENT IS ON THE TITLE CELL, NOT ON THE ROW. Padding on the row shifts
   every track with it — measured at 12px, so an episode's own sub and tags
   columns stopped lining up with the film rows above and below, and this is a
   list read DOWN its columns as much as across them. Indenting one cell keeps
   the checkboxes in one line to tick down and the other three columns where
   they were; the rule down its left edge is what says the row is inside
   something.

   Selected through .bulk-row, so it beats the striping and the hover on
   SPECIFICITY rather than on file order — a bare .bl-series is (0,1,0) and
   :nth-child(odd) is (0,2,0), so the stripe would otherwise paint over the
   heading on every other one (§4's standing lesson about this stylesheet). */
.bulk-row.bl-series{background:rgba(216,192,120,.22);
  border-top:1px solid rgba(59,42,23,.3)}
.bulk-row.bl-series:hover{background:rgba(216,192,120,.3)}
.bulk-row.bl-series .bl-title{font-size:.98rem;letter-spacing:.01em}
.bulk-row.bl-ep .bl-title{padding-left:.7rem;
  border-left:2px solid rgba(59,42,23,.24)}
.bl-title{font-family:var(--body);font-weight:700;font-size:.92rem}
/* A row that is off the site. The WORDS are the carrier and the tint only
   reinforces them (§7) — an editor about to bulk-edit twenty rows needs to know
   which of them no reader can reach, and a colour cannot say that.

   Selected through .bulk-row so it beats :nth-child(odd) at (0,2,0) on
   SPECIFICITY rather than on file order, which is this stylesheet's standing
   lesson (§4) and exactly what .bl-series two rules up is doing. */
.bulk-row.bl-off{background:rgba(59,42,23,.1)}
.bulk-row.bl-off:hover{background:rgba(59,42,23,.16)}
.bulk-row.bl-off .bl-title{text-decoration:line-through;
  text-decoration-color:rgba(59,42,23,.5)}
.bl-offmark{font-family:var(--utility);font-size:.62rem;letter-spacing:.08em;
  text-transform:uppercase;text-decoration:none;white-space:nowrap;
  color:var(--paper);background:var(--ink);padding:.05rem .3rem}
/* A row this panel will not touch (§6d3). The same word-shaped mark as the one
   above it, in the site's own lake blue rather than ink, because the two say
   different things about the same row and a reader of this list may meet both
   at once: one is about whether READERS can reach the entry, the other about
   whether a SWEEP can. Outlined rather than filled, so a locked row does not
   read as louder than a withdrawn one. */
.bl-lockmark{font-family:var(--utility);font-size:.62rem;letter-spacing:.08em;
  text-transform:uppercase;text-decoration:none;white-space:nowrap;
  color:var(--lake);border:1px solid var(--lake);padding:0 .28rem}
/* No tint on the row and no strike-through: the entry is perfectly ordinary in
   every respect a reader can see, and only this panel treats it differently.
   The mark is the whole of the signal, which is what §7 asks for anyway. */
.bulk-row.bl-held .bl-title{text-decoration:none}
.bl-sub{font-family:var(--utility);font-size:.7rem;opacity:.75}
.bl-tags{font-family:var(--utility);font-size:.7rem;color:var(--lake)}
@media (max-width:640px){
  .bulk-row{grid-template-columns:1.4rem minmax(0,1fr);row-gap:.15rem}
  .bl-sub,.bl-tags,.bl-salt{grid-column:2}
}

/* --- admin: duplicate warning --- */
.dup-warn{margin:.6rem 0;padding:.6rem .8rem;border:2px solid var(--oxblood);
  background:rgba(158,43,37,.08);font-family:var(--utility);font-size:.82rem}
.dup-warn strong{font-family:var(--body)}
.dup-warn ul{margin:.4rem 0 0;padding-left:1.2rem}
.dup-warn li{padding:.1rem 0}
.dup-warn button{font-family:var(--utility);font-size:.76rem;background:none;border:none;
  padding:0;cursor:pointer;color:var(--oxblood);text-decoration:underline}

/* ============================================================
   Scrollbars — every scrollable surface on the site, not a list of
   selectors that has to be kept in step with new panels.
   ============================================================ */
html{scrollbar-width:thin;scrollbar-color:var(--oxblood) var(--paper-deep)}
*{scrollbar-width:thin;scrollbar-color:var(--oxblood) var(--paper-deep)}

::-webkit-scrollbar{width:11px;height:11px}
::-webkit-scrollbar-track{background:var(--paper-deep);border:1px solid rgba(59,42,23,.25)}
::-webkit-scrollbar-thumb{background:var(--oxblood);border:1px solid var(--ink)}
::-webkit-scrollbar-thumb:hover{background:var(--oxblood-deep)}
::-webkit-scrollbar-corner{background:var(--paper-deep)}

/* --- compare: illuminated A/B/C initials on poster cards --- */
.slot-marks{position:absolute;top:8px;left:8px;z-index:3;display:flex;gap:3px}
.slot-mark{
  display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;font-family:var(--display);font-size:1rem;line-height:1;
  color:var(--paper);border:2px solid var(--ink);
  box-shadow:1px 1px 0 rgba(59,42,23,.4);
}
.slot-mark.slot-a{background:var(--lake)}
.slot-mark.slot-b{background:var(--moss)}
.slot-mark.slot-c{background:var(--oxblood)}

/* --- admin: list filters --- */
.admin-filter{display:flex;flex-wrap:wrap;gap:.9rem;align-items:flex-end;
  margin:.8rem 0 .4rem;padding:.7rem .8rem;
  border:2px dashed var(--ink);background:rgba(59,42,23,.04)}
.admin-filter .field{margin:0;min-width:11rem}
.admin-filter .field label{font-size:.7rem}
/* A CEILING AS WELL AS A FLOOR. A select is as wide as its widest option, and
   the Period list carries "American Civil Rights Movement  (1954–1968)" — which
   measured 423px and pushed the two controls beside it onto a row of their own.
   The names are still readable at 16rem and the full one is in the open list. */
.admin-filter select{min-width:11rem;max-width:16rem}
/* The search box wants more room than a select and less than the whole row: at
   `flex:1 1 16rem` it took every spare pixel (692 of 912) and left Era stranded
   beside it. It sits at a comfortable measure and does not grow. Styled through
   `.admin-filter .field input` because the kit's `input()` emits a bare <input>
   with no type attribute, so `input[type=text]` would match none of them. */
.admin-filter .field:first-child{flex:0 1 18rem}
.admin-filter .field input{min-width:0;width:100%}
.admin-filter .clear-filters{margin-bottom:.35rem}
.admin-count{display:inline-block;font-family:var(--utility);font-size:.76rem;
  opacity:.85;margin:.3rem 0 .4rem}
.admin-list .row.on{background:var(--oxblood);color:var(--paper)}
.admin-list .row.on .meta{color:var(--paper);opacity:.85}
@media (max-width:640px){
  .admin-filter{gap:.5rem}
  .admin-filter .field,.admin-filter select{min-width:0;width:100%}
}

/* --- admin: publish diff --- */
.diff-report{margin-top:.7rem}
.diff-clean{font-family:var(--utility);font-size:.86rem;color:var(--moss)}
.diff-summary{font-family:var(--utility);font-size:.86rem;color:var(--oxblood);margin-bottom:.6rem}
.diff-group{margin:.6rem 0;border-left:4px solid var(--ink);padding-left:.7rem}
.diff-group.added{border-left-color:var(--moss)}
.diff-group.removed{border-left-color:var(--oxblood)}
.diff-group.changed{border-left-color:var(--lake)}
.diff-group h4{font-family:var(--utility);font-size:.78rem;letter-spacing:.06em;
  text-transform:uppercase;margin:0 0 .25rem}
.diff-group.added h4{color:var(--moss)}
.diff-group.removed h4{color:var(--oxblood)}
.diff-group.changed h4{color:var(--lake)}
.diff-group ul{list-style:none;margin:0;padding:0}
.diff-group > ul > li{font-family:var(--body);font-size:.9rem;padding:.15rem 0}
.dc-title{font-weight:700}
.dc-fields{margin:.1rem 0 .3rem .8rem !important}
.dc-fields li{display:flex;flex-wrap:wrap;gap:.4rem;align-items:baseline;
  font-family:var(--utility);font-size:.76rem;padding:.1rem 0}
.dc-field{min-width:6rem;color:var(--lake)}
.dc-from{opacity:.7;text-decoration:line-through}
.dc-arrow{opacity:.6}
.dc-to{color:var(--ink);font-weight:700}
@media (max-width:640px){ .dc-fields li{gap:.2rem} .dc-field{min-width:0;flex:1 1 100%} }

/* --- admin: choosing what a publish carries ------------------------------
   One file per row, because a file is what publish actually commits. */
.pub-pick{margin:.2rem 0 .8rem;padding:.6rem .8rem;border:2px solid var(--ink);background:#F5EFE0}
.pub-pick > p{font-family:var(--utility);font-size:.74rem;margin:0 0 .5rem;opacity:.75}
.pub-row{display:flex;align-items:baseline;gap:.5rem;font-family:var(--utility);font-size:.8rem;padding:.15rem 0}
.pub-row code{font-size:.78rem}
.pub-row .pub-what{opacity:.7}
.pub-held{font-family:var(--utility);font-size:.76rem;color:var(--oxblood);margin:.5rem 0 0}

/* --- admin: click feedback ------------------------------------------------
   A button that does nothing on press is indistinguishable from a broken one,
   which is exactly how the silent save failure looked. Every control now
   depresses, and a busy state is available for anything that takes a moment. */
.btn, .admin-tabs button, .val-badge, .undo-btn, .cite-copy,
.period-row .btn, .credit-pager button, .thread-pager button, .browse-tabs button{
  transition:transform .06s ease, box-shadow .06s ease, background .12s ease;
}
.btn:active, .admin-tabs button:active, .undo-btn:active, .cite-copy:active,
.period-row .btn:active, .credit-pager button:active, .thread-pager button:active{
  transform:translate(2px,2px);
  box-shadow:none !important;
}
.btn:focus-visible, .admin-tabs button:focus-visible{
  outline:3px solid var(--gold); outline-offset:2px;
}
.btn[disabled]{opacity:.45;cursor:not-allowed;transform:none}
.btn.busy{position:relative;color:transparent !important}
.btn.busy::after{
  content:"\2026";position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  color:var(--paper);font-family:var(--display);font-size:1.1rem;letter-spacing:.1em;
}
.btn.secondary.busy::after{color:var(--ink)}

/* the status line should be impossible to miss when something goes wrong */
.admin-status-error{
  color:var(--paper) !important;background:var(--oxblood);
  border:2px solid var(--ink);padding:.4rem .7rem;opacity:1 !important;
  font-family:var(--utility);
}
.admin-status-ok{color:var(--moss);opacity:1 !important}

/* --- year flavour text, plain and quoted --- */
.year-banner .sub-quote{margin:.3rem auto 0;max-width:46rem;border:none;padding:0}
.year-banner .sq-text{font-family:var(--body);font-style:italic;font-size:1.05rem;
  color:var(--ink);opacity:.9;margin:0}
.year-banner .sq-credit{font-family:var(--utility);font-size:.76rem;letter-spacing:.04em;
  color:var(--oxblood);margin-top:.25rem}
.year-banner .sq-credit cite{font-style:normal;color:var(--lake)}

/* --- admin: years / flavour text --- */
.year-results{display:flex;flex-direction:column;gap:.25rem;max-height:280px;overflow:auto;margin-top:.5rem}
.year-hit{display:flex;align-items:baseline;gap:.7rem;text-align:left;cursor:pointer;
  background:var(--paper);border:2px solid var(--ink);padding:.35rem .6rem;font-family:var(--body)}
.year-hit:hover{background:rgba(216,192,120,.2)}
.year-hit.on{background:var(--oxblood);color:var(--paper);border-color:var(--gold)}
.yh-label{font-weight:700;flex:0 0 auto;min-width:7rem}
.yh-meta{font-family:var(--utility);font-size:.72rem;opacity:.8}
.year-hit.on .yh-meta{opacity:.9}
.year-editor h3{font-family:var(--display);color:var(--oxblood);font-weight:400;margin-bottom:.5rem}
.flavour-list{list-style:none;margin:.4rem 0 1rem;padding:0;display:flex;flex-direction:column;gap:.4rem}
.flavour-item{position:relative;border:2px solid var(--ink);background:var(--paper);
  padding:.5rem 2rem .5rem .7rem}
.flavour-item.is-quote{border-left:5px solid var(--lake);background:rgba(39,75,142,.05)}
.fi-body{font-family:var(--body);font-size:.95rem}
.flavour-item.is-quote .fi-body{font-style:italic}
.fi-credit{font-family:var(--utility);font-size:.72rem;color:var(--oxblood);margin-top:.2rem}
.flavour-item .tc-remove{position:absolute;top:.35rem;right:.4rem}
.flavour-add{border-top:2px dashed var(--ink);padding-top:.8rem}
.quote-fields{margin:.3rem 0 .5rem;padding-left:1.6rem;border-left:3px solid var(--lake)}

/* --- timeline: why it is narrowed, and how to undo it --- */
.credit-banner{max-width:1180px;margin:.8rem auto 0;padding:.5rem .9rem;
  display:flex;align-items:center;gap:.9rem;flex-wrap:wrap;
  background:rgba(39,75,142,.09);border:2px solid var(--lake);
  box-shadow:2px 2px 0 rgba(59,42,23,.2)}
.credit-banner .cb-what{font-family:var(--display);font-size:1.15rem;color:var(--lake)}
.credit-banner .cb-count{font-family:var(--utility);font-size:.76rem;opacity:.85}
.credit-banner .cb-clear{margin-left:auto;font-family:var(--utility);font-size:.76rem;
  cursor:pointer;background:var(--paper);color:var(--oxblood);
  border:2px solid var(--oxblood);padding:.25rem .7rem}
.credit-banner .cb-clear:hover{background:var(--oxblood);color:var(--paper)}
/* A LOCATION FILTER IS GREEN, because a location is green everywhere else on
   the site — `.rail-locations`, /locations' own chips, the coverage map's
   legend. This banner was ultramarine for all five kinds, so "Titles set in
   California" was drawn in the colour the site uses for THREADS.
   One prefix selector for all three location kinds (plain, grouped, tree), so a
   fourth is caught without anybody remembering to add it. The heading takes the
   darker green `.rail-locations` already uses for text: --moss is a border
   weight and does not clear 4.5:1 as type on parchment. */
.credit-banner[data-credit-kind^="location"]{
  background:rgba(62,107,69,.10);border-color:var(--moss)}
.credit-banner[data-credit-kind^="location"] .cb-what{color:#2F5436}

/* --- and the way onward, where what is narrowing the rule has a page ---
   The search box lands a period and a figure on the TIMELINE rather than
   leaving for their pages, so this is the plate that offers the page — in the
   same eyeline as the filter and directly under the banner explaining it.

   Its own class names sharing Browse's look rather than its names: `.see-
   timeline` is that page's plate and a second surface reachable by one
   selector is how a check that means one starts counting both (§3.11i3). The
   moss ground is the same one Browse's plate carries, so a reader who has met
   it there recognises it here; the arrow is aria-hidden and the label says
   where it goes in words (§7). */
.timeline-about{max-width:1180px;margin:.5rem auto 0;padding:0 .9rem;
  display:flex;flex-wrap:wrap;gap:.6rem}
a.tl-about{font-family:var(--utility);font-size:.82rem;text-decoration:none;
  background:var(--moss);color:#F2EFE4;border:2px solid var(--ink);
  padding:.3rem .8rem;box-shadow:2px 2px 0 rgba(59,42,23,.25)}
a.tl-about:hover,a.tl-about:focus-visible{background:var(--ink)}
a.tl-about:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
@media print{ .timeline-about{display:none} }

/* credit rows are links now */
a.credit-row{text-decoration:none;color:inherit}
a.credit-row:hover{background:rgba(158,43,37,.08)}
a.credit-row:focus-visible{outline:3px solid var(--gold);outline-offset:-2px}
a.sc-big{display:block;text-decoration:none;color:var(--oxblood)}
a.sc-big:hover{text-decoration:underline}

/* --- list pagination (browse, filmographies) --- */
.list-pager{display:flex;align-items:center;justify-content:center;gap:.9rem;
  margin:1rem 0 .4rem;font-family:var(--utility);font-size:.8rem}
.list-pager button{font-family:var(--utility);font-size:.8rem;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--gold);
  padding:.35rem .9rem;box-shadow:2px 2px 0 rgba(59,42,23,.24)}
.list-pager button:hover:not(:disabled){background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.list-pager button:active:not(:disabled){transform:translate(2px,2px);box-shadow:none}
.list-pager button:disabled{opacity:.4;cursor:default;box-shadow:none}
.list-pager .pg-count{color:rgba(59,42,23,.8)}

/* --- review: the original title, and the language it was made in ---
   TWO CLASSES, one look. They are two different facts and a check asserts
   that the title block is omitted where there is no original title — so the
   language line sharing `orig-title` made "has a language" indistinguishable
   from "has an original title", and the first entry to carry one without the
   other went red. §4's "a class name already spoken for", from the other
   end: not a collision with somebody else's component, but a name reused for
   a second meaning inside one. The selectors are shared; the names are not. */
/* FOUR classes now, one look. Runtime and genre join on exactly the same
   terms: each is a distinct fact with a check that can ask about it on its own,
   and folding any of them into a neighbour's class is what made "has a
   language" answer a question about the original title. */
.orig-title,.orig-lang,.title-runtime,.title-genres{display:flex;align-items:baseline;
  gap:.5rem;flex-wrap:wrap;margin:.2rem 0 0}
.orig-title .ot-label,.orig-lang .ot-label,
.title-runtime .ot-label,.title-genres .ot-label{font-family:var(--utility);font-size:.64rem;
  letter-spacing:.16em;text-transform:uppercase;color:var(--lake);flex:0 0 auto}
.orig-title .ot-value,.orig-lang .ot-value,
.title-runtime .ot-value,.title-genres .ot-value{font-family:var(--body);font-style:italic;
  font-size:1rem;color:var(--ink);opacity:.9}
/* Upright, unlike the three italic values beside it: a runtime is a measurement
   and a genre is a label, where an original title and a language name are words
   from another tongue — which is what the italic was for. */
.title-runtime .ot-value,.title-genres .ot-value{font-style:normal;
  font-variant-numeric:tabular-nums}
/* Each genre is a link into /browse — the one facet a review page named and
   could not be followed from. Oxblood like every other tag link on the page,
   and the separator is aria-hidden so a screen reader hears a list of names
   rather than a run of middots. */
.title-genres .ot-value a{color:var(--oxblood);text-decoration:none}
.title-genres .ot-value a:hover,
.title-genres .ot-value a:focus-visible{text-decoration:underline;
  text-underline-offset:2px}
.tg-sep{opacity:.5}

/* --- timeline: asking for a title on an empty year ---
   Same face and weight as the review page's dispute line, because it is the
   same kind of offer: one small link into the contact form, under the thing
   it is about. */
.empty-ask{font-family:var(--utility);font-size:.72rem;text-align:center;
  margin:1rem 0 0;padding-top:.7rem;border-top:1px dashed rgba(59,42,23,.3)}
.empty-ask a{color:var(--oxblood)}
.empty-ask .ea-note{opacity:.72}

/* --- timeline: what the rule is currently showing ---
   A caption, so it sits under the rule the way the era hint sits over it and
   does not compete with either. */
.tl-scope{font-family:var(--utility);font-size:.7rem;letter-spacing:.06em;
  text-align:center;color:var(--lake);opacity:.9;margin:.5rem 0 0}

/* --- review: when the entry was last gone over ---
   Quiet on purpose. It qualifies the two figures above it rather than
   competing with them, so it reads as a marginal note in the same utility
   face the labels use. */
.entry-checked{display:flex;align-items:baseline;gap:.4rem;flex-wrap:wrap;
  margin:.9rem 0 0;font-family:var(--utility);font-size:.68rem;color:var(--lake)}
.entry-checked .ec-label{text-transform:uppercase;letter-spacing:.16em;flex:0 0 auto}
/* The dotted rule is the only affordance saying the tooltip is there — a
   `title` on a bare date announces itself to nobody. */
.entry-checked time{border-bottom:1px dotted currentColor;cursor:help}

/* --- contact: optional field marker --- */
.field-optional{font-family:var(--utility);font-size:.62rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--lake);opacity:.85;margin-left:.4rem}

/* --- headings: one h1 per page, sized to its context --- */
/* The homepage h1 is for crawlers and screen readers; the masthead carries the
   visual identity, so this sits quietly above the era bar. */
.page-h1{
  font-family:var(--utility);font-size:1rem;letter-spacing:.08em;
  text-align:center;color:rgba(59,42,23,.7);font-weight:400;
  margin:.6rem auto .6rem;max-width:60rem;text-transform:none;
}
/* Content pages: an h1 should look like the h2 it replaced. */
.content-page > h1,.browse-page > h1,.stats-page > h1{
  font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.9rem;letter-spacing:.02em;margin-bottom:.4rem;
}
/* Review and filmography titles are the h1 now. */
h1.entry-title{
  font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:2.1rem;line-height:1.12;letter-spacing:.01em;margin:0;
}
@media (max-width:640px){
  h1.entry-title{font-size:1.6rem}
  .content-page > h1,.browse-page > h1,.stats-page > h1{font-size:1.55rem}
}

/* ============================================================
   The Breakdown — four judgements behind a saltiness score
   ============================================================ */
.breakdown{margin-top:2rem;border-top:3px double var(--gold);padding-top:1rem}
.breakdown h3{font-family:var(--utility);color:var(--lake);text-transform:none;
  letter-spacing:.06em;margin-bottom:.2rem}
.bd-intro{font-family:var(--body);font-size:.86rem;font-style:italic;
  opacity:.8;margin:0 0 .8rem}

/* ---- on screen, and on the record (§3.12g) --------------------------------
   Deliberately the Breakdown's own furniture — the double gold rule, the lake
   heading, the italic intro — because the two are one argument in two forms and
   sit directly against each other on the page. §3.10g's borrowing test asks
   whether the two are the same KIND of thing, and here they are: both are the
   evidence behind one verdict.

   A DIPTYCH, not a table and not a slider. Two equal halves that STACK below
   the measure, because two 190px images side by side on a phone are two
   thumbnails and the whole point is that they can be looked at. */
.on-record{margin-top:2rem;border-top:3px double var(--gold);padding-top:1rem}
.on-record h3{font-family:var(--utility);color:var(--lake);text-transform:none;
  letter-spacing:.06em;margin-bottom:.2rem}
/* Selected through .on-record: review.html's main is not a .content-page, but
   a period or series page reusing this block later would be, and .content-page p
   is (0,1,1) and beats a bare class — §4's standing lesson about this
   stylesheet, applied before it bites rather than after. */
.on-record .or-intro{font-family:var(--body);font-size:.86rem;font-style:italic;
  opacity:.8;margin:0 0 .9rem;max-width:44rem}
.or-pair{margin:0 0 1.4rem;padding:0}
.or-pair:last-child{margin-bottom:.2rem}
/* ---- a filmography's board: one record, every screen (§3.12g4) ----
   A review draws pairs; a filmography is about the PERSON, so the sitter is
   drawn once and every actor who has worn the face is ranged against them.
   The reference STICKS while the screens scroll past it, which is the whole
   point of drawing it once — a reader comparing the fourth still against the
   painting should not have to remember what the painting looked like. */
.fr-board{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,2.1fr);
  gap:1.2rem;align-items:start}
.fr-ref{margin:0;position:sticky;top:1rem}
/* The screens are a grid of their own so a person with nine credits reads as a
   contact sheet rather than a column — `auto-fill` rather than a fixed count,
   because how many fit is a fact about the width and not about the archive. */
.fr-screens{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(13rem,100%),1fr));
  gap:1rem;min-width:0}
.fr-screen{margin:0;min-width:0}
@media (max-width:760px){
  /* Below the width where two columns are two thumbnails, the reference goes
     back to the top of the flow and stops sticking — a sticky box on a phone
     eats a third of the viewport for the whole scroll. */
  .fr-board{grid-template-columns:1fr}
  .fr-ref{position:static;max-width:20rem}
}
.or-sides{display:grid;grid-template-columns:1fr 1fr;gap:.9rem;align-items:start}
.or-side{display:flex;flex-direction:column;min-width:0}
/* The images are the point, so they are given a shared aspect and cropped to it
   rather than left to whatever proportion each source happens to have: a
   portrait daguerreotype beside a 16:9 still, both at their natural ratio, puts
   the two subjects at wildly different sizes and the comparison stops being
   one. `object-fit:cover` keeps the subject centred at the cost of the edges,
   which is the right trade for a face and for a battle line alike. */
.or-side img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;
  border:2px solid var(--ink);background:rgba(59,42,23,.06);
  box-shadow:3px 3px 0 rgba(59,42,23,.22)}
/* WORDS, not position or colour (§7). A reader must not have to learn that the
   left one is the real one. */
.or-tag{font-family:var(--utility);font-size:.66rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--paper);background:var(--ink);
  align-self:flex-start;padding:.1rem .4rem;margin-top:.45rem}
.or-screen .or-tag{background:var(--oxblood)}
/* .78 on the COLOUR rather than opacity: opacity fades ink toward the paper at
   exactly the sizes least able to afford it, which §4 records costing two
   strings their AA rating at 12.8px and 10.88px. */
.or-credit{font-family:var(--utility);font-size:.66rem;line-height:1.45;
  color:rgba(36,28,18,.78);margin-top:.3rem}
.or-credit a{color:var(--lake)}
/* THE BASIS, in the slot a licence occupies (§3.12g6). Italic because it is a
   statement about why the archive may show the picture rather than the NAME of
   a licence, which is what the plain text beside it always is — and the
   distinction is carried by the words themselves, so the styling reinforces
   rather than carries it (§7). The dotted rule and the help cursor are what
   say the precise claim is in the title. */
.or-basis{font-style:italic;border-bottom:1px dotted rgba(36,28,18,.45);
  cursor:help}
/* WHERE A PICTURE THIS ARCHIVE DOES NOT HOST CAME FROM. The dotted rule and
   the help cursor are the basis line's, because they say the same thing — the
   full sentence is in the title — and it is deliberately NOT italic: this is a
   plain statement of provenance beside the name of an author, not a claim
   about permission. */
.or-host{border-bottom:1px dotted rgba(36,28,18,.45);cursor:help}
/* WHAT WAS DONE TO THE FIGURE (§3.2b), directly under the stars it qualifies.
   .mini-note already declares itself at both (0,1,0) and (0,2,0) so it wins
   inside a .content-page too (§4) — all this adds is the spacing, and the 44rem
   measure every run of prose on the site is set to. */
.rating-scale{margin:.3rem 0 0;max-width:44rem}
.or-cap{margin-top:.55rem}
.or-subject{display:block;font-family:var(--display);font-size:1.05rem;
  color:var(--oxblood);line-height:1.2}
/* WHICH TITLE MADE THIS ONE — drawn on a filmography and never on a review,
   where the title is the page's own <h1> (§3.12g2). The episode rides after the
   programme because the programme is what the pair stands for and the episode
   is where to find the scene. */
.or-from{display:block;font-family:var(--utility);font-size:.74rem;
  letter-spacing:.04em;margin-top:.1rem}
.or-from a{color:var(--lake)}
.or-ep{color:rgba(36,28,18,.78);font-style:italic}
.or-ep::before{content:" · "}
.or-note{display:block;font-family:var(--body);font-size:.86rem;
  color:rgba(36,28,18,.82);margin-top:.15rem;max-width:44rem}
@media (max-width:640px){
  .or-sides{grid-template-columns:1fr;gap:1rem}
}

.bd-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:0;
  border:3px solid var(--ink);background:var(--paper);
  box-shadow:3px 3px 0 rgba(59,42,23,.22)}
.bd-cell{display:flex;flex-direction:column;align-items:center;text-align:center;
  padding:.9rem .6rem 1rem;border-right:2px solid var(--ink);position:relative}
.bd-cell:last-child{border-right:none}
.bd-cell:nth-child(odd){background:rgba(216,192,120,.10)}

.bd-title{font-family:var(--utility);font-size:.72rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--oxblood);margin:0 0 .5rem;line-height:1.25}
.bd-art{width:52px;height:52px;color:var(--ink);opacity:.85;margin-bottom:.45rem}
.bd-art svg{width:100%;height:100%;display:block}

.bd-score{display:flex;align-items:baseline;gap:.1rem;line-height:1}
.bd-num{font-family:var(--display);font-size:2rem;color:var(--oxblood)}
.bd-of{font-family:var(--utility);font-size:.7rem;opacity:.6}
.bd-tier{font-family:var(--body);font-style:italic;font-size:.76rem;
  opacity:.8;margin-top:.15rem}
.bd-hint{font-family:var(--utility);font-size:.64rem;line-height:1.35;
  opacity:.66;margin-top:.45rem;max-width:14ch}

/* An unassessed category stays in the grid so the shape is honest. */
.bd-cell.unrated .bd-art{opacity:.32}
.bd-score.bd-none{font-family:var(--utility);font-size:.82rem;font-style:italic;
  color:rgba(59,42,23,.55);letter-spacing:.04em;padding-top:.45rem}
.bd-cell.unrated .bd-hint{opacity:.45}

@media (max-width:640px){
  .bd-grid{grid-template-columns:repeat(2,1fr)}
  .bd-cell{border-right:none;border-bottom:2px solid var(--ink)}
  .bd-cell:nth-child(odd){border-right:2px solid var(--ink)}
  .bd-cell:nth-child(3),.bd-cell:nth-child(4){border-bottom:none}
  .bd-num{font-size:1.7rem}
  .bd-art{width:44px;height:44px}
}
@media print{
  .bd-grid{box-shadow:none;border-width:1pt}
  .bd-cell{border-right-width:.75pt}
  .breakdown{page-break-inside:avoid}
}

/* --- The Breakdown: the argument behind each sub-score (§3.12h) ------------
   BELOW THE GRID, NOT INSIDE A CELL, and the reason is a measurement rather
   than a preference: .bd-grid is four equal columns, so a cell is about 166px
   at this page's own measure and a bulleted list of inaccuracies at 166px is a
   column of broken words. Stacked here they read at the page's full 44rem.

   The disclosure furniture is the year panel's (§3.11l) in its own namespace,
   never its class names — §4 records `pa-row` silently re-laying a whole table
   because a name was already spoken for, and two panels reachable by one
   selector is how a rule meant for one starts moving the other. */
.bd-notes{margin-top:1rem;display:flex;flex-direction:column;gap:.4rem}
.bd-note{border:1.5px solid rgba(59,42,23,.4);background:rgba(216,192,120,.10)}
.bd-note > summary{
  cursor:pointer;list-style:none;display:flex;align-items:center;
  gap:.5rem;flex-wrap:wrap;padding:.45rem .7rem;
  font-family:var(--utility);font-size:.74rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--lake)}
.bd-note > summary::-webkit-details-marker{display:none}
.bd-note > summary::marker{content:""}
.bd-note > summary:hover{color:var(--oxblood);background:rgba(158,43,37,.07)}
.bd-note > summary:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.bdn-chev{display:inline-block;color:var(--oxblood);font-size:.9rem;line-height:1;
  transition:transform .15s ease}
.bd-note[open] .bdn-chev{transform:rotate(90deg)}
.bdn-cat{min-width:0}
.bdn-score{font-family:var(--display);font-size:.95rem;color:var(--oxblood);
  border:1.5px solid currentColor;padding:0 .35rem;line-height:1.3}
/* Unrated is a WORD, never a nought and never an em dash (§3.2a) — a note may
   be written about a category nobody has scored, which is most of the point. */
.bdn-score.bdn-unrated{font-family:var(--utility);font-size:.7rem;font-style:italic;
  color:rgba(59,42,23,.78);border-color:rgba(59,42,23,.45);
  text-transform:none;letter-spacing:0}
/* The alpha is on the COLOUR, not on `opacity`: opacity fades ink toward the
   paper at exactly the sizes least able to afford it (§4). */
.bdn-cue{margin-left:auto;font-size:.64rem;color:rgba(59,42,23,.78);
  text-transform:uppercase}
.bdn-cue .bdn-hide{display:none}
.bd-note[open] .bdn-cue .bdn-show{display:none}
.bd-note[open] .bdn-cue .bdn-hide{display:inline}
.bdn-body{padding:.2rem 1rem .9rem;max-width:44rem}
/* Selected through .bd-note so these win on SPECIFICITY rather than on file
   order: a bare `.bdn-body p` is (0,1,1) and ties with `.content-page p`, and
   a tie is decided by whichever rule was written last (§3.9c, §4). */
.bd-note .bdn-body p{font-family:var(--body);font-size:.95rem;line-height:1.6;margin:.5rem 0}
.bd-note .bdn-body ul,.bd-note .bdn-body ol{margin:.5rem 0 .5rem 1.15rem;padding:0}
.bd-note .bdn-body li{font-family:var(--body);font-size:.95rem;line-height:1.6;margin:.3rem 0}
.bd-note .bdn-body blockquote{margin:.6rem 0 .6rem .8rem;padding-left:.8rem;
  border-left:3px solid var(--gold);font-style:italic}
@media print{
  .bd-note{border-width:.75pt;break-inside:avoid}
  .bdn-cue{display:none}
  /* Print has no way to open a disclosure, so everything is shown. */
  .bdn-body{display:block !important}
}

/* --- Revisions: what has changed here, and why (§3.12i) -------------------
   A ruled gold margin rather than a box, because this is a RECORD kept beside
   the page rather than a control on it — the same manuscript ruling a gloss
   hangs off (§3.10g), and gold rather than ink because a ruled line is not
   writing. */
/* --- who wrote this review ------------------------------------------------
   Directly above the revision log and drawn as its sibling: who wrote it and
   what has changed since are one pair, and a reader meets both immediately
   before being invited to say the verdict is wrong. The gold rule is the
   log's own, so the two read as one apparatus rather than as two boxes.

   `review.html`'s main is `.review-inner` and not a `.content-page`, so the
   bare classes here are not up against `.content-page p` at (0,1,1) — the
   trap §4 records for `.mini-note` on five pages. Measured rather than
   assumed: 15.2px for the name, 13.12px for the note. */
.review-byline{margin:2rem 0 0}
.rb-who{font-family:var(--body);font-size:.95rem;line-height:1.55;margin:.2rem 0 .4rem;
  padding-left:.85rem;border-left:3px solid var(--gold)}
.review-byline .mini-note{max-width:44rem;margin:0}
@media print{ .review-byline{break-inside:avoid} }

.revisions{margin:2rem 0 0}
.rev-lede{margin:.2rem 0 .7rem;max-width:44rem}
.rev-list{list-style:none;margin:0;padding:0;border-left:3px solid var(--gold)}
.rev-item{display:flex;gap:.8rem;align-items:baseline;flex-wrap:wrap;
  padding:.35rem 0 .35rem .85rem}
.rev-when{font-family:var(--utility);font-size:.7rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--oxblood);white-space:nowrap;flex:0 0 auto}
/* min-width:0 as well as the flex basis: a flex item's automatic minimum is
   its content's intrinsic width, which is §4's fixed-track trap in its
   flexbox spelling. */
.rev-note{font-family:var(--body);font-size:.95rem;line-height:1.55;
  color:var(--ink);flex:1 1 18rem;min-width:0}
@media print{ .revisions{break-inside:avoid} }

/* --- Cite this review (§3.12j) --------------------------------------------
   Ships hidden and is revealed by PP.wireCite, which removes it outright where
   there is no clipboard — so there is no state here for a page without
   JavaScript to be caught in. */
.cite-this{margin:2rem auto 0;max-width:44rem;
  border-top:2px solid rgba(59,42,23,.3);padding-top:.5rem}
.cite-this[hidden]{display:none}
.cite-this > summary{
  cursor:pointer;list-style:none;display:flex;align-items:center;
  gap:.5rem;flex-wrap:wrap;padding:.4rem .7rem;
  font-family:var(--utility);font-size:.74rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--lake);
  border:1.5px solid rgba(59,42,23,.4);background:rgba(216,192,120,.16)}
.cite-this > summary::-webkit-details-marker{display:none}
.cite-this > summary::marker{content:""}
.cite-this > summary:hover{color:var(--oxblood);border-color:var(--oxblood);
  background:rgba(158,43,37,.08)}
.cite-this > summary:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.ct-chev{display:inline-block;color:var(--oxblood);font-size:.9rem;line-height:1;
  transition:transform .15s ease}
.cite-this[open] .ct-chev{transform:rotate(90deg)}
.ct-head{min-width:0}
.ct-cue{margin-left:auto;font-size:.64rem;color:rgba(59,42,23,.78);
  text-transform:uppercase}
.ct-cue .ct-hide{display:none}
.cite-this[open] .ct-cue .ct-show{display:none}
.cite-this[open] .ct-cue .ct-hide{display:inline}
.ct-body{padding:.8rem 0 .2rem}
.ct-style{margin-bottom:.85rem}
.ct-row{display:flex;align-items:center;gap:.6rem;margin-bottom:.25rem}
.ct-name{font-family:var(--utility);font-size:.7rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--lake)}
.ct-copy{font-family:var(--utility);font-size:.66rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--lake);background:none;
  border:1.5px solid var(--lake);padding:.1rem .45rem;cursor:pointer;margin-left:auto}
.ct-copy:hover{background:var(--lake);color:var(--paper)}
.ct-copy:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
/* pre-wrap keeps BibTeX's own line breaks; `anywhere` is what stops a long URL
   pushing the page into a horizontal scroll at 375px. */
.ct-text{margin:0;font-family:var(--body);font-size:.86rem;line-height:1.5;
  color:var(--ink);white-space:pre-wrap;overflow-wrap:anywhere;
  background:rgba(216,192,120,.14);border:1px solid rgba(59,42,23,.28);
  padding:.5rem .6rem}
.ct-note{margin:.3rem 0 0;min-height:1.1em}
@media print{ .cite-this{display:none} }

/* --- admin: how far a write-up has got, on the row (§3.12l) ---------------
   SHAPE rather than colour. This admin already spends three colours on the
   editor's own flags (§6d) and a fourth meaning would collide with them, so a
   filled circle against a half circle carries the difference and the words ride
   in the title (§7). Ink, so contrast is never in question at this size. */
.bl-depth{font-size:.8rem;color:var(--ink);letter-spacing:0}
.bl-depth.rd-partial{color:rgba(59,42,23,.72)}

/* --- admin: a duplicate says what it carried (§3.12m) --- */
.dup-note{margin:.2rem 0 .8rem;border-left:3px solid var(--gold);padding-left:.6rem;
  max-width:52rem}

/* --- admin: the per-sub-score notes (§3.12h) ------------------------------
   Four shut disclosures rather than four boxes, so the section costs four rows
   until one is wanted — §6h's rule for the things set once or not at all. The
   summary says whether anything is in it, which is what makes shutting them
   affordable. */
.bdn-stack{display:flex;flex-direction:column;gap:.35rem}
.bdn-edit{border:2px solid rgba(59,42,23,.35);background:rgba(216,192,120,.08)}
.bdn-edit > summary{cursor:pointer;list-style:none;display:flex;align-items:center;
  gap:.6rem;padding:.4rem .6rem;
  font-family:var(--utility);font-size:.76rem;letter-spacing:.06em;color:var(--lake)}
.bdn-edit > summary::-webkit-details-marker{display:none}
.bdn-edit > summary::marker{content:""}
.bdn-edit > summary:hover{color:var(--oxblood);background:rgba(158,43,37,.06)}
.bdn-edit > summary:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.bdn-edit .form-sec-body{padding:.5rem .6rem .7rem}
/* A short box: these are a paragraph or a list, not a second write-up. */
.bdn-edit .rt-body{min-height:7rem;max-height:18rem}

/* --- admin: the revision log (§3.12i) -------------------------------------
   An entry can be corrected with the pencil and deleted with the ×, and the two
   controls are told apart by hue as well as by glyph — lake for the edit,
   oxblood for the removal — which is the vocabulary the citation rows three
   sections down already use, borrowed whole rather than re-invented. The × is
   the only one that confirms: rewording a line leaves the fact that a revision
   happened standing, and taking one away removes something a reader has already
   been shown. */
.rev-admin-list{list-style:none;margin:0 0 .6rem;padding:0;
  display:flex;flex-direction:column;gap:.25rem}
.rev-admin-list li{display:flex;align-items:baseline;gap:.7rem;flex-wrap:wrap;
  border:2px solid var(--ink);background:var(--paper);padding:.3rem .5rem}
.ra-acts{flex:0 0 auto;margin-left:auto;display:flex;align-items:center;gap:.15rem}
.ra-when{font-family:var(--utility);font-size:.72rem;letter-spacing:.06em;
  color:var(--oxblood);white-space:nowrap;flex:0 0 auto}
.ra-note{font-family:var(--body);font-size:.86rem;flex:1 1 14rem;min-width:0}

/* --- admin: the live preview (§3.12k) -------------------------------------
   Rendered through the page's own functions, so the site's stylesheet has to
   reach it — the drop cap, the rubrication and the footnote markers are exactly
   the parts an editor cannot picture from the source. Bounded and scrolling,
   because a long review would otherwise push the Save bar off the form. */
.review-preview{border:2px dashed rgba(59,42,23,.45);background:var(--paper);
  padding:.9rem 1.1rem;max-height:30rem;overflow:auto}
/* The preview draws a whole review body, so it must not inherit the admin's
   own tighter measure — this is what the page looks like, at the page's size. */
.review-preview .review-body{max-width:44rem}
.review-preview .bd-notes{margin-top:.9rem}

/* --- admin: The Breakdown fields --- */
.breakdown-field .bd-fields{display:grid;grid-template-columns:repeat(4,1fr);gap:.7rem;margin-top:.3rem}
.breakdown-field .field{margin:0}
.breakdown-field .bd-input{width:100%;text-align:center;font-family:var(--display);font-size:1.2rem}
@media (max-width:820px){ .breakdown-field .bd-fields{grid-template-columns:repeat(2,1fr)} }

/* --- figures: portrayed vs inspiration ------------------------------------
   Verdigris for someone actually on screen; dark orange for a real person who
   shaped a fictional character. The distinction is explained in a footnote, so
   colour is never the only signal — the asterisk and the tooltip carry it too. */
.figure-list a.inspired{
  color:#8A3A0B;background:rgba(180,95,20,.14);border-color:#B45F14;
}
.figure-list a.inspired:hover,.figure-list a.inspired:focus-visible{
  background:#8A3A0B;color:var(--paper);border-color:var(--ink);
}
.fi-star{font-weight:700;margin-left:.15rem;vertical-align:super;font-size:.72em}
.figure-note{font-family:var(--utility);font-size:.72rem;line-height:1.45;
  color:rgba(59,42,23,.78);margin:.6rem 0 0;max-width:44rem}
.figure-note .fi-star{color:#8A3A0B;vertical-align:baseline;font-size:.9em}

/* No margin: this is a flex item on `.br-title`, whose own `gap` owns the
   spacing — the rule the write-up chip beside it already follows, and for the
   documented reason (a margin is something a narrow breakpoint can zero, and
   zeroing this one put the chip flush against the era ribbon). The ribbons now
   sit between the name and this chip, so a margin here would space one side of
   them differently from the other. */
.br-inspired{padding:0 .3rem;flex:0 0 auto;
  font-family:var(--utility);font-size:.6rem;letter-spacing:.06em;
  text-transform:uppercase;color:#8A3A0B;border:1.5px solid #B45F14;
  border-radius:2px}

@media print{
  .figure-list a.inspired{color:#000;background:none;border-style:dashed}
  .br-inspired{color:#000;border-color:#000}
}

/* --- admin: portrayed vs inspiration --- */
.tag-inspired-toggle{display:inline-flex;align-items:center;gap:.3rem;
  font-family:var(--utility);font-size:.72rem;white-space:nowrap;cursor:pointer;
  color:#8A3A0B;margin-left:.2rem}
.tag-chip.inspired{border-color:#B45F14;background:rgba(180,95,20,.10)}
.tc-inspired{font-family:var(--utility);font-size:.6rem;letter-spacing:.05em;
  text-transform:uppercase;background:none;border:1.5px solid currentColor;
  border-radius:2px;padding:0 .25rem;cursor:pointer;color:rgba(59,42,23,.6)}
.tag-chip.inspired .tc-inspired{color:#8A3A0B}

/* --- list search (Browse, Filmographies) --- */
.list-search{position:relative;max-width:34rem;margin:.9rem 0 .2rem}
.list-search input[type="search"]{
  width:100%;font-family:var(--body);font-size:1rem;
  padding:.6rem 2.2rem .6rem .8rem;
  border:2px solid var(--ink);background:var(--paper);color:var(--ink);
  box-shadow:2px 2px 0 rgba(59,42,23,.2);
}
.list-search input[type="search"]::placeholder{color:rgba(59,42,23,.5);font-style:italic}
.list-search input[type="search"]:focus{outline:none;border-color:var(--oxblood);
  box-shadow:2px 2px 0 var(--gold)}
.list-search input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
.ls-clear{position:absolute;right:.45rem;top:50%;transform:translateY(-50%);
  background:none;border:none;cursor:pointer;font-size:1.3rem;line-height:1;
  color:var(--oxblood);padding:0 .25rem}
.ls-clear:hover{color:var(--ink)}

/* offscreen but readable by assistive tech */
.visually-hidden{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
@media (max-width:640px){ .list-search{max-width:none} }

/* ============================================================
   Scatterplot — hand-drawn SVG, no charting library
   ============================================================ */
.sc-controls{display:flex;flex-wrap:wrap;gap:.9rem;align-items:flex-end;
  margin:.8rem 0 .6rem;padding:.7rem .8rem;
  border:2px dashed var(--ink);background:rgba(59,42,23,.04)}
.sc-controls label{display:flex;flex-direction:column;gap:.2rem;
  font-family:var(--utility);font-size:.7rem;letter-spacing:.05em;
  text-transform:uppercase;color:rgba(59,42,23,.75)}
.sc-controls select{font-family:var(--body);font-size:.92rem;padding:.35rem .5rem;
  border:2px solid var(--ink);background:var(--paper);color:var(--ink);min-width:11rem}
/* A checkbox reads along the line it labels, not above it — the column layout
   every other control here uses would leave the box orphaned under its words.
   Selected as `.sc-controls label.sc-check` so it beats `.sc-controls label`
   on SPECIFICITY rather than on file order: moving this block must not be able
   to turn the control back into a column (§3.9c's rule, one stylesheet over).
   `align-self` keeps it level with the selects beside it, which stand taller
   than one line of label. */
.sc-controls label.sc-check{flex-direction:row;align-items:center;gap:.45rem;
  align-self:flex-end;padding-bottom:.45rem;cursor:pointer;text-transform:none;
  letter-spacing:.03em;font-size:.72rem}
.sc-check input{width:1.05rem;height:1.05rem;accent-color:var(--oxblood);
  margin:0;cursor:pointer}
.sc-check.off{opacity:.5;cursor:default}
.sc-check.off input{cursor:default}

.sc-mount{margin-top:.4rem}
svg.scatter{width:100%;height:auto;display:block;
  border:2px solid var(--ink);background:var(--paper);
  box-shadow:3px 3px 0 rgba(59,42,23,.2)}
.sc-field{fill:rgba(216,192,120,.10)}
.sc-grid{stroke:rgba(59,42,23,.16);stroke-width:1}
.sc-axis{stroke:var(--ink);stroke-width:2}
.sc-tick{font-family:var(--utility);font-size:11px;fill:rgba(59,42,23,.8)}
.sc-axis-label{font-family:var(--utility);font-size:12px;letter-spacing:.05em;fill:var(--ink)}

.sc-pt{fill:var(--pt,var(--oxblood));fill-opacity:.62;
  stroke:var(--ink);stroke-width:1;cursor:pointer;
  transition:fill-opacity .1s ease,r .1s ease}
.sc-pt:hover{fill-opacity:1;r:7}
svg.scatter a:focus-visible .sc-pt{fill-opacity:1;stroke:var(--gold);stroke-width:3}

.sc-fit{stroke:var(--fit,var(--ink));stroke-width:2.5;stroke-dasharray:7 4;
  stroke-linecap:round;opacity:.9}

.sc-count{font-family:var(--utility);font-size:.78rem;opacity:.8;margin:.5rem 0 .2rem}
/* What the marks are doing, in words. Not the caveat's oxblood: this states
   how the plot is drawn, it does not warn about it. */
.sc-spread-note{font-family:var(--body);font-size:.82rem;font-style:italic;
  opacity:.75;max-width:52rem;margin:.15rem 0 .3rem}
.sc-legend{list-style:none;margin:.2rem 0 0;padding:0;display:flex;
  flex-direction:column;gap:.25rem}
.sc-legend li{display:flex;align-items:baseline;gap:.6rem;flex-wrap:wrap;
  font-family:var(--utility);font-size:.76rem}
.sc-swatch{width:1.6rem;height:0;border-top:3px dashed var(--pt,var(--ink));flex:0 0 auto;
  align-self:center}
.sc-name{font-weight:700;min-width:9rem}
.sc-n{opacity:.75}
.sc-r2{color:var(--lake)}
.sc-r2 em{font-style:italic;opacity:.8}
.sc-weak{color:var(--oxblood);font-style:italic}
.sc-caveat{max-width:52rem;margin-top:.7rem}
.sc-empty{padding:1.4rem 0}

@media (max-width:640px){
  .sc-controls{gap:.5rem}
  .sc-controls label,.sc-controls select{width:100%;min-width:0}
  .sc-name{min-width:0}
  .sc-tick{font-size:13px}
  .sc-axis-label{font-size:14px}
}
@media print{
  .sc-controls{display:none}
  svg.scatter{box-shadow:none}
}

/* --- scatterplot: era multi-select --- */
.sc-eras{display:flex;flex-direction:column;gap:.3rem;flex:1 1 100%}
.sc-eras-head{display:flex;align-items:baseline;gap:.7rem}
.sc-eras-label{font-family:var(--utility);font-size:.7rem;letter-spacing:.05em;
  text-transform:uppercase;color:rgba(59,42,23,.75)}
.sc-eras-all{font-family:var(--utility);font-size:.68rem;cursor:pointer;
  background:none;border:none;padding:0;color:var(--oxblood);text-decoration:underline}
.sc-eras-all:disabled{color:rgba(59,42,23,.45);cursor:default;text-decoration:none}
.sc-era-chips{display:flex;flex-wrap:wrap;gap:.35rem}
.sc-era-chip{font-family:var(--utility);font-size:.74rem;cursor:pointer;
  background:var(--paper);color:rgba(59,42,23,.55);
  border:2px solid rgba(59,42,23,.3);padding:.25rem .6rem;
  border-left:5px solid rgba(59,42,23,.25);
  transition:background .12s ease,color .12s ease,border-color .12s ease}
.sc-era-chip.on{color:var(--ink);border-color:var(--ink);
  border-left-color:var(--era-c);background:rgba(216,192,120,.16)}
.sc-era-chip:hover{border-color:var(--ink)}
.sc-era-chip:active{transform:translate(1px,1px)}
.sc-era-chip:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
/* Nothing in the archive falls here, so there is nothing to switch. Drawn as
   plainly unavailable rather than hidden — a value that only appears once
   somebody happens to use it is one nobody discovers — and the reason is on
   the chip's own title, because greyed out is not an explanation. */
.sc-era-chip:disabled{opacity:.42;cursor:default;border-left-color:rgba(59,42,23,.2)}
.sc-era-chip:disabled:hover{border-color:rgba(59,42,23,.3)}
.sc-era-chip:disabled:active{transform:none}
@media (max-width:640px){ .sc-era-chip{flex:1 1 calc(50% - .35rem);text-align:left} }

/* The same row standing on its own, above a ranked list rather than inside the
   plot's control strip: /browse, /figures, /locations and the statistics
   page's location list. It is one control in one shape on all five surfaces,
   which is the point — a reader who has learnt the chips on the plot has
   learnt them everywhere, and the colour on each is the colour of the era
   ribbons on the rows underneath. */
.filter-chips{margin:.9rem 0 .2rem}
.filter-chips:empty{display:none}
.browse-filters + .filter-chips{margin-top:.4rem}
@media print{ .filter-chips{display:none} }

/* ============================================================
   Box plots and group comparison
   ============================================================ */
svg.boxplot{width:100%;height:auto;display:block;border:2px solid var(--ink);
  background:var(--paper);box-shadow:3px 3px 0 rgba(59,42,23,.2)}
.bx-box{fill:var(--c);fill-opacity:.28;stroke:var(--c);stroke-width:2}
.bx-median{stroke:var(--ink);stroke-width:3}
.bx-whisk{stroke:var(--c);stroke-width:2}
.bx-cap{stroke:var(--c);stroke-width:2}
.bx-out{fill:var(--c);fill-opacity:.7;stroke:var(--ink);stroke-width:1}
.bx-label{font-family:var(--utility);font-size:11px;fill:var(--ink)}
.bx-n{font-family:var(--utility);font-size:10px;fill:rgba(59,42,23,.7)}
.bx-thin{font-family:var(--utility);font-size:12px;fill:rgba(59,42,23,.5)}
.bx-thin-sub{font-size:10px;font-style:italic}

.bx-table{margin-top:.8rem;overflow-x:auto}
.bx-table table{width:100%;border-collapse:collapse;font-family:var(--utility);font-size:.78rem}
.bx-table th,.bx-table td{padding:.35rem .5rem;text-align:right;
  border-bottom:1px solid rgba(59,42,23,.2)}
.bx-table th[scope="row"]{text-align:left;font-weight:700}
.bx-table thead th{border-bottom:2px solid var(--ink);color:var(--lake);
  text-transform:uppercase;font-size:.68rem;letter-spacing:.05em}
.bx-swatch{display:inline-block;width:.7rem;height:.7rem;margin-right:.4rem;
  background:var(--c);border:1.5px solid var(--ink);vertical-align:baseline}
.bx-thin-cell{text-align:left;font-style:italic;opacity:.7}

.cd-result{border:2px solid var(--ink);background:var(--paper);padding:1rem;
  box-shadow:3px 3px 0 rgba(59,42,23,.2)}
.cd-headline{display:flex;align-items:baseline;gap:.7rem;flex-wrap:wrap}
.cd-value{font-family:var(--display);font-size:2.4rem;color:var(--oxblood);line-height:1}
.cd-mag{font-family:var(--utility);font-size:.78rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--lake)}
svg.cd-bar{width:100%;max-width:520px;height:auto;display:block;margin:.5rem 0}
.cd-axis{stroke:rgba(59,42,23,.35);stroke-width:2}
.cd-zero{stroke:var(--ink);stroke-width:2}
.cd-fill{fill:var(--oxblood);fill-opacity:.35}
.cd-dot{fill:var(--oxblood);stroke:var(--ink);stroke-width:2}
.cd-end{font-family:var(--utility);font-size:11px;fill:rgba(59,42,23,.7)}
.cd-plain{font-family:var(--body);font-size:.95rem;line-height:1.5;margin:.5rem 0 .8rem;
  max-width:46rem}
.cd-table{width:100%;border-collapse:collapse;font-family:var(--utility);font-size:.78rem}
.cd-table th,.cd-table td{padding:.35rem .5rem;text-align:right;
  border-bottom:1px solid rgba(59,42,23,.2)}
.cd-table th[scope="row"]{text-align:left}
.cd-table thead th{border-bottom:2px solid var(--ink);color:var(--lake);
  text-transform:uppercase;font-size:.68rem;letter-spacing:.05em}
@media (max-width:640px){ .cd-value{font-size:1.9rem} .bx-label{font-size:13px} }
@media print{ .cd-result{box-shadow:none} svg.boxplot{box-shadow:none} }

/* --- admin: the panels that are DATA rather than prose --- */
/* The admin column is 960px because most of its panels are a list and a form
   and read like prose. Three are not.

   The Locations tab is genuinely a wide TABLE — seven columns per row, plus a
   second column of groups beside it — and at 960px the list column came out
   around 530px and truncated every name to "Anc… Gre…".

   Films and TV shows joined it for the mirror-image reason: their forms are
   two dozen short boxes, and at 960px a section could pack three across at
   most, so a release year took a third of the page and the form ran to nearly
   four screens. Measured at 1320: the same fields sit four and five across and
   the film form loses about a third of its height on that one number alone.

   Scoped with `:has()` to the panel actually on screen, so a tab that IS prose
   — Infrastructure pages, Marginalia — keeps its measure. One rule and one
   number for all three: a second copy of 1320px is a second thing to keep in
   step. */
.admin-wrap:has(#locationsPanel.on),
.admin-wrap:has(#filmsPanel.on),
.admin-wrap:has(#showsPanel.on){max-width:1320px}
.loc-cols{display:grid;grid-template-columns:2fr 1fr;gap:1.2rem;margin-top:.6rem}
/* Below that the two columns stop being two columns. A 300px group panel
   beside a 400px list is not a narrower version of this layout, it is a
   ruined one — the same call §3.7a makes about the statistics sidebar. */
@media (max-width:1024px){
  .loc-cols{grid-template-columns:1fr}
}
.loc-list-wrap h3,.loc-group-wrap h3{font-family:var(--utility);font-size:.8rem;
  letter-spacing:.06em;text-transform:uppercase;color:var(--lake);margin:0 0 .4rem}
.loc-list{border:2px solid var(--ink);background:var(--paper);max-height:460px;overflow:auto}
.loc-row{display:grid;grid-template-columns:1fr 5.5rem 8rem auto;align-items:center;
  gap:.6rem;padding:.4rem .6rem;border-bottom:1px solid rgba(59,42,23,.16)}
.loc-row:nth-child(odd){background:rgba(216,192,120,.09)}
.loc-row.grouped .lr-group{color:var(--moss);font-weight:700}
.loc-row.in-selected{background:rgba(62,107,69,.12)}
.lr-name{font-family:var(--body);font-weight:700;font-size:.92rem}
.lr-n{font-family:var(--utility);font-size:.7rem;opacity:.75;white-space:nowrap}
.lr-group{font-family:var(--utility);font-size:.72rem;opacity:.75;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lr-act{font-family:var(--utility);font-size:.68rem;cursor:pointer;white-space:nowrap;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--gold);padding:.15rem .5rem}
.lr-act:hover{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}

.loc-group{border:2px solid var(--ink);background:var(--paper);margin-bottom:.5rem}
.loc-group.on{border-color:var(--oxblood);box-shadow:2px 2px 0 rgba(158,43,37,.25)}
.lg-head{display:flex;width:100%;align-items:baseline;justify-content:space-between;gap:.6rem;
  background:none;border:none;cursor:pointer;padding:.5rem .6rem;text-align:left;font:inherit}
.loc-group.on .lg-head{background:rgba(158,43,37,.08)}
.lg-name{font-family:var(--body);font-weight:700}
.lg-n{font-family:var(--utility);font-size:.7rem;opacity:.75;white-space:nowrap}
.lg-members{list-style:none;margin:0;padding:.2rem .6rem .5rem;
  border-top:1px solid rgba(59,42,23,.18)}
.lg-members li{display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  font-family:var(--body);font-size:.88rem;padding:.15rem 0}
.loc-group .btn{margin:.2rem .6rem .6rem}
@media (max-width:900px){ .loc-cols{grid-template-columns:1fr} }
@media (max-width:640px){
  .loc-row{grid-template-columns:1fr auto;row-gap:.15rem}
  .lr-n,.lr-group{grid-column:1}
}

/* --- statistics: grouped location names --- */
.tl-parts{font-family:var(--utility);font-size:.66rem;opacity:.7;line-height:1.35}

/* the members a grouped location filter gathers */
.credit-banner .cb-detail{font-family:var(--utility);font-size:.7rem;
  opacity:.75;flex:1 1 100%;order:3;color:rgba(59,42,23,.8)}

/* --- the facet colours, wherever a rail of chips draws one -----------------
   Each facet has one colour across the whole site, which is the thing a reader
   carries from page to page: periods oxblood (the default, so no rule here),
   locations verdigris, threads ultramarine, genres purple.

   GENRES WERE OXBLOOD, which is to say they had no rule and fell through to the
   default — so on a filmography "Periods associated with X" and "Genres they
   turn up in" were the same red, and the one rail whose values come from
   OUTSIDE the archive looked like the one that is the editor's own tagging.
   That is the distinction the rail's own note spends a sentence making. Purple
   because it is the one hue the era palette does not use and the two facets
   either side of it do not either; measured at 5.8:1 on parchment for the
   border and 7.5:1 for the type, so the chip reads at chip size. */
.rail-threads .period-tags a{border-color:var(--lake);color:var(--lake)}
.rail-threads .period-tags a:hover{background:var(--lake);color:var(--paper)}
.rail-locations .period-tags a{border-color:var(--moss);color:#2F5436}
.rail-locations .period-tags a:hover{background:var(--moss);color:var(--paper)}
.rail-genres .period-tags a{border-color:var(--murex);color:var(--murex-text)}
.rail-genres .period-tags a:hover{background:var(--murex);color:var(--paper)}

/* ============================================================
   Marginalia — the blog
   ============================================================ */
/* THE CLASS THE INJECTOR STAMPS, not one an editor could write. An intro is
   authored in pages.js and sanitised on the way in, which strips every
   attribute (§3.10) — so `page-intro` could not survive the move and this
   rule silently stopped matching. `lede` is put back by PP.markLede on the
   first top-level paragraph of every injected body (§3.11g), which is
   exactly what this paragraph is. */
.marginalia-page .lede{font-family:var(--body);font-style:italic;
  font-size:1.05rem;opacity:.85;max-width:44rem;margin:-.2rem 0 1rem}

/* Topics and series are different things and used to look identical: one is
   a subject a note is about, the other a run of notes meant in order. Own
   section, own label, own colour — and the series chips carry a mark as well,
   because colour alone is never the carrier (§7). */
.post-tagbar{display:flex;flex-direction:column;gap:.45rem;margin:.6rem 0 .9rem}
.pt-group{display:flex;align-items:baseline;flex-wrap:wrap;gap:.35rem .6rem}
.pt-label{font-family:var(--utility);font-size:.64rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--lake);opacity:.85;flex:0 0 4.6rem}
.pt-chips{display:flex;flex-wrap:wrap;gap:.35rem}
.pt-all{margin-bottom:.1rem}
.pt-chip.is-series{color:var(--moss);border-color:var(--moss);
  border-radius:0 .8rem .8rem 0}
.pt-chip.is-series.on{background:var(--moss);color:var(--paper);border-color:var(--ink)}
.pt-chip.is-series:hover{border-color:var(--ink)}
.pt-mark{margin-right:.3rem;opacity:.75}
.pt-chip{font-family:var(--utility);font-size:.74rem;cursor:pointer;
  background:var(--paper);color:rgba(59,42,23,.7);
  border:2px solid rgba(59,42,23,.3);padding:.25rem .6rem}
.pt-chip.on{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.pt-chip:hover{border-color:var(--ink)}
.pt-n{margin-left:.35rem;opacity:.7;font-size:.66rem}

.post-list{display:flex;flex-direction:column;gap:0}
.post-card{padding:1.1rem 0;border-bottom:2px solid rgba(59,42,23,.18)}
.post-card:first-child{padding-top:.4rem}
.pc-title{font-family:var(--display);font-weight:400;font-size:1.7rem;
  line-height:1.15;margin:0 0 .2rem}
.pc-title a{color:var(--oxblood);text-decoration:none}
.pc-title a:hover{text-decoration:underline}
.pc-excerpt{font-family:var(--body);font-size:1rem;line-height:1.5;
  margin:.4rem 0 .5rem;max-width:44rem}
.post-meta{font-family:var(--utility);font-size:.72rem;letter-spacing:.05em;
  color:rgba(59,42,23,.75);margin:0;display:flex;gap:.8rem;flex-wrap:wrap}
.post-author::before{content:"\00b7";margin-right:.8rem;opacity:.5}
.post-tags{list-style:none;display:flex;flex-wrap:wrap;gap:.3rem;margin:.5rem 0 0;padding:0}
.post-tags a{font-family:var(--utility);font-size:.68rem;text-decoration:none;
  color:var(--lake);border:1.5px solid var(--lake);padding:.1rem .45rem;display:inline-block}
.post-tags a:hover{background:var(--lake);color:var(--paper)}

/* a single post */
.post{max-width:44rem}
.post-head{border-bottom:3px double var(--gold);padding-bottom:.7rem;margin-bottom:1.1rem}
.post-head .entry-title{margin-bottom:.35rem}
/* .post-meta is a flex row with a gap; the author's leading interpunct is its
   own separator, so the reading time sits between date and author without
   one and the row still reads as a single line of furniture. */
.post-read{opacity:.85}
.copy-link{font-family:inherit;font-size:inherit;letter-spacing:inherit;
  color:var(--lake);background:none;border:1.5px solid var(--lake);
  padding:.1rem .45rem;cursor:pointer;margin-left:auto}
.copy-link:hover{background:var(--lake);color:var(--paper)}
.copy-said{color:var(--lake)}
.copy-link[hidden]{display:none}

/* Contents. A note with two or more sections gets one; a note with one
   section has a heading, not a contents. */
.post-toc{border:2px solid var(--gold);background:rgba(197,160,62,.07);
  padding:.7rem 1rem;margin:0 0 1.3rem;max-width:44rem}
/* Scoped under .post-toc deliberately. `.content-page h2` is (0,1,1) and a
   bare `.toc-head` is (0,1,0), so it lost — and what won was the display
   blackletter at clamp(1.6rem,4vw,2.3rem), which this rule then set in
   UPPERCASE. Blackletter capitals are the hardest thing to read on the site,
   and a contents is pure navigation: it has to be scannable before it is
   decorative. The whole block is the body serif for that reason. */
.post-toc .toc-head{font-family:var(--body);font-size:.95rem;font-weight:700;
  letter-spacing:.02em;text-transform:none;color:var(--lake);margin:0 0 .45rem;
  line-height:1.3}
.post-toc .toc-list{font-family:var(--body);font-size:1.02rem;line-height:1.5;
  margin:0;padding-left:1.4rem}
/* A sub-section, marked rather than nested. `.content-page li` is (0,1,1) and
   a bare `.toc-sub` is (0,1,0), so this is selected through the nav for the
   same reason every other rule in this block is. */
.post-toc .toc-list .toc-sub{margin-left:1rem;font-size:.94em;
  list-style-type:none}
.post-toc .toc-list .toc-sub::before{content:"\2014\00a0";color:var(--lake);
  opacity:.7}
/* `.content-page li` is (0,1,1) and sets 1.12rem, so without this the items
   come out larger than the list that supposedly sizes them — the same
   specificity trap as the heading above. Inherit, so the <ol> stays the one
   place the size is decided. */
.post-toc .toc-list li{font-size:inherit;margin-bottom:.32rem}
.post-toc .toc-list a{color:var(--oxblood);text-decoration-thickness:1px;
  text-underline-offset:2px}
/* A jump lands the heading under nothing, so give it room to breathe. Both
   anchored ranks, because the contents links either (§3.10a). */
.post-body h2[id],.post-body h3[id]{scroll-margin-top:1.5rem}
.post-body{font-family:var(--body);font-size:1.06rem;line-height:1.62}
.post-body p{margin:0 0 1rem}
/* THE LARGE HEADING WINS ON SPECIFICITY, NOT ON FILE ORDER. post.html's main
   is `.content-page post-page`, so `.content-page h2` at (0,1,1) beats a bare
   `.post-body h2` — measured at the page's clamp(1.6rem,4vw,2.3rem) rather
   than at the size wanted here. Selecting through `.post-page` makes it
   (0,2,1), so moving this block cannot silently undo it (§3.9c, §4). */
.post-page .post-body h2{font-family:var(--display);font-weight:400;
  color:var(--oxblood);font-size:1.8rem;letter-spacing:.01em;
  margin:2.1rem 0 .6rem;border-bottom:2px solid var(--gold);padding-bottom:.25rem}
.post-body h3{font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.35rem;margin:1.6rem 0 .5rem}
.post-body h4{font-family:var(--utility);font-size:.82rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--lake);margin:1.3rem 0 .4rem}
.post-body blockquote{margin:1.2rem 0;padding:.2rem 0 .2rem 1.1rem;
  border-left:4px solid var(--gold);font-style:italic;color:rgba(59,42,23,.9)}
.post-body blockquote p{margin:0}
.post-body ul,.post-body ol{margin:0 0 1rem 1.4rem}
.post-body li{margin-bottom:.3rem}
.post-body a{color:var(--oxblood)}
.post-body code{font-family:var(--utility);font-size:.9em;
  background:rgba(59,42,23,.07);padding:.05em .3em}
.post-body u{text-decoration-thickness:1px;text-underline-offset:2px}
.post-figure{margin:1.2rem 0}
.post-figure img{width:100%;height:auto;display:block;border:2px solid var(--ink);
  box-shadow:3px 3px 0 rgba(59,42,23,.22)}
.post-figure figcaption{font-family:var(--utility);font-size:.72rem;
  opacity:.75;margin-top:.35rem}

/* --- admin: marginalia --- */
.post-admin-list{display:flex;flex-direction:column;gap:.2rem;
  max-height:320px;overflow:auto;margin:.4rem 0 1rem}
.pa-row{display:grid;grid-template-columns:6.5rem 1fr 10rem auto;gap:.7rem;
  align-items:baseline;text-align:left;cursor:pointer;font:inherit;
  background:var(--paper);border:2px solid var(--ink);padding:.35rem .6rem}
.pa-row:hover{background:rgba(216,192,120,.18)}
.pa-row.on{background:var(--oxblood);color:var(--paper);border-color:var(--gold)}
.pa-row.draft .pa-title{opacity:.7;font-style:italic}
.pa-date{font-family:var(--utility);font-size:.7rem;opacity:.8}
.pa-title{font-family:var(--body);font-weight:700}
.pa-tags{font-family:var(--utility);font-size:.68rem;opacity:.7;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pa-draft{font-family:var(--utility);font-size:.6rem;text-transform:uppercase;
  letter-spacing:.06em;color:var(--oxblood);border:1.5px solid currentColor;padding:0 .3rem}
.pa-row.on .pa-draft{color:var(--paper)}

.rt-tools{display:flex;flex-wrap:wrap;gap:.25rem;margin-bottom:.3rem}
.rt-btn{font-family:var(--utility);font-size:.8rem;min-width:2rem;cursor:pointer;
  background:var(--paper);border:2px solid var(--ink);padding:.2rem .45rem;color:var(--ink)}
.rt-btn:hover{background:var(--gold)}
.rt-btn:active{transform:translate(1px,1px)}
.rt-b{font-weight:700}.rt-i{font-style:italic}
.rt-u{text-decoration:underline}.rt-s{text-decoration:line-through}
/* Three ranks, told apart by SIZE — which is what a heading picker is. The
   name each carries is what says which is which (§7); the glyph only has to
   put them in order. */
.rt-h2{font-family:var(--display);font-size:1.3rem;line-height:1}
.rt-h3{font-family:var(--display);font-size:1rem}
.rt-h4{font-family:var(--display);font-size:.75rem}
.rt-code{font-family:var(--utility);letter-spacing:-.05em}
.rt-link{color:var(--lake);border-color:var(--lake)}
/* Groups the toolbar into inline marks, blocks, and lists. Decoration only —
   every button says what it is in its own title and aria-label. */
.rt-sep{width:2px;align-self:stretch;background:rgba(59,42,23,.25);margin:0 .2rem}
/* The Widget button in the infrastructure-page editor. The same shape as the
   Marginalia embed button beside it and deliberately its own class: a review
   body cannot hydrate an embed, and a check asserts admin.js never mentions
   `rt-embed` at all — sharing the name would have made that rule unassertable
   (§4). */
.rt-btn.rt-widget{color:var(--lake);font-weight:700}
.rt-picker{border:2px dashed var(--lake);padding:.6rem;margin-bottom:.4rem;
  background:rgba(39,75,142,.05)}
.rt-body{min-height:16rem;max-height:34rem;overflow:auto;
  border:2px solid var(--ink);background:var(--paper);padding:.8rem 1rem;
  font-family:var(--body);font-size:1rem;line-height:1.6}
.rt-body:focus{outline:none;border-color:var(--oxblood);box-shadow:2px 2px 0 var(--gold)}
.rt-body p{margin:0 0 .8rem}
.rt-body blockquote{border-left:4px solid var(--gold);margin:.8rem 0;padding-left:.9rem;font-style:italic}
.rt-body h3{font-family:var(--display);font-weight:400;color:var(--oxblood);margin:.9rem 0 .4rem}
/* The box shows each block the way the page will, or an editor is composing
   blind — the whole reason this is not a textarea. */
.rt-body h4{font-family:var(--utility);font-size:.82rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--lake);margin:.9rem 0 .35rem}
.rt-body ul,.rt-body ol{margin:0 0 .8rem 1.4rem}
.rt-body li{margin-bottom:.25rem}
.rt-body code{font-family:var(--utility);font-size:.9em;
  background:rgba(59,42,23,.07);padding:.05em .3em}
.rt-body hr{border:0;border-top:2px solid var(--ink);opacity:.35;margin:1.1rem 0}
.rt-body a{color:var(--oxblood)}

/* The inline-code tool is the one button on this row that carries a STATE,
   because it is the one that is not an execCommand and so the one an editor
   can be inside without the browser telling them (§3.12k). aria-pressed rides
   with the fill: a fill is not a state to a screen reader (§7). */
.rt-btn.rt-code.on{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.rt-btn.rt-code.on:hover{background:var(--oxblood);border-color:var(--oxblood)}

/* --- the editor's own chrome (§3.12k) -------------------------------------
   The outline sits BESIDE the box on a wide admin column and above it on a
   narrow one. `minmax(0,1fr)` on the writing track and `min-width:0` on the
   item, because a grid item's default width is its content's intrinsic width —
   §4's fixed-track trap, recorded five times over, and a contenteditable full
   of long words is exactly the content that finds it. */
.rt-deck{display:grid;grid-template-columns:minmax(0,1fr) 13rem;gap:.6rem;align-items:start}
.rt-deck > .rt-body{min-width:0}
.rt-outline{min-width:0;max-height:34rem;overflow:auto;
  border:2px solid rgba(59,42,23,.35);background:rgba(216,192,120,.10);padding:.5rem .4rem}
.rt-outline[hidden]{display:none}

/* THE HTML SOURCE VIEW (admin-kit's `</>` tool).

   It spans the whole deck rather than sitting in the body's column: the
   outline beside it is hidden while the source is up, so the second track is
   empty, and markup wants every pixel of the measure — a stored body is one
   long line and the point of opening this is to read it.

   MONOSPACE and never var(--utility). That face is a display face used small
   for rubrics; what this shows is code, where the character grid IS the
   information — an indent, a doubled quote, a tag that does not line up with
   its neighbour. `tab-size` for the same reason.

   `white-space:pre` with a horizontal scroll, not `pre-wrap`: a wrapped tag
   reads as two tags, which is precisely the mistake an editor opens this to
   avoid. The box scrolls itself, so the admin page does not (§3.7a). */
.rt-source{grid-column:1/-1;min-width:0}
.rt-source[hidden]{display:none}
/* WHAT THE FILTER TOOK, under the box and outside the pane — a message inside
   the source view would be written and hidden in the same breath, which is the
   silence it exists to end. Empty most of the time: `:empty` so a report that
   says nothing takes no room and leaves no rule floating under the editor. */
.rt-src-say{margin:.35rem 0 0;color:var(--oxblood);
  border-left:3px solid var(--oxblood);padding-left:.6rem}
.rt-src-say:empty{display:none}
/* The picker's own refusal, beside the controls that caused it (§6f). */
.rt-picker-say{margin:.4rem 0 .2rem;color:var(--oxblood)}
.rt-picker-say:empty{display:none}
/* Who is publishing, and why — directly above the Publish button, because a
   signature and the act it signs belong together. A dashed rule so it reads as
   something attached to the button rather than as another block of the export
   panel. */
.publish-sign{border:1px dashed var(--gold);padding:.6rem .7rem;margin:.6rem 0}
/* SELECTED THROUGH ITS WRAPPER, and that is not tidiness. This textarea sits
   inside a field('Prose', ...), and `.field textarea` is (0,1,1) — it sets
   var(--body) at 1rem and beats a bare `.rt-src` at (0,1,0) outright, so the
   source view came back in Cardo at reading size with the monospace rule
   present and losing. §4 records the identical failure for `.mini-note` on
   five pages and for `.proceed-btn` rendering oxblood on oxblood. Winning on
   SPECIFICITY rather than on file order is also what stops moving this block
   quietly undoing it. Measured, not assumed. */
.rt-source .rt-src{display:block;width:100%;box-sizing:border-box;
  min-height:16rem;max-height:34rem;overflow:auto;white-space:pre;
  border:2px solid var(--ink);background:var(--paper);padding:.8rem 1rem;
  font-family:ui-monospace,"Cascadia Mono","SFMono-Regular",Menlo,Consolas,monospace;
  font-size:.82rem;line-height:1.55;color:var(--ink);tab-size:2;resize:vertical}
.rt-source .rt-src:focus{outline:none;border-color:var(--oxblood);box-shadow:2px 2px 0 var(--gold)}
/* The toggle wears the fill its state deserves, in the lake blue the Widget
   button already uses for a control that is about the page's plumbing rather
   than about its words — never the green `.rt-embed` is, which names an
   element of the archive (§3.9c). */
.rt-btn.rt-html{font-family:ui-monospace,Consolas,monospace;letter-spacing:-.02em}
.rt-btn.rt-html.on{background:var(--lake);color:var(--paper);border-color:var(--lake)}
.rt-ol{list-style:none;margin:0;padding:0;counter-reset:none}
.rt-oli{margin:0}
/* Three ranks, indented in step. The h2 row is the only one set in the
   oxblood a heading takes everywhere else on the site, so the outline reads
   as the shape of the draft rather than as a flat list of jumps. */
.rt-o-h3{padding-left:.7rem}
.rt-o-h4{padding-left:1.4rem}
.rt-ojump{display:block;width:100%;text-align:left;cursor:pointer;
  font-family:var(--utility);font-size:.72rem;line-height:1.35;
  background:none;border:0;border-left:2px solid transparent;
  padding:.22rem .3rem;color:var(--lake);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rt-o-h2 .rt-ojump{font-size:.76rem;font-weight:700;color:var(--oxblood)}
.rt-o-h4 .rt-ojump{font-size:.68rem;color:rgba(59,42,23,.82)}
.rt-ojump:hover{border-left-color:var(--oxblood);color:var(--oxblood);
  background:rgba(158,43,37,.07)}
.rt-ojump:focus-visible{outline:3px solid var(--gold);outline-offset:-2px}
/* Under the box rather than in the toolbar: it is a reading OF what has been
   written, so it belongs at the end of it. */
.rt-meta{margin:.35rem 0 0;text-align:right}
@media (max-width:820px){
  /* A 13rem sidebar on a narrow column is not a smaller sidebar, it is a
     ruined one — §3.7a's rule for the statistics contents, at admin width. */
  .rt-deck{grid-template-columns:minmax(0,1fr)}
  .rt-outline{max-height:11rem;order:-1}
}

.post-img-box{border:2px dashed var(--ink);padding:.7rem;background:rgba(59,42,23,.03)}
.post-img-list{list-style:none;margin:0 0 .6rem;padding:0;display:flex;flex-direction:column;gap:.25rem}
.post-img-list li{display:flex;align-items:baseline;gap:.6rem;
  border:2px solid var(--ink);background:var(--paper);padding:.3rem .5rem}
.pi-src{font-family:var(--utility);font-size:.72rem;flex:1 1 auto;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pi-alt{font-family:var(--body);font-size:.8rem;opacity:.75;flex:0 1 auto}
@media (max-width:700px){
  .pa-row{grid-template-columns:1fr auto}
  .pa-date,.pa-tags{grid-column:1}
}

/* ============================================================
   Marginalia — related entries, series nav, reverse links, feed
   ============================================================ */
.feed-link{font-family:var(--utility);font-size:.8rem;margin:.3rem 0 .8rem}
.feed-link a{color:var(--oxblood)}

.pc-series{font-family:var(--utility);font-size:.7rem;letter-spacing:.05em;
  text-transform:uppercase;color:var(--lake);margin:.15rem 0 0}

/* "What this note is about" — on the post itself */
.post-related h3{font-family:var(--utility);font-size:.8rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--lake);margin-bottom:.4rem}
.post-related ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.3rem}
.post-related li{display:flex;align-items:baseline;gap:.6rem;font-family:var(--body);font-size:.92rem}
.pr-kind{font-family:var(--utility);font-size:.62rem;letter-spacing:.05em;text-transform:uppercase;
  color:rgba(59,42,23,.6);flex:0 0 auto;min-width:6.5rem}
.post-related a{color:var(--oxblood)}

/* series navigation on a post page */
.series-nav{margin-top:2rem;padding-top:1rem;border-top:2px dashed var(--ink)}
.sn-head{font-family:var(--utility);font-size:.72rem;letter-spacing:.05em;
  text-transform:uppercase;color:var(--lake);margin:0 0 .5rem}
.sn-links{display:flex;justify-content:space-between;gap:1rem}
.sn-prev,.sn-next{font-family:var(--body);font-size:.92rem;color:var(--oxblood);
  text-decoration:none;max-width:47%}
.sn-next{text-align:right}
.sn-prev:hover,.sn-next:hover{text-decoration:underline}

/* reverse link: reviews/filmographies pointing back at a note */
.marginalia-rail h3{font-family:var(--utility);font-size:.8rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--lake);margin-bottom:.4rem}
.marginalia-rail ul{list-style:none;margin:0;padding:0}
.marginalia-rail li{display:flex;justify-content:space-between;gap:.7rem;
  font-family:var(--body);font-size:.9rem;padding:.15rem 0}
.marginalia-rail a{color:var(--oxblood)}
.mr-date{font-family:var(--utility);font-size:.68rem;opacity:.65;white-space:nowrap}
/* A gloss row is the note ITSELF rather than a link to one, so it stacks
   where a post row is a title against a date. The li above is display:flex,
   which would otherwise set the sentence beside its own credit line.

   Every rule here is selected through .marginalia-rail, and that is not
   tidiness: show.html, figure.html and period.html are all .content-page, so
   `.content-page p` at (0,1,1) beats a bare .mr-text at (0,1,0) and the gloss
   would render at body size in three of the four places it appears. §4
   records that exact selector doing exactly that to .mini-note on five page
   types. Winning on specificity rather than on file order also means moving
   this block cannot silently undo it. */
.marginalia-rail li.mr-gloss{display:block}
.marginalia-rail .mr-text{font-family:var(--body);font-size:.9rem;
  font-style:italic;margin:0 0 .2rem;line-height:1.45}
.marginalia-rail .mr-src{display:flex;justify-content:space-between;gap:.7rem;
  align-items:baseline;margin:0;font-family:var(--utility);font-size:.68rem;opacity:.75}

/* the one-line note on a year banner */

/* --- admin: related entries + series --- */
.post-related-box{border:2px dashed var(--ink);padding:.7rem;background:rgba(59,42,23,.03)}
/* Kind / Era / Which sit on one line, like the episode editor's three-up row. */
.post-related-box .field-row{grid-template-columns:1fr 1fr 1fr}
@media (max-width:640px){
  .post-related-box .field-row{grid-template-columns:1fr}
}
.post-related-list{list-style:none;margin:0 0 .6rem;padding:0;display:flex;flex-direction:column;gap:.25rem}
.post-related-list li{display:flex;align-items:center;gap:.6rem;
  border:2px solid var(--ink);background:var(--paper);padding:.3rem .5rem}
.pr-kind-tag{font-family:var(--utility);font-size:.62rem;letter-spacing:.05em;text-transform:uppercase;
  color:var(--lake);border:1.5px solid var(--lake);padding:0 .3rem;flex:0 0 auto}

/* ============================================================
   Marginalia embeds — live elements inside a post
   ============================================================ */
.embed{margin:1.6rem 0;padding:0}
.embed figcaption,.embed-caption{font-family:var(--utility);font-size:.72rem;
  line-height:1.45;opacity:.78;margin-top:.5rem}
.embed figcaption a,.embed-caption a{color:var(--oxblood)}

/* 1. Breakdown spotlight */
.embed-breakdown .bd-grid{box-shadow:3px 3px 0 rgba(59,42,23,.2)}

/* 2. Live chart */
.embed-chart svg.scatter,.embed-chart svg.boxplot{box-shadow:3px 3px 0 rgba(59,42,23,.18)}
.embed-chart .sc-legend{font-size:.72rem}

/* 3. Timeline excerpt
   Year · how many · the titles. The count carries a bar as well as a
   number, because the point of putting a run of years in a post is almost
   always the comparison between them, and that should read before any
   title does. Titles run inline and wrap: one per line spent most of the
   width on nothing and still ran out of room after six. */
/* label · count+bar · fold · titles. The fold column is fixed so the title
   column starts in the same place whether or not a year has one.

   The GRID IS ON THE LIST and each row subgrids into it, which is what lets
   the label column be `auto`. It was a flat 3.2rem — enough for "1944" and
   not for "10,000 BCE", and a fixed track does not clip, it overflows: long
   year names ran straight over the bar to their right. Sizing per row would
   fix the overrun and lose the alignment, and the alignment is the whole
   point — the comparison between the years is why the embed exists, and it
   only reads if every bar starts in the same place. `auto` on the shared
   grid gives both: one column, as wide as the longest label in THIS embed,
   so a run of four-digit years stays as tight as it was.

   The pair of grid-template-columns declarations is deliberate. A browser
   with no subgrid drops the second and keeps the first, where the minmax
   sizes per row: misaligned, which is a real loss, but never overlapping,
   which is the bug. */
.embed-timeline .et-years{list-style:none;margin:0;padding:0;
  border:2px solid var(--ink);background:var(--paper);
  box-shadow:3px 3px 0 rgba(59,42,23,.2);
  display:grid;grid-template-columns:auto 3.6rem 1.4rem 1fr}
.et-year{display:grid;grid-column:1 / -1;
  grid-template-columns:minmax(3.2rem,auto) 3.6rem 1.4rem 1fr;
  grid-template-columns:subgrid;
  gap:.1rem .7rem;
  align-items:baseline;padding:.35rem .7rem;
  border-bottom:1px solid rgba(59,42,23,.18)}
/* Empty years have no button; their "nothing catalogued" spans the gap. */
.et-year.is-empty .et-empty{grid-column:3 / -1}
.et-fold{font-family:var(--utility);font-size:.9rem;line-height:1;
  width:1.4rem;height:1.4rem;padding:0;cursor:pointer;
  background:var(--paper);color:var(--ink);border:1.5px solid rgba(59,42,23,.5)}
.et-fold:hover{border-color:var(--ink);background:var(--gold-bright);color:var(--ink)}
.et-fold:focus-visible{outline:2px dashed var(--oxblood);outline-offset:2px}
/* Folded hides the titles only. The label, count and bar stay — they are the
   comparison the embed exists for. */
.et-year.folded .et-titles{display:none}
.et-year:last-child{border-bottom:none}
.et-year:nth-child(odd){background:rgba(216,192,120,.10)}
.et-label{font-family:var(--display);font-size:1.05rem;color:var(--oxblood);
  text-decoration:none;white-space:nowrap}
.et-label:hover{text-decoration:underline}

.et-count{display:flex;align-items:center;gap:.35rem;font-family:var(--utility);font-size:.7rem}
.et-bar{flex:1 1 auto;height:.5rem;background:rgba(59,42,23,.12);
  border:1px solid rgba(59,42,23,.35)}
.et-bar span{display:block;height:100%;background:var(--oxblood);opacity:.6}
.et-n{flex:0 0 auto;opacity:.75;min-width:1ch;text-align:right}

.et-titles{list-style:none;margin:0;padding:0;
  display:flex;flex-wrap:wrap;gap:.05rem .5rem}
.et-titles li{font-family:var(--body);font-size:.9rem;line-height:1.45;
  display:inline-flex;align-items:baseline;gap:.25rem}
/* A separator between titles, so two run-on names stay two names. It trails
   the title it follows rather than leading the next one: as a `::before` it
   ended up at the start of every wrapped line, which reads like a bullet. */
.et-titles li:not(:last-child)::after{content:"·";opacity:.4;margin-left:.3rem}
.et-titles a{color:var(--ink);text-decoration:none}
.et-titles a:hover{color:var(--oxblood);text-decoration:underline}
.et-salt{font-family:var(--utility);font-size:.6rem;color:var(--oxblood);
  border:1px solid currentColor;border-radius:2px;padding:0 .2rem;
  flex:0 0 auto;position:relative;top:-.15em}
.et-more a{font-family:var(--utility);font-size:.7rem;opacity:.7;
  font-style:italic;color:var(--oxblood)}
.et-empty{font-family:var(--utility);font-size:.7rem;opacity:.55;font-style:italic}
.et-year.is-empty .et-label{opacity:.6}
.et-key{display:block;margin-top:.3rem;opacity:.8}

/* 4. Then and now */
.embed-thennow .tn-pair{display:grid;grid-template-columns:1fr 1fr;gap:.6rem}
.tn-side{position:relative}
.tn-side img{width:100%;height:auto;display:block;border:2px solid var(--ink);
  box-shadow:3px 3px 0 rgba(59,42,23,.22)}
.tn-tag{position:absolute;top:.4rem;left:.4rem;font-family:var(--utility);
  font-size:.62rem;letter-spacing:.06em;text-transform:uppercase;
  background:var(--ink);color:var(--paper);padding:.1rem .4rem}
.tn-link{color:var(--oxblood)}

/* 5. Reading roundup */
.embed-reading .er-list{list-style:none;margin:0;padding:0;
  border-left:4px solid var(--gold);padding-left:.9rem}
.er-list li{margin-bottom:.6rem}
.er-book{display:block;font-family:var(--body);font-size:.98rem}
.er-book cite{font-style:italic}
.er-from{display:block;font-family:var(--utility);font-size:.68rem;opacity:.72;margin-top:.1rem}
.er-from a{color:var(--oxblood)}

/* 6. Disputed score */
.dispute-line{font-family:var(--utility);font-size:.72rem;margin:.9rem 0 0;
  padding-top:.6rem;border-top:1px dashed rgba(59,42,23,.3)}
.dispute-line a{color:var(--oxblood)}
.dispute-note{opacity:.72}

/* 7. Reader feedback: the disagreement tally and the suggestion box.
   Both arrive hidden and are revealed by review-feedback.js only once the
   backend has answered, so [hidden] must actually hide — a display rule
   further down the cascade would otherwise show a control that can't work. */
.reader-feedback [hidden]{display:none !important}
.reader-feedback{margin-top:.4rem}
.dispute-vote{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;margin:.5rem 0 0}
.dispute-btn{font-family:var(--utility);font-size:.7rem;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--oxblood);
  padding:.3rem .6rem;box-shadow:2px 2px 0 rgba(59,42,23,.2)}
.dispute-btn:hover:not(:disabled){background:var(--oxblood);color:var(--paper)}
.dispute-btn:disabled{cursor:default;opacity:.6;box-shadow:none}
.dispute-tally{font-family:var(--utility);font-size:.7rem;opacity:.75}

/* "Review this one next." Same shape as the disagreement control, in moss
   rather than oxblood: one is a complaint about a score, the other a request
   for prose, and a title only ever shows one of them. */
.request-vote{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;margin:.5rem 0 0}
.request-btn{font-family:var(--utility);font-size:.7rem;cursor:pointer;
  background:var(--paper);color:var(--moss);border:2px solid var(--moss);
  padding:.3rem .6rem;box-shadow:2px 2px 0 rgba(59,42,23,.2)}
.request-btn:hover:not(:disabled){background:var(--moss);color:var(--paper)}
.request-btn:disabled{cursor:default;opacity:.6;box-shadow:none}
.request-tally{font-family:var(--utility);font-size:.7rem;opacity:.75}
.request-note{font-family:var(--utility);font-size:.66rem;opacity:.6;flex:1 1 100%}

.suggest-box{margin:.9rem 0 0;border:2px solid var(--moss);background:rgba(62,107,69,.06);
  padding:.5rem .75rem;font-family:var(--utility);font-size:.72rem}
.suggest-box summary{cursor:pointer;color:var(--moss)}
.sg-intro{margin:.5rem 0;opacity:.8;line-height:1.5}
.sg-label{display:block;margin:.5rem 0 .15rem}
/* Block, not the default inline-block: otherwise the send button flows onto
   the same line as the right-hand edge of the textarea and reads as though it
   belongs to nothing. */
.suggest-box select,.suggest-box textarea{display:block;width:100%;max-width:32rem;font-family:inherit;
  font-size:.75rem;padding:.3rem;border:1px solid var(--ink);background:var(--paper);color:var(--ink)}
.sg-send{margin-top:.5rem}
.sg-status{margin-left:.6rem;opacity:.8}
/* The honeypot. Kept out of sight without display:none, which some autofill
   agents skip and some screen readers announce anyway; aria-hidden would lie
   to a reader who does reach it, so it is simply parked off-canvas. */
.sg-hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* --- admin: embed inserter --- */
.rt-embed{color:var(--moss);border-color:var(--moss)}
/* --- admin: the sources on a review --- */
.rt-cite{color:var(--oxblood);border-color:var(--oxblood)}
.cite-admin-list{list-style:decimal;margin:0 0 0 1.4rem;padding:0;
  display:flex;flex-direction:column;gap:.3rem}
/* FOUR TRACKS, not three: cite-again, correct, remove. The prose track stays
   `minmax(0,1fr)` for the reason spelled out under `.rt-embed-fields` below —
   a bare `1fr` never shrinks past its content's intrinsic width. */
.cite-admin-list li{border:2px solid var(--ink);background:var(--paper);
  padding:.35rem .5rem;display:grid;
  grid-template-columns:minmax(0,1fr) auto auto auto;grid-template-rows:auto auto auto;
  column-gap:.5rem;align-items:baseline}
.cite-admin-list li.tag-empty{display:block;border-style:dashed}
.ca-claim{font-family:var(--body);font-style:italic;font-size:.9rem;grid-column:1}
.ca-source{font-family:var(--utility);font-size:.74rem;opacity:.8;grid-column:1;grid-row:2}
/* An editor cannot see this by reading the prose: a marker deleted while
   tidying a sentence leaves an entry that would fail the build. */
.ca-uses{font-family:var(--utility);font-size:.66rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--moss);grid-column:1;grid-row:3}
.ca-uses.none{color:var(--oxblood)}
.cite-admin-list .tc-add{grid-column:2;grid-row:1 / span 3;
  background:none;border:none;cursor:pointer;font-size:1.1rem;line-height:1;
  color:var(--moss);padding:0 .2rem}
.cite-admin-list .tc-edit{grid-column:3;grid-row:1 / span 3}
.cite-admin-list .tc-remove{grid-column:4;grid-row:1 / span 3}
/* CORRECTING A SOURCE rather than deleting it and re-citing it everywhere. The
   lake blue is the site's own "this is a link to somewhere else" colour and the
   one thing on the row that is neither an addition (moss) nor a removal
   (oxblood) — so the three verbs are told apart by hue as well as by glyph, and
   the glyph and the accessible name carry it on their own (§7). */
.tc-edit{background:none;border:none;cursor:pointer;font-size:.95rem;line-height:1;
  color:var(--lake);padding:0 .2rem}
.tc-edit:focus-visible{outline:2px solid var(--lake);outline-offset:2px}
/* The row whose boxes are open below. A tint and a rule, because the form can
   be several rows away and "which one am I correcting" is not a question the
   sentence above the boxes should be the only answer to. */
.cite-admin-list li.ca-editing,.rev-admin-list li.ra-editing{
  border-color:var(--lake);background:rgba(39,75,142,.07)}
.ca-formsay,.ra-say{margin:0 0 .5rem}
/* `minmax(0,1fr)`, NOT `1fr`. A bare `1fr` is `minmax(auto,1fr)`, so a track
   never shrinks below its content's intrinsic width — and the citation embed's
   "Which claim" select carries whole sentences as option text, giving it a
   min-content width of 632px inside a 423px half. The first track took what it
   wanted and pushed the Caption box 62px out through the picker's dashed
   border. §4 records this failure three times already (the timeline embed's
   label column, the bulk editor's `.bl-sub`, the Locations row); this is the
   fourth, and the first where a FORM CONTROL rather than text was the thing
   that would not shrink.

   `min-width:0` on the item as well, because a grid item's own default width is
   also its content's intrinsic width — `minmax(0,…)` on the track alone is not
   enough, which is the half that is easy to miss. And `max-width:100%` on the
   control, so a long option is clipped by the box rather than sizing it. */
.rt-embed-fields{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:.5rem;margin:.4rem 0}
.rt-embed-fields .field{margin:0;min-width:0}
.rt-embed-fields .field select,
.rt-embed-fields .field input,
.rt-embed-fields .field textarea{max-width:100%;box-sizing:border-box}
/* THE CITATION MARKER, DRAWN IN THE BOX AN EDITOR IS TYPING IN.
   The stored marker is an EMPTY <cite data-cite="c1"></cite> (§3.10c) — right
   for the record, invisible in a contenteditable. So pressing Cite left no
   trace whatever in the box it was pressed in, and a marker put in the wrong
   sentence could not be found, let alone taken out.

   The number comes from `data-n`, written onto the live node by the picker's
   own pass over every attached box in the order the PAGE draws them — so it is
   the number the reader will see, not a count of this box. Neither that
   attribute nor the class carrying it can reach a record: getValue() sanitises,
   and `data-cite` is the only attribute a <cite> survives with.

   `content` rather than text, because the element has to stay empty — anything
   real inside it would be prose the sanitiser keeps and the renderer's own
   matcher, which wants the bare element, would stop recognising it. */
.rt-body cite[data-cite]{display:inline-block;font-style:normal;
  font-family:var(--utility);font-size:.66em;line-height:1.4;vertical-align:super;
  color:var(--paper);background:var(--oxblood);border:1px solid var(--oxblood);
  border-radius:2px;padding:0 .28em;margin:0 .08em;cursor:pointer;
  user-select:none;-webkit-user-select:none}
.rt-body cite[data-cite]::after{content:"[" attr(data-n) "]"}
/* A marker whose source has gone. The renderer deletes it and the validator
   refuses the record before that, so what an editor needs is to SEE it — hence
   the reversal, which is the loudest thing this small a mark can do without
   inventing a fourth colour. */
.rt-body cite.rt-cite-lost{color:var(--oxblood);background:var(--paper);
  border-style:dashed}
.rt-body [data-pp-embed]{display:block;border:2px dashed var(--moss);
  background:rgba(62,107,69,.08);padding:.5rem;margin:.6rem 0;
  font-family:var(--utility);font-size:.7rem;color:var(--moss);min-height:2rem}
.rt-body [data-pp-embed]::before{content:"⬗ live embed: " attr(data-pp-embed)}
/* A page widget, in the infrastructure-page editor. Same device as the embed
   above and deliberately a different colour: an embed is a live element of the
   archive and a widget is a piece of the site's furniture, so an editor
   glancing at a body can tell which of the two they are looking at. Without
   this the placeholder is an EMPTY DIV — invisible, unselectable, and
   impossible to delete except by guessing where the caret is. */
.rt-body [data-pp-widget]{display:block;border:2px dashed var(--lake);
  background:rgba(39,75,142,.07);padding:.5rem;margin:.6rem 0;
  font-family:var(--utility);font-size:.7rem;color:var(--lake);min-height:2rem}
.rt-body [data-pp-widget]::before{content:"▤ page furniture: " attr(data-pp-widget)}
/* The builder's live preview. Rendered by the post page's own hydrator, so
   the dashed placeholder styling above must NOT apply inside it — what you
   look at here is the finished embed. */
.rt-embed-preview{margin:.6rem 0;border-top:1px dashed rgba(59,42,23,.35);padding-top:.5rem}
.rt-embed-stage{border:2px solid var(--ink);background:var(--paper);padding:.6rem;
  max-height:32rem;overflow:auto;resize:vertical}
.rt-embed-stage [data-pp-embed]{border:none;background:none;padding:0;margin:0;
  font-family:inherit;font-size:inherit;color:inherit;min-height:0}
.rt-embed-stage [data-pp-embed]::before{content:none}
.rt-prev-wait{opacity:.7;font-style:italic}
@media (max-width:640px){
  /* Too narrow for three columns, but the year and its count still belong
     on one line — stacking all three left a full-width bar floating between
     a year and its titles. Titles then span the row beneath. */
  /* The shared grid changes, not the row: the row is a subgrid of it. */
  .embed-timeline .et-years{grid-template-columns:auto 1fr auto}
  .et-year{grid-template-columns:auto 1fr auto;grid-template-columns:subgrid;gap:.15rem .6rem}
  .et-titles,.et-empty{grid-column:1 / -1}
  .embed-thennow .tn-pair{grid-template-columns:1fr}
  .rt-embed-fields{grid-template-columns:1fr}
}
@media print{
  .embed-chart,.dispute-line,.dispute-vote,.request-vote,.suggest-box{display:none}
  .embed-timeline .et-years{box-shadow:none}
}

/* ============================================================
   The map — where the archive looks
   ============================================================ */
.wm-wrap{border:2px solid var(--ink);background:var(--paper);
  box-shadow:3px 3px 0 rgba(59,42,23,.2);overflow:hidden}
svg.worldmap{width:100%;height:auto;display:block;color:var(--ink)}
/* Zooming to a continent scales the user units, which would thicken every
   line with it. The graticule should read the same at any frame. */
svg.worldmap .wm-base *{vector-effect:non-scaling-stroke}
.wm-base{color:rgba(59,42,23,.55)}
/* Filled, never stroked. Each country is still its own closed subpath, so a
   stroke would draw every modern border back in — the anachronism §3.8 of
   CLAUDE.md exists to avoid. Unstroked, the shape's edge is the coastline. */
.wm-land path{fill:rgba(216,192,120,.55);stroke:none}
.wm-graticule line,.wm-equator,.wm-tropic{stroke:rgba(59,42,23,.28)}

/* A place with a defensible centre reads as a mark; a vanished polity reads
   as a soft area, because a pin would claim precision the tag lacks. */
/* --era is set per mark from the era holding most of that place's titles;
   it falls back to oxblood where a place has no dated titles at all. */
.wm-mark circle{fill:var(--era,var(--oxblood));fill-opacity:.55;stroke:var(--ink);stroke-width:1.5;
  cursor:pointer;transition:fill-opacity .12s ease}
.wm-mark:hover circle{fill-opacity:.85}
/* A region keeps its dashed, washed-out treatment whatever its era tint —
   point versus region must survive being read in one colour. */
.wm-mark.region circle{fill:var(--era,var(--lake));fill-opacity:.20;
  stroke:var(--era,var(--lake));stroke-width:1.5;stroke-dasharray:5 3}
.wm-mark.region:hover circle{fill-opacity:.40}
svg.worldmap a:focus-visible circle{stroke:var(--gold);stroke-width:3}

.wm-coverage{margin-top:1rem}
.wm-head{font-family:var(--utility);font-size:.78rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--lake);margin:0 0 .5rem}
.wm-bars{list-style:none;margin:0 0 .6rem;padding:0;display:flex;flex-direction:column;gap:.3rem}
.wm-bars li{display:grid;grid-template-columns:11rem 1fr 3rem;align-items:center;gap:.7rem;
  font-family:var(--utility);font-size:.76rem}
.wm-region{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.wm-bar{background:rgba(59,42,23,.12);height:.85rem;border:1.5px solid var(--ink)}
/* The fill is the continent's share; the segments inside it are that
   share's era mix, so the bar reads as one quantity split, not two. */
.wm-fill{display:flex;height:100%;opacity:.82}
.wm-seg{display:block;height:100%}
.wm-seg + .wm-seg{border-left:1px solid rgba(244,236,216,.55)}
.wm-legend{list-style:none;display:flex;flex-wrap:wrap;gap:.25rem .9rem;
  margin:.1rem 0 .6rem;padding:0;opacity:.85}
/* Size and family sit on the item, not the list: a general `li` rule wins
   over inheritance and the legend came out at body size. */
.wm-legend li{display:flex;align-items:center;gap:.3rem;
  font-family:var(--utility);font-size:.7rem;line-height:1.4}
.wm-swatch{width:.62rem;height:.62rem;border:1px solid var(--ink);flex:0 0 auto}
.wm-pct{text-align:right;opacity:.8}
.wm-unplaced{opacity:.75;font-style:italic}
.embed-map .wm-wrap{box-shadow:3px 3px 0 rgba(59,42,23,.18)}

@media (max-width:640px){
  .wm-bars li{grid-template-columns:7.5rem 1fr 2.6rem;font-size:.7rem}
}
@media print{ .wm-wrap{box-shadow:none} }

/* ============================================================
   Television series pages
   ============================================================ */
/* The way back to the programme, from an episode. Directly under the episode
   title, which is where a reader asks what this is an episode of. */
.ep-series{margin:.35rem 0 .2rem}
.ep-series a{
  font-family:var(--utility);font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--lake);text-decoration:none;border-bottom:1.5px solid var(--gold);
}
.ep-series a:hover,.ep-series a:focus-visible{color:var(--oxblood);border-color:var(--oxblood)}
.es-n{font-family:var(--body);text-transform:none;letter-spacing:0;opacity:.7;margin-left:.35rem}

.show-page .show-years{margin-top:.5rem}
.show-yearlist{font-family:var(--utility);font-size:.72rem;letter-spacing:.06em;margin:.3rem 0 .6rem}
.show-yearlist a{color:var(--lake);text-decoration:none;border-bottom:1px solid rgba(216,192,120,.7)}
.show-yearlist a:hover{color:var(--oxblood);border-color:var(--oxblood)}

/* The saltiness spread. An average reads the same for a run that is evenly
   loose and one that is faithful with a single lapse, so the shape is drawn —
   and every row carries its count in figures as well as in width (§7). */
.show-spread{margin:1.8rem 0}
.show-spread h2,.show-episodes h2,.show-page .marginalia-rail h2{
  font-family:var(--display);font-weight:400;color:var(--oxblood);font-size:1.35rem;
}
.salt-dist{list-style:none;margin:.8rem 0;padding:0;display:flex;flex-direction:column;gap:.3rem}
.sd-row{display:flex;align-items:center;gap:.6rem;font-family:var(--utility);font-size:.76rem}
.sd-row.is-empty{opacity:.45}
.sd-level{
  flex:0 0 1.5rem;height:1.5rem;display:flex;align-items:center;justify-content:center;
  border:1.5px solid var(--ink);background:var(--paper-deep);font-size:.8rem;
}
.sd-name{flex:0 0 9.5rem}
.sd-bar{flex:1 1 auto;height:.85rem;background:rgba(59,42,23,.08);border:1px solid rgba(59,42,23,.18)}
.sd-fill{display:block;height:100%;background:var(--oxblood)}
.sd-count{flex:0 0 2rem;text-align:right;font-size:.9rem}
@media (max-width:560px){ .sd-name{flex:0 0 6.5rem;font-size:.68rem} }

/* Season tabs reuse the browse tab row; the count rides along so a reader can
   see how long each season is before choosing one. */
.season-tabs{margin-bottom:.6rem}
.ss-n{margin-left:.4rem;opacity:.65;font-size:.9em}
.ep-code{font-family:var(--utility);font-size:.7rem;width:3.2rem;letter-spacing:.06em;opacity:.75}
.ep-written{
  margin-left:.5rem;font-family:var(--utility);font-size:.6rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--paper);background:var(--lake);padding:.08rem .35rem;
}
.ep-count{margin-top:.6rem}
@media (max-width:640px){ .ep-code{width:auto;min-width:2.6rem} }

/* ---- Where to watch ----
   Fills in from TMDB after load, so it ships hidden and there is no reserved
   space to collapse: it either arrives with content or is removed outright. */
.watch-box{margin:1.8rem 0;border-top:3px double var(--gold);padding-top:1rem}
.watch-box h3{font-family:var(--display);font-weight:400;color:var(--oxblood);font-size:1.2rem}
.wb-head{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin:.6rem 0 .9rem}
.wb-region-label{font-family:var(--utility);font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:rgba(36,28,18,.7)}
.wb-head select{font-family:var(--body);font-size:.95rem;padding:.3rem .5rem;
  border:2px solid var(--ink);background:#F5EFE0;color:var(--ink)}
.wb-group{margin-bottom:.9rem}
.wb-kind{font-family:var(--utility);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--lake);margin:0 0 .4rem}
.wb-list{list-style:none;display:flex;flex-wrap:wrap;gap:.45rem;margin:0;padding:0}
.wb-item{display:flex;align-items:center;gap:.45rem;border:1.5px solid var(--gold);
  background:rgba(216,192,120,.14);padding:.25rem .55rem .25rem .3rem}
/* The logo is decorative and the name sits beside it, so a service with no
   artwork is a name on its own rather than a gap (§7). */
.wb-logo{width:32px;height:32px;object-fit:contain;display:block}
.wb-name{font-family:var(--utility);font-size:.76rem;letter-spacing:.03em}
.wb-link{margin:.6rem 0 0}
.wb-link a{font-family:var(--utility);font-size:.76rem;letter-spacing:.06em;color:var(--oxblood)}
.wb-credit{margin-top:.7rem}
@media print{ .watch-box{display:none} }

/* ---- "Where it is set", on a review ----
   The names are the content and are always there; the map is the picture of
   them and arrives only if the places are anchored. The list reads as a row of
   chips rather than a bulleted list — these are tags, and each is a link into
   the timeline narrowed to that place. */
.review-places{margin:1.6rem 0}
/* THE SAME HEADING EVERY OTHER SECTION ON THE PAGE WEARS. This was the one
   section header in oxblood display type at 1.2rem while "Notable Historical
   Figures Referenced", "Recommended Reading", "The Breakdown" and "More from
   <period>" were all lake-blue utility caps — so the page had two kinds of
   section heading and nothing decided which a section got. It reads as a
   different LEVEL of thing rather than as one more section, which is the one
   claim it must not make. */
.review-places h3{font-family:var(--utility);color:var(--lake);text-transform:none;
  letter-spacing:.06em;margin-bottom:.6rem}
.rp-list{list-style:none;display:flex;flex-wrap:wrap;gap:.4rem;margin:.6rem 0 .9rem;padding:0}
.rp-list li{margin:0}
.rp-list a{
  display:inline-block;text-decoration:none;
  font-family:var(--utility);font-size:.74rem;letter-spacing:.06em;
  color:var(--ink);background:rgba(216,192,120,.18);
  border:1.5px solid var(--gold);padding:.24rem .6rem;
}
.rp-list a:hover,.rp-list a:focus-visible{background:var(--oxblood);color:var(--paper);border-color:var(--oxblood)}
/* A place the reader has STEPPED UP to: what the tagged places sit inside,
   rather than something this title is tagged with. Dotted and cooler, so the
   two kinds of chip are distinguishable at a glance — but never by that
   alone (§7): each carries a visually-hidden phrase naming what it sits above,
   and the title says the archive inferred it.

   Selected as `.rp-list a.rp-inherited` and `.period-tags a.rp-inherited`,
   both (0,2,1), because `.rp-list a` and `.period-tags a` are (0,1,1) and a
   bare `.rp-inherited` would be (0,1,0) — it would lose outright, and even
   `a.rp-inherited` would only TIE and fall to file order. That is §3.9c's
   lesson (the oxblood-on-oxblood Proceed button) and §4's, and this rule sits
   in a stylesheet where both have already happened once. Winning on
   specificity means moving this block cannot silently undo it. */
.rp-list a.rp-inherited,.period-tags a.rp-inherited{
  border:1.5px dashed var(--moss);
  background:rgba(51,96,66,.07);
  color:rgba(36,28,18,.78);
  font-style:italic;
}
.rp-list a.rp-inherited:hover,.rp-list a.rp-inherited:focus-visible,
.period-tags a.rp-inherited:hover,.period-tags a.rp-inherited:focus-visible{
  background:var(--moss);color:var(--paper);border-color:var(--moss);border-style:solid;
}
@media print{
  /* The dash survives where the tint does not. */
  .rp-list a.rp-inherited,.period-tags a.rp-inherited{
    background:none;border:.75pt dashed #000;color:#000}
}
/* No count and no era tint here: one title is one title, so a mark's size
   would have nothing to say, and the review already states its own era. */
.review-map .wm-mark circle{fill:var(--oxblood);fill-opacity:.5}
.review-map .wm-mark.region circle{fill:var(--lake);fill-opacity:.22}
.rv-map-note{margin-top:.5rem}

/* ============================================================
   Admin — placing a location on the map
   ============================================================ */
.loc-map-box{margin-bottom:1rem}
.lm-head{margin:0 0 .5rem}
.lm-shown{margin:.4rem 0 0}
.lm-shown:empty{display:none}
.lm-offscope{color:var(--oxblood);font-style:italic}
.lm-wrap{cursor:crosshair}
.lm-map{display:block}
.lm-mark{fill:var(--oxblood);fill-opacity:.5;stroke:var(--ink);stroke-width:1.2}
.lm-mark.region{fill:var(--lake);fill-opacity:.18;stroke:var(--lake);stroke-dasharray:5 3}
/* The one being edited is the only mark with a solid dark ring, and it also
   carries a crosshair — the highlight is never colour alone. */
.lm-mark.on{fill:var(--gold);fill-opacity:.6;stroke:var(--ink);stroke-width:2.5;stroke-dasharray:none}
.lm-cross{stroke:var(--ink);stroke-width:1.6;fill:none}
/* Zoomed in to place one anchor, the neighbours are context, not content. */
.wm-marks.zoomed .lm-mark:not(.on){opacity:.18}
.wm-marks.zoomed .lm-mark.region:not(.on){fill-opacity:.05}
.lm-controls{display:grid;grid-template-columns:1fr 1fr;gap:.6rem;margin-top:.7rem;align-items:end}
.lm-controls .field{margin:0}
.lm-radius{display:flex;align-items:center;gap:.6rem}
.lm-radius input[type=range]{flex:1 1 auto;accent-color:var(--oxblood)}
.lm-r-out{font-family:var(--utility);font-size:.72rem;white-space:nowrap;min-width:5.5rem}
.lm-readout{grid-column:1/-1;margin:0}
.loc-row.anchoring{outline:2px solid var(--gold);outline-offset:-2px}
button.lr-name{font:inherit;text-align:left;background:none;border:0;padding:0;
  color:inherit;cursor:pointer;text-decoration:underline;text-decoration-style:dotted}
button.lr-name:hover{color:var(--oxblood)}
.lr-anchor{font-family:var(--utility);font-size:.62rem;letter-spacing:.04em;
  text-transform:uppercase;border:1.5px solid currentColor;padding:0 .3rem;
  white-space:nowrap;flex:0 0 auto}
.lr-anchor.is-point{color:var(--oxblood)}
.lr-anchor.is-region{color:var(--lake)}
.lr-anchor.is-excused{color:var(--ink);opacity:.6}
.lr-anchor.is-missing{color:var(--oxblood);background:rgba(122,29,29,.12);font-weight:700}
/* An anchor nothing names any more. The row says "no entries" in words and
   the panel says so again above the map, so this only reinforces it (§7) —
   struck through because the name has left the catalogue and the row is
   what is left behind. */
.loc-row.orphan .lr-name{text-decoration:line-through;opacity:.7}
.loc-row.orphan .lr-n{font-style:italic;opacity:1;color:var(--oxblood)}
@media (max-width:640px){
  .lm-controls{grid-template-columns:1fr}
}

/* The spread and the effect size for the pulled threads, inside the thread
   panel rather than on a page of their own. Same components the statistics
   page uses; only the grouping differs. */
.thread-stats{border-top:2px solid var(--ink);padding:.8rem;background:var(--paper)}
.th-stats-head{font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.1rem;margin-bottom:.2rem}
.th-stats-btn{flex:0 0 auto;align-self:flex-start;margin-right:.4rem}
.th-box,.th-delta{margin-top:.6rem}
@media print{ .thread-stats{display:none} }

/* ==========================================================================
   The location hierarchy (§3.11k) — the admin editor, the map layers, and
   the /locations page.

   One palette across all three, so a tier reads the same wherever it turns
   up: city ultramarine, province verdigris, region gold, state vermilion.
   COLOUR IS NEVER THE CARRIER (§7) — every tier is spelled out in words in
   the chip, the checkbox label, the tooltip and the filter dropdown, and
   these tints only make a scanned column easier to group by eye.
   ========================================================================== */

/* ---- admin: marking a location ---- */
.loc-tier-set{display:flex;flex-wrap:wrap;gap:.35rem}
.loc-tier-opt{display:flex;align-items:baseline;gap:.35rem;cursor:pointer;
  border:1.5px solid rgba(59,42,23,.35);background:var(--paper);padding:.25rem .5rem;
  font-family:var(--utility);font-size:.76rem}
.loc-tier-opt:has(input:checked){border-color:var(--oxblood);background:rgba(158,43,37,.08)}
.loc-tier-opt:has(input:disabled){opacity:.5;cursor:default}
.loc-tier-opt input{accent-color:var(--oxblood)}
.lt-name{font-weight:700}
.lt-hint{font-size:.66rem;opacity:.7}
.loc-span{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap}
.loc-span-out{font-family:var(--utility);font-size:.72rem;opacity:.75}
/* The tier column in the Locations list. Sits between the anchor state and
   the group, because it is a fact about the place rather than about the map
   or about the reader's headings. */
.loc-row{grid-template-columns:1fr 5.5rem 8rem 5.5rem auto}
.lr-tier{font-family:var(--utility);font-size:.62rem;letter-spacing:.04em;
  text-transform:uppercase;white-space:nowrap;font-weight:700}
.lr-tier.is-city{color:var(--lake)}
.lr-tier.is-province{color:var(--moss)}
/* --gold is 2.37:1 on parchment. --gold-text is the same hue darkened to
   4.50:1, and it exists in this file for exactly this case. */
.lr-tier.is-region{color:var(--gold-text)}
.lr-tier.is-state{color:var(--oxblood)}
.lr-tier.is-none{opacity:.4;font-weight:400}

/* ---- admin: "you tagged Munich; did you want Bavaria too?" ---- */
.loc-suggest{margin:.4rem 0 .8rem;padding:.5rem .6rem;
  border:1.5px dashed rgba(59,42,23,.4);background:rgba(216,192,120,.12)}
.ls-head{margin:0 0 .4rem}
.ls-chips{display:flex;flex-wrap:wrap;gap:.4rem}
.btn.ls-chip{display:inline-flex;flex-direction:column;align-items:flex-start;
  gap:.1rem;text-align:left;line-height:1.2}
.ls-why{font-family:var(--utility);font-size:.62rem;opacity:.75;font-weight:400}

/* ---- a title's map, read at more than one height ---- */
.rv-map-layers{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;
  margin-bottom:.5rem;font-family:var(--utility);font-size:.76rem}
.rv-layers-label{text-transform:uppercase;letter-spacing:.08em;font-size:.66rem;
  color:var(--lake)}
.rv-layer{display:inline-flex;align-items:center;gap:.3rem;cursor:pointer;
  border:1.5px solid rgba(59,42,23,.35);background:var(--paper);padding:.15rem .45rem}
.rv-layer:has(input:checked){border-color:var(--oxblood);background:rgba(158,43,37,.08)}
/* Greyed out because the archive has nothing at that level. The title on the
   label says which of the two it is; this only makes it visible at a glance. */
.rv-layer:has(input:disabled){opacity:.45;cursor:default}
.rv-layer input{accent-color:var(--oxblood)}
.rv-layer-note{font-size:.68rem;opacity:.72;flex-basis:100%}
/* A mark nothing on the page is tagged with — the archive's inference from
   the hierarchy rather than the entry's own claim. Paler, and the tooltip
   says so in words, because a lighter circle is not an explanation. */
.wm-mark.inherited{opacity:.55}
.wm-mark.inherited circle{stroke-dasharray:3 2}

/* ---- /locations ---- */
.lp-list{border:2px solid var(--ink);background:var(--paper)}
.lp-row{display:grid;grid-template-columns:1.6rem 1fr 5.5rem 3.2rem 3.4rem;
  align-items:center;gap:.6rem;padding:.5rem .6rem;
  border-bottom:1px solid rgba(59,42,23,.16);
  /* Nested rows step in from the left; the tree is also carried by the
     disclosure buttons and by the "inherited" wording on the row, so indent
     alone is never the only signal that one place sits inside another. */
  padding-left:calc(.6rem + var(--depth, 0) * 1.1rem)}
.lp-row-wrap:nth-child(odd) > .lp-row{background:rgba(216,192,120,.09)}
.lp-nested{background:rgba(39,75,142,.05)}
.lp-toggle{background:none;border:0;padding:0;cursor:pointer;color:var(--oxblood);
  font-size:.9rem;width:1.6rem;text-align:center}
.lp-toggle:hover{color:var(--ink)}
.lp-nokids{cursor:default;visibility:hidden}
.lp-main{display:flex;flex-direction:column;min-width:0;text-decoration:none;color:var(--ink)}
.lp-main:hover .lp-name,.lp-main:focus-visible .lp-name{color:var(--oxblood)}
.lp-name{font-family:var(--body);font-weight:700;font-size:1rem;
  display:flex;align-items:baseline;gap:.4rem;flex-wrap:wrap}
.lp-sub{font-family:var(--utility);font-size:.72rem;opacity:.72}
.lp-tier{font-family:var(--utility);font-size:.6rem;letter-spacing:.05em;
  text-transform:uppercase;border:1.5px solid currentColor;padding:0 .3rem;font-weight:400}
.lp-tier.is-city{color:var(--lake)}
.lp-tier.is-province{color:var(--moss)}
.lp-tier.is-region{color:var(--gold-text)}
.lp-tier.is-state{color:var(--oxblood)}
.lp-count{font-family:var(--utility);font-size:.9rem;text-align:right;white-space:nowrap}
.lp-count small{opacity:.55;font-size:.62em;display:block;line-height:1}
.lp-salt{flex:0 0 auto}
.lp-rating{font-family:var(--utility);font-size:.92rem;text-align:right;white-space:nowrap}
.lp-rating small{opacity:.55;font-size:.7em}
/* An average over nothing. A dash rather than a 0, which would rank as a
   score and read as one (§3.2). */
.lp-none{opacity:.45}
.lp-kids{border-left:2px solid rgba(39,75,142,.25);margin-left:.6rem}

@media (max-width:640px){
  /* Two rows rather than five. The three figures drop UNDER the name and sit
     on one line together — placed explicitly, because three grid items sharing
     a column auto-place into three separate rows and turn every place into a
     four-line block. None of them is dropped: a place with no rating is a
     different claim from one whose column was squeezed out of the layout. */
  .lp-row{grid-template-columns:1.4rem 1fr auto auto;row-gap:.15rem}
  .lp-toggle{grid-row:1/3}
  .lp-main{grid-column:2/-1}
  .lp-count{grid-column:2;text-align:left}
  .lp-count small{display:inline;margin-left:.2rem}
  .lp-salt{grid-column:3}
  .lp-rating{grid-column:4}
  .loc-row{grid-template-columns:1fr auto}
  .lr-anchor,.lr-tier{grid-column:auto}
}

/* ---- location dates: a circa per end, and "Present" as a real answer ---- */
.loc-span-end{display:inline-flex;align-items:center;gap:.35rem}
.loc-circa{display:inline-flex;align-items:center;gap:.2rem;cursor:pointer;
  font-family:var(--utility);font-size:.72rem;white-space:nowrap}
.loc-circa input{accent-color:var(--oxblood)}
.loc-circa:has(input:disabled){opacity:.45;cursor:default}
/* Set apart from the two "c." boxes: it answers a different question — not
   "how sure is this year" but "is there a year at all". */
.loc-present{margin-left:.5rem;padding-left:.5rem;border-left:1.5px solid rgba(59,42,23,.3)}

/* ---- what names the selected location ---- */
.loc-used{grid-column:1/-1;border-top:1.5px dashed rgba(59,42,23,.3);
  margin-top:.4rem;padding-top:.5rem}
.lu-head{margin:0 0 .35rem}
.lu-list{display:flex;flex-wrap:wrap;gap:.35rem;max-height:9rem;overflow:auto}
.lu-list li{display:inline-flex;align-items:center;gap:.3rem;
  border:1.5px solid var(--gold);background:var(--paper);padding:.1rem .4rem}
.lu-open{font:inherit;font-family:var(--body);font-size:.82rem;background:none;border:0;
  padding:0;color:var(--oxblood);cursor:pointer;text-decoration:underline;
  text-decoration-style:dotted}
.lu-open:hover{color:var(--ink)}
.lu-kind{font-family:var(--utility);font-size:.6rem;letter-spacing:.04em;
  text-transform:uppercase;opacity:.7}

/* Why a bulk row matched, when the title was not the reason. Without it a row
   appears under a search matching nothing visible on it, which reads as a
   broken filter. */
.bl-why{font-style:italic;color:var(--oxblood)}
/* Sits under the rows, inside the bordered list, so it reads as a caption on
   what is above it rather than as a note about the panel. */
.bl-order{margin:0;padding:.4rem .7rem;border-top:1px solid rgba(59,42,23,.16);
  background:rgba(216,192,120,.09)}

/* ---- /locations: the groups, in their own window above the ranked list ----
   A group is the coarsest thing on the page and the one a reader reaches for
   first — "Egypt" long before "Ptolemaic Egypt". It is also the group CONTROL:
   the select that used to do this is gone, because two surfaces owning one
   piece of state is how they come to disagree about what is chosen. */
.loc-groups{border:2px solid var(--ink);background:rgba(216,192,120,.14);
  padding:.8rem .9rem;margin-bottom:1.2rem}
/* A <details>, so the open/shut costs no script of ours and the keyboard and
   ARIA are already right (§3.11a).

   The marker is a boxed PLUS/MINUS, not the small rotating chevron it was. A
   bare ▸ at .9rem reads as ornament next to a display-face heading — it is
   the same glyph the tree rows use as a bullet, and at that size the rotation
   is the only thing distinguishing the two states. A framed + and − is the
   one disclosure affordance nobody has to learn, and it is legible at a
   glance from across the page. The state is still carried by `open` on the
   element, so this is a second signal rather than the only one (§7). */
.loc-groups-box{margin:0}
.lg-summary{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;
  cursor:pointer;list-style:none}
.lg-summary::-webkit-details-marker{display:none}
.lg-summary::before{content:'\2212';              /* minus: open, press to shut */
  display:inline-flex;align-items:center;justify-content:center;
  width:1.45rem;height:1.45rem;flex:0 0 auto;
  border:2px solid var(--oxblood);color:var(--oxblood);background:var(--paper);
  font-family:var(--utility);font-size:1.05rem;line-height:1;
  box-shadow:2px 2px 0 rgba(158,43,37,.2)}
.loc-groups-box:not([open]) > .lg-summary::before{content:'+'}
.lg-summary:hover::before{background:var(--oxblood);color:var(--paper)}
.lg-summary:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.lg-summary:hover .lg-head{color:var(--ink)}
.lg-head{font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.35rem;margin:0}
/* The count is on the summary, so a collapsed section still says what it is
   holding — a shut box that names nothing is a box nobody opens. */
.lg-count{font-family:var(--utility);font-size:.74rem;opacity:.75}
.lg-body{margin-top:.5rem}
.lg-sort{display:flex;gap:.4rem;flex-wrap:wrap;margin:.5rem 0}
.lg-sort-btn{font-family:var(--utility);font-size:.72rem;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--gold);
  padding:.15rem .55rem}
.lg-sort-btn:hover{background:rgba(158,43,37,.09)}
/* The chosen button is FILLED. Which one is chosen is the only thing this
   colour says — it never says which way an order runs (§3.7b). */
.lg-sort-btn.on{background:var(--oxblood);color:var(--paper);border-color:var(--ink)}
.lg-pager{margin-top:.6rem}
.lg-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(15rem,1fr));
  gap:.6rem;margin-top:.6rem}
.lg-card{display:flex;flex-direction:column;border:2px solid var(--ink);
  background:var(--paper)}
.lg-card.on{border-color:var(--oxblood);box-shadow:2px 2px 0 rgba(158,43,37,.25)}
.lg-pick{flex:1 1 auto;display:flex;flex-direction:column;gap:.15rem;
  text-align:left;background:none;border:0;padding:.55rem .65rem;cursor:pointer;
  font:inherit;color:var(--ink)}
.lg-pick:hover{background:rgba(158,43,37,.07)}
.lg-card.on .lg-pick{background:rgba(158,43,37,.08)}
.lg-name{font-family:var(--body);font-weight:700;font-size:1.02rem}
.lg-n{font-family:var(--utility);font-size:.74rem;color:var(--oxblood)}
/* The members are the whole point of a heading — they say what the word
   gathers, which is the question a group entry exists to answer. */
.lg-members{font-family:var(--utility);font-size:.68rem;opacity:.75;line-height:1.35}
.lg-go{font-family:var(--utility);font-size:.7rem;text-decoration:none;
  border-top:1.5px solid rgba(59,42,23,.25);padding:.35rem .65rem;color:var(--oxblood)}
.lg-go:hover{background:var(--oxblood);color:var(--paper)}
.lg-said:empty{display:none}
.lg-said{margin-top:.5rem}

/* ---- era ribbons -----------------------------------------------------------
   One strip, two meanings, and the class is shared because the DRAWING is:
   on /locations a ribbon is an era a place's own span reached, on /browse it
   is an era a title is set in. A reader who has learnt the colours on one page
   should not have to learn them again on the other, and PP.eraRibbonsHTML is
   the one thing emitting both (§3.8's argument for one map canvas and two
   maps).

   COLOUR IS NEVER THE ONLY CARRIER (§7): the strip has an accessible name
   listing the eras in words, every ribbon carries its era's name in a title,
   and both callers print the fact — a span, or the years — beside it. */
.era-ribbons{display:inline-flex;gap:2px;align-items:center;margin-left:.15rem;
  vertical-align:middle}
.era-ribbon{display:inline-block;width:.45rem;height:.85rem;border:1px solid rgba(59,42,23,.45)}

/* ---- the continent reference (§3.11k) ------------------------------------
   Required, unlike everything else on the Locations panel, and checkboxes
   rather than the tier's radios because an empire is not on one continent. */
.loc-cont-set{display:flex;flex-wrap:wrap;gap:.3rem}
.loc-cont-opt{display:inline-flex;align-items:center;gap:.3rem;cursor:pointer;
  border:1.5px solid rgba(59,42,23,.35);background:var(--paper);padding:.2rem .45rem;
  font-family:var(--utility);font-size:.74rem}
.loc-cont-opt:has(input:checked){border-color:var(--oxblood);background:rgba(158,43,37,.08)}
.loc-cont-opt:has(input:disabled){opacity:.5;cursor:default}
.loc-cont-opt input{accent-color:var(--oxblood)}
/* Context beside the year boxes, never a value in them: the archive knows
   which years its titles use, and that is a floor for the dates rather than
   the dates. */
.loc-span-hint{flex-basis:100%;margin:.3rem 0 0}

/* ---- placing many locations at once ---- */
.loc-bulk{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;margin-bottom:.5rem;
  padding:.45rem .55rem;border:1.5px dashed rgba(59,42,23,.4);
  background:rgba(216,192,120,.12)}
/* It sits outside a .field wrapper, so it was inheriting NO input styling at
   all — a pale borderless box stretched across the panel while every other
   search on the site has an ink border and a shadow. Same declarations as
   `.field input`, with the placeholder and focus treatment `.list-search`
   uses, and a cap so it stops sprawling. */
.loc-bulk input[type=text],.loc-bulk input:not([type]){
  flex:1 1 14rem;min-width:0;max-width:22rem;
  font-family:var(--body);font-size:1rem;padding:.5rem .7rem;
  border:2px solid var(--ink);background:#F5EFE0;color:var(--ink);
  box-shadow:2px 2px 0 rgba(59,42,23,.2)}
.loc-bulk input::placeholder{color:rgba(59,42,23,.5);font-style:italic}
.loc-bulk input:focus{outline:none;border-color:var(--oxblood);
  box-shadow:2px 2px 0 var(--gold)}
.loc-bulk input:disabled{opacity:.55;box-shadow:none}
.loc-bulk .btn{margin:0;flex:0 0 auto}
.loc-bulk-say{font-family:var(--utility);font-size:.7rem;opacity:.75;white-space:nowrap}

/* The search over the Locations list. It sits outside a `.field`, which is
   where the admin's input styling lives — so without this it renders as a pale
   borderless box beside a properly bordered one, which is §4's "a control
   styled by the wrapper it was not put in", recorded about the bulk box three
   rules above and walked into again here.

   The same DECLARATIONS as its neighbour rather than a copy of the block: what
   has to be true is that it looks like an admin input, and asserting the
   properties is what survives the block being retuned. `type=search` needs the
   appearance reset, or WebKit draws its own control inside the border. */
.loc-search{display:flex;flex-wrap:wrap;align-items:baseline;gap:.5rem;margin:0 0 .5rem}
.loc-search h3{margin:0;flex:0 0 auto}
.loc-search input[type=search]{
  -webkit-appearance:none;appearance:none;
  flex:1 1 12rem;min-width:0;max-width:20rem;
  font-family:var(--body);font-size:1rem;padding:.5rem .7rem;
  border:2px solid var(--ink);background:#F5EFE0;color:var(--ink);
  box-shadow:2px 2px 0 rgba(59,42,23,.2)}
.loc-search input::placeholder{color:rgba(59,42,23,.5);font-style:italic}
.loc-search input:focus{outline:none;border-color:var(--oxblood);
  box-shadow:2px 2px 0 rgba(158,43,37,.25)}
.loc-search-say{font-family:var(--utility);font-size:.7rem;opacity:.75;white-space:nowrap}

/* The two list filters, moved under the map and directly above the list they
   narrow. Side by side where there is room: they are one decision ("which rows
   am I working on") asked two ways, and stacking them put the list another
   screen down. */
.loc-filter-row{display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;margin:.8rem 0 .2rem}
.loc-filter-row > *{flex:1 1 18rem;min-width:0;margin:0}
/* SEVEN cells now — the select tick joined name, count, anchor, tier, group
   and the group action — and a grid track does not clip what overflows it.
   Adding the tick pushed the row past its width and cells painted over one
   another: the third time this trap has been walked into (§4), so every cell
   clips and `min-width:0` overrides the intrinsic-width default that makes
   `minmax(0,…)` on the track insufficient on its own. */
.loc-row{grid-template-columns:1.2rem minmax(0,1fr) minmax(0,4.5rem) minmax(0,6.5rem)
  minmax(0,4.5rem) minmax(0,6rem) auto}
.loc-row > *{min-width:0;overflow:hidden;text-overflow:ellipsis}
.lr-tick{accent-color:var(--oxblood);overflow:visible}
.lr-tick{accent-color:var(--oxblood)}

/* ---- the whole hierarchy, as an outline ---- */
.loc-tree-sum{cursor:pointer;font-family:var(--utility);font-size:.8rem;
  letter-spacing:.04em;color:var(--lake)}
.loc-tree{max-height:26rem;overflow:auto;margin-top:.5rem}
.lt-row{display:flex;align-items:baseline;gap:.45rem;flex-wrap:wrap;
  padding:.15rem .3rem;border-bottom:1px solid rgba(59,42,23,.1);
  /* The indent is the shape. Every row also names its tier in words, so the
     depth is a shortcut to the hierarchy rather than the only carrier (§7). */
  padding-left:calc(.3rem + var(--d, 0) * 1.2rem)}
.lt-row:nth-child(odd){background:rgba(216,192,120,.09)}
.lt-n{font-family:var(--body);font-weight:700;font-size:.86rem}
.lt-t{font-family:var(--utility);font-size:.6rem;letter-spacing:.04em;
  text-transform:uppercase;font-weight:700}
.lt-t.is-city{color:var(--lake)}
.lt-t.is-province{color:var(--moss)}
.lt-t.is-region{color:var(--gold-text)}
.lt-t.is-state{color:var(--oxblood)}
.lt-c,.lt-s,.lt-k{font-family:var(--utility);font-size:.66rem;opacity:.72}
.lt-k{color:var(--oxblood);opacity:1}

/* ---- entries naming a place and its ancestor ---- */
.loc-dup{margin-top:.5rem;max-height:20rem;overflow:auto}
.ld-row{display:flex;flex-wrap:wrap;align-items:baseline;gap:.45rem;
  padding:.2rem .3rem;border-bottom:1px solid rgba(59,42,23,.1)}
.ld-why{font-family:var(--utility);font-size:.68rem;opacity:.75}

/* ---- a group whose members' spans tile is a succession -------------------
   One place changing hands down the centuries, which the spans already
   encoded. The arrows are aria-hidden and the card says "one place, three
   names in turn" in words, because an arrow is not a relationship (§7). */
.lg-chain{display:flex;flex-wrap:wrap;align-items:baseline;gap:.25rem;
  font-family:var(--utility);font-size:.68rem;line-height:1.35}
.lg-link{display:inline-flex;flex-direction:column}
.lg-link-n{font-weight:700}
.lg-link-y{opacity:.7;font-size:.92em}
.lg-arrow{color:var(--oxblood);align-self:center}

/* Two lines rather than seven squeezed columns. The badges wrap under the
   name and keep their own order; nothing is dropped, because a location with
   no tier is a different claim from one whose column was squeezed out. */
@media (max-width:900px){
  .loc-row{grid-template-columns:1.2rem 1fr auto;row-gap:.15rem}
  .lr-n,.lr-anchor,.lr-tier,.lr-group{grid-column:2/-1;
    display:inline-block;margin-right:.6rem}
  .lr-name{grid-column:2/-1}
}

/* ---- when a title is SET ---------------------------------------------------
   The whole site files a title by the year it depicts, and on a review page
   that year used to be a 0.72rem line of uppercase grey at 60% opacity,
   buried under the write-up and the Sources — the least prominent thing on a
   page about it. It sits in the header now, at the size of a fact. */
.set-in-plate{display:flex;align-items:baseline;flex-wrap:wrap;gap:.5rem;
  margin:.9rem 0 .2rem;padding:.45rem .7rem;
  border-left:4px solid var(--oxblood);background:rgba(216,192,120,.22)}
.sip-label{font-family:var(--utility);font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--lake)}
.sip-years{display:flex;align-items:baseline;flex-wrap:wrap;gap:.4rem;
  font-family:var(--display);font-size:1.5rem;line-height:1.1}
.sip-years a{color:var(--oxblood);text-decoration:none;
  border-bottom:2px solid rgba(158,43,37,.3)}
.sip-years a:hover,.sip-years a:focus-visible{border-bottom-color:var(--oxblood);
  background:rgba(158,43,37,.07)}
.sip-sep{color:var(--gold-text);font-size:1.1rem}
.set-in-plate .circa-note{font-family:var(--utility);font-size:.7rem;
  color:rgba(59,42,23,.75);font-style:italic}
/* ---- the plate on a title that names no year (§3.11i3) --------------------
   THE DISPLAY FACE IS FOR A YEAR, NOT FOR A SENTENCE. `.sip-years` is
   UnifrakturMaguntia at 1.5rem, which is right for "1943" and wrong for
   "somewhere between 1865 and 1890" — thirty characters of blackletter is a
   thing a reader decodes rather than reads. So the RANGE takes the body face
   at a prose size, and the FILED YEAR keeps the display face at the plate's own
   size: the shape of an ordinary plate survives, with the width as the clause
   qualifying it. */
.set-in-span .sip-years{font-family:var(--body);font-size:1.05rem;
  font-style:italic;line-height:1.3}
.sip-filed{display:flex;align-items:baseline;gap:.35rem}
.sip-filed .sf-label{font-family:var(--utility);font-size:.68rem;
  letter-spacing:.14em;text-transform:uppercase;color:var(--lake)}
.sip-filed a{font-family:var(--display);font-size:1.5rem;line-height:1.1;
  color:var(--oxblood);text-decoration:none;
  border-bottom:2px solid rgba(158,43,37,.3)}
.sip-filed a:hover,.sip-filed a:focus-visible{border-bottom-color:var(--oxblood);
  background:rgba(158,43,37,.07)}
@media (max-width:640px){
  .sip-years{font-size:1.25rem}
  .set-in-span .sip-years{font-size:1rem}
  .sip-filed a{font-size:1.25rem}
}

/* ---- "show what these sit inside" ------------------------------------------
   The one control on a title's map that a reader who has not thought about
   tiers can use: it answers "what was this part of?" without their needing to
   know that Bastogne's answer is filed under Provinces and Hawaii's under
   States. It drives the same state the boxes beside it do, so it leads them
   rather than sitting apart. */
.rv-step-up{font-family:var(--utility);font-size:.74rem;cursor:pointer;
  background:var(--paper);color:var(--oxblood);border:2px solid var(--oxblood);
  padding:.25rem .6rem;box-shadow:2px 2px 0 rgba(158,43,37,.2)}
.rv-step-up:hover{background:var(--oxblood);color:var(--paper)}
.rv-step-up[hidden]{display:none}

/* ============================================================
   Period pages (§3.11l)
   A period is a SPAN, and the boundaries are the loudest thing on
   the page after the title — they were previously visible only as
   two numbers inside a glossary sentence.
   ============================================================ */
.period-head{margin-bottom:1.4rem}
.pd-bounds{margin-top:1rem}
/* The width of the span beside the two dates. Two four-digit numbers do not
   read as a duration, and most of the difference between the Roman Empire and
   the Trojan War is one of scale. */
.pd-span{font-family:var(--utility);font-size:.7rem;letter-spacing:.1em;
  text-transform:uppercase;color:rgba(59,42,23,.75)}
.pd-unbounded{font-family:var(--display);font-size:1.2rem;font-style:italic;
  color:rgba(59,42,23,.7)}
.pd-eras{display:flex;align-items:center;flex-wrap:wrap;gap:.5rem;margin:.5rem 0 .8rem}
.pd-era-names{font-family:var(--utility);font-size:.7rem;letter-spacing:.08em;
  color:rgba(59,42,23,.8)}
.pd-descriptor{margin:.8rem 0 1rem;max-width:44rem}
.pd-timeline{margin:.2rem 0 1.4rem}
.pd-timeline a{font-family:var(--utility);font-size:.74rem;letter-spacing:.08em;
  color:var(--lake);text-decoration:none;border-bottom:1.5px solid var(--gold)}
.pd-timeline a:hover,.pd-timeline a:focus-visible{color:var(--oxblood);
  border-color:var(--oxblood)}

.pd-titles,.pd-density,.pd-spread,.pd-credits,.pd-around{margin:1.8rem 0}
.period-page h2{font-family:var(--display);font-weight:400;color:var(--oxblood);
  font-size:1.35rem}
.pd-credit-head{font-family:var(--display);font-weight:400;font-size:1.05rem;
  color:var(--ink);margin:1rem 0 .3rem}
/* The depicted year leads each row, the way an episode code leads a series
   row: this is a chronological shelf, not a ranking, so a position number
   would claim an order that is not being applied. */
/* Selected through the page wrapper so it beats `.br-rank`'s 2.2rem on
   SPECIFICITY (0,2,0 against 0,1,0) rather than on file order — moving this
   block would otherwise silently hand a prehistoric year a two-character
   column. §3.9c's lesson, one stylesheet section over. */
.period-page .pd-yr{font-family:var(--utility);font-size:.72rem;letter-spacing:.04em;
  width:5.4rem;opacity:.8;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pd-outside{margin-left:.5rem;font-family:var(--utility);font-size:.6rem;
  letter-spacing:.08em;text-transform:uppercase;color:var(--paper);
  background:rgba(59,42,23,.6);padding:.08rem .35rem}
@media (max-width:640px){ .period-page .pd-yr{width:auto;min-width:3rem} }

/* ---- density ----
   The percentage is the headline and the fraction is beside it: a percentage
   with no denominator is the thing §3.7 refuses. */
.pd-dense-lead{display:flex;align-items:baseline;flex-wrap:wrap;gap:.7rem;
  margin:.8rem 0;padding:.7rem .9rem;border:2px solid var(--oxblood);
  background:rgba(158,43,37,.07)}
.pd-pct{font-family:var(--display);font-size:2.1rem;line-height:1;
  color:var(--oxblood)}
.pd-dense-say{flex:1 1 16rem;min-width:0;font-family:var(--body);font-size:.95rem}

/* The years inside the boundaries. Grid on the LIST with each row subgridding
   into it, never a fixed track per row: a track does not clip what overflows
   it, and "80,000 BCE" is three times the width of "1944" — the trap §4 has
   already recorded three times. The label track is `auto`, so it is one width
   set by the longest label here and the same width on every row, which is the
   only way the bars beneath each other compare. */
.pd-years{list-style:none;margin:.9rem 0 .4rem;padding:0;
  border:2px solid var(--ink);background:var(--paper);
  box-shadow:3px 3px 0 rgba(59,42,23,.2);
  display:grid;grid-template-columns:auto 1fr auto}
.pd-year{display:grid;grid-column:1 / -1;
  grid-template-columns:minmax(3.2rem,auto) 1fr auto;
  grid-template-columns:subgrid;
  gap:.1rem .7rem;align-items:center;padding:.28rem .7rem;
  border-bottom:1px solid rgba(59,42,23,.18)}
.pd-year:last-child{border-bottom:none}
.pd-year:nth-child(odd){background:rgba(216,192,120,.10)}
.pd-year > *{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pd-y-label{font-family:var(--display);font-size:1rem;color:var(--oxblood);
  text-decoration:none}
.pd-y-label:hover{text-decoration:underline}
.pd-year.is-empty .pd-y-label{opacity:.55}
/* Two bars nested: the outer is this year's share of the busiest year, the
   inner the tagged share of this year. Both numbers are printed beside it, so
   the drawing summarises figures rather than replacing them (§7). */
.pd-y-bar{height:.6rem;background:rgba(59,42,23,.10);
  border:1px solid rgba(59,42,23,.28);overflow:hidden}
.pd-y-total{display:block;height:100%;background:rgba(59,42,23,.22)}
.pd-y-tag{display:block;height:100%;background:var(--oxblood);opacity:.75}
.pd-y-n{font-family:var(--utility);font-size:.7rem;opacity:.85;text-align:right}
.pd-y-none{font-style:italic;opacity:.6}

/* ---- around it on the timeline ---- */

/* Which titles put a book on the list — the part a reader uses to decide, and
   what makes the de-duplication visible rather than a silent merge. */
.bk-from{font-family:var(--utility);font-size:.68rem;color:rgba(59,42,23,.75)}
.bk-from a{color:var(--lake);text-decoration:none;
  border-bottom:1px solid rgba(216,192,120,.7)}
.bk-from a:hover{color:var(--oxblood);border-color:var(--oxblood)}

/* ---- period pages, second pass -------------------------------------------
   The way onto the timeline, as a plate rather than a line of small text: this
   page is the only route to the rule that arrives already filtered to a
   stretch of history, so it should read as somewhere to go. */
.pd-timeline{margin:.4rem 0 1.6rem}
.pd-tl-btn{
  display:grid;grid-template-columns:1fr auto;align-items:center;
  gap:.1rem .8rem;text-decoration:none;color:var(--ink);
  border:2px solid var(--oxblood);background:rgba(158,43,37,.07);
  padding:.6rem .9rem;box-shadow:3px 3px 0 rgba(158,43,37,.18);
}
.pd-tl-btn:hover,.pd-tl-btn:focus-visible{background:rgba(158,43,37,.14)}
.pd-tl-what{font-family:var(--display);font-size:1.15rem;color:var(--oxblood);
  grid-column:1;min-width:0}
.pd-tl-why{font-family:var(--utility);font-size:.7rem;letter-spacing:.04em;
  opacity:.8;grid-column:1;min-width:0}
.pd-tl-arrow{grid-column:2;grid-row:1 / span 2;font-size:1.4rem;color:var(--oxblood)}

/* ---- around it on the timeline ----
   A TABLE, because it is tabular: three indented lists made the relation a
   fact about which column a name landed in, and said so nowhere. */
.pd-around-wrap{overflow-x:auto}
.pd-around-table{border-collapse:collapse;width:100%;font-family:var(--body)}
.pd-around-table th,.pd-around-table td{
  text-align:left;padding:.45rem .6rem;border-bottom:1px solid rgba(59,42,23,.18);
  vertical-align:baseline}
.pd-around-table thead th{
  font-family:var(--utility);font-size:.66rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--lake);border-bottom:2px solid var(--ink);
  white-space:nowrap}
.pdn-rel{font-family:var(--utility);font-size:.68rem;letter-spacing:.08em;
  text-transform:uppercase;font-weight:400;white-space:nowrap;color:rgba(59,42,23,.8)}
/* The relation is written in its own cell; the tint only reinforces it (§7). */
.pdn-before .pdn-rel{color:var(--lake)}
.pdn-conc   .pdn-rel{color:var(--oxblood)}
.pdn-after  .pdn-rel{color:var(--moss,#3f6b46)}
.pdn-name a{color:var(--oxblood)}
.pdn-span,.pdn-shared{font-family:var(--utility);font-size:.76rem;white-space:nowrap}
.pdn-shared{color:rgba(59,42,23,.8)}
.pdn-titles{font-family:var(--utility);font-size:.78rem;text-align:right;white-space:nowrap}
.pdn-none{opacity:.6;font-style:italic}
@media (max-width:560px){
  .pd-around-table th,.pd-around-table td{padding:.4rem .35rem;font-size:.9rem}
  .pdn-span,.pdn-shared,.pdn-titles{font-size:.68rem}
}

/* A second fact on a rail chip — the period page's threads carry the year they
   are filed under. Distinct from .tag-count, which is a number of titles. */
.tag-meta{margin-left:.4rem;font-family:var(--utility);font-size:.68em;
  opacity:.7;font-variant-numeric:tabular-nums}
.period-tags a:hover .tag-meta{opacity:.9}

/* ---- threads, as blocks rather than chips --------------------------------
   A thread has no page and is not getting one (§3.10e), so the period pages it
   runs through are where its descriptor, its titles and its reach have to
   live. That is a block, not a chip.

   EVERY RULE IS SELECTED THROUGH `.pd-threads`, and not for tidiness: this is
   a `.content-page`, whose `.content-page p` and `.content-page li` are both
   (0,1,1) and beat a bare class — the trap §3.9c records for `.proceed-btn`
   and §4 for `.mini-note`, where a caption rendered at body size on five page
   types because the class was losing. (0,2,0) wins, and winning on specificity
   rather than on file order means moving this block cannot undo it.

   THE PREFIX IS `pdt-`, NOT `pt-`. `.pt-*` is the post tagbar's — nine rules
   of it — and §4 records `pa-row` silently re-laying a whole <table> as a grid
   because the name was already spoken for. */
.pd-threads{margin:1.8rem 0}
/* `scroll-margin-top` rather than arithmetic in the controller: a deep link to
   one thread lands the book clear of the viewport edge, and the rule stays with
   the box it is about.

   Why blue: the site gives each facet a colour — periods oxblood, locations
   verdigris, threads ultramarine — and threads were blue on filmographies and
   red or green everywhere else. The TIMELINE keeps its six colours, which are
   not decoration there: a pulled thread's badge on a poster has to be matched
   to its tab, and six threads can be pulled at once (§3.10e). Nothing here is
   badged, so one colour is the whole of what is needed.

   SET AS ITS OWN DECLARATION rather than by feeding `--th-c`, which the
   timeline's tab already reads. Either works; this one is explicit about which
   property it is changing, does not depend on what `--th-c` is taken to mean,
   and wins on SPECIFICITY (0,3,0 against `.thread-tab.on`'s 0,2,0) rather than
   on file order — so moving this block cannot undo it. The panel's own name
   needed a second declaration regardless, because it carries its own colour.

   *A caveat for whoever measures this next: `background` is in `.thread-tab`'s
   `transition` list, and the in-app browser's animation clock does not advance —
   so a tab whose `.on` class was added by script reads as `rgba(0,0,0,0)` from
   getComputedStyle, frozen at the start of a transition that never runs.
   `color` and `outline` are not transitioned and read correctly, which is what
   makes the reading look like a cascade bug rather than a stopped clock. Turn
   the transition off, or measure a tab that was `.on` at first paint.* */
.pd-thread-book{margin:.8rem 0 0;scroll-margin-top:1.5rem}
.pd-thread-book .thread-tab.on{background:var(--lake)}
/* The tab row is a nav until the client makes it a tablist, so it is anchors
   rather than buttons and needs the underline taken off (§3.11l2). Everything
   else about the tab — the paper, the stitch, the lift on hover, the oxblood
   fill when chosen — is the timeline's own rule, unchanged and unduplicated. */
.pd-threads .pdt-tab{text-decoration:none;display:inline-block}
.pd-threads .pdt-tab.on{color:var(--paper)}
/* A panel is prose on the leaf. `.content-page p`/`li` are (0,1,1) and beat a
   bare class, so every rule below is selected through the section (§3.9c). */
.pd-threads .pdt-panel{padding:.35rem .1rem .2rem;font-size:1rem;line-height:1.6}
.pd-threads .pdt-panel:focus-visible{outline:3px solid var(--lake);outline-offset:3px}
.pd-threads .pdt-head{font-family:var(--display);font-weight:400;font-size:1.1rem;
  margin:0;display:flex;align-items:baseline;flex-wrap:wrap;gap:.2rem .55rem}
/* What the name does, said in words on the link rather than left to be
   discovered: the tab turns the page and this leaves for the timeline, and two
   controls carrying one thread's name owe the reader the difference (§7). */
.pd-threads .pdt-pull{font-family:var(--utility);font-size:.6rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--lake);margin-left:.5rem;
  border-bottom:0;white-space:nowrap}
.pd-threads .pdt-head a:hover .pdt-pull,
.pd-threads .pdt-head a:focus-visible .pdt-pull{color:var(--oxblood)}
/* Ultramarine, the site's thread colour, so the name in the panel matches the
   tab that revealed it and the facet it belongs to (see .pd-thread-book above
   for why blue). Oxblood on hover, which is the site's link-hover throughout. */
.pd-threads .pdt-head a{color:var(--lake);text-decoration:none;
  border-bottom:1.5px solid rgba(216,192,120,.8)}
.pd-threads .pdt-head a:hover,.pd-threads .pdt-head a:focus-visible{
  color:var(--oxblood);border-color:var(--oxblood)}
/* The year it is filed under, in the rail's own idiom (see .tag-meta above):
   the ordering is chronological and an order nobody can see is not one. */
.pd-threads .pdt-year{font-family:var(--utility);font-size:.7rem;letter-spacing:.06em;
  color:rgba(59,42,23,.72);font-variant-numeric:tabular-nums}
/* The registry's own prose, on a page at last. 44rem is the site's measure —
   a 1,000px line of running text is not an improvement on a 720px one. */
.pd-threads .pdt-desc{font-family:var(--body);font-size:.95rem;line-height:1.6;
  margin:.35rem 0 0;max-width:44rem}
/* The stand-in where nobody has written a descriptor yet. Set apart from prose
   somebody wrote, because it is a fact about the archive rather than a sentence
   about the thread — italic, and the alpha is on the COLOUR rather than on
   `opacity`, which fades ink toward the paper at exactly the sizes least able
   to afford it (§4). .78 is what .mini-note already settled on. */
.pd-threads .pdt-unwritten{font-style:italic;color:rgba(59,42,23,.78)}
.pd-threads .pdt-count{font-family:var(--utility);font-size:.7rem;letter-spacing:.06em;
  color:rgba(59,42,23,.7);margin:.35rem 0 0}
.pd-threads .pdt-titles{list-style:none;margin:.3rem 0 0;padding:0;
  display:flex;flex-direction:column;gap:.1rem}
.pd-threads .pdt-title{display:flex;align-items:center;flex-wrap:wrap;gap:.2rem .6rem;
  font-size:.95rem;min-width:0}
.pd-threads .pdt-title > a{color:var(--lake);text-decoration:none;
  border-bottom:1px solid rgba(216,192,120,.7);min-width:0;overflow-wrap:anywhere}
.pd-threads .pdt-title > a:hover,.pd-threads .pdt-title > a:focus-visible{
  color:var(--oxblood);border-color:var(--oxblood)}
/* The emblem's own top margin is for a stacked card; on one line it is not. */
.pd-threads .pdt-salt .salt-compact{margin-top:0}
.pd-threads .pdt-also{font-family:var(--utility);font-size:.72rem;line-height:1.5;
  margin:.4rem 0 0;color:rgba(59,42,23,.8)}
.pd-threads .pdt-also-label{letter-spacing:.1em;text-transform:uppercase;
  font-size:.62rem;color:var(--lake);margin-right:.4rem}
.pd-threads .pdt-also a{color:var(--oxblood);text-decoration:none;
  border-bottom:1px solid rgba(216,192,120,.7)}
.pd-threads .pdt-also a:hover,.pd-threads .pdt-also a:focus-visible{
  border-color:var(--oxblood)}
.pd-threads .pdt-also-n{margin-left:.25rem;opacity:.7;font-size:.9em;
  font-variant-numeric:tabular-nums}

/* ---- how the camera has come to see it (§3.12g7) ----
   The same event, staged by different films, in the order those films came
   out. Every rule is selected through .pd-threads because `.content-page p`
   and `.content-page li` are both (0,1,1) and beat a bare class outright —
   the trap that rendered .mini-note at body size on five pages (§4). */
.pd-threads .pdt-evolve{margin:.9rem 0 .2rem;padding-top:.7rem;
  border-top:2px solid var(--gold)}
.pd-threads .pdt-evolve h4{font-family:var(--utility);font-size:.68rem;
  letter-spacing:.14em;text-transform:uppercase;color:var(--lake);
  margin:0 0 .3rem;font-weight:400}
.pd-threads .pdt-evolve .mini-note{margin:0 0 .6rem;max-width:44rem}
/* A WRAPPING GRID, not a scroller. Reading order is left-to-right and then
   down, which is still the chronological order the row is sorted in, and a
   horizontal scroller hides the later films behind a gesture on the one block
   whose whole point is the span from the earliest to the latest. */
.pd-threads .pdt-stills{list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(11rem,1fr));
  gap:.9rem}
.pd-threads .pdt-still{margin:0;padding:0;min-width:0}
.pd-threads .pdt-frame{margin:0}
/* The tag on each frame is the RELEASE YEAR rather than "On screen": every
   frame here is a screen half and the heading says so, so what earns the label
   is the position each one holds on the axis the row is ordered by. */
.pd-threads .pdt-frame .or-tag{font-variant-numeric:tabular-nums}
.pd-threads .pdt-still-cap{display:flex;flex-direction:column;gap:.1rem;
  margin-top:.35rem;min-width:0}
.pd-threads .pdt-still-cap a{color:var(--lake);text-decoration:none;
  font-size:.92rem;border-bottom:1px solid rgba(216,192,120,.7);
  min-width:0;overflow-wrap:anywhere}
.pd-threads .pdt-still-cap a:hover,.pd-threads .pdt-still-cap a:focus-visible{
  color:var(--oxblood);border-color:var(--oxblood)}
/* .78 on the COLOUR rather than opacity, which fades ink toward the paper at
   exactly the sizes least able to afford it (§4). */
.pd-threads .pdt-still-ep,.pd-threads .pdt-still-subject{
  font-family:var(--utility);font-size:.66rem;line-height:1.4;
  color:rgba(59,42,23,.78)}
.pd-threads .pdt-still-subject{font-style:italic}
@media (max-width:480px){
  .pd-threads .pdt-stills{grid-template-columns:repeat(auto-fill,minmax(8.5rem,1fr));
    gap:.6rem}
}

/* ---- the essay a thread or a place points at ------------------------------
   One renderer (PP.threadNotesHTML) on six surfaces, so one base rule and a
   per-surface adjustment rather than six copies of a look. Ultramarine like
   everything else about a thread off the timeline (§3.11l2), because that is
   what the facet's colour is for — and the label says "Read" in words beside
   it, so the colour reinforces and never carries (§7).

   THE FIRST DECLARATION IS DOUBLED AT TWO SPECIFICITIES for the reason §4
   records about `.mini-note`: three of the pages drawing this are
   `.content-page`, where `.content-page p` is (0,1,1) and beats a bare class,
   so the whole strip would render at body size inside the thread book. Only
   the size and family are raised, exactly as `.mini-note`'s fix is — lifting
   the entire block would beat later rules that legitimately override it. */
.thread-notes,.content-page .thread-notes{font-family:var(--utility);
  font-size:.72rem;line-height:1.5}
.thread-notes{margin:.4rem 0 0;color:rgba(59,42,23,.8)}
.thread-notes .tn-label{letter-spacing:.1em;text-transform:uppercase;
  font-size:.86em;color:var(--lake);margin-right:.4rem}
.thread-notes a{color:var(--oxblood);text-decoration:none;
  border-bottom:1px solid rgba(216,192,120,.7)}
.thread-notes a:hover,.thread-notes a:focus-visible{border-color:var(--oxblood)}
/* In the timeline's thread panel the definition state is a block and the legend
   is a two-column grid, so the strip has to be told which column it is in —
   the same instruction .th-desc beside it already carries. */
.th-one .th-notes{display:block;margin-top:.3rem}
.th-legend .th-notes{grid-column:2;margin-top:.2rem}
/* The banner is a flex row and the strip is one item in it, so it keeps the
   row's baseline rather than opening a line of its own. */
.credit-banner .cb-notes{margin:0}
/* On /locations it sits UNDER the row, indented past the chevron column so it
   reads as belonging to the name above it rather than to the tree. Never a
   sixth grid cell — §4 records that failure on this exact list. */
.lp-note{margin:0;padding:0 .6rem .45rem calc(2.8rem + var(--depth, 0) * 1.1rem)}
.lp-row-wrap:nth-child(odd) > .lp-note{background:rgba(216,192,120,.09)}

/* What an overlap is MADE of. Deliberately not `white-space:nowrap` like the
   two columns beside it: those hold years and this holds thread names, which
   are long enough that refusing to wrap would push the table into its own
   scroller on every period that shares one. */
.pdn-threads{font-family:var(--utility);font-size:.74rem;line-height:1.45;
  min-width:8rem}
.pdn-threads a{color:var(--oxblood);text-decoration:none;
  border-bottom:1px solid rgba(216,192,120,.7)}
.pdn-threads a:hover,.pdn-threads a:focus-visible{border-color:var(--oxblood)}
@media (max-width:560px){ .pdn-threads{font-size:.68rem;min-width:6rem} }

/* ---- the ledger, sliced to one period ------------------------------------
   The rows are the glossary ledger's own (PP.citationRowHTML in config.js), so
   the section carries `.book-of-citations` and inherits every text rule from
   it rather than declaring a second look. What is local is the plate down to
   the whole book, whose arrow points right because this one leaves the page —
   the glossary's own points down (§3.11c3).

   Through the page wrapper, so (0,2,0) beats `.content-page p+p`'s (0,1,2) on
   margin-top: a bare `.pd-tothe` would lose to it wherever the plate follows a
   paragraph, which here it always does. */
.period-page .pd-tothe{margin:1.6rem 0 .4rem}

.pd-places{margin:1.8rem 0}
/* The genre block, which is the places block one section down and drawn in the
   genre facet's own colour. `.rail-genres` already carries the chips (see the
   facet-colour rules); what is here is the heading, so the section reads as
   purple before a reader has looked at a single chip — and the roundel under it
   is the statistics page's, unchanged. */
.pd-genres{margin:1.8rem 0}
.pd-genres .related h3{color:var(--murex-text)}
.pd-genres .lang-roundel{border-top-color:rgba(106,61,154,.28)}
/* The period's reading list and the filmography's Scholarship list are the
   same rows under two headings (§3.3), so they share these declarations and
   NOT the class names: two lists reachable by one selector is how a check that
   means one starts counting both, and §4 records `pa-row` re-laying a whole
   table because a name was already spoken for. */
.pd-reading .reading-list,.fg-reading .reading-list{margin-bottom:.4rem}
.pd-book[hidden],.fg-book[hidden]{display:none}
.pd-book-count,.fg-book-count{margin:.4rem 0 .2rem}

/* ---- the timeline's per-year period panel ----
   Below the posters and shut: the titles are what the reader opened the year
   for, and this is a second question about them.

   The gloss block below is deliberately NOT this. It borrowed all of this
   furniture once — the same box, summary, chevron and Show/Hide — and stacked
   under it the two read as one control repeated twice. See the note there. */
.year-periods{margin:1.2rem auto 0;max-width:1100px;
  border-top:2px solid rgba(59,42,23,.3);padding-top:.5rem}
/* It has to read as a control. The count said there was something here;
   it did not say it could be opened — so the summary is a bordered, tinted
   button-shaped row with a chevron that turns and a word that changes. The
   default triangle is dropped because a custom one can be placed and animated;
   `list-style:none` plus the WebKit pseudo-element covers both engines. */
.year-periods > summary{
  cursor:pointer;list-style:none;
  font-family:var(--utility);font-size:.74rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--lake);padding:.4rem .7rem;
  display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;
  border:1.5px solid rgba(59,42,23,.4);background:rgba(216,192,120,.16)}
.year-periods > summary::-webkit-details-marker{display:none}
.year-periods > summary::marker{content:""}
.year-periods > summary:hover{color:var(--oxblood);border-color:var(--oxblood);
  background:rgba(158,43,37,.08)}
.year-periods > summary:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.yp-chev{display:inline-block;color:var(--oxblood);font-size:.9rem;line-height:1;
  transition:transform .15s ease}
.year-periods[open] .yp-chev{transform:rotate(90deg)}
/* The word is the half that survives with no colour and no glyph, and it is
   the one that tells a reader what pressing DOES rather than merely that
   something is collapsed. Both words are in the markup and the stylesheet
   swaps which is shown — a generated `content:` string would put user-facing
   text in the stylesheet, where nothing that checks the site's wording can
   see it. */
.yp-cue{margin-left:auto;font-size:.64rem;opacity:.75;text-transform:uppercase}
.yp-cue .yp-hide{display:none}
.year-periods[open] .yp-cue .yp-show{display:none}
.year-periods[open] .yp-cue .yp-hide{display:inline}
.yp-head{min-width:0}
.yp-n{font-family:var(--display);font-size:.95rem;color:var(--oxblood);
  border:1.5px solid currentColor;padding:0 .35rem;line-height:1.3}
.yp-list{list-style:none;margin:.5rem 0 0;padding:0;
  display:flex;flex-wrap:wrap;gap:.4rem}
.yp-list li{display:inline-flex;align-items:baseline;gap:.35rem;
  border:1.5px solid rgba(59,42,23,.35);background:var(--paper);padding:.2rem .5rem}
.yp-list a{color:var(--oxblood);text-decoration:none;font-family:var(--body)}
.yp-list a:hover{text-decoration:underline}
.yp-span{font-family:var(--utility);font-size:.66rem;opacity:.7;white-space:nowrap}
.yp-c{font-family:var(--utility);font-size:.68rem;background:var(--gold-bright);
  color:var(--ink);padding:0 .28rem}
.yp-note{margin:.5rem 0 0}

/* ---- and the gloss, which is a marginal note and not a menu ----
   THE THING THIS IS NOT. It was a <details> wearing the period panel's own
   summary bar, and directly under that panel the two read as one control
   printed twice: same grey button, same chevron, same Show/Hide. The panel
   above is a list of LINKS — navigation, which can run long and which a
   reader is either using or not. This is two sentences of prose. A disclosure
   is right for the first and pure ceremony around the second, and borrowing
   it made a gloss look like a menu, which is the one thing it is not.

   What it is instead is the apparatus a real gloss has. A scribe annotating a
   manuscript did three things, and all three are cheap to draw:

     - drew a MANICULE, the pointing hand, out in the margin beside the line
       worth noticing. It is the mark that says "a gloss" the way nothing else
       does, and it is a real .svg inheriting currentColor (§7) rather than a
       glyph, because the site's own art convention is drawings;
     - RUBRICATED the opener — literally red, which is what `--oxblood` is
       commented as being in :root;
     - RULED the margin. The vertical line is the manuscript's own ruling, and
       it is what carries the eye down a run of notes.

   No box, no tint, no button. The block is set on the page rather than in a
   panel, which is the whole difference between an annotation and a control. */
.year-gloss{margin:1.4rem auto 0;max-width:1100px}
/* The rubric. Not a heading element: it names the block through
   aria-labelledby, and an <h*> here would insert a level into the year's
   outline for two sentences of marginalia. */
/* `flex-start`, not `center`: a manicule points at the LINE it marks, so on
   a narrow screen where the rubric wraps the hand must stay with the first
   one. Centred, it drifted to the middle of a two-line label and pointed at
   nothing — measured at 375px before the wording was shortened, and kept
   because the year is a variable-length string and will wrap again. */
.yg-rubric{display:flex;align-items:flex-start;gap:.5rem;margin:0 0 .5rem;
  font-family:var(--utility);font-size:.74rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--oxblood)}
/* The nudge is optical: the hand is centred on the first line's x-height
   rather than hung from its top, which is where a scribe would have put it. */
.yg-hand{flex:0 0 auto;width:1.9rem;margin-top:.1rem;
  color:var(--oxblood);line-height:0}
.yg-hand svg{display:block;width:100%;height:auto}
/* The year, set apart the way a manuscript's running head is: same rubric,
   thinner, after a divider drawn rather than typed.

   NO `opacity`, here or on the credit below, and that is a contrast fix
   rather than a preference. Both were `opacity:.7` and measured **3.32:1** on
   parchment at 12.8px and 10.88px — under AA, on the two smallest strings in
   the block. Opacity is how that happens: it fades the ink toward the paper
   at exactly the sizes that can least afford it. The alpha is on the COLOUR
   now, at .78 — the value `.mini-note` already settled on — which measures
   5.73:1. Measured in a browser, not reasoned about (§4). */
.yg-rubric-year{font-family:var(--body);font-size:.8rem;letter-spacing:.02em;
  text-transform:none;color:rgba(59,42,23,.78);padding-left:.5rem;
  border-left:1.5px solid rgba(158,43,37,.4)}

/* The ruling: one line down the margin, gold rather than ink, because a
   ruled line is not writing. The list hangs off it. */
.yg-list{list-style:none;margin:0;padding:0 0 0 1.1rem;
  border-left:1.5px solid rgba(185,138,47,.7)}
.yg-list li{margin:0 0 .85rem;max-width:44rem}
.yg-list li:last-child{margin-bottom:0}
/* A smaller hand than the main text, which is what a marginal note was
   written in. Italic Cardo, so it reads as a second voice beside the shelf
   rather than as more of the site's own furniture.

   Selected through .year-gloss so it wins on SPECIFICITY: index.html is not a
   .content-page today, but .mr-text one section up had to be fixed for
   exactly that reason and a bare .yg-text would be the same trap waiting
   (§4 — .mini-note, five page types). */
.year-gloss .yg-text{font-family:var(--body);font-style:italic;
  font-size:1.02rem;line-height:1.55;margin:0;color:var(--ink)}
/* The credit, in the rubric's own hand so the block reads as one piece.
   Colour rather than opacity, for the reason above — and the link is left at
   full oxblood (5.65:1) because the parent's opacity was dragging it to
   3.32:1, which is the worse of the two failures: it was the only thing here
   a reader could press. */
.year-gloss .yg-src{margin:.3rem 0 0;font-family:var(--utility);
  font-size:.68rem;letter-spacing:.06em;text-transform:uppercase;
  color:rgba(59,42,23,.78)}
.year-gloss .yg-src a{color:var(--oxblood)}
/* On a phone the hand shrinks with the rubric rather than dominating it. */
@media (max-width:520px){
  .yg-hand{width:1.25rem}
  .yg-rubric{gap:.4rem;font-size:.68rem;letter-spacing:.08em}
  .yg-list{padding-left:.8rem}
}

/* The compare column heading is a link now — it is the one place a reader is
   already looking at a period by name and thinking about it. */
a.cc-name{color:var(--oxblood);text-decoration:none;
  border-bottom:1.5px solid rgba(158,43,37,.35)}
a.cc-name:hover,a.cc-name:focus-visible{border-bottom-color:var(--oxblood);
  background:rgba(158,43,37,.07)}

/* Does this period have a page of its own? The word carries it, never the
   colour (§7); the tint only reinforces what the cell already says. */
.pr-page{font-family:var(--utility);font-size:.64rem;letter-spacing:.08em;
  text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  border:1.5px solid rgba(59,42,23,.35);color:rgba(59,42,23,.7);
  padding:.12rem .4rem;text-align:center}
.pr-page.has{border-color:var(--oxblood);color:var(--oxblood);
  background:rgba(158,43,37,.08)}
@media (max-width:900px){
  .period-row{grid-template-columns:1fr 1fr;}
  .period-row .pr-page{justify-self:start}
}

/* "Look closer at" on a title's own map — the statistics page's framing select
   (§3.8: framing, not filtering), offered where the places span a continent.
   It leads the layer boxes rather than sitting among them: it moves the
   camera, where they decide what is drawn. */
.rv-region{display:inline-flex;align-items:center;gap:.35rem;
  font-family:var(--utility);font-size:.7rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--lake)}
.rv-region select{font-family:var(--body);font-size:.9rem;text-transform:none;
  letter-spacing:0;color:var(--ink);padding:.2rem .35rem;
  border:1.5px solid rgba(59,42,23,.45);background:#F5EFE0}
.rv-region select:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
@media (max-width:560px){ .rv-region{flex-basis:100%} }

/* --- admin: the bulk editor's action group (§6h, one panel over) ---
   Four action boxes stacked open put the LIST — the thing an editor works in —
   at 1,527px down a 2,023px panel, so every job began by scrolling past three
   actions to reach the rows. Folded and moved below the list, they read as what
   they are: a menu of things to do to what you have just ticked. */
.bulk-actions{margin-top:1rem}
.bulk-actions-head{font-family:var(--utility);font-size:.8rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--oxblood);margin:0 0 .4rem}
/* The box keeps its own padding and border as a disclosure body; what it loses
   is the outer shadow, which stacked four deep reads as four cards rather than
   one menu. */
.bulk-action-body{box-shadow:none;margin:0;border:none;padding:.2rem 0 0}
/* ---- Timeline Explorer (§3.19) ---------------------------------------------
   Every text rule is selected through `.explorer-page`, because this main is a
   `.content-page` and `.content-page p` and `.content-page li` are both (0,1,1)
   — a bare class loses to them outright, which is the trap §4 records rendering
   `.mini-note` at body size on five pages. Winning on SPECIFICITY rather than
   on file order means moving this block cannot silently undo it. */
/* THE PAGE IS WIDER THAN THE PROSE MEASURE, and only because of the triptych.
   `.content-page` is 720px, which is right for reading and leaves the centre
   leaf 177px between a 172 poster and the guess — measured, and it is the leaf
   the hints grow into. So the page takes the room and the PROSE is pinned back
   to it, which is §3.7a's arrangement on the statistics page read the other way
   round: there the layout widened and the running text kept its 44rem, and the
   reason is the same one. */
.explorer-page{max-width:1040px}
.explorer-page > h1,
.explorer-page > .lede,
.explorer-page > #txSetup,
.explorer-page > #txDone{max-width:44rem}
.explorer-page .tx-panel{margin-top:1.6rem}
.explorer-page .tx-mods{display:flex;flex-direction:column;gap:.7rem;margin:.8rem 0 1.2rem}
.explorer-page .tx-mod{display:flex;gap:.6rem;align-items:flex-start;
  border:2px solid rgba(59,42,23,.3);background:#F5EFE0;padding:.7rem .9rem;cursor:pointer}
.explorer-page .tx-mod:hover{border-color:var(--ink)}
.explorer-page .tx-mod input{margin-top:.25rem;flex:0 0 auto}
.explorer-page .tx-mod-body{display:flex;flex-direction:column;gap:.15rem}
.explorer-page .tx-mod-name{font-family:var(--utility);font-size:.86rem;
  letter-spacing:.06em;text-transform:uppercase;color:var(--ink)}
.explorer-page .tx-mod-say{font-size:.86rem;line-height:1.45;color:rgba(59,42,23,.78)}
.explorer-page .tx-max-line{font-family:var(--utility);font-size:1.05rem;
  letter-spacing:.06em;color:var(--oxblood);margin-top:.4rem}

/* ---- the triptych ----------------------------------------------------------
   Three leaves of one subject: what you are looking at, what you can buy, and
   what you say. The drawing is the anniversary arcade's (§3.9c4) — an arched
   head over a ruled bay, a gold trellis in the spandrel, small caps in the
   rubric — and the CLASS NAMES are its own, because §3.11i3's rule is that a
   second control sharing a neighbour's declarations must not share its names,
   and §4 records `pa-row` silently re-laying a whole table when one did.

   WHAT IT DOES NOT BORROW IS THE COLOUR. A bay there wears the era of the year
   it counts back to; a bay here is ink and gold at every round, because here
   the era is the answer. */
/* ILLUMINATED, and the two files are the whole of it. A running vine along the
   top and bottom edges (`illumination-band.svg`, tileable, so it fits any
   width), and a corner spray at the two outer corners — ONE drawing mirrored,
   rather than four files to keep in step, which is why the corners are
   pseudo-elements: a background layer cannot be flipped and a second file for
   the opposite corner is the copy §3.3 is a long argument about.

   ERA-NEUTRAL, like everything else in this frame: ultramarine, vermilion,
   verdigris and gold at every round, because here the era is the answer. */
.explorer-page .tx-trip{position:relative;margin:1.4rem 0;
  padding:1.5rem 1.7rem;
  background-image:url(../art/illumination-band.svg),url(../art/illumination-band.svg);
  background-repeat:repeat-x,repeat-x;
  background-position:left top,left bottom;
  background-size:auto 15px}
/* PULLED OUT INTO THE CORNER, and that is a measurement rather than a nudge.
   Sat inside the frame at 78px the spray's diagonal stem put a bloom on the
   first bay's rubric — the ink, not the bounding box, which is the only version
   of that question worth asking and the one a glance at a screenshot does not
   answer. Out here it overlaps the running band instead, which is what a spray
   does on a real page. */
.explorer-page .tx-trip::before,
.explorer-page .tx-trip::after{content:"";position:absolute;
  width:72px;height:72px;pointer-events:none;
  background:url(../art/illumination-corner.svg) no-repeat;background-size:100% 100%}
.explorer-page .tx-trip::before{top:-4px;left:-8px}
/* The same file, turned through 180° — the drawing's own comment says the
   other three corners are this one mirrored. */
.explorer-page .tx-trip::after{bottom:-4px;right:-8px;transform:scale(-1,-1)}
/* The band across the head of the whole piece: which leaf of the run this is,
   and what has been earned so far. */
.explorer-page .tx-band{display:flex;justify-content:space-between;align-items:baseline;
  gap:1rem;flex-wrap:wrap;padding:0 .2rem .55rem}
.explorer-page .tx-step{font-family:var(--utility);font-size:.86rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink);margin:0}
.explorer-page .tx-running{font-family:var(--utility);font-size:.86rem;letter-spacing:.08em;
  color:var(--oxblood);margin:0}
/* The round clock, between the step and the running total. Tabular numerals so
   a count down from 25 to 9 does not shuffle the band sideways once a digit is
   dropped, and `nowrap` because "8s left" on two lines is not a clock. */
.explorer-page .tx-clock{font-family:var(--utility);font-size:.86rem;letter-spacing:.08em;
  color:var(--ink);margin:0;font-variant-numeric:tabular-nums;white-space:nowrap;
  border:2px solid var(--ink);padding:.05rem .5rem;background:var(--paper-deep)}
/* The last five seconds. The WORD is already there and the number is already
   falling — this is the third carrier, never the first (§7). Paper on oxblood
   measures 5.65:1, the ratio every rubric on the site draws at. */
.explorer-page .tx-clock.urgent{background:var(--oxblood);color:var(--paper);
  border-color:var(--ink)}
@media (prefers-reduced-motion:reduce){ .explorer-page .tx-clock{transition:none} }

/* THE CENTRE LEAF TAKES THE SLACK, which is the altarpiece's own proportion and
   also the practical one: the poster is a fixed 172 and the guess is a year and
   two controls, while the hints grow as they are bought. minmax(0,…) on both
   flexible tracks, or a long period name sets the column's width and pushes the
   guess leaf off the measure (§4, five occurrences of that family). */
.explorer-page .tx-leaves{display:grid;
  grid-template-columns:auto minmax(0,1fr) minmax(0,17rem);
  gap:.7rem;align-items:stretch}
.explorer-page .tx-bay{min-width:0;display:flex;flex-direction:column;
  border:2px solid var(--ink);background:var(--paper);
  /* The arch. Shallow, for the arcade's own reason: a semicircle over a column
     this wide is a doorway, and the suggestion of one is what is wanted. */
  border-radius:1.4rem 1.4rem 3px 3px;
  box-shadow:2px 2px 0 rgba(59,42,23,.16);overflow:hidden}
/* THE HEAD, on the gold lozenge trellis that fills the spandrel of an arcaded
   page. Two repeating gradients, no image and no library (§3.1). The flat
   ground is declared first so a browser without color-mix keeps a band rather
   than a transparent head — the subgrid arrangement §3.10 records. */
.explorer-page .tx-bay-head{margin:0;padding:.42rem .6rem .38rem;
  font-family:var(--utility);font-size:.68rem;letter-spacing:.18em;
  text-transform:uppercase;text-align:center;color:var(--ink);
  border-bottom:1px solid var(--gold);
  background:var(--paper-deep);
  background:
    repeating-linear-gradient(45deg, rgba(185,138,47,.30) 0 1px, transparent 1px 9px),
    repeating-linear-gradient(-45deg, rgba(185,138,47,.30) 0 1px, transparent 1px 9px),
    var(--paper-deep)}
.explorer-page .tx-bay-body{flex:1 1 auto;padding:.75rem .8rem;display:flex;
  flex-direction:column;gap:.5rem;min-width:0}

/* ---- the left leaf: what you are looking at ---- */
.explorer-page .tx-bay-title .tx-bay-body{align-items:center;text-align:center}
.explorer-page .tx-poster{width:172px;height:250px;flex:0 0 auto;
  border:2px solid var(--ink);background:var(--paper-deep);overflow:hidden;
  color:var(--ink);box-shadow:2px 2px 0 rgba(59,42,23,.2)}
/* A covered poster is a decision the reader made, so it is drawn as a shuttered
   panel rather than as a gap: the same neutral card, on a hatched ground, so it
   reads as closed rather than as failed to load. */
.explorer-page .tx-poster.covered{background:
  repeating-linear-gradient(45deg, rgba(59,42,23,.07) 0 6px, transparent 6px 12px),
  var(--paper-deep)}
.explorer-page .tx-poster img,.explorer-page .tx-noposter{display:block;
  width:100%;height:100%;object-fit:cover}
.explorer-page .tx-title{font-family:var(--display);font-size:clamp(1.2rem,2.4vw,1.6rem);
  line-height:1.15;margin:.15rem 0 0;max-width:14rem}
.explorer-page .tx-kind{font-family:var(--utility);font-size:.7rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--lake);margin:0}

/* ---- the centre leaf: what you can buy ---- */
.explorer-page .tx-hint-lede{font-size:.84rem;font-style:italic;line-height:1.4;
  color:rgba(59,42,23,.78);margin:0}
.explorer-page .tx-hints{display:flex;flex-direction:column;gap:.55rem}
.explorer-page .tx-hint{min-width:0}
.explorer-page .tx-hint .tx-buy{width:100%;display:flex;justify-content:space-between;
  align-items:baseline;gap:.6rem;text-align:left}
/* The price, drawn as a price: rubricated, so a reader scanning the bay sees
   what each one takes before they see what it gives. */
.explorer-page .tx-cost{font-family:var(--utility);letter-spacing:.06em;
  color:var(--oxblood);flex:0 0 auto}
.explorer-page .tx-buy:disabled .tx-cost{color:inherit}
.explorer-page .tx-hint.bought{border:2px solid #2F5436;background:rgba(62,107,69,.07);
  border-radius:.7rem .7rem 3px 3px;padding:.5rem .7rem}
/* The darker verdigris rather than --moss, which is a border weight and does
   not clear 4.5:1 as type — measured at 4.31 on this ground before the change
   and 5.99 after. §3.11l2 records the same finding one rail over; this reuses
   that value rather than inventing a near-miss of it. */
.explorer-page .tx-hint-head{font-family:var(--utility);font-size:.7rem;letter-spacing:.14em;
  text-transform:uppercase;color:#2F5436;margin:0 0 .3rem;
  display:flex;justify-content:space-between;gap:.5rem}
.explorer-page .tx-spent{color:var(--oxblood)}
.explorer-page .tx-hint-list{list-style:none;margin:0;padding:0}
/* SIZED ON THE `li`, not inherited from the list. `.content-page li` is (0,1,1)
   and beats an inherited value outright, so the names came out at 17.92px
   inside a bay set at 14.72 — §4's most repeated CSS trap, in the one shape a
   sweep over the classes a client emits cannot see, since `li` is not a class. */
.explorer-page .tx-hint-list li{font-size:.88rem;line-height:1.35;padding:.1rem 0}
.explorer-page .tx-hint-when{font-family:var(--utility);font-size:.76rem;
  color:rgba(59,42,23,.78)}
.explorer-page .tx-hint-why{display:block;font-size:.78rem;font-style:italic;
  color:rgba(59,42,23,.78);margin-top:.25rem}

/* ---- the right leaf: what you say ---- */
.explorer-page .tx-ceiling{font-family:var(--display);font-size:1.5rem;line-height:1;
  color:var(--oxblood);margin:0}
.explorer-page .tx-from{font-family:var(--utility);font-size:.7rem;letter-spacing:.06em;
  text-transform:uppercase;color:rgba(59,42,23,.78);margin:0}
.explorer-page .tx-from:empty{display:none}
.explorer-page .tx-form{margin:0}
.explorer-page .tx-form label{font-family:var(--utility);font-size:.8rem;letter-spacing:.06em;
  display:block;margin-bottom:.35rem}
.explorer-page .tx-guess-row{display:flex;gap:.45rem;align-items:center;flex-wrap:wrap}
/* min-width:0, because a flex item's automatic minimum is its content's own
   width and an input's is its `size` — about 268px, which is wider than this
   leaf (§4, five occurrences). */
.explorer-page .tx-guess-row input[type=number]{flex:1 1 6rem;min-width:0;
  font-family:var(--body);font-size:1.15rem;padding:.45rem .55rem;
  border:2px solid var(--ink);background:#F5EFE0;color:var(--ink)}
/* ---- CE and BCE, both on screen -------------------------------------------
   The select this replaced is gone rather than left unused: a dead rule is
   weight on every page that loads this file, and the next person to read it
   has to work out which control it is for (§6d).

   EVERY RULE IS SELECTED THROUGH .tx-form, at (0,3,0). `.explorer-page
   .tx-form label` is (0,2,0) and sets `display:block` and `.8rem` on every
   label in the leaf — including these two — so a bare class would win only by
   sitting later in the file, and moving the block would silently undo it. §4
   records that trap on five pages at once.

   The tick is DRAWN and the word is beside it, so the mark reinforces what the
   label already says rather than carrying it alone (§7). */
.explorer-page .tx-form .tx-scale{display:flex;gap:.35rem;border:0;padding:0;margin:0;min-width:0}
.explorer-page .tx-form .tx-scale-pick{display:flex;align-items:center;gap:.4rem;
  font-family:var(--utility);font-size:.88rem;letter-spacing:.06em;
  margin:0;padding:.4rem .6rem;cursor:pointer;
  border:2px solid var(--ink);background:#F5EFE0;color:var(--ink)}
.explorer-page .tx-form .tx-scale-pick:hover{background:var(--paper)}
/* The native control keeps its place in the tab order and keeps being
   announced; only its own box is replaced by the one drawn beside it.
   `display:none` would take it out of both, which is how a radio group stops
   being reachable by keyboard at all. */
.explorer-page .tx-form .tx-scale-pick input{position:absolute;opacity:0;
  width:1px;height:1px;margin:0;pointer-events:none}
.explorer-page .tx-form .tx-scale-tick{display:inline-flex;align-items:center;
  justify-content:center;width:1.05em;height:1.05em;flex:0 0 auto;line-height:1;
  border:1.5px solid var(--ink);background:var(--paper)}
.explorer-page .tx-form .tx-scale-pick input:checked ~ .tx-scale-tick{
  background:var(--ink);color:var(--paper)}
.explorer-page .tx-form .tx-scale-pick input:checked ~ .tx-scale-tick::before{
  content:"✓";font-size:.78em}
/* The ring goes on the drawn box, because the real one is a pixel wide and
   invisible — a focus ring nobody can see is a keyboard user with no cursor. */
.explorer-page .tx-form .tx-scale-pick input:focus-visible ~ .tx-scale-tick{
  outline:2px solid var(--lake);outline-offset:2px}
.explorer-page .tx-do{display:flex;gap:.5rem;flex-wrap:wrap;margin-top:.6rem}
.explorer-page .tx-do .btn{margin-left:0}
.explorer-page .tx-say:not(:empty){display:block;font-size:.82rem;font-style:italic;
  color:var(--oxblood);border-left:3px solid var(--oxblood);padding-left:.55rem;
  margin-top:.55rem}
.explorer-page .tx-scored{font-family:var(--utility);font-size:1rem;letter-spacing:.06em;
  color:var(--oxblood);margin:0}

/* ---- the answer, below the triptych ----------------------------------------
   The plate the round is judged on, and the one place on this page with room
   for a picture. Two halves: what the archive says, and a marginal beast
   unrolling it.

   NO ILLUMINATION HERE, and that is the point of the plate rather than an
   omission. It carried the triptych's band and one corner spray, on the
   argument that the two would read as one piece — and what it actually did was
   make the answer look like a second frame competing with the frame above it,
   on the one block a reader is trying to READ rather than admire. The vine is
   the round's chrome; the answer is the round's content, and the beside-it
   drollery is all the ornament it needs.

   The border, the ground and the shadow stay: those are what make it a plate. */
.explorer-page .tx-answer{position:relative;border:2px solid var(--ink);
  background:#F5EFE0;padding:1.5rem 1.3rem 1.1rem;margin-top:1.2rem;
  box-shadow:3px 3px 0 rgba(59,42,23,.18);
  display:grid;grid-template-columns:minmax(0,1fr) auto;gap:1rem;align-items:start}
/* No corner spray to clear, so the prose runs to the plate's own padding. */
.explorer-page .tx-ans-text{min-width:0}
/* THE DROLLERY. It is decoration and says the same thing every round, so the
   markup marks it aria-hidden — the verdict, the bar and the percentage beside
   it are what a reader is actually told (§7). */
.explorer-page .tx-ans-art{flex:0 0 auto;width:150px;line-height:0}
.explorer-page .tx-ans-art svg{display:block;width:100%;height:auto}
.explorer-page .tx-verdict{font-family:var(--display);font-size:1.6rem;margin:0}
/* The bar REPEATS what the two lines around it already say in words — the
   distance and the percentage — so nothing here carries meaning by colour or by
   length alone (§7). It is not drawn at all on a passed round: a 0% bar over a
   round nobody attempted reads as a wrong answer. */
.explorer-page .tx-bar{height:10px;border:1.5px solid var(--ink);background:var(--paper-deep);
  margin:.6rem 0}
.explorer-page .tx-bar span{display:block;height:100%;background:var(--moss)}
.explorer-page .tx-points{font-size:1rem;margin:.3rem 0}
.explorer-page .tx-was{font-size:.95rem;margin:.3rem 0 0}
.explorer-page .tx-ans-periods{font-family:var(--utility);font-size:.82rem;letter-spacing:.06em;
  color:var(--oxblood);margin:.3rem 0 0}
.explorer-page .tx-salt{margin:.7rem 0}
.explorer-page .tx-open{font-size:.95rem;margin:.3rem 0 .9rem}

/* ---- the results ---- */
.explorer-page .tx-total{font-family:var(--display);font-size:clamp(2.4rem,9vw,4rem);
  color:var(--oxblood);line-height:1;margin:.4rem 0 .2rem}
.explorer-page .tx-beat{font-family:var(--utility);font-size:.86rem;letter-spacing:.14em;
  text-transform:uppercase;color:#2F5436}
/* A table is wider than a phone, so it gets its own scroller rather than making
   the page scroll sideways. */
.explorer-page #txTable{overflow-x:auto;margin:1.2rem 0}
.explorer-page .tx-table{border-collapse:collapse;width:100%;font-size:.92rem}
.explorer-page .tx-table th,.explorer-page .tx-table td{
  border-bottom:1px solid rgba(59,42,23,.25);padding:.4rem .6rem;text-align:left}
.explorer-page .tx-table th{font-family:var(--utility);font-size:.72rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--lake)}
.explorer-page .tx-table .tx-num{text-align:right;font-variant-numeric:tabular-nums}
/* A passed round is quieter than a wrong one, and it says so in the cells as
   well — the tint reinforces the words rather than carrying them (§7). */
.explorer-page .tx-table tr.tx-passed td{color:rgba(59,42,23,.7);font-style:italic}
.explorer-page .tx-table tr.tx-passed td a{font-style:normal}
/* Said once, under the table, where the run is being read as a whole. */
.explorer-page .tx-timeouts{margin-top:.7rem}
/* Three buttons now, so the row wraps rather than overflowing at a phone
   width — the third is a download and its label is the longest of them. */
.explorer-page .tx-again{margin-top:1.2rem;display:flex;flex-wrap:wrap;gap:.6rem}

/* THE LEAVES STACK rather than shrinking past use. Below 900px the three do not
   fit beside each other with a 172px poster in the first; below 560 the poster
   comes down with them. */
@media (max-width:900px){
  .explorer-page .tx-leaves{grid-template-columns:minmax(0,1fr)}
  .explorer-page .tx-bay-title .tx-bay-body{flex-direction:row;text-align:left;
    align-items:flex-start;gap:.9rem}
  .explorer-page .tx-title{max-width:none}
  /* The drollery goes UNDER the answer rather than beside it — beside a column
     this narrow it takes half the plate and the verdict is what the reader
     came for. Centred, because a picture aligned left under full-width prose
     reads as one that failed to place. */
  .explorer-page .tx-answer{grid-template-columns:minmax(0,1fr);justify-items:center}
  .explorer-page .tx-ans-art{width:120px}
}
@media (max-width:560px){
  .explorer-page .tx-poster{width:110px;height:160px}
  /* The sprays come in as the frame narrows, or they crowd the bays; the
     running vine along the edges stays, because it costs no width. */
  .explorer-page .tx-trip{padding:1.3rem .9rem}
  .explorer-page .tx-trip::before,
  .explorer-page .tx-trip::after{width:50px;height:50px}
  .explorer-page .tx-answer{padding-left:.9rem;padding-right:.9rem}
}
/* Ink on paper: the illumination is the one thing here that means nothing
   printed, and a tiled vine at 15px is a grey smear on a laser printer. */
@media print{
  .explorer-page .tx-trip{background-image:none}
  .explorer-page .tx-trip::before,.explorer-page .tx-trip::after,
  .explorer-page .tx-ans-art{display:none}
}
