/* ── Variables ─────────────────────────────────────────────────────────────── */

:root {
  color-scheme: light dark;

  --font-liturgy: 'EB Garamond', Georgia, 'Times New Roman', serif;
  /* True small caps for heads — see the note in assets/fonts/fonts.css. Falls
     back through the reading face, where small caps are synthesized instead. */
  --font-liturgy-sc: 'EB Garamond SC', 'EB Garamond', Georgia, 'Times New Roman', serif;
  --font-ui: 'IBM Plex Sans', system-ui, -apple-system, sans-serif;
  --line-height: 1.5;

  /* ACC / PWC palette */
  --color-bg:          #F4EEDF;
  --color-text:        #262219;
  --color-rubric:      #9A2B22;
  --color-nav-bg:      #15382A;
  --color-nav-text:    #F3EEDF;
  --color-link:        #2C7060;
  /* Darkened from #7B7460, which cleared neither page ground (4.02 on --color-bg,
     4.32 on --color-surface) while carrying most of the small print. 5.57 / 5.98
     here, and still visibly quieter than --color-text at 13.69. See issue #85;
     audit_a11y.cjs now measures both grounds so it cannot drift back. */
  --color-muted:       #655E4B;
  --color-border:      #E2D8C2;
  --color-surface:     #FBF6EB;
  --color-heading:     #15382A;
  --color-brass:       #9A7B3F;
  /* Darkened from #8A6B2F, which cleared only the surface ground (4.61) and
     not the page ground (4.29) for the verse numbers and psalm midpoint —
     both small, so no large-text exemption. 4.72 / 5.07 here, and still
     visibly quieter than --color-text at 13.69. See issue #107;
     audit_a11y.cjs measures both grounds so it cannot drift back. */
  --color-brass-ink:   #826527;
  --color-brass-on-nav:#CBA85A;

  /* Liturgical accent — overridden per season on <html> */
  --color-accent: #3B6B4E;

  /* Type scale — 8 steps, ratios from the printed book */
  --fs-day-title:    1.75rem;
  --fs-head-section: 1.3rem;
  --fs-head-sub:     1.05rem;
  --fs-liturgy:      1.1rem;
  --fs-rubric:       1.02rem;
  --fs-ui:           0.8rem;
  --fs-eyebrow:      0.78rem;
  --fs-micro:        0.66rem;

  /* Spacing — Fibonacci steps (1, 2, 3, 5, 8, 13) on a 4 px unit. The unit
     follows the root font, so it goes to 5 px at the 820px breakpoint. */
  --sp-1: 4px;   /* inside a couplet, label→value */
  --sp-2: 8px;   /* head→rubric, chip padding */
  --sp-3: 12px;  /* rubric→said text */
  --sp-4: 20px;  /* between stanzas and alternatives */
  --sp-5: 32px;  /* above a section head, with its rule */
  --sp-6: 52px;  /* day header→first section */

  --radius-sm:   4px;
  --radius-md:   8px;
  --radius-lg:   16px;  /* bottom sheets only */
  --radius-pill: 999px;

  /* Structural offset: px, so text scaling never eats measure */
  --indent: 18px;
  /* Typographic offset: em, it belongs to the line */
  --verse-indent: 0.9em;

  /* Measure in rem, not ch: `ch` resolves against the UI sans on <body> while
     the text is Garamond, so 62ch was ~70 Garamond characters. 31rem is ~64 at
     the desktop step, and wider than any phone viewport, so mobile is unchanged. */
  --content-max: 31rem;

  /* One horizontal gutter for the bar and the page, so they cannot drift. */
  --gutter: 1.25rem;

  /* safe area for notched devices */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}

/* Font size — scale html so all rem values change uniformly */
[data-font-size="medium"] { font-size: 100%;   --line-height: 1.5; }
[data-font-size="large"]  { font-size: 112.5%; --line-height: 1.55; }

/* Seasonal accent colours */
[data-season="Advent"]       { --color-accent: #4B3F8C; }
/* Darkened from #B0863A (same hue, H39), which failed AA as text on both
   light grounds — 2.87 on --color-bg, 3.08 on --color-surface. 4.59 / 4.93.
   See #106. */
[data-season="Christmas"]    { --color-accent: #86662C; }
[data-season="Epiphany"]     { --color-accent: #2C7370; }
[data-season="Lent"]         { --color-accent: #6B4C8A; }
[data-season="Passiontide"]  { --color-accent: #7E2420; }
[data-season="Easter"]       { --color-accent: #86662C; }
[data-season="Pentecost"]    { --color-accent: #A43328; }
[data-season="AllSaints"]    { --color-accent: #4A6080; }
[data-season="OrdinaryTime"] { --color-accent: #3B6B4E; }

/* ── Dark mode ──────────────────────────────────────────────────────────────── */

[data-theme="dark"] {
  --color-bg:       #15140E;
  --color-text:     #E9E2D2;
  --color-rubric:   #E0907A;
  --color-nav-bg:   #0F1A14;
  --color-nav-text: #D8D0BF;
  --color-link:     #7EC0A8;
  --color-muted:    #9A9281;
  --color-border:   #322F23;
  --color-surface:  #1E1C14;
  --color-heading:  #86C0A4;
  --color-brass:    #CBA24E;
  --color-brass-ink:#B88E3E;
  --color-brass-on-nav:#D8B968;
}

/* Dark-mode seasonal accents — lighten for visibility on dark background.
   Every season gets an explicit value here, even where the light value
   already clears AA on dark ground (Christmas, Easter), so none of them
   depend on inheriting an accent chosen against the other ground. See #106.
   Advent, Lent, Passiontide and Pentecost are lightened further still (same
   hue in each case) — the first pass cleared --color-bg but not the lighter
   --color-surface: Advent 4.25/3.93, Lent 4.51/4.17, Passiontide 4.11/3.80,
   Pentecost 4.81/4.44. Now 5.06/4.68, 4.90/4.53, 5.00/4.62, 4.97/4.60. */
[data-theme="dark"][data-season="Advent"]       { --color-accent: #887DC2; }
[data-theme="dark"][data-season="Christmas"]    { --color-accent: #B0863A; }
[data-theme="dark"][data-season="Epiphany"]     { --color-accent: #38928F; }
[data-theme="dark"][data-season="Lent"]         { --color-accent: #9577B4; }
[data-theme="dark"][data-season="Passiontide"]  { --color-accent: #CF6658; }
[data-theme="dark"][data-season="Easter"]       { --color-accent: #B0863A; }
[data-theme="dark"][data-season="Pentecost"]    { --color-accent: #D16454; }
[data-theme="dark"][data-season="AllSaints"]    { --color-accent: #6E87AB; }
[data-theme="dark"][data-season="OrdinaryTime"] { --color-accent: #51926B; }

/* ── Reset ─────────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
a, button { -webkit-tap-highlight-color: transparent; }
:focus:not(:focus-visible) { outline: none; }
:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

body {
  font-family: var(--font-ui);
  /* Nothing inherits this: every text class sets its own size and the --fs-*
     tokens resolve against the root, so the old 1.1875rem only misdescribed
     the page. Verified as a no-op — no leaf element's computed size moves. */
  font-size: 1rem;
  line-height: var(--line-height);
  background: var(--color-bg);
  color: var(--color-text);
  -webkit-font-smoothing: antialiased;
  touch-action: manipulation;
  min-height: 100vh;
  padding-left: var(--safe-left);
  padding-right: var(--safe-right);
  transition: background 0.25s, color 0.25s;
}

/* ── Navigation ────────────────────────────────────────────────────────────── */

#nav {
  background: var(--color-nav-bg);
  color: var(--color-nav-text);
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  box-shadow: 0 1px 3px rgba(0,0,0,0.12);
  padding-top: var(--safe-top);
  padding-left: var(--safe-left);
  padding-right: var(--safe-right);
}

#nav-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0.25rem var(--gutter);
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  transition: padding 0.2s ease;
}

.nav-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
}
/* Flush left: centring is only honest when the bar is otherwise empty. The
   icons sit in the row rather than over it, so the brand can truncate instead
   of running under them. Matches the book, whose running heads sit at the margin. */
.nav-top { justify-content: flex-start; gap: 0.5rem; position: relative; }
#nav-brand {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex: 1 1 auto;
  min-width: 0;
  text-decoration: none;
}
.nav-logo { flex-shrink: 0; color: var(--color-brass-on-nav); opacity: 0.95; }
@media (max-width: 520px) {
  .nav-logo { width: 32px; height: 32px; }
}
.nav-brand-name {
  font-family: var(--font-liturgy);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--color-brass-on-nav);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
@media (max-width: 520px) {
  .nav-brand-name { font-size: 1rem; }
}

.nav-icon-group {
  position: static;
  transform: none;
  flex-shrink: 0;
  display: flex; align-items: center; gap: 0.15rem;
}
.nav-icon-btn {
  background: none; border: none; cursor: pointer;
  color: var(--color-brass-on-nav); opacity: 0.7;
  padding: 0.35rem; border-radius: var(--radius-md);
  display: flex; align-items: center;
  transition: opacity 0.1s, background 0.1s;
}
.nav-icon-btn:hover { opacity: 1; background: rgba(255,255,255,0.08); }

/* Nav links */
#nav a {
  color: var(--color-nav-text);
  text-decoration: none;
  opacity: 0.78;
  padding: 0.2rem 0.5rem;
  border-radius: var(--radius-sm);
  transition: opacity 0.1s, background 0.1s;
  white-space: nowrap;
}
@media (hover: hover) {
  #nav a:hover { opacity: 1; background: rgba(255,255,255,0.08); }
}

/* ── Settings bottom sheet ──────────────────────────────────────────────────── */

.settings-sheet {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: flex-end;
  visibility: hidden; transition: visibility 0s 0.28s;
}
.settings-sheet[aria-hidden="false"] { pointer-events: all; visibility: visible; transition: visibility 0s; }

.settings-backdrop {
  position: absolute; inset: 0;
  background: rgba(10,18,14,0.45); opacity: 0;
  transition: opacity 0.22s;
}
.settings-sheet[aria-hidden="false"] .settings-backdrop { opacity: 1; }

.settings-panel {
  position: relative; width: 100%;
  background: var(--color-surface);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: 0.6rem 1.25rem calc(2.4rem + var(--safe-bottom));
  transform: translateY(100%);
  transition: transform 0.28s cubic-bezier(0.32,0.72,0,1);
  max-width: 480px; margin: 0 auto;
}
.settings-sheet[aria-hidden="false"] .settings-panel { transform: translateY(0); box-shadow: 0 -12px 40px rgba(0,0,0,0.22); }

/* Grip handle */
.settings-panel::before {
  content: ''; display: block;
  width: 38px; height: 4px; border-radius: var(--radius-pill);
  background: var(--color-border);
  margin: 0.4rem auto 0.9rem;
}

.settings-header {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 1.1rem;
  /* app chrome, not a liturgical head — small caps are the book's heading
     convention, and a sheet title is the one place they don't belong */
  font-family: var(--font-ui);
  font-size: var(--fs-ui); font-weight: 600;
  color: var(--color-heading);
  letter-spacing: 0.02em;
}
.sheet-close-btn {
  background: none; border: none; cursor: pointer;
  color: var(--color-muted); padding: 0.25rem; display: flex;
}

.settings-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 0.85rem 0; border-bottom: 1px solid var(--color-border);
  gap: 1rem;
}
.settings-row:last-child { border-bottom: none; }

.settings-label { font-family: var(--font-ui); font-size: var(--fs-ui); color: var(--color-text); }
.settings-sublabel { font-family: var(--font-ui); font-size: var(--fs-micro); color: var(--color-muted); margin-top: 2px; }

.settings-row select, .settings-row button, .settings-row input[type=date] {
  font-family: var(--font-ui); font-size: var(--fs-ui);
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); padding: 0.3rem 0.65rem;
  color: var(--color-text); cursor: pointer;
}
.date-picker-row {
  display: flex; gap: 0.5rem; align-items: center; flex: 1;
}
.date-picker-row input[type=date] { flex: 1; }
.today-btn {
  font-family: var(--font-ui); font-size: var(--fs-ui); font-weight: 500;
  background: var(--color-nav-bg); color: var(--color-nav-text);
  border: none; border-radius: var(--radius-md); padding: 0.35rem 0.75rem;
  cursor: pointer; white-space: nowrap;
  transition: opacity 0.15s;
}
.today-btn:hover { opacity: 0.85; }
/* Mini segmented control inside settings */
.settings-mini-seg {
  display: flex; gap: 3px; padding: 3px;
  background: var(--color-bg); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); flex-shrink: 0;
}
.settings-mini-seg button {
  background: transparent; border: none; cursor: pointer;
  font-family: var(--font-ui); font-size: var(--fs-ui); font-weight: 500;
  /* concentric: inner radius = outer − padding, or the filled pill bulges */
  color: var(--color-muted); padding: 0.3rem 0.65rem; border-radius: var(--radius-sm);
}
.settings-mini-seg button.is-active {
  background: var(--color-nav-bg); color: var(--color-nav-text);
  box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}

/* The Opening toggle is the same seg shape as the office toggle — the shared
   .day-ctrl-seg/.day-ctrl-btn rules cover it; nothing opening-specific needed. */

/* ── Main content ───────────────────────────────────────────────────────────── */

#nav-spacer { display: block; }

#main {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 1.5rem var(--gutter) calc(5rem + var(--safe-bottom));
}

/* ── Day header ─────────────────────────────────────────────────────────────── */

#day-brand { display: none; }

/* One alignment axis: the header sits at the same left margin as the prayer
   below it, so the eye never resets between them. */
#day-header {
  text-align: left;
  /* The office controls now close the header, so the header→first-section
     gap tightens from the standalone --sp-6 to a control-level --sp-4; the
     section head's own rule and margin still carry the breathing room. */
  padding: var(--sp-2) 0 var(--sp-4);
}

#day-title {
  font-family: var(--font-liturgy);
  font-size: var(--fs-day-title); font-weight: 600; line-height: 1.2;
  color: var(--color-heading);
  margin-bottom: var(--sp-2);
}

/* The civil date. Plain text — the nav bar's calendar button owns the date
   picker (#163). */
#day-date-label {
  display: block; margin-bottom: 0.5rem;
  font-family: var(--font-liturgy); font-size: 1.15rem; font-style: italic;
  color: var(--color-text);
}

#day-meta {
  display: flex; justify-content: flex-start; align-items: flex-start;
  gap: var(--sp-1) var(--sp-2);
  flex-wrap: wrap; font-size: var(--fs-ui);
}
/* A bar token trails its · only when another bar token follows it — never
   after a marker, which wraps to its own full-width line beneath, and never
   orphaned onto a wrapped line, because the token that carries the · is the
   one that wrapped (#124). */
.meta-item:not(.meta-item--marker):has(+ .meta-item:not(.meta-item--marker))::after {
  content: '·'; color: var(--color-border); margin-left: var(--sp-1);
}

/* Meta: season item */
/* No opacity here. It dimmed --color-muted to 3.64:1 on the page ground, which
   is the #85 defect by a second route — and with the token now properly quiet,
   the muted ink already reads quieter than .meta-val's weight and colour. */
.meta-item { display: flex; align-items: center; gap: 0.35rem; color: var(--color-muted); white-space: nowrap; }
.meta-item--season { font-weight: 500; color: var(--color-text); }
/* Markers are sentences, not tokens — "Day of discipline and self-denial" is
   wider than a phone's measure, so this is the one meta item that wraps
   inside itself rather than pushing the row (#128). They sit as their own
   full-width line beneath the bar: a marker's margin doubles the gap to mark
   the boundary, and a second marker just follows the first (#152). */
.meta-item--marker { flex-basis: 100%; margin-top: var(--sp-1); white-space: normal; text-wrap: pretty; }
.meta-item--marker + .meta-item--marker { margin-top: 0; }
.meta-val {
  font-family: var(--font-ui); font-size: var(--fs-ui);
  color: var(--color-text); font-weight: 500;
}

/* Colour chip */
.colour-chip {
  display: inline-block; width: 13px; height: 13px;
  border-radius: var(--radius-sm); border: 1px solid rgba(0,0,0,0.18);
  flex-shrink: 0; vertical-align: middle; padding: 0;
}
.colour-chip-toggle { cursor: pointer; transition: transform 0.15s; }
.colour-chip-toggle:hover { transform: scale(1.25); }
.colour-cycle-hint { font-size: 0.7em; opacity: 0.55; }
.colour-name { color: var(--color-muted); font-family: var(--font-ui); font-size: var(--fs-ui); }
.colour-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.18);
  flex-shrink: 0;
  vertical-align: middle;
  margin-right: var(--sp-1);
}

/* ── View toggle (book mode) ────────────────────────────────────────────────── */

body.book-mode .verse-num { display: inline; }
body.book-mode .alt-panel         { display: block !important; }
body.book-mode .alt-panel-hidden  { display: block !important; }
/* The printed page has no selector — it prints every alternative with "or"
   between them. */
body.book-mode .alt-tabs { display: none; }
body.book-mode .alt-panel + .alt-panel::before {
  content: "or";
  display: block;
  font-family: var(--font-liturgy);
  font-style: italic;
  font-size: var(--fs-rubric);
  color: var(--color-rubric);
  margin: var(--sp-3) 0;
}

/* ── Section headings ───────────────────────────────────────────────────────── */

/* Rank is carried by case first, size second: a main component of the liturgy
   is set in caps, its subcomponents in upper-and-lower. Size alone was a 13%
   step and read as one level, which upstream review rejected. */
.office-section-title {
  font-family: var(--font-liturgy-sc);
  font-size: var(--fs-head-section);
  font-weight: 600;
  font-variant: small-caps;
  text-transform: lowercase;   /* with small-caps → full small caps, as printed */
  letter-spacing: 0.07em;      /* caps want more air than upper-and-lower */
  color: var(--color-heading);
  margin: var(--sp-5) 0 var(--sp-4);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--color-accent);
}

/* When the office content opens straight onto the section head — no FATS
   biography between header and liturgy — the header's own padding already
   separates them, and the full --sp-5 would read as dead space (#165). A day
   with a biography keeps the full margin: the biography absorbs the band. */
#office-content > h2.office-section-title:first-child { margin-top: var(--sp-2); }


/* Subcomponent: same face as the section head, no small caps. The reading face
   rather than the SC family — nothing here asks for the smcp table. */
.office-subsection-title {
  font-family: var(--font-liturgy);
  font-size: var(--fs-head-sub);
  font-weight: 600;
  letter-spacing: 0;
  color: var(--color-heading);
  margin: var(--sp-4) 0 var(--sp-2);
  padding-top: 0;
  border-top: none;
}
.obs-readings h3:first-of-type { margin-top: 0; }

.observance-label {
  margin: var(--sp-1) 0 var(--sp-3);
}

/* A rubric the lectionary attaches to one office rather than to a segment —
   the condition on which the office is said at all (#132). Set as the office's
   own rubrics are, so it reads as the book speaking and not as a caption. */
.office-rubric {
  font-family: var(--font-liturgy);
  font-size: var(--fs-rubric);
  font-style: italic;
  color: var(--color-rubric);
  margin: var(--sp-1) 0 var(--sp-3);
}

/* ── Labels ─────────────────────────────────────────────────────────────────── */

/* Two label styles carry every non-liturgical caption in the app. Colour stays
   on the individual selectors where it carries meaning. */
.label-eyebrow,
.note-antiphon-label {
  font-family: var(--font-ui);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.label-micro,
.observance-label {
  font-family: var(--font-ui);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* ── Liturgical segments ────────────────────────────────────────────────────── */

.liturgy { font-family: var(--font-liturgy); }

.seg-leader,
.seg-response {
  font-family: var(--font-liturgy);
  font-size: var(--fs-liturgy);
  line-height: var(--line-height);
  margin: 0 0 0 var(--indent);
  white-space: pre-wrap;
}
.seg-response { font-weight: 600; }

.seg-label {
  font-family: var(--font-liturgy); font-style: italic;
  font-size: 0.95rem; color: var(--color-muted);
  margin: var(--sp-3) 0 var(--sp-1);
}
/* Verse lines (psalm/canticle/invitatory line-pairs). Each line is its own
   block with a hanging indent: a full verse starts flush and its wraps tuck
   under it, a half-line starts at --verse-indent and its wraps at twice that.
   So a wrapped line can never be mistaken for a genuine half-verse. */
.psalm-verse,
.verse-line,
.verse-cont { display: block; }
.verse-line {
  padding-left: var(--verse-indent);
  text-indent: calc(-1 * var(--verse-indent));
}
.verse-cont {
  padding-left: calc(2 * var(--verse-indent));
  text-indent: calc(-1 * var(--verse-indent));
}
/* The stanza gap inside a single said text. Same value as the gap between two
   adjacent said texts below, which is the same relationship. */
.stanza-break { display: block; height: var(--sp-4); }

/* The book prints versicle/response dialogue as one continuous, single-spaced
   block — no gap between a response and the next leader line. Matching that
   here rather than inserting stanza-sized air between couplets (#157); a real
   stanza break within a said text still gets one, via the explicit
   .stanza-break marker below, not this rule. Verified against the source
   page for the three sections that actually run more than one consecutive
   leader/response pair today — Introductory Responses, the Litany, the
   Responsory — since the selector is global across every .seg-leader/
   .seg-response pair in the app: a new section added later with its own
   multi-pair dialogue inherits this silently and should be checked against
   its own page before assuming it's covered. */
.seg-response + .seg-leader,
.seg-leader   + .seg-leader,
.seg-response + .seg-response,
.seg-leader   + .seg-response { margin-top: 0; }
.seg-label    + .seg-leader   { margin-top: 0; }
/* A said text running straight into an alternatives block: .alt-block carries
   spacing below it only, and the segment rules above cover segment→segment, so
   this boundary would otherwise compute to 0 on both sides. */
.seg-leader   + .alt-block,
.seg-response + .alt-block    { margin-top: var(--sp-4); }
/* Same shape for a rubric: it carries bottom margin only, so without this the
   red line sits on the last line of the prayer it follows (#120). */
.seg-leader   + .seg-rubric,
.seg-response + .seg-rubric   { margin-top: var(--sp-4); }
/* A response that continues the same said text past a closed alt-block
   (Ordinary Time's "Alleluia." after the doxology's "Amen.") needs the
   widget's own bottom margin gone, not a margin-top:0 on the response —
   margins collapse to the larger side, so only the earlier element's
   margin-bottom can actually close the gap (same reasoning as
   collectTextHtml's comment in app.js, #156/#160). Scoped to .seg-response —
   every alt-block followed by a .seg-leader today (e.g. Thanksgiving for
   Light) starts a new prayer, not a continuation, and should keep the gap.
   Keyed on adjacency, not on what the response actually continues, so a
   future alt-block placed directly before an unrelated response would
   silently inherit this too — check against its own page before assuming
   it's covered, same caveat as the leader/response rule above. */
.alt-block:has(+ .seg-response) { margin-bottom: 0; }

.seg-rubric {
  font-family: var(--font-liturgy);
  font-size: var(--fs-rubric);
  font-style: italic;
  color: var(--color-rubric);
  margin: 0 0 var(--sp-3);
  white-space: pre-wrap;
}

/* ── Psalm text ─────────────────────────────────────────────────────────────── */

/* Separate consecutive psalms within a single office section (each carries
   its own "Psalm N — Title" heading, so no group heading precedes them). */
.psalm-loading + .psalm-loading {
  margin-top: var(--sp-4);
}
.psalm-title {
  font-family: var(--font-liturgy); font-size: 0.9rem; font-style: italic;
  color: var(--color-muted); margin: 0 0 var(--sp-3);
}

.psalm-block {
  margin: 0 0 var(--sp-4) var(--indent);
  font-family: var(--font-liturgy); font-size: var(--fs-liturgy); line-height: var(--line-height);
  white-space: pre-wrap;
}
.scripture-block {
  margin: 0 0 var(--sp-4) var(--indent);
  font-family: var(--font-liturgy); font-size: var(--fs-liturgy); line-height: var(--line-height);
}
.scripture-ch-num {
  font-family: var(--font-liturgy);
  font-size: 1.6em; font-weight: 700; line-height: 0.85;
  color: var(--color-heading);
  padding-right: 0.25em;
}
.verse-num {
  font-size: 0.68em; color: var(--color-brass-ink);
  font-family: var(--font-ui);
  user-select: none; font-weight: 600;
  padding-right: 0.15em;
}
.midpoint { color: var(--color-brass-ink); font-style: normal; }
.midpoint-group { white-space: nowrap; }

/* No divider: the book prints the Gloria Patri as plain running text after
   its rubric, the same as the Invitatory's and the Canticle's own Gloria
   (#159) — this class no longer sets anything beyond the shared face, kept
   as a hook for the wrapper rather than removed. */
.psalm-gloria {
  font-family: var(--font-liturgy);
}

/* ── Scripture reading ──────────────────────────────────────────────────────── */

/* Subcomponent rank — "The Reading: Isaiah 55" must not outrank
   "Introductory Responses", so it matches .office-subsection-title. */
.reading-heading {
  font-family: var(--font-liturgy);
  font-size: var(--fs-head-sub);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--color-heading);
  margin: var(--sp-4) 0 var(--sp-2);
  padding-top: 0;
  border-top: none;
}
.scripture-attr {
  font-family: var(--font-ui); font-size: var(--fs-micro); color: var(--color-muted);
  font-style: italic; margin-top: var(--sp-5); padding-top: var(--sp-3);
  text-align: left;
}
.scripture-fallback-note {
  font-family: var(--font-ui); font-size: var(--fs-micro); font-style: italic;
  color: var(--color-muted); margin-top: 0.4rem;
}
.scripture-offline {
  font-family: var(--font-ui); font-size: var(--fs-micro); font-style: italic;
  color: var(--color-muted); margin-top: 0.4rem;
}

/* ── Collect ────────────────────────────────────────────────────────────────── */

.collect-text {
  font-family: var(--font-liturgy); font-size: var(--fs-liturgy);
  white-space: pre-wrap; margin: 0 0 var(--sp-4) var(--indent);
  line-height: var(--line-height);
}

.obs-readings.obs-hidden { display: none; }

/* ── FATS biographical notice ───────────────────────────────────────────────── */
.fats-bio {
  /* Rides with the day identity above the office controls: top gap from the
     day meta, and the controls' own margin-top supplies the space below. */
  margin: var(--sp-4) 0 0;
  border: 1px solid var(--color-border); border-left: 2px solid var(--color-accent);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
.fats-bio-toggle {
  display: block; width: 100%; padding: 0.55rem 0.9rem;
  font-family: var(--font-ui); font-size: 0.8rem; font-weight: 500;
  color: var(--color-accent); cursor: pointer;
  list-style: none;
}
.fats-bio-toggle::-webkit-details-marker { display: none; }
.fats-bio-toggle::before { content: '▶ '; font-size: 0.65rem; }
details[open] .fats-bio-toggle::before { content: '▼ '; }
.fats-bio-body {
  padding: 0 0.9rem 0.9rem;
  font-family: var(--font-ui); font-size: 0.9rem; line-height: 1.65;
  color: var(--color-text);
}
.fats-bio-body p { margin: 0 0 0.75em; }
.fats-bio-body p:last-child { margin-bottom: 0; }

/* ── Alternatives ───────────────────────────────────────────────────────────── */

.alt-source {
  font-family: var(--font-liturgy); font-size: 0.92rem;
  font-style: italic; color: var(--color-rubric);
  margin: var(--sp-1) 0 var(--sp-2);
}
/* The block carries no indent of its own. The selector is app chrome and
   belongs on the margin beside the rubric that introduces the choice; the text
   inside a panel indents by the same rules as text outside one, so a heading in
   a panel stays on the margin and a psalm in a panel stays on --indent. Two
   axes, and no accumulation when alternatives nest inside alternatives. */
.alt-block { margin: 0 0 var(--sp-4); }

/* Inline pills, not a segmented track: a choice inside the liturgy is an aside
   to the reading eye, and upstream review asked for the smaller inline toggles
   back. They keep the head face of the typographic pass rather than reverting
   to sans. */
.alt-tabs {
  display: flex;
  flex-wrap: wrap;
  /* 10px, so the hit areas below tile exactly rather than overlap */
  gap: 10px;
  margin: 0 0 var(--sp-3);
}
.alt-tab {
  flex: 0 0 auto;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 36px;
  text-align: center;
  font-family: var(--font-liturgy-sc);
  font-size: 0.9rem;
  font-variant: small-caps;
  font-weight: 500;
  letter-spacing: 0.03em;
  line-height: 1.25;
  /* Not --color-muted. That started as a contrast workaround — muted was then
     4.02:1 on the page ground, under AA at the ~10px this small-caps label
     draws — and #85 has since fixed the token itself, so the reason is now
     purely typographic: the pill recedes by its outline and its weight, and an
     inactive pill next to an active one reads as unselected rather than faint. */
  color: var(--color-text);
  background: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  padding: 4px 14px;
  cursor: pointer;
  text-transform: none;
  transition: color 0.1s, background 0.1s, border-color 0.1s;
  /* A long book name — worst case "A Song of Jerusalem Our Mother" — wraps the
     row rather than the pill; one wider than the measure wraps inside it. */
  white-space: normal;
  text-wrap: pretty;
  max-width: 100%;
}
/* 44px target without 44px of pill: the row's 10px gap is twice this bleed, so
   neighbouring hit areas meet and never overlap. */
.alt-tab::after { content: ''; position: absolute; inset: -4px -5px; }
.alt-tab:hover { border-color: var(--color-muted); }
.alt-tab.alt-tab-active {
  font-weight: 600;
  color: var(--color-heading);
  border-color: var(--color-brass);
  background: color-mix(in oklab, var(--color-brass) 10%, var(--color-bg));
}
.alt-panel-hidden { display: none; }

/* ── Day notes ──────────────────────────────────────────────────────────────── */

.day-note {
  font-family: var(--font-liturgy); font-size: 0.95rem;
  font-style: italic; color: var(--color-muted); margin: var(--sp-2) 0;
  text-align: left;
}
.day-note a { color: var(--color-link); text-decoration: underline; font-style: normal; }

.day-note--antiphon {
  font-style: normal; color: var(--color-text);
  border-left: 2px solid var(--color-accent);
  padding-left: var(--sp-3); margin: var(--sp-3) 0;
}
.note-antiphon-label {
  display: block;
  color: var(--color-accent); margin-bottom: 0.2rem;
}
.note-antiphon-body {
  font-family: var(--font-liturgy); font-size: 1rem;
  font-style: italic; line-height: var(--line-height);
}
.day-note--info {
  font-size: 0.85rem; font-style: normal; font-family: var(--font-ui);
  color: var(--color-muted);
}
.day-note--info strong { font-weight: 500; color: var(--color-text); }

/* Source notes: the compiler's apparatus, closed by default (#127). Quieter
   than .fats-bio — that card holds a saint's biography, this holds the
   provenance of a citation. */
.day-note-details {
  /* Clears the office controls above it (the header's own padding carries the
     space below); the note is apparatus, not a sibling of the controls. */
  margin: var(--sp-4) 0 0;
  /* The same accent rule and accent toggle as .fats-bio, so both disclosures
     read as one family; the note keeps no enclosing box — just the rule —
     and a muted body. */
  border-left: 2px solid var(--color-accent);
}
.day-note-details-toggle {
  padding: 0.15rem 0 0.15rem 0.7rem;
  font-family: var(--font-ui); font-size: 0.8rem;
  color: var(--color-accent); cursor: pointer;
  list-style: none;
}
.day-note-details-toggle::-webkit-details-marker { display: none; }
.day-note-details-toggle::before { content: '▶ '; font-size: 0.6rem; }
.day-note-details[open] .day-note-details-toggle::before { content: '▼ '; }
.day-note-details-toggle:hover { color: var(--color-text); }
.day-note-details-body {
  padding: 0.35rem 0 0.35rem 0.7rem;
  font-family: var(--font-ui); font-size: 0.85rem; line-height: 1.6;
  color: var(--color-muted); text-align: left;
}
.day-note-details-body p { margin: 0 0 0.6em; }
.day-note-details-body p:last-child { margin-bottom: 0; }
.day-note-details-body a { color: var(--color-link); text-decoration: underline; }
/* The gloss is ours, not the calendar's; it does not read as quoted text. */
.day-note-gloss { font-style: italic; }

.note-expand-btn {
  background: none; border: none; font-family: inherit; font-size: inherit;
  color: var(--color-accent); cursor: pointer; padding: 0;
  text-decoration: underline; font-style: normal;
}

/* ── Office & Observance controls in day header ────────────────────────────── */

#day-office-controls { margin-top: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-4); }
#day-office-controls[style*="display: none"] { margin-top: 0; }

.day-ctrl-group {
  display: flex; flex-direction: column; gap: var(--sp-2);
  justify-content: flex-start; align-items: flex-start;
  /* Full-width tracks: the controls flush with the saints note above them, so
     the header reads as one aligned block rather than pills of differing
     lengths (#82). Each seg fills the column; a long observance name still
     wraps inside its own half of the track. */
  width: 100%; max-width: 100%;
}

.day-ctrl-seg {
  display: flex; gap: 3px; padding: 3px;
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  width: 100%; max-width: 100%; min-width: 0;
}

.day-ctrl-btn {
  /* 44px minimum target: these are the primary controls on a phone, and the
     padding alone leaves them at ~35px once the label sits on the UI step.
     Growable so the buttons split its full-width track evenly; the min-height
     target never shrinks. */
  flex: 1 1 0%; min-height: 44px;
  display: flex; align-items: center; justify-content: center;
  /* concentric: inner radius = outer − padding */
  text-align: center; padding: 0.5rem 0.9rem; border-radius: var(--radius-sm);
  font-family: var(--font-ui); font-size: var(--fs-ui); font-weight: 500; letter-spacing: 0.01em;
  color: var(--color-muted); background: none; border: none; cursor: pointer;
  transition: background 0.15s, color 0.15s, box-shadow 0.15s;
}
.day-ctrl-btn:hover { color: var(--color-text); }
.day-ctrl-btn.is-active {
  background: var(--color-nav-bg); color: var(--color-nav-text);
  box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
/* Observance seg: same styling family as the other header toggles — the
   active button uses the green nav block like Office and Opening, so who is
   being prayed reads as the same kind of choice as which office or opening. */
.day-ctrl-seg--obs { background: transparent; border-color: var(--color-border); }
/* Both slots here are calendar names rather than verbs — "Martyrs of Uganda,
   1886, and Janani Luwum, Archbishop of Uganda, 1977" is a routine one — so the
   segment's max-width sets either of them in as many lines as it takes (#82).
   Left-aligned and tightened, so a wrap reads as a name rather than as centred
   ragged type. The office toggle names two times of day and never wraps, so it
   keeps the shared centring. */
.day-ctrl-seg--obs .day-ctrl-btn { justify-content: flex-start; text-align: left; line-height: 1.35; }
.loading {
  color: var(--color-muted); font-style: italic; font-size: 0.9rem;
  margin: 2rem 0; text-align: left;
}
.error-msg {
  font-family: var(--font-ui); font-size: 0.9rem; color: var(--color-rubric);
  border: 1px solid var(--color-rubric); border-radius: var(--radius-md);
  padding: 0.75rem 1rem; margin: 1rem 0;
}
.error-msg p { margin: 0; }
.error-retry-btn {
  display: inline-block; margin-top: 0.6rem;
  font-family: var(--font-ui); font-size: 0.78rem; font-weight: 500;
  color: var(--color-rubric); background: none;
  border: 1px solid var(--color-rubric); border-radius: var(--radius-pill);
  padding: 0.3rem 0.85rem; cursor: pointer;
  transition: background 0.1s, color 0.1s;
}
.error-retry-btn:hover { background: var(--color-rubric); color: var(--color-bg); }
.out-of-range-msg {
  padding: 2rem 0 1rem; font-family: var(--font-liturgy);
  font-size: 1.05rem; line-height: 1.7;
}
.out-of-range-title { font-weight: 600; font-size: 1.2rem; margin-bottom: 0.75rem; }
.out-of-range-note  { font-style: italic; color: var(--color-muted); margin-top: 0.5rem; }

/* ── Evaluation banner ──────────────────────────────────────────────────────── */

.eval-banner {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem;
  padding: 0.55rem 0.75rem; margin-bottom: var(--sp-5);
  background: var(--color-surface); border-left: 2px solid var(--color-accent);
  font-family: var(--font-ui); font-size: var(--fs-micro); font-style: italic; color: var(--color-muted);
}
.eval-banner-dismiss {
  /* Not dimmed: at opacity 0.6 this control's × drew at 2.57:1 on the banner,
     and it is the only way to dismiss the banner. Hover darkens instead. */
  background: none; border: none; cursor: pointer; color: var(--color-muted);
  font-size: 1.1rem; line-height: 1; padding: 0; flex-shrink: 0;
}
.eval-banner-dismiss:hover { color: var(--color-text); }

/* ── Desktop layout ─────────────────────────────────────────────────────────── */

@media (min-width: 820px) {
  :root {
    --indent: 1.7em;                   /* measure to spare here */
    --gutter: 2rem;
    /* The root font grows 25% here and the scale's unit grows with it, 4 px to
       5 px. Held at 4 px, "couplets touch; stanzas breathe" holds on a phone
       and not here: the stanza reads 1 : 1.61 against the larger type rather
       than the book's 1 : 1.76. Same steps, one unit up. */
    --sp-1: 5px;
    --sp-2: 10px;
    --sp-3: 15px;
    --sp-4: 25px;
    --sp-5: 40px;
    --sp-6: 65px;
  }
  [data-font-size="medium"] { font-size: 125%; }
  [data-font-size="large"]  { font-size: 140%; }
  #day-title { font-size: 2rem; }
  /* horizontal padding comes from --gutter; only the vertical differs here */
  #main { padding-top: 1.25rem; padding-bottom: calc(3rem + var(--safe-bottom)); }
  /* step 10 had this centred; step 11's single axis supersedes it, or the
     header would re-centre at the breakpoint only */
  #day-office-controls { align-items: flex-start; }
  /* head and rule move together, so they cannot drift apart */
  .office-section-title { margin: var(--sp-5) 0 var(--sp-4); padding-top: var(--sp-3); }
}

/* ── Print ──────────────────────────────────────────────────────────────────── */

@media print {
  /* px, not em: data-font-size survives into print, so an em indent would still
     scale with the reader's text setting — and paper is the one medium whose
     measure cannot absorb it. */
  :root { --indent: 18px; }
  #nav { display: none; position: static; }
  #main { max-width: 100%; padding: 1rem; }
  .seg-rubric { color: #7A3030; }
  .alt-panel-hidden { display: block !important; }
  .alt-tabs { display: none; }
  .alt-source { margin-top: 0; }
  .eval-banner, #theme-toggle { display: none; }
  /* Controls print as dead buttons; the date label is already plain text,
     and the sheet has to say which day it is. */
  #day-office-controls { display: none; }
}
