/* GENERATED by build-program-page.py - do not hand-edit.
   Block one is the program's own CSS from the press proof (page chrome
   removed, tokens scoped to .bifold). Block two is the web presentation. */

.bifold{
  --paper:#f6f1e4; --paper-deep:#eee6d2; --ink:#221c12; --ink-2:#4b4232;
  --muted:#786c5b; --saddle:#8e4a2b; --saddle-deep:#6c3117; --gold:#a97f3f;
  --line:rgba(70,55,32,.35); --line-soft:rgba(70,55,32,.18);
  --chrome-bg:#e7e0d0; --chrome-ink:#3c3427; --chrome-muted:#6d6353; --chrome-edge:rgba(60,48,28,.18);
  --serif-display:"Besley","Clarendon","Times New Roman",serif;
  --serif-body:"Lora",Georgia,serif;
  --sans:"Libre Franklin","Helvetica Neue",Arial,sans-serif;
}@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
  --chrome-bg:#191510; --chrome-ink:#e8e0cf; --chrome-muted:#9c9282; --chrome-edge:rgba(230,220,200,.16);
}}
:root[data-theme="dark"]{
  --chrome-bg:#191510; --chrome-ink:#e8e0cf; --chrome-muted:#9c9282; --chrome-edge:rgba(230,220,200,.16);
}
*{box-sizing:border-box}
.panel{aspect-ratio:5.5/8.5;padding:clamp(1rem,2.4vw,1.9rem);display:flex;flex-direction:column;
  position:relative;overflow:hidden}
.panel + .panel{border-left:1px solid var(--line-soft)}
.panel{container-type:inline-size}
.imk{font-family:var(--sans);font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;color:var(--muted);
  text-align:center}
/* FRONT */
.front{text-align:center;justify-content:flex-start;gap:0;padding:0}
.front .imk{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
  font-family:var(--serif-display);font-style:normal;font-weight:600;
  font-size:3.15cqw;letter-spacing:.34em;text-indent:.34em;text-transform:uppercase;
  color:var(--saddle-deep);margin:0;padding:9.88cqw 1rem 9.88cqw}
.front img{width:100%;aspect-ratio:1/1;flex:0 0 auto;object-fit:cover;object-position:50% 10%;
  display:block;border:0;box-shadow:none}
.bd{display:flex;justify-content:center;gap:clamp(1rem,5cqw,2.6rem);margin:0}
.bd > div{display:flex;flex-direction:column;align-items:center;gap:.16rem}
.bd .d{font-family:var(--serif-body);font-size:2.62cqw;letter-spacing:.03em;
  color:var(--ink-2);font-variant-numeric:tabular-nums;white-space:nowrap}
.bd .pl{font-family:var(--serif-display);font-variant:small-caps;font-size:2.55cqw;
  letter-spacing:.06em;color:var(--ink-2);white-space:nowrap}
.idblock{flex:1 1 auto;display:flex;flex-direction:column;justify-content:center;
  padding:0 clamp(.8rem,2vw,1.4rem)}
.bigname{font-family:var(--serif-display);font-weight:600;font-variant:small-caps;text-transform:none;
  font-size:5.0cqw;letter-spacing:.035em;line-height:1.24;
  margin:0 0 .88rem;color:var(--saddle-deep);text-wrap:balance}
/* INSIDE RIGHT — type scale in cqw; 1cqw = 3.96pt at 5.5in panel width */
.ir{gap:0}
.ttl{font-family:var(--serif-display);font-variant:small-caps;font-weight:600;font-size:4.7cqw;
  text-align:center;margin:0 0 .55rem;line-height:1.16;letter-spacing:.012em}
.svc{font-family:var(--serif-display);font-variant:small-caps;font-size:2.6cqw;line-height:1.6;
  text-align:center;color:var(--muted);margin:0 0 1.4rem;letter-spacing:.028em}
.svc b{display:block;font-weight:600;color:var(--ink-2);font-size:2.8cqw;margin-bottom:.18rem}
.prog{list-style:none;margin:0 0 1.85rem;padding:0;display:flex;flex-direction:column;gap:.6rem}
.prog li{display:flex;align-items:baseline;gap:.55rem;
  font-family:var(--serif-body);font-size:2.92cqw;font-weight:500;
  letter-spacing:.01em;line-height:1.3}
.prog li i{flex:1;border-bottom:1px dotted var(--line);transform:translateY(-.2em)}
.prog li span:first-child{color:var(--ink-2);white-space:nowrap}
.prog li span:last-child{color:var(--ink);text-align:right;font-weight:600}
.hph{font-family:var(--sans);font-weight:600;font-size:2.3cqw;font-variant:normal;
  text-align:center;margin:0 0 .55rem;letter-spacing:.26em;text-indent:.26em;
  text-transform:uppercase;color:var(--saddle-deep)}
.hpl{list-style:none;margin:0 0 1.5rem;padding:0;display:grid;grid-template-columns:1fr 1fr;
  gap:.36rem .8rem;font-family:var(--serif-display);font-variant:small-caps;font-size:2.6cqw;
  letter-spacing:.028em;color:var(--ink-2);text-align:center;line-height:1.3}
.rcp{margin-top:auto;text-align:center;font-family:var(--serif-display);font-variant:small-caps;
  font-weight:600;font-size:3.05cqw;letter-spacing:.03em;color:var(--ink);line-height:1.35}
.rcp span{display:block;font-weight:400;color:var(--ink-2);font-size:2.72cqw;margin-top:.12rem}
/* INSIDE LEFT */
.oos{list-style:none;margin:.15rem 0 0;padding:0;display:flex;flex-direction:column;gap:.3rem}
.lyr{margin:auto 0;transform:translateY(-3.5%);text-align:center;display:flex;flex-direction:column;gap:1.5rem}
.lyr h4{font-family:var(--serif-display);font-variant:small-caps;font-size:4.5cqw;font-weight:600;
  letter-spacing:.04em;color:var(--ink);margin:0 0 .1rem}
.lyr h4::after{content:"";display:block;width:2.2rem;height:1px;background:var(--gold);margin:.55rem auto 0}
.lyr p{margin:0;font-family:var(--serif-body);font-size:3.35cqw;line-height:1.75;color:var(--ink-2)}
/* BACK */
.back img{width:100%;aspect-ratio:3/2;object-fit:cover;border:1px solid var(--line-soft)}
.back{display:flex;flex-direction:column}
.links{margin-top:auto;padding-top:.7rem;border-top:1px solid var(--line-soft);text-align:center;
  display:flex;flex-direction:column;gap:.28rem}
.links .lead{font-family:var(--sans);font-size:2.46cqw;letter-spacing:.05em;color:var(--muted);line-height:1.5}
.links b{font-family:var(--sans);color:var(--saddle);font-weight:600;letter-spacing:.03em;font-size:2.82cqw;display:block}
.links .ask{display:block;font-family:var(--serif-body);font-style:italic;font-size:2.68cqw;color:var(--ink);line-height:1.5}

.il{justify-content:center}






/* Devil's Gate — USGS, 1925. Public domain (US government work).
   ONE photograph spanning the open inside spread: the left panel
   carries its left half, the right panel its right half. */
.panel.il, .panel.ir{position:relative}
.panel.il::before, .panel.ir::before{
  content:"";position:absolute;top:0;bottom:0;width:200%;z-index:0;pointer-events:none;
  background-image:url(program/back-photo.jpg);
  background-size:cover;background-position:center 46%;
  opacity:.22;filter:sepia(.55) saturate(.7) brightness(1.16) contrast(.78);
  mix-blend-mode:multiply;}
.panel.il::before{left:0}
.panel.ir::before{right:0}
.panel.il > *, .panel.ir > *{position:relative;z-index:1}

/* Hudson street grid — drawn from OpenStreetMap geometry.
   The town he was mayor of, as the ground the back page sits on. */
.panel.back{position:relative}
.panel.back::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:url("program/hudson-map.svg");
  background-size:cover;
  opacity:.5;background-position:50% 50%;mix-blend-mode:multiply}
.panel.back > *{position:relative;z-index:1}
/* paper scrim: the grid reads at full strength up top, then falls away
   under the text so nothing has to compete with a road for legibility */
.panel.back::after{content:"";position:absolute;left:0;right:0;bottom:0;height:46%;z-index:0;
  pointer-events:none;background:linear-gradient(to bottom,
    rgba(246,241,228,0) 0%, rgba(246,241,228,.86) 14%, rgba(246,241,228,.9) 100%)}
.mapzone{flex:1 1 auto;display:flex;align-items:flex-end;justify-content:center;padding-bottom:.5rem}
.mapzone span{font-family:var(--sans);font-weight:600;font-size:2.5cqw;letter-spacing:.3em;
  text-indent:.3em;text-transform:uppercase;color:var(--saddle-deep)}

/* a life in elevations — the away places, then the return */
.elev{margin:0 0 1.6rem}
.elev h4{font-family:var(--sans);font-weight:600;font-size:2.3cqw;letter-spacing:.26em;text-indent:.26em;
  text-transform:uppercase;color:var(--saddle-deep);text-align:center;margin:0 0 .8rem}
.elev ul{list-style:none;margin:0 auto;padding:0;max-width:78%;display:flex;flex-direction:column;gap:.28rem}
.elev li{display:flex;align-items:baseline;gap:.5rem;font-family:var(--serif-body);font-size:2.62cqw;
  color:var(--ink-2);font-variant-numeric:tabular-nums}
.elev li i{flex:1;border-bottom:1px dotted var(--line);transform:translateY(-.2em)}
.elev li.home{font-family:var(--serif-display);font-variant:small-caps;font-weight:600;font-size:3.1cqw;
  color:var(--saddle-deep);margin-top:.2rem}
.elev li.home i{border-bottom-color:var(--saddle)}

.tdates{font-family:var(--serif-body);font-size:2.5cqw;letter-spacing:.05em;text-align:center;
  color:var(--ink-2);margin:-.35rem 0 .8rem;font-variant-numeric:tabular-nums}
.osh{font-family:var(--sans);font-weight:600;font-size:2.3cqw;
  text-align:center;margin:0 0 .6rem;letter-spacing:.26em;text-indent:.26em;
  text-transform:uppercase;color:var(--saddle-deep)}
.prog li.ph{margin-top:.55rem}
.prog li em{font-style:italic}
.pv{text-align:center;margin:0 0 .1rem;position:relative;z-index:1}
.pv .l1{display:block;font-family:var(--serif-body);font-style:italic;font-size:3.3cqw;color:var(--ink-2)}
.pv .l2{display:block;font-family:var(--serif-display);font-variant:small-caps;font-weight:700;
  font-size:4.7cqw;letter-spacing:.055em;color:var(--saddle-deep);margin-top:.12rem;line-height:1.1}
/* DECISIONS */
section h2{font-family:var(--serif-display);font-weight:600;font-size:clamp(1.15rem,2.6vw,1.5rem);
  margin:0 0 .35rem;color:var(--chrome-ink);text-wrap:balance}
section > p.lede{margin:0 0 1.4rem;color:var(--chrome-muted);max-width:44rem;font-size:.95rem}@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}

/* ==========================================================================
   Web presentation - the bifold, behaving like a bifold.

   Three states on a wide screen: closed (front cover) -> open (the inside
   spread) -> back (the back cover). The cover is a single leaf hinged on the
   centre fold with two faces, front outside and inside-left behind it, so
   opening it is one rotation rather than a crossfade between pictures.

   The two inside panels share one photograph - each ::before is 200% wide and
   anchored to its outer edge - so they must sit flush for the halves to meet.
   That is why the open state has no gap at the fold.

   Without JavaScript the whole thing degrades to the four panels stacked in
   reading order, which is also what narrow screens get before the script
   switches them to one panel per tap.
   ========================================================================== */

/* The program is drawn at the exact size the press proof was tuned at -
   544 x 841 - and then scaled. The proof mixes container-relative type with
   rem-based spacing, so resizing the panel makes the gaps grow relative to the
   text and the densest page overflows; scaling it keeps the layout identical
   to the paper at any size. --k is a plain number, so CSS can derive both the
   box and the scale from it. program.js measures the space actually available
   and sets it; this value is the pre-script fallback. */
.bifold {
  --design-w: 544px;
  --design-h: 841px;
  --k: .68;
  --pw: calc(var(--design-w) * var(--k));
  --ph: calc(var(--design-h) * var(--k));
}
.bifold .bf-face .panel {
  width: var(--design-w); height: var(--design-h); aspect-ratio: auto;
  transform: scale(var(--k)); transform-origin: top left;
}

/* ---------- no-JS / pre-hydration fallback: four panels, stacked ---------- */

.bifold:not(.is-ready) .bf-stage {
  display: flex; flex-direction: column; align-items: center; gap: 1.6rem;
}
.bifold:not(.is-ready) .bf-leaf { display: contents; }
.bifold:not(.is-ready) .bf-controls,
.bifold:not(.is-ready) .bf-hint { display: none; }
.bifold:not(.is-ready) .bf-face { position: static; width: var(--pw); height: var(--ph); transform: none; }

/* ---------------------------- the hinged bifold --------------------------- */
/*
   Two leaves, both hinged on the centre fold, exactly like the paper:

     leaf A   front cover  /  inside left
     leaf B   inside right /  back cover

   Closed, both sit in the right half with A on top, so you see the front
   cover. Turning A left gives the spread. Turning B left after it gives the
   back cover - which is B's own reverse, so the front cover never comes back
   into view on the way. Depth order is done with a 1px translateZ in the
   parent's frame rather than z-index, because z-index is ignored between
   siblings inside a preserve-3d context.
*/

.bifold.is-ready .bf-viewport {
  position: relative;
  width: calc(var(--pw) * 2);
  height: var(--ph);
  margin: 0 auto;
  perspective: 2600px;
  cursor: pointer;
}
.bifold.is-ready .bf-stage {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transition: transform .62s cubic-bezier(.22,.61,.36,1);
}
.bifold.is-ready .bf-leaf {
  position: absolute; top: 0; left: var(--pw);
  width: var(--pw); height: var(--ph);
  transform-origin: left center;
  transform-style: preserve-3d;
  transition: transform .78s cubic-bezier(.62,.03,.26,1);
}
.bifold.is-ready .bf-face {
  position: absolute; inset: 0;
  backface-visibility: hidden;
}
.bifold.is-ready .bf-in,
.bifold.is-ready .bf-back { transform: rotateY(180deg); }

/* closed - A in front, both in the right half */
.bifold.is-ready[data-state="closed"] .bf-stage  { transform: translateX(calc(var(--pw) / -2)); }
.bifold.is-ready[data-state="closed"] .bf-leaf-a { transform: translateZ(1px) rotateY(0deg); }
.bifold.is-ready[data-state="closed"] .bf-leaf-b { transform: translateZ(0px) rotateY(0deg); }

/* open - A turned left, B still right: the spread, flush at the fold */
.bifold.is-ready[data-state="open"] .bf-stage  { transform: none; }
.bifold.is-ready[data-state="open"] .bf-leaf-a { transform: translateZ(0px) rotateY(-180deg); }
.bifold.is-ready[data-state="open"] .bf-leaf-b { transform: translateZ(0px) rotateY(0deg); }

/* back - B turned left too, landing on top of A showing its own reverse */
.bifold.is-ready[data-state="back"] .bf-stage  { transform: translateX(calc(var(--pw) / 2)); }
.bifold.is-ready[data-state="back"] .bf-leaf-a { transform: translateZ(0px) rotateY(-180deg); }
.bifold.is-ready[data-state="back"] .bf-leaf-b { transform: translateZ(1px) rotateY(-180deg); }

/* the panels are pages: give them paper, an edge and a shadow */
.bifold .bf-face .panel {
  background: var(--paper);
  border: 1px solid var(--line-soft);
  box-shadow: 0 1px 0 rgba(255,255,255,.5), 0 18px 40px -22px rgba(20,14,4,.6);
}

/* ------------------------------- controls -------------------------------- */

.bf-controls {
  display: flex; justify-content: center; align-items: center;
  gap: 1.1rem; margin: 1.4rem 0 0;
}
.bf-btn {
  font-family: var(--sans); font-size: 1rem; line-height: 1;
  color: var(--saddle-deep); background: rgba(255,255,255,.45);
  border: 1px solid var(--line); padding: .6rem .95rem; cursor: pointer;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.bf-btn:hover:not(:disabled) { background: var(--saddle-deep); border-color: var(--saddle-deep); color: var(--paper); }
.bf-btn:disabled { opacity: .32; cursor: default; }
.bf-label {
  font-family: var(--sans); font-size: .7rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--muted); min-width: 11rem; text-align: center;
}
.bf-hint {
  margin: .9rem 0 0; text-align: center;
  font-size: .88rem; color: var(--muted); font-style: italic;
}

/* ------------------------- one panel per tap, small ----------------------- */

@media (max-width: 780px) {
  .bifold.is-ready .bf-viewport { width: var(--pw); perspective: none; }
  .bifold.is-ready .bf-stage { transform: none !important; transform-style: flat; }
  .bifold.is-ready .bf-leaf  { left: 0; transform: none !important; transform-style: flat; }
  .bifold.is-ready .bf-face {
    opacity: 0; z-index: 1; backface-visibility: visible;
    transform: none !important; transition: opacity .32s ease;
  }
  .bifold.is-ready[data-state="closed"] .bf-out  { opacity: 1; z-index: 3; }
  .bifold.is-ready[data-state="left"]   .bf-in   { opacity: 1; z-index: 3; }
  .bifold.is-ready[data-state="right"]  .bf-ir   { opacity: 1; z-index: 3; }
  .bifold.is-ready[data-state="back"]   .bf-back { opacity: 1; z-index: 3; }
  .bf-label { min-width: 8rem; font-size: .64rem; }
}

@media (prefers-reduced-motion: reduce) {
  .bifold.is-ready .bf-stage,
  .bifold.is-ready .bf-leaf,
  .bifold.is-ready .bf-face { transition-duration: .001s !important; transition-delay: 0s !important; }
}

/* ---------------------------- page furniture ----------------------------- */

.sec-head {
  font-family: var(--sans); font-weight: 600; font-size: .82rem;
  letter-spacing: .26em; text-indent: .26em; text-transform: uppercase;
  color: var(--saddle-deep); text-align: center; margin: 3.4rem 0 .5rem;
}
.sec-intro { max-width: 32rem; margin: 0 auto 1.8rem; text-align: center; color: var(--ink-2); font-size: .98rem; }
.dl-row { text-align: center; margin: 2.4rem 0 0; }
.dl {
  display: inline-block; font-family: var(--sans); font-weight: 600;
  font-size: .76rem; letter-spacing: .16em; text-transform: uppercase;
  text-decoration: none; color: var(--saddle-deep); border: 1px solid var(--line);
  padding: .72rem 1.5rem; background: rgba(255,255,255,.4);
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.dl:hover { background: var(--saddle-deep); border-color: var(--saddle-deep); color: var(--paper); }

.rec-frame {
  position: relative; width: 100%; aspect-ratio: 16 / 9; background: #17130c;
  border: 1px solid var(--line-soft); box-shadow: 0 10px 26px rgba(70,55,32,.16); overflow: hidden;
}
.rec-frame iframe, .rec-frame video { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
.rec-pending {
  max-width: 32rem; margin: 0 auto; padding: 1.8rem 1.6rem; text-align: center;
  color: var(--ink-2); border: 1px dashed var(--line); background: rgba(255,255,255,.34);
}

.closer { margin-top: 3.6rem; text-align: center; }
.closer p { max-width: 32rem; margin: 1.1rem auto 0; color: var(--ink-2); }
.closer-give { font-size: .95rem; }

/* obituary.css lays the masthead out as a three-item flex row with wide letter
   spacing and no wrap, which is wider than a phone. Let it wrap here. */
@media (max-width: 600px) {
  .masthead-inner { flex-wrap: wrap; justify-content: center; text-align: center; gap: .35rem 1rem; }
}

/* ---------------- a compact head, so the program is above the fold --------- */

.sheet > .titles { margin-top: 1rem; margin-bottom: .2rem; }
.sheet > .titles h1 {
  font-size: clamp(1.6rem, 3.2vw, 2.3rem);
  line-height: 1.05;
  margin: 0;
}
.sheet > .titles .eyebrow {
  margin: .45rem 0 0;
  font-size: .68rem;
  letter-spacing: .2em;
}

/* the section heading is kept for structure and screen readers, not for show */
.vh {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

.bf-controls { margin-top: .9rem; }
.bf-hint { margin-top: .5rem; }
.dl-row { display: flex; flex-wrap: wrap; justify-content: center; gap: .7rem; margin-top: 1.4rem; }
.dl-quiet { background: none; border-color: var(--line-soft); color: var(--muted); }
.dl-quiet:hover { background: var(--saddle-deep); border-color: var(--saddle-deep); color: var(--paper); }

/* the recording and the closer come after a deliberate breath */
.rec-sec { margin-top: 2.2rem; }

/* ---------------- full screen on a phone ---------------- */
/*
   A 26rem page on a handset is a postage stamp, so a tap lifts the program out
   of the page and onto the whole screen, where it steps through the four pages
   one at a time. Position:fixed rather than the Fullscreen API, because iOS
   Safari won't put an arbitrary element into real fullscreen. The body is
   pinned while it's open so the page behind can't scroll under the reader, and
   the scroll position is restored on the way out.
*/

.bf-close { display: none; }

body.bf-locked {
  position: fixed;
  width: 100%;
  overflow: hidden;
}

.bifold.is-immersive {
  position: fixed;
  inset: 0;
  z-index: 9999;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .2rem;
  background: var(--paper);
  padding: calc(env(safe-area-inset-top, 0px) + .6rem) .6rem
           calc(env(safe-area-inset-bottom, 0px) + .6rem);
  animation: bf-rise .26s ease-out;
}
@keyframes bf-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

.bifold.is-immersive .bf-close {
  display: block;
  position: absolute;
  top: calc(env(safe-area-inset-top, 0px) + .5rem);
  right: .7rem;
  width: 2.6rem; height: 2.6rem;
  font-size: 1.5rem; line-height: 1;
  color: var(--muted);
  background: none; border: 0; cursor: pointer;
  z-index: 2;
}
.bifold.is-immersive .bf-close:hover { color: var(--saddle-deep); }

.bifold.is-immersive .bf-controls { margin-top: 1rem; }
.bifold.is-immersive .bf-hint { margin-top: .4rem; }

@media (prefers-reduced-motion: reduce) {
  .bifold.is-immersive { animation: none; }
}

/* where real fullscreen is granted, the UA paints a backdrop behind the
   element - make it paper rather than the default black */
.bifold.is-immersive::backdrop { background: var(--paper); }


/* ==========================================================================
   The recording of the service - chapter list and download row.
   Paired with the block appended to bifold.js.
   ========================================================================== */

/* Chapter list and download row for the recording of the service.

   Deliberately built from the tokens program.css already defines, so this
   reads as part of the printed piece rather than as a video widget bolted
   underneath it. The chapter rows borrow the dotted leader from ul.prog on
   the inside spread - the order of service is the same list, so it should
   look like the same list. */

/* The theme's .rec-frame is width:100% with no ceiling, written before there
   was a video to put in it. Left alone it renders about 1300px wide on a
   desktop, against a program that reads at ~220px and a page whose text measure
   is 32rem - so the recording overruns the thing it is meant to accompany, and
   the poster's own name-and-dates ends up larger than the page's headline.
   Capping it puts the video back inside the page's rhythm. The chapter list
   takes the same width so the two read as one block rather than two. */
.rec-frame {
  max-width: 50rem;
  margin-inline: auto;
}

.rec-chapters {
  max-width: 50rem;
  margin: 1.6rem auto 0;
}

.rec-ch-head {
  font-family: var(--sans);
  font-weight: 600;
  font-size: .74rem;
  letter-spacing: .26em;
  text-indent: .26em;
  text-transform: uppercase;
  color: var(--saddle-deep);
  text-align: center;
  margin: 0 0 1rem;
}

/* Same register as the program's own "tap to open" hint above it. */
.rec-ch-hint {
  margin: -.5rem 0 1rem;
  text-align: center;
  font-family: var(--serif-body);
  font-style: italic;
  font-size: .88rem;
  color: var(--muted);
}

.rec-ch-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line-soft);
}

.rec-ch-list li {
  border-bottom: 1px solid var(--line-soft);
}

.rec-ch {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  width: 100%;
  padding: .62rem .55rem;
  border: 0;
  background: none;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--ink);
  transition: background .16s ease, color .16s ease;
}

.rec-ch:hover,
.rec-ch:focus-visible {
  background: rgba(255, 255, 255, .5);
  color: var(--saddle-deep);
}

.rec-ch:focus-visible {
  outline: 1px solid var(--line);
  outline-offset: -1px;
}

.rec-ch-label {
  flex: 0 1 auto;
  font-family: var(--serif-body);
  font-size: .98rem;
}

/* The leader. Its own element, so it can absorb the slack without ever
   competing with the words either side of it. */
.rec-ch-lead {
  flex: 1 1 auto;
  min-width: 1.25rem;
  align-self: center;
  border-bottom: 1px dotted var(--line);
}

.rec-ch-who {
  flex: 0 1 auto;
  font-family: var(--serif-body);
  font-style: italic;
  font-size: .9rem;
  color: var(--muted);
  white-space: nowrap;
}

.rec-ch-time {
  flex: 0 0 auto;
  font-family: var(--sans);
  font-size: .74rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
  color: var(--muted);
}

/* The chapter currently playing. A rule in the saddle colour rather than a
   filled row: this sits directly under a funeral recording and should stay
   quiet. */
/* Colour and a little weight, the way the rest of the page marks anything.
   This also carried a tinted background and an inset saddle rail - four
   signals for one piece of state, and the rail in particular is furniture
   the page uses nowhere else. */
.rec-ch.is-playing {
  color: var(--saddle-deep);
}

.rec-ch.is-playing .rec-ch-label {
  font-weight: 600;
}

.rec-ch.is-playing .rec-ch-time {
  color: var(--saddle-deep);
}

.rec-dl {
  margin-top: 1.6rem;
}

@media (max-width: 600px) {
  /* On a handset the leader is clutter rather than structure, and a 44px
     target matters more than the printed-program look. The item takes the
     first line, the speaker and the time share the second. */
  .rec-ch {
    flex-wrap: wrap;
    gap: .1rem .5rem;
    padding: .72rem .5rem;
    min-height: 44px;
  }
  .rec-ch-label { flex: 1 0 100%; white-space: normal; }
  /* Nothing to put on a second line, so don't make one. */
  .rec-ch.is-solo .rec-ch-label { flex: 1 1 auto; }
  .rec-ch-lead  { display: none; }
  .rec-ch-who   { flex: 1 1 auto; }
  /* 11.8px is too small to read comfortably, and a good share of the people
     opening this page are in their seventies and eighties. */
  .rec-ch-time  { margin-left: auto; font-size: .82rem; }
}

@media (prefers-reduced-motion: reduce) {
  .rec-ch { transition: none; }
}

/* Parts of the service that were never filmed. Listed for completeness,
   greyed and inert - there is nothing to seek to. */
/* Italic and grey, and that is all. These rows were hatched with diagonal
   stripes, which is decoration doing a job the words already do: the label is
   italic and the right-hand column literally reads "not recorded". */
.rec-ch.is-missing {
  cursor: default;
  color: var(--muted);
}

.rec-ch.is-missing .rec-ch-label,
.rec-ch.is-missing .rec-ch-time { font-style: italic; }

/* ==========================================================================
   The two halves.

   On a desktop the printed program and the recording sit side by side, so both
   are visible the moment the page opens. Before this the recording began a full
   screen down, directly beneath a row of buttons that read as the end of the
   document - the page looked finished before the video was ever mentioned.

   Below 1024px there is not enough width for a two-panel spread and a watchable
   video at the same time, so the halves stack. The program's own sizing code
   measures its container, so it rescales into the column without being told.
   ========================================================================== */

@media (min-width: 1024px) {
  .service-split {
    display: grid;
    /* minmax(0, 1fr), not 1fr: a bare 1fr keeps each column at least as wide as
       its own min-content, and the program's spread is wide enough to claim the
       extra - which quietly makes the halves unequal (684 against 618). */
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 2.6rem;
    align-items: start;
  }

  /* Both columns start on the same line, and the two headings sit on the same
     baseline, so the halves read as a pair rather than as a stack that happens
     to be beside itself. */
  .service-split > section { margin-top: 0; }
  .service-split .sec-head { margin-top: 0; }

  /* Inside a half-width column the caps set for the full-width layout would
     only ever fight the grid. */
  .service-split .rec-frame,
  .service-split .rec-chapters { max-width: none; }

  /* The chapter list is the taller half; let it breathe rather than align to
     the program's shorter column. */
  .service-split .rec-chapters { margin-top: 1.4rem; }
}

/* One row of actions for the whole page, under both halves. */
.page-actions {
  margin-top: 3rem;
}

@media (max-width: 600px) {
  /* Stacked full-width on a phone, in the order people want them: the program
     they may want to keep, then his obituary, then the recording. */
  .page-actions { flex-direction: column; align-items: stretch; gap: .6rem; }
  .page-actions .dl { text-align: center; }
}

/* The column label only earns its place when there are two columns. Stacked,
   the program is simply the first thing on the page and needs no sign over it -
   and the ~77px it costs is precisely what was still holding the recording
   below the fold on a phone. Hidden from sight, kept for screen readers. */
@media (max-width: 1023.98px) {
  #prog-title {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    clip-path: inset(50%); overflow: hidden; white-space: nowrap;
  }
}

/* ---------------- "the recording is below" ---------------- */
/*
   Only ever seen on a phone. With the halves side by side the recording is
   already on screen and a downward arrow would be pointing at nothing; stacked,
   this is the one thing standing between someone and a video they do not know
   exists, so it is a full-width button rather than a quiet link.
*/
.jump-rec {
  margin: 1.4rem 0 0;
  /* Padding, not margin: fit() sizes the card from this element's bounding box,
     and margins fall outside it. This is the clearance under the button on the
     shortest phones, where it would otherwise sit 14px off the bottom edge. */
  padding-bottom: 1.1rem;
  text-align: center;
}

.jump-rec .dl {
  display: block;
  max-width: 26rem;
  margin-inline: auto;
}

@media (min-width: 1024px) {
  .jump-rec { display: none; }
}

/* Scrolling rather than jumping is the point here: the movement is what tells
   you the recording was below all along. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* The anchor lands on a heading that sits right under the masthead rule;
   a little breathing room stops it butting against the top of the screen. */
#rec-title { scroll-margin-top: 1rem; }


/* ---------------- the list scrolls, not the page ---------------- */
/*
   Ten parts is more than fits beside the video, and paging the whole document
   to read them means leaving the player behind. Giving the list its own window
   keeps the recording, the heading and the list all on screen at once: the only
   thing that moves is the list itself.

   Phones keep the full list inline - a small scrolling box inside a page you
   are already scrolling is a trap on touch.
*/
@media (min-width: 1024px) {
  .service-split .rec-ch-list {
    /* Sized from what is left of the screen rather than a flat share of it:
       38rem is roughly the masthead, title, video and heading stacked above.
       A plain 38vh left the last row clipped by the fold, which is the one
       thing this was meant to stop. */
    max-height: clamp(12rem, calc(100vh - 38rem), 30rem);
    overflow-y: auto;
    /* Don't hand the scroll back to the page when the list reaches its end. */
    overscroll-behavior: contain;
    /* Reserve the scrollbar's width so the rows don't shift when it appears. */
    scrollbar-gutter: stable;
  }

  /* A hairline where the list is clipped, so the cut edge reads as "more
     below" rather than as the end of the list. */
  .service-split .rec-ch-list { border-bottom: 1px solid var(--line-soft); }
}
