/* cgsoc2027.com
 *
 * There is no inline <style> block in anything server.ts renders, and that is
 * not a style preference. This site's CSP is `default-src 'self'` with no
 * `style-src 'unsafe-inline'`, so a browser silently drops inline styles on the
 * floor. If a page here ever renders as naked black-on-white text, check for an
 * inline style before checking anything else.
 */

/* --- PALETTE -------------------------------------------------------------
 *
 * Self-contained on purpose. This domain used to carry a copy of the dark,
 * high-accent design system used elsewhere on this host; it now has its own,
 * and there is nothing to keep in sync. Edit the values here.
 *
 * The brief: a printed staff document, not a console. Warm eggshell paper,
 * neutral cards sitting on it, near-black text, and colour used sparingly and
 * only where it carries meaning.
 *
 * Contrast was measured, not eyeballed. Against the eggshell ground: --text
 * 14.6:1, --text-2 8.1:1, --muted 5.3:1, and every accent between 5.2:1 and
 * 6.7:1 — so any colour here is safe for normal-size text, not just for large
 * text or decoration. On the neutral cards each figure is higher still. Keep
 * it that way: if you retune a value, re-measure rather than assuming a small
 * nudge is free. --ochre is the tightest of them and the first to fail.
 *
 * The ground is also a deliberate half-step darker than the obvious choice.
 * A near-white eggshell leaves only ~1.09:1 between page and card, at which
 * point the cards stop reading as separate surfaces at all; this is 1.17:1,
 * which is enough with the hairline and the shadow doing the rest.
 */
:root {
  /* Ground — warm eggshell, the colour of paper. */
  --bg:         #f0ebde;
  --bg-2:       #e8e2d1;   /* a banded or recessed area on the same page */

  /* Cards — deliberately NEUTRAL rather than warm. Sitting a grey-white card
     on a warm ground is what separates the two surfaces without a heavy
     border, and it is what keeps text on a card as sharp as it can be. */
  --surface:    #fdfdfd;
  --surface-2:  #f4f4f5;

  /* Edges. Warm ones rule the page, neutral ones outline the cards — a warm
     border around a neutral card reads as a mismatch at close range. */
  --edge:       #d9d4c6;
  --edge-2:     #bdb8a9;
  --card-edge:  #dedee0;

  /* Text — neutral near-black. Never pure #000: on a warm ground it looks
     like a hole rather than ink. */
  --text:       #1a1a1c;
  --text-2:     #43454a;
  --muted:      #5e6067;   /* supporting text at normal size only */

  /* Accents. Muted and few. Each one has a job; none is decorative. */
  --navy:       #14538c;   /* links, focus, active state */
  --slate:      #3a5670;   /* section labels and rules */
  --ochre:      #8e5409;   /* the class year, and a hard deadline */
  --gold:       #75590a;   /* an examination — "look here" */
  --forest:     #2a6349;   /* confirmation, an available item */
  --red:        #9c211a;   /* FAILURE ONLY — see the rule below */

  /* Semantic aliases — rules below reference these, not the raw hues, so a
     hue can be retuned in one place. */
  --accent:     var(--navy);
  --accent-2:   var(--slate);
  --alert:      var(--red);     /* failure states only, and nothing else */
  --warn:       var(--gold);
  --ok:         var(--forest);

  /* The work-week calendar is the one panel on this site that inverts: a deep
     blue ground with the event cards left exactly as they are elsewhere, white
     with near-black text. That inversion is why these are their own tokens
     rather than reuses — every colour the page normally puts on the eggshell
     ground fails on this blue, and the two that were on it before this panel
     existed failed badly (--muted hour labels 2.12:1, --ok today marker
     1.89:1). Measured against --cal-bg, and re-measured against --cal-bg-2
     because the today column is lighter and is the tighter of the two:
     --cal-ink 7.9:1, --cal-ink-2 5.8:1, --cal-ink-3 4.8:1, --cal-today 5.8:1.
     All clear 4.5:1 for normal-size text. Retune one and re-measure both. */
  --cal-bg:     #10314f;   /* the panel */
  --cal-bg-2:   #17406a;   /* today's column — 1.26:1 against the panel */
  --cal-ink:    #cfe0f0;   /* day name */
  --cal-ink-2:  #a9c2da;   /* hour labels, hint line */
  --cal-ink-3:  #96b2cc;   /* day date */
  --cal-today:  #7fd1a4;   /* today marker — a tint of --forest, legible on blue */
  --cal-line:   rgba(255, 255, 255, 0.09);   /* quarter-hour rule */
  --cal-line-2: rgba(255, 255, 255, 0.20);   /* hour rule */
  --cal-edge:   rgba(255, 255, 255, 0.16);   /* panel hairlines */

  /* Work-week entry fills. Purely positional — the Nth entry in the displayed
     week's chronological order gets the Nth colour, cycling — so two blocks
     that overlap in the grid are never left the same colour just because
     they share a --kind. Independent of the --kind aliases above on purpose:
     this is "which one is this", not "what type is this". Pale enough that
     --text (#1a1a1c) clears 4.5:1 against all four by a wide margin — nothing
     this light gets close to the threshold, so it was not re-measured. */
  --week-1: #d7e7fb;   /* light blue */
  --week-2: #fbdad9;   /* light red */
  --week-3: #dbf1e0;   /* light green */
  --week-4: #e8ddf6;   /* light purple */

  /* Geometry. Corners stay square — on a light ground that reads as a set
     document rather than as a terminal, so there is still no radius token. */
  --line:       2px;   /* structural: section rules, the spine of an agenda row */
  --hair:       1px;   /* dividers and card outlines */

  --serif: ui-serif, Georgia, "Iowan Old Style", "Times New Roman", serif;
  --sans:  ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono:  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* --- BASE --------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 1.5rem 4rem;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  /* Light only, on purpose: this is a document, and a document has a page
     colour. There is no prefers-color-scheme variant to keep in step. */
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
a:focus-visible { outline: var(--line) solid var(--accent); outline-offset: 3px; }

code { font-family: var(--mono); font-size: 0.92em; color: var(--accent-2); }

/* --- MASTHEAD ----------------------------------------------------------- */

.hero {
  max-width: 62rem;
  margin: 0 auto;
  padding: 4.5rem 0 2.5rem;
  border-bottom: var(--line) solid var(--edge-2);
}

/* Sans rather than monospace. A letterspaced monospace label is the single
   strongest "terminal" signal a page can send, and this one is a masthead
   line on a document. */
.kicker {
  margin: 0 0 0.9rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-2);
}

h1 {
  margin: 0 0 1.1rem;
  font-family: var(--serif);
  font-size: clamp(1.2rem, 2.8vw, 1.65rem);
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* Ochre is rationed to exactly two jobs on this site: the class year here, and
   a hard deadline in an agenda (.ev-due). If a third thing turns warm, one of
   them is wrong. */
h1 .year { color: var(--ochre); }

/* h1 carries its own bottom margin for the tagline that usually follows it. The
   homepage masthead has no tagline, so without this the hero's own padding and
   that margin stack into a gap that reads as a mistake. */
.hero h1:last-child { margin-bottom: 0; }

/* Homepage masthead only: no kicker line, so the h1 stands alone and centered
   rather than left-aligned like every other page's hero. */
.hero-home { text-align: center; }

.tagline {
  margin: 0;
  max-width: 46rem;
  font-size: 1.1rem;
  color: var(--text-2);
}

/* --- ICONS ---------------------------------------------------------------
 * One glyph per heading concept, reused wherever that concept repeats
 * (Graded Events on the homepage and on a coursework block page share the
 * same one, rather than each literal heading inventing its own). Sized to
 * 1em so a single rule works at every heading size on the site, and colored
 * by currentColor rather than a color of their own — an icon takes whatever
 * job's color the text beside it already has (an h2's deep blue, a card
 * name's near-black, a meta line's grey), so it is never a color this
 * system has to ration on top of the ones it already does.
 */
.hicon {
  display: inline-block;
  width: 1em;
  height: 1em;
  margin-right: 0.42em;
  vertical-align: -0.15em;
  flex-shrink: 0;
}

/* --- SECTIONS ----------------------------------------------------------- */

main { max-width: 62rem; margin: 0 auto; }

section { margin: 3rem 0 0; }

/* A page with no header block: the 3rem that normally separates a section from
   the one above it would otherwise sit under the breadcrumb as dead space. */
.bare > section:first-child { margin-top: 1.5rem; }

h2 {
  margin: 0 0 0.55rem;
  font-size: 1.05rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-2);
}

h2 + .note { margin: 0 0 1.4rem; color: var(--muted); font-size: 0.95rem; }

/* The calendar day each agenda section covers. Stronger than .note: it is the
   heading's other half, not commentary on it — "Next 24" says which window,
   this says which day the window landed on. */
h2 + .daynote {
  margin: 0 0 1.1rem;
  font-family: var(--serif);
  font-size: 1.05rem;
  color: var(--text-2);
}

/* --- CARDS -------------------------------------------------------------- */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1rem;
}

/* A neutral card on the warm ground. The shadow is barely there and doing real
   work: on a light page a hairline border alone leaves a card looking printed
   on rather than laid on. */
.card {
  display: block;
  padding: 1.15rem 1.25rem;
  background: var(--surface);
  border: var(--hair) solid var(--card-edge);
  box-shadow: 0 1px 2px rgba(26, 26, 28, 0.05);
  color: inherit;
}

a.card:hover {
  border-color: var(--accent);
  box-shadow: 0 2px 6px rgba(26, 26, 28, 0.09);
  text-decoration: none;
}

/* Square, like everything else — a rounded pill in this system reads as a
   mistake rather than a variation. */
.card .state {
  display: inline-block;
  margin-bottom: 0.7rem;
  padding: 0.1rem 0.5rem;
  border: var(--hair) solid var(--edge-2);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.card .state.live { border-color: var(--ok); color: var(--ok); }

.card .cname { display: block; font-weight: 620; font-size: 1.05rem; }
.card .chost { display: block; font-family: var(--mono); font-size: 0.8rem; color: var(--muted); margin-top: 0.15rem; }
.card .cdesc { display: block; margin-top: 0.6rem; color: var(--text-2); font-size: 0.95rem; }

/* --- HOMEPAGE NAV BUTTONS -------------------------------------------------
 *
 * The homepage's "where do I go" rows, distinct from .grid/.card: each one is
 * meant to be taken in as a whole without scrolling, so every item is a
 * compact button — name and a count, no description, no badge. Each row lives
 * in its own titled <section>, on the same `section { margin: 3rem 0 0 }` as
 * every other block on the page — that's what keeps this margin from needing
 * a value of its own, and keeps the gap the .rule dividers sit in the same
 * everywhere rather than varying block to block.
 */
.navgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0.6rem;
  margin-top: 0.6rem;
}

/* The same rule as the one under the masthead (.hero), repeated between every
   section of the homepage rather than only there. Sections only ever set a
   *top* margin, never a bottom one, so the gap above the rule has nowhere to
   come from unless the rule supplies it itself — hence margin-top here but no
   margin-bottom: the section that follows brings its own 3rem top margin,
   which collapses with this rule's 0 the same way two adjoining sections
   would. That's what keeps the gap identical on both sides of every rule on
   this page, rather than depending on which two blocks happen to meet. */
.rule {
  margin: 3rem 0 0;
  border: none;
  border-bottom: var(--line) solid var(--edge-2);
}

.navcard {
  display: block;
  padding: 0.6rem 0.8rem;
  background: var(--surface);
  border: var(--hair) solid var(--card-edge);
  box-shadow: 0 1px 2px rgba(26, 26, 28, 0.05);
  color: inherit;
}

a.navcard:hover {
  border-color: var(--accent);
  box-shadow: 0 2px 6px rgba(26, 26, 28, 0.09);
  text-decoration: none;
}

.navcard .navname { display: block; font-weight: 620; font-size: 0.95rem; }
.navcard .navmeta {
  display: block;
  margin-top: 0.1rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--muted);
}

/* --- FILTERS ------------------------------------------------------------ */

/* The buttons above a file list — weeks on a section page, sections/tags/weeks
   on /library. They are links, not scripted toggles: the selection is in the
   query string and the page is rendered per request, so there is no script to
   serve — which this domain's CSP would forbid inline anyway — a filtered view
   is a shareable URL, and Back undoes a click. */
.facets { margin: 0 0 1.5rem; }

.facet { margin-bottom: 0.9rem; }
.facet:last-child { margin-bottom: 0; }

.facetlabel {
  margin: 0 0 0.35rem;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0;
}

/* Square, like the cards. A row of pills would be the one rounded thing on the
   site. */
.chip {
  display: block;
  padding: 0.4rem 0.75rem;
  background: var(--surface);
  border: var(--hair) solid var(--card-edge);
  color: var(--text-2);
}

a.chip:hover { border-color: var(--accent); text-decoration: none; }

.chipname { display: block; font-weight: 600; font-size: 0.92rem; color: var(--text); white-space: nowrap; }

/* The count, so an option with nothing behind it says so on the button rather
   than after a click. Monospace for the same reason the agenda's times are: a
   column of numbers at mixed widths does not scan. */
.chipn {
  margin-left: 0.5rem;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--muted);
}

.chipsub {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Selected. A filled chip rather than a tinted border: with several in a row,
   which ones are on has to be legible at a glance and not by comparing edges.
   Every label inside goes to the page colour at full strength — dimming the
   sub-line to suggest hierarchy costs it AA contrast on this fill. */
.chip.on { background: var(--accent); border-color: var(--accent); }
.chip.on .chipname, .chip.on .chipn, .chip.on .chipsub { color: var(--bg); }
.chip.on:hover { border-color: var(--accent-2); }

/* Nothing behind it yet: present, because the week or the section exists
   whether or not a file does, but not a link and drawn as unfilled. */
.chip.off { background: var(--bg-2); border-style: dashed; }
.chip.off .chipname { color: var(--muted); font-weight: 500; }

/* --- SEARCH -------------------------------------------------------------- */

.search { margin: 0 0 1.4rem; }

.search label {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.searchrow { display: flex; gap: 0.5rem; max-width: 34rem; }

/* Square corners and the card's hairline, same as every other control here.
   `appearance: none` because type="search" otherwise draws a rounded field with
   a clear button of its own in some browsers. */
.search input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.5rem 0.7rem;
  appearance: none;
  background: var(--surface);
  border: var(--hair) solid var(--edge-2);
  border-radius: 0;
  font-family: inherit;
  font-size: 0.95rem;
  color: var(--text);
}

.search input:focus-visible {
  outline: var(--line) solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

.search button {
  padding: 0.5rem 1.1rem;
  background: var(--accent);
  border: var(--hair) solid var(--accent);
  border-radius: 0;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--surface);
  cursor: pointer;
}

.search button:hover { background: var(--accent-2); border-color: var(--accent-2); }
.search button:focus-visible { outline: var(--line) solid var(--accent); outline-offset: 2px; }

.resultnote { margin: 0 0 1rem; color: var(--muted); font-size: 0.9rem; }

.alsonote { margin: 1.6rem 0 0; color: var(--muted); font-size: 0.9rem; }

/* --- THE SITE INDEX ------------------------------------------------------
 *
 * /index, plus the box in the homepage masthead that leads there.
 *
 * The rows are a list rather than .grid/.card, and that is the whole layout
 * decision: the index is every page, link and file on the site read top to
 * bottom, and a hundred cards is a wall rather than a list. A row is one <a>
 * with three stacked lines — name, mono meta, description — which is the same
 * shape .card uses, at a third of the height.
 */

/* The homepage's box. .search supplies the field, the button and the label;
   this only re-centres them under the masthead, which is text-align: center. */
.findbar { margin: 1.7rem 0 0; }
.findbar .searchrow { margin: 0 auto; }

.findlinks { margin: 0.9rem 0 0; font-size: 0.85rem; color: var(--muted); }

/* THE LEAD ROWS, above the results and not among them. Neither is something
   the index found: one jumps to a lesson page named by the query itself, the
   other hands the query to the passphrase-gated coursework search, which this
   page does not read. The left rule is what separates them visually from the
   rows below, and it is the accent rather than a --kind because there is one
   kind of thing here: a way onward. */
.idxlead {
  display: block;
  margin: 0 0 0.7rem;
  padding: 0.7rem 0.9rem;
  background: var(--surface);
  border: var(--hair) solid var(--card-edge);
  border-left: var(--line) solid var(--accent);
  box-shadow: 0 1px 2px rgba(26, 26, 28, 0.05);
  color: inherit;
}

a.idxlead:hover {
  border-color: var(--accent);
  box-shadow: 0 2px 6px rgba(26, 26, 28, 0.09);
  text-decoration: none;
}

.idxleadname { display: block; font-weight: 620; font-size: 0.95rem; }
.idxleadmeta { display: block; margin-top: 0.1rem; font-size: 0.85rem; color: var(--muted); }

.idxgroup { margin-bottom: 2rem; }
.idxgroup:last-child { margin-bottom: 0; }

/* Not a flex row: .hicon aligns itself with vertical-align, which a flex
   container would take away from it. */
.idxgroup h3 {
  margin: 0 0 0.5rem;
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-2);
}

.idxcount {
  margin-left: 0.5rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--muted);
}

.idxlist { list-style: none; margin: 0; padding: 0; }

/* A transparent border on three sides so the hover outline does not shift the
   row by a pixel when it appears. */
.idxrow {
  display: block;
  padding: 0.5rem 0.7rem;
  border: var(--hair) solid transparent;
  border-bottom-color: var(--edge);
  color: inherit;
}

.idxlist a.idxrow:hover {
  background: var(--surface);
  border-color: var(--accent);
  text-decoration: none;
}

.idxname { display: block; font-weight: 620; font-size: 0.95rem; }
.idxmeta { display: block; margin-top: 0.1rem; font-family: var(--mono); font-size: 0.75rem; color: var(--muted); }
.idxdesc { display: block; margin-top: 0.2rem; font-size: 0.88rem; color: var(--text-2); }

/* Square and bordered like .card .state. It marks a destination that asks
   for the passphrase; it is not a control, and it is not a link of its
   own — the whole row is the link. */
.idxflag {
  margin-left: 0.5rem;
  padding: 0.05rem 0.4rem;
  border: var(--hair) solid var(--edge-2);
  background: var(--surface-2);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  vertical-align: 0.1em;
}

/* The matched terms inside a row. Deliberately the same treatment the
   coursework search uses for a snippet, so a hit reads the same on both sides
   of the gate. --bg-2 behind --text is 12.5:1 — the marking is a change of
   ground, not a drop in contrast. */
mark {
  padding: 0 0.1em;
  background: var(--bg-2);
  color: var(--text);
  font-weight: 600;
}

/* --- SUBPAGE HEADER ----------------------------------------------------- */

.crumb {
  max-width: 62rem;
  margin: 0 auto;
  padding: 1.75rem 0 0;
  font-size: 0.85rem;
  letter-spacing: 0.02em;
}

.page {
  max-width: 62rem;
  margin: 0 auto;
  padding: 1.5rem 0 2.25rem;
  border-bottom: var(--line) solid var(--edge-2);
}

.page h1 { font-size: clamp(1.35rem, 2.4vw, 1.55rem); font-weight: 700; }

/* --- SCHEDULE --------------------------------------------------------- */

/* The left rule is the only thing carrying event kind, so the colours have to
   stay distinguishable rather than decorative. Kinds come from data/events.json;
   anything unrecognised renders as .ev-event. The class sets a variable rather
   than the property, because the rule lands on both the work-week grid's
   blocks and BLUF's rows below. */
.ev-class { --kind: var(--accent); }
.ev-event { --kind: var(--accent-2); }
.ev-exam  { --kind: var(--warn); }
.ev-due   { --kind: var(--ochre); }
.ev-admin { --kind: var(--edge-2); }

/* "Nothing scheduled" is real information, not a placeholder — it gets the same
   left rule as a row so an empty window still reads as part of the schedule. */
.empty {
  margin: 0;
  padding: 0.9rem 0 0.9rem 0.9rem;
  border-left: var(--line) solid var(--edge);
  border-bottom: var(--hair) solid var(--edge);
  border-top: var(--hair) solid var(--edge);
  color: var(--muted);
}

/* --- GRADED EVENTS ---------------------------------------------------------
 *
 * The homepage's first section. Reads straight off data/events.json
 * (kind: "exam"/"due"), so there is no field of its own to keep in sync with
 * the schedule. Same card recipe as .howto on the Calendar page; its own
 * class names because the content shape (a dated, kind-coloured row) is
 * unrelated to a numbered how-to step.
 */
.blufrows {
  list-style: none;
  margin: 0.6rem 0 0;
  padding: 0.9rem 1.1rem 1rem;
  background: var(--surface);
  border: var(--hair) solid var(--card-edge);
}

.blufrow {
  padding-left: 0.7rem;
  border-left: var(--line) solid var(--kind, var(--edge-2));
}

.blufrow + .blufrow {
  margin-top: 0.8rem;
  padding-top: 0.8rem;
  border-top: var(--hair) solid var(--edge);
}

.blufwhen { display: block; font-family: var(--mono); font-size: 0.8rem; color: var(--accent-2); }
.blufname { display: block; margin-top: 0.15rem; font-weight: 620; }

.blufkind {
  display: inline-block;
  margin-right: 0.3rem;
  padding: 0.05rem 0.4rem;
  border: var(--hair) solid var(--kind, var(--edge-2));
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--kind, var(--muted));
}

.bluff { display: block; margin-top: 0.25rem; font-size: 0.88rem; color: var(--muted); }
.bluff b { margin-right: 0.35rem; font-weight: 600; color: var(--text-2); }

.blufsec .empty { margin-top: 0.6rem; }

/* --- LINK LISTS --------------------------------------------------------- */

/* Buttons rather than a list of underlined text, so a grid of equal rectangles
   replaces the old CSS columns — `columns` cannot lay out bordered blocks
   without splitting one across the column break. */
/* Fixed column width, not auto-fit's minmax(…, 1fr): each group is its own
   <ul>/grid, and 1fr stretches a column to fill whatever is left over in that
   particular group's row count — so the same button came out a different
   width in a group of three than in a group of eleven. auto-fill with a fixed
   width keeps every button the same size on the whole page; the grid just
   wraps at however many fit. */
.links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 15rem));
  gap: 0.6rem;
}

/* Square corners, same as the cards: this is a document, not a console. Fixed
   min-height plus a centred flex column, because titles range from "myPay
   (DFAS)" to "DTS — Defense Travel System" and only some links carry a note —
   without both, buttons in the same row size to their tallest neighbour but
   different rows still disagree, and a bare title sits flush at the top
   instead of centred like a two-line one. */
.lbtn {
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100%;
  min-height: 4.2rem;
  padding: 0.7rem 0.9rem;
  background: var(--surface);
  border: var(--hair) solid var(--card-edge);
  font-weight: 500;
}

.lbtn:hover { border-color: var(--accent); }

.ltitle { display: block; }

.lnote {
  display: block;
  margin-top: 0.2rem;
  color: var(--muted);
  font-size: 0.86rem;
  font-weight: 400;
}

/* --- CALENDAR SUBSCRIPTION ---------------------------------------------- */

/* The feed address, sized to be read off a screen and typed if it has to be.
   word-break rather than a horizontal scroll: this is a string someone copies,
   and a scrolled one copies short. */
.feedurl {
  margin: 0;
  padding: 0.8rem 0.9rem;
  background: var(--surface);
  border: var(--hair) solid var(--edge-2);
  border-left: var(--line) solid var(--accent);
  font-family: var(--mono);
  font-size: 1rem;
  color: var(--text);
  word-break: break-all;
  -webkit-user-select: all;
  user-select: all;
}

.feednote { margin: 0.6rem 0 0; color: var(--muted); font-size: 0.9rem; }

/* The one instruction on the site that people will get wrong, given its own
   weight. --warn, not --alert: nothing has failed, this is a caution. */
.warn {
  margin: 0;
  padding: 0.9rem 1rem;
  background: var(--surface);
  border-left: var(--line) solid var(--warn);
  color: var(--text-2);
}

.warn em { font-style: italic; color: var(--text); }

.howtos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: 1rem;
}

.howto {
  padding: 0.9rem 1.1rem 1rem;
  background: var(--surface);
  border: var(--hair) solid var(--card-edge);
}

.howto h3 {
  margin: 0 0 0.5rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent-2);
}

.steps {
  margin: 0;
  padding-left: 1.15rem;
  color: var(--text-2);
  font-size: 0.95rem;
}

.steps li { margin-bottom: 0.3rem; }
.steps li:last-child { margin-bottom: 0; }
.steps strong { font-weight: 620; color: var(--text); }

.howto .note { margin: 0.6rem 0 0; color: var(--muted); font-size: 0.86rem; }

/* A list that reads as prose rather than as a set of controls — no bullets on
   the marker, the text carries itself. */
.plain {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 46rem;
  color: var(--text-2);
}

.plain li {
  padding: 0.6rem 0 0.6rem 0.9rem;
  border-left: var(--hair) solid var(--edge);
}


/* --- THE WORK-WEEK GRID --------------------------------------------------
 *
 * The homepage's week-at-a-glance, ported from the editor at /input and tuned
 * for a fraction of the height. Monday-Friday across, fifteen minutes to a row
 * down.
 *
 * --slot is the height of fifteen minutes and the unit the whole grid is in:
 * hour lines are drawn every fourth one, so changing it rescales everything.
 * 0.55rem is the compression, and it was chosen against a floor rather than
 * picked: at ~37px to the hour a one-hour block still fits its three lines
 * (time, title, location) at the sizes set below, while a fifteen-minute entry
 * is a sliver. That is intended — every field is in the markup regardless, and
 * .pop shows the entry in full on hover or focus, so nothing is unreachable at
 * any block size. Lowering --slot further starts costing the one-hour block its
 * location line, which is the first thing you would notice.
 *
 * Positions are class names, never a style attribute: the CSP is
 * `default-src 'self'` with no 'unsafe-inline', so a computed
 * style="grid-row: 8/20" is dropped silently and the block lands wherever
 * auto-placement puts it. Hence the generated .rs-/.re- block at the end of
 * this file. */

/* The "This Week" heading stays literally that regardless of which week is
   drawn — .daynote's date range is what says which one — so the forward/reset
   links live inside the <h2> rather than the section growing a second
   heading. Flex, not grid, so it still wraps under the label on a narrow
   screen instead of overlapping it. */
.homeweek .weeksechead {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.4rem 0.6rem;
}

/* Reset every property the plain h2 rule sets for a link nested inside it —
   uppercase/letter-spacing/weight read fine on a short label, not on "Next
   week". */
.homeweek .weeknavbtns { display: inline-flex; gap: 0.5rem; }

.homeweek .weeknav {
  text-transform: none;
  letter-spacing: normal;
  font-weight: 500;
  font-size: 0.78rem;
  padding: 0.25rem 0.6rem;
  border: var(--hair) solid var(--card-edge);
  background: var(--surface);
  color: var(--accent);
}

.homeweek .weeknav:hover { border-color: var(--accent); text-decoration: none; }

/* Two grids share one grid-template-columns so the day headings sit over their
   columns. The heading strip cannot be part of the calendar grid itself: that
   grid numbers its rows from the top of the drawn window, and a heading row
   would push every entry down by one.
   minmax(0, 1fr) rather than 1fr — a long title would otherwise set a
   min-content floor and push the five columns wider than the page. */
.homeweek .weekhead,
.homeweek .weekgrid {
  display: grid;
  grid-template-columns: 2.9rem repeat(5, minmax(0, 1fr));
}

.homeweek .weekhead { margin-bottom: 0.4rem; }

/* The panel. Both breakpoints get it, so the calendar is the same object
   whether it draws as a grid or as a list — the padding is what stops the
   day columns and the event cards from touching the blue's edge. */
.homeweek .weekwide,
.homeweek .weeknarrow {
  padding: 0.9rem 1rem 1rem;
  background: var(--cal-bg);
}

.homeweek .dh {
  padding: 0.15rem 0.35rem 0.2rem;
  border-bottom: var(--line) solid var(--cal-edge);
}

.homeweek .dh b {
  display: block;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--cal-ink);
}

.homeweek .dh i {
  display: block;
  font-family: var(--mono);
  font-style: normal;
  font-size: 0.7rem;
  color: var(--cal-ink-3);
}

.homeweek .dh-today b { color: var(--cal-today); }
.homeweek .dh-today { border-bottom-color: var(--cal-today); }

/* grid-auto-rows rather than a repeat() template because the number of rows is
   data-driven — server.ts draws only the hours the week actually uses. */
.homeweek .weekgrid {
  --slot: 0.55rem;
  grid-auto-rows: var(--slot);
  /* transparent, not a colour of its own — the panel above supplies the blue,
     which is what keeps the grid and the empty-state message on one ground. */
  background: transparent;
  border-bottom: var(--hair) solid var(--cal-edge);
}

/* One per day, spanning the window and sitting under the entries. The
   quarter-hour and hour lines are a background rather than an element per line:
   at four rows to the hour that would be a hundred-odd empty spans. */
.homeweek .col {
  border-left: var(--hair) solid var(--cal-line);
  background-image:
    repeating-linear-gradient(to bottom, var(--cal-line-2) 0 1px, transparent 1px calc(var(--slot) * 4)),
    repeating-linear-gradient(to bottom, var(--cal-line) 0 1px, transparent 1px var(--slot));
}

.homeweek .col-today { background-color: var(--cal-bg-2); box-shadow: inset 2px 0 0 var(--cal-today); }

/* Pulled up by half a line so the label sits on its hour rule rather than
   floating in the middle of the hour it opens. */
.homeweek .hr {
  grid-column: 1;
  padding-right: 0.4rem;
  font-family: var(--mono);
  font-size: 0.62rem;
  line-height: 1;
  text-align: right;
  color: var(--cal-ink-2);
  transform: translateY(-0.35em);
}

.c2 { grid-column: 2; }
.c3 { grid-column: 3; }
.c4 { grid-column: 4; }
.c5 { grid-column: 5; }
.c6 { grid-column: 6; }

/* --kind comes from the .ev-<kind> rules above, so the left rule on a block
   still carries the entry's type. The fill itself is set by .wc-0..3 below,
   independent of that — see the comment on --week-1..4. */
.homeweek .ev {
  position: relative;
  z-index: 1;
  margin: 0 1px 1px;
  padding: 0 0.22rem;
  background: var(--surface);
  border: var(--hair) solid var(--card-edge);
  border-left: var(--line) solid var(--kind, var(--edge-2));
  line-height: 1.1;
  color: var(--text);
}

.homeweek .ev:hover,
.homeweek .ev:focus-visible { border-color: var(--accent); border-left-color: var(--kind, var(--accent)); }
.homeweek .ev:focus-visible { outline: var(--line) solid var(--accent); outline-offset: 1px; }

/* The rotating fill from weekColorIndex() in server.ts — see --week-1..4
   above. Same four classes on .wlrow below, so an entry is one colour in
   both the grid and the narrow list. */
.homeweek .ev.wc-0, .homeweek .wlrow.wc-0 { background: var(--week-1); }
.homeweek .ev.wc-1, .homeweek .wlrow.wc-1 { background: var(--week-2); }
.homeweek .ev.wc-2, .homeweek .wlrow.wc-2 { background: var(--week-3); }
.homeweek .ev.wc-3, .homeweek .wlrow.wc-3 { background: var(--week-4); }

/* The clipping happens here, not on .ev — .ev must stay overflow: visible or
   the popover cannot escape a block a few pixels tall. */
.homeweek .evi { display: block; height: 100%; overflow: hidden; }

.homeweek .evw { display: block; font-family: var(--mono); font-size: 0.56rem; color: var(--accent-2); }
.homeweek .evn { display: block; font-size: 0.6rem; font-weight: 700; }
.homeweek .evl { display: block; font-size: 0.55rem; font-style: italic; color: var(--text-2); }

/* Overlapping entries are dealt lanes by server.ts and share the column width.
   The percentages are of the grid area; 2px comes off the width so the 1px
   margins on both sides still fit. Scoped under .homeweek (rather than bare
   .l-N-M) to match the specificity of .homeweek .ev's own `margin` shorthand
   above, which also sets margin-left — a bare .l-N-M selector loses that
   cascade regardless of source order, and every lane past the first silently
   collapses back to margin-left: 1px, stacking every overlapping entry at the
   same position with the last one in document order painted on top. */
.homeweek .l-0-2,
.homeweek .l-1-2 { width: calc(50% - 2px); }
.homeweek .l-1-2 { margin-left: 50%; }
.homeweek .l-0-3,
.homeweek .l-1-3,
.homeweek .l-2-3 { width: calc(33.33% - 2px); }
.homeweek .l-1-3 { margin-left: 33.33%; }
.homeweek .l-2-3 { margin-left: 66.66%; }
.homeweek .l-0-4,
.homeweek .l-1-4,
.homeweek .l-2-4,
.homeweek .l-3-4 { width: calc(25% - 2px); }
.homeweek .l-1-4 { margin-left: 25%; }
.homeweek .l-2-4 { margin-left: 50%; }
.homeweek .l-3-4 { margin-left: 75%; }
.homeweek .l-0-5,
.homeweek .l-1-5,
.homeweek .l-2-5,
.homeweek .l-3-5,
.homeweek .l-4-5 { width: calc(20% - 2px); }
.homeweek .l-1-5 { margin-left: 20%; }
.homeweek .l-2-5 { margin-left: 40%; }
.homeweek .l-3-5 { margin-left: 60%; }
.homeweek .l-4-5 { margin-left: 80%; }
.homeweek .l-0-6,
.homeweek .l-1-6,
.homeweek .l-2-6,
.homeweek .l-3-6,
.homeweek .l-4-6,
.homeweek .l-5-6 { width: calc(16.66% - 2px); }
.homeweek .l-1-6 { margin-left: 16.66%; }
.homeweek .l-2-6 { margin-left: 33.33%; }
.homeweek .l-3-6 { margin-left: 50%; }
.homeweek .l-4-6 { margin-left: 66.66%; }
.homeweek .l-5-6 { margin-left: 83.33%; }

/* The whole entry, on hover or keyboard focus. This is what makes the
   compression above safe to do. :focus-visible is not enough on its own —
   a tap on a touch screen focuses without ever firing :hover, and that is the
   only way this opens there. */
.homeweek .pop {
  display: none;
  position: absolute;
  top: calc(100% + 3px);
  left: 0;
  z-index: 30;
  width: 16rem;
  max-width: 60vw;
  padding: 0.55rem 0.7rem;
  background: var(--surface);
  border: var(--hair) solid var(--edge-2);
  box-shadow: 0 2px 7px rgba(26, 26, 28, 0.16);
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--text-2);
}

.homeweek .ev:hover .pop,
.homeweek .ev:focus .pop,
.homeweek .ev:focus-visible .pop { display: block; }

.homeweek .ev:hover,
.homeweek .ev:focus,
.homeweek .ev:focus-visible { z-index: 40; }

/* Thursday and Friday open leftward, and anything low in the window opens
   upward — otherwise the panel hangs off the grid. */
.homeweek .c5 .pop,
.homeweek .c6 .pop { left: auto; right: 0; }
.homeweek .ev.low .pop { top: auto; bottom: calc(100% + 3px); }

.homeweek .popw { display: block; font-family: var(--mono); font-size: 0.75rem; color: var(--accent-2); }

.homeweek .popn {
  display: block;
  margin: 0.1rem 0 0.4rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text);
}

.homeweek .popf { display: block; margin-top: 0.3rem; }

.homeweek .popf b {
  display: block;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-2);
}

.homeweek .gridnote { margin: 0.5rem 0 0; font-size: 0.85rem; color: var(--cal-ink-2); }

/* The "nothing scheduled" fallback sits inside the panel, so the page-level
   .empty (dark text, warm rules) would be unreadable on the blue. */
.homeweek .empty {
  border-left-color: var(--cal-edge);
  border-top-color: var(--cal-edge);
  border-bottom-color: var(--cal-edge);
  color: var(--cal-ink-2);
}

/* --- THE WEEK, AS A LIST -------------------------------------------------
 *
 * The same five days for a screen the grid cannot serve. Five columns are
 * unreadable on a phone and squeezing them produces a grid that is present and
 * useless — but hiding the week outright would drop Thursday and Friday, which
 * the three day-tables above never reach. So it becomes a list there. */

.homeweek .weeknarrow { display: none; }

@media (max-width: 52rem) {
  .homeweek .weekwide { display: none; }
  .homeweek .weeknarrow { display: block; }
}

.homeweek .weeklist,
.homeweek .wlevents { list-style: none; margin: 0; padding: 0; }

.homeweek .wlday + .wlday { margin-top: 1.1rem; }

.homeweek .wldh {
  margin: 0 0 0.4rem;
  font-family: var(--serif);
  font-size: 1rem;
  color: var(--cal-ink);
}

/* Cards on the blue, exactly like the blocks on the grid — near-black text
   throughout, same as everywhere else on the site, so every rule below this
   one is unchanged. The white default is overridden per entry by the
   .wc-0..3 rules above. */
.homeweek .wlrow {
  margin-bottom: 2px;
  padding: 0.5rem 0.7rem 0.55rem;
  background: var(--surface);
  border-left: var(--line) solid var(--kind, var(--edge-2));
  border-bottom: none;
}

.homeweek .wlw { font-family: var(--mono); font-size: 0.85rem; color: var(--accent-2); margin-right: 0.5rem; }
.homeweek .wln { font-weight: 620; }

.homeweek .wlf { display: block; margin-top: 0.2rem; font-size: 0.9rem; color: var(--muted); }
.homeweek .wlf b {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-2);
  margin-right: 0.4rem;
}

/* --- SLOT POSITIONS ------------------------------------------------------
 *
 * Mechanical and generated rather than typed: one rule per quarter-hour slot in
 * a day (0..96), which is how server.ts positions a block without the style
 * attribute the CSP would drop. Nothing else should reference these by hand. */

/* grid-row-start — one rule per quarter-hour slot from the top of the drawn window. */
.rs-0{grid-row-start:1}
.rs-1{grid-row-start:2}
.rs-2{grid-row-start:3}
.rs-3{grid-row-start:4}
.rs-4{grid-row-start:5}
.rs-5{grid-row-start:6}
.rs-6{grid-row-start:7}
.rs-7{grid-row-start:8}
.rs-8{grid-row-start:9}
.rs-9{grid-row-start:10}
.rs-10{grid-row-start:11}
.rs-11{grid-row-start:12}
.rs-12{grid-row-start:13}
.rs-13{grid-row-start:14}
.rs-14{grid-row-start:15}
.rs-15{grid-row-start:16}
.rs-16{grid-row-start:17}
.rs-17{grid-row-start:18}
.rs-18{grid-row-start:19}
.rs-19{grid-row-start:20}
.rs-20{grid-row-start:21}
.rs-21{grid-row-start:22}
.rs-22{grid-row-start:23}
.rs-23{grid-row-start:24}
.rs-24{grid-row-start:25}
.rs-25{grid-row-start:26}
.rs-26{grid-row-start:27}
.rs-27{grid-row-start:28}
.rs-28{grid-row-start:29}
.rs-29{grid-row-start:30}
.rs-30{grid-row-start:31}
.rs-31{grid-row-start:32}
.rs-32{grid-row-start:33}
.rs-33{grid-row-start:34}
.rs-34{grid-row-start:35}
.rs-35{grid-row-start:36}
.rs-36{grid-row-start:37}
.rs-37{grid-row-start:38}
.rs-38{grid-row-start:39}
.rs-39{grid-row-start:40}
.rs-40{grid-row-start:41}
.rs-41{grid-row-start:42}
.rs-42{grid-row-start:43}
.rs-43{grid-row-start:44}
.rs-44{grid-row-start:45}
.rs-45{grid-row-start:46}
.rs-46{grid-row-start:47}
.rs-47{grid-row-start:48}
.rs-48{grid-row-start:49}
.rs-49{grid-row-start:50}
.rs-50{grid-row-start:51}
.rs-51{grid-row-start:52}
.rs-52{grid-row-start:53}
.rs-53{grid-row-start:54}
.rs-54{grid-row-start:55}
.rs-55{grid-row-start:56}
.rs-56{grid-row-start:57}
.rs-57{grid-row-start:58}
.rs-58{grid-row-start:59}
.rs-59{grid-row-start:60}
.rs-60{grid-row-start:61}
.rs-61{grid-row-start:62}
.rs-62{grid-row-start:63}
.rs-63{grid-row-start:64}
.rs-64{grid-row-start:65}
.rs-65{grid-row-start:66}
.rs-66{grid-row-start:67}
.rs-67{grid-row-start:68}
.rs-68{grid-row-start:69}
.rs-69{grid-row-start:70}
.rs-70{grid-row-start:71}
.rs-71{grid-row-start:72}
.rs-72{grid-row-start:73}
.rs-73{grid-row-start:74}
.rs-74{grid-row-start:75}
.rs-75{grid-row-start:76}
.rs-76{grid-row-start:77}
.rs-77{grid-row-start:78}
.rs-78{grid-row-start:79}
.rs-79{grid-row-start:80}
.rs-80{grid-row-start:81}
.rs-81{grid-row-start:82}
.rs-82{grid-row-start:83}
.rs-83{grid-row-start:84}
.rs-84{grid-row-start:85}
.rs-85{grid-row-start:86}
.rs-86{grid-row-start:87}
.rs-87{grid-row-start:88}
.rs-88{grid-row-start:89}
.rs-89{grid-row-start:90}
.rs-90{grid-row-start:91}
.rs-91{grid-row-start:92}
.rs-92{grid-row-start:93}
.rs-93{grid-row-start:94}
.rs-94{grid-row-start:95}
.rs-95{grid-row-start:96}
.rs-96{grid-row-start:97}

/* grid-row-end — same scale. .re-N closes the block at the bottom of slot N-1. */
.re-1{grid-row-end:2}
.re-2{grid-row-end:3}
.re-3{grid-row-end:4}
.re-4{grid-row-end:5}
.re-5{grid-row-end:6}
.re-6{grid-row-end:7}
.re-7{grid-row-end:8}
.re-8{grid-row-end:9}
.re-9{grid-row-end:10}
.re-10{grid-row-end:11}
.re-11{grid-row-end:12}
.re-12{grid-row-end:13}
.re-13{grid-row-end:14}
.re-14{grid-row-end:15}
.re-15{grid-row-end:16}
.re-16{grid-row-end:17}
.re-17{grid-row-end:18}
.re-18{grid-row-end:19}
.re-19{grid-row-end:20}
.re-20{grid-row-end:21}
.re-21{grid-row-end:22}
.re-22{grid-row-end:23}
.re-23{grid-row-end:24}
.re-24{grid-row-end:25}
.re-25{grid-row-end:26}
.re-26{grid-row-end:27}
.re-27{grid-row-end:28}
.re-28{grid-row-end:29}
.re-29{grid-row-end:30}
.re-30{grid-row-end:31}
.re-31{grid-row-end:32}
.re-32{grid-row-end:33}
.re-33{grid-row-end:34}
.re-34{grid-row-end:35}
.re-35{grid-row-end:36}
.re-36{grid-row-end:37}
.re-37{grid-row-end:38}
.re-38{grid-row-end:39}
.re-39{grid-row-end:40}
.re-40{grid-row-end:41}
.re-41{grid-row-end:42}
.re-42{grid-row-end:43}
.re-43{grid-row-end:44}
.re-44{grid-row-end:45}
.re-45{grid-row-end:46}
.re-46{grid-row-end:47}
.re-47{grid-row-end:48}
.re-48{grid-row-end:49}
.re-49{grid-row-end:50}
.re-50{grid-row-end:51}
.re-51{grid-row-end:52}
.re-52{grid-row-end:53}
.re-53{grid-row-end:54}
.re-54{grid-row-end:55}
.re-55{grid-row-end:56}
.re-56{grid-row-end:57}
.re-57{grid-row-end:58}
.re-58{grid-row-end:59}
.re-59{grid-row-end:60}
.re-60{grid-row-end:61}
.re-61{grid-row-end:62}
.re-62{grid-row-end:63}
.re-63{grid-row-end:64}
.re-64{grid-row-end:65}
.re-65{grid-row-end:66}
.re-66{grid-row-end:67}
.re-67{grid-row-end:68}
.re-68{grid-row-end:69}
.re-69{grid-row-end:70}
.re-70{grid-row-end:71}
.re-71{grid-row-end:72}
.re-72{grid-row-end:73}
.re-73{grid-row-end:74}
.re-74{grid-row-end:75}
.re-75{grid-row-end:76}
.re-76{grid-row-end:77}
.re-77{grid-row-end:78}
.re-78{grid-row-end:79}
.re-79{grid-row-end:80}
.re-80{grid-row-end:81}
.re-81{grid-row-end:82}
.re-82{grid-row-end:83}
.re-83{grid-row-end:84}
.re-84{grid-row-end:85}
.re-85{grid-row-end:86}
.re-86{grid-row-end:87}
.re-87{grid-row-end:88}
.re-88{grid-row-end:89}
.re-89{grid-row-end:90}
.re-90{grid-row-end:91}
.re-91{grid-row-end:92}
.re-92{grid-row-end:93}
.re-93{grid-row-end:94}
.re-94{grid-row-end:95}
.re-95{grid-row-end:96}
.re-96{grid-row-end:97}

/* --- COURSEWORK BLOCK PAGES (/c101, /c102, ...) --------------------------
 *
 * Reading questions and a post-reading self-check, generated from the
 * block's own assigned readings — both plain lists of {question, source}.
 * There is no `.qa` disclosure widget here any more: CGSOC guidance
 * prohibits posting self-check answers, so a question has nothing to reveal
 * and renders as an ordinary <li> (see .steps in the base styles below),
 * the same as a reading's own prep questions.
 */

.reading { margin-bottom: 1.6rem; }
.reading:last-child { margin-bottom: 0; }
.reading h3 { margin: 0 0 0.4rem; font-size: 0.88rem; font-weight: 700; color: var(--text); }
.reading .note { margin: 0 0 0.6rem; }

.qsource {
  display: block;
  margin-top: 0.2rem;
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--muted);
}

.stdgroup { margin-bottom: 1.8rem; }
.stdgroup:last-child { margin-bottom: 0; }
.stdgroup h3 { margin: 0 0 0.7rem; font-size: 0.88rem; font-weight: 700; color: var(--text); }

/* --- FOOTER ------------------------------------------------------------- */

footer {
  max-width: 62rem;
  margin: 3.5rem auto 0;
  padding-top: 1.25rem;
  border-top: var(--hair) solid var(--edge-2);
  color: var(--muted);
  font-size: 0.9rem;
}
