/* ============================================================
   THE DECORUM STANDARD — havesomedecorum.com

   ART DIRECTION: "The Monogram" over "The Register".

   The shell is B. A twelve column grid, type that starts at column
   two and never at column one, flush ruled rows instead of cards,
   and the engraved DS mark blown up and cropped by the page edge.
   The tension is deliberate: a Victorian blackletter mark holding
   still inside a flat modernist grid.

   The working pages are C. A ruled document, not a page. Density is
   the luxury. Whitespace is used where it means something and never
   as padding for comfort.

   THINGS THAT ARE BANNED HERE, because they are what a templated
   site looks like and this one has already drifted twice:
     - cards, boxes, rounded corners, drop shadows
     - a row of three equal tiles
     - fade-up-on-scroll
     - centred body copy
     - a heading, a paragraph and two buttons, repeated down the page

   Palette and type are lifted from the shipped card build
   (06-build-scripts/plates_lib.py, fonts.py). Lora reads, Poppins
   labels. That split is the same one used inside the guide PDFs.
   ============================================================ */

:root {
  --bone:   #f4efe6;
  --bone-2: #ede7da;
  --rule:   #d9d1c3;
  --rule-2: #c8bfad;   /* the heavier rule, used once per document */
  --camel:  #9c7b4a;
  --gold:   #c9a268;
  --char:   #26251f;
  --navy:   #13233f;
  --stone:  #8a8377;
  --set:    #4a473f;   /* body copy that is not display */

  /* Light text on a navy ground. This was --bone-2, which is the second
     PAPER: the two are the same colour on a light theme and nothing alike
     on a dark one. Separating them is what lets dark mode be nothing but
     a token flip. */
  --on-navy: var(--bone-2);
  /* the header nav ink, navy on paper and the paper's ink on dark */
  --nav-ink: var(--navy);
  /* which monogram the paper watermark uses */
  --wm-mark: url("/assets/wm-dark.png");

  --rule-navy: rgba(237, 231, 218, 0.24);

  /* THE SCALE. Six steps and nothing else. Every rule below points at one
     of these. If a new size feels necessary, one of the six is being used
     in the wrong place. There were twenty-two sizes here before this; that
     is what a page with too many fonts on it is actually made of. */
  --t-d1:    clamp(2.25rem, 1.3rem + 4vw, 4.5rem);      /* page title, one per page */
  --t-d2:    clamp(1.625rem, 1.2rem + 1.8vw, 2.5rem);   /* section title */
  --t-d3:    clamp(1.125rem, 1.05rem + 0.55vw, 1.4375rem); /* sub title, register row */
  --t-read:  1.125rem;                                  /* the one reading size */
  --t-meta:  0.9375rem;                                 /* short annotation, sans */
  --t-label: 0.6875rem;                                 /* uppercase label, sans */

  --serif: "Lora", Georgia, "Times New Roman", serif;
  --sans:  "Poppins", -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
  --mono:  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --pad:  clamp(1rem, 2.4vw, 2.25rem);   /* the document margin */
  --colgap: clamp(1rem, 1.6vw, 1.5rem);
  --read: 34rem;
}

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

/* The UA rule for [hidden] is display:none at specificity 0,1,0, so any author
   rule that sets display on the same element beats it. That is exactly what
   happened: .scrim { display: block } inside the phone media query left the
   scrim covering the whole viewport at z-index 90 while it was still hidden,
   and it swallowed every tap on the site. Nothing on mobile was clickable.
   This is the guard, not a style choice. */
[hidden] { display: none !important; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* clip, not hidden: hidden on the root kills position: sticky, which the
     document head depends on. This is a backstop, not the fix. */
  overflow-x: clip;
}

body {
  margin: 0;
  padding: 0 var(--pad) var(--pad);
  background: var(--bone);
  color: var(--char);
  font-family: var(--sans);
  font-weight: 300;
  font-size: 1rem;   /* document default, not a scale step */
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--camel); outline-offset: 2px; }

.skip { position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--navy); color: var(--on-navy); padding: 0.75rem 1.25rem; }
.skip:focus { left: 0; }

/* ============================================================
   1. DOCUMENT HEAD
   Three part masthead with the heavy rule under it, then the nav on
   its own hairline. Straight off the Record card.
   ============================================================ */

.dochead { position: sticky; top: 0; z-index: 50; background: var(--bone); }

.dochead__top {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem; align-items: center;
  padding-block: 0.75rem 0.5rem; border-bottom: 2px solid var(--char);
}

.dochead__nav {
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  padding-block: 0.7rem; border-bottom: 1px solid var(--rule);
}

.micro {
  margin: 0; font-size: var(--t-label); font-weight: 400; letter-spacing: 0.24em;
  text-transform: uppercase; color: var(--stone-ink); white-space: nowrap;
}

.micro--ink { color: var(--char); }
.micro--camel { color: var(--camel-ink); }
.dochead__top .r { text-align: right; }
/* lifted with the nav. At 11px grey under a 14px navy row it read as
   something left over rather than as the masthead. */
.dochead__top .micro { font-size: 0.75rem; letter-spacing: 0.2em; }
.dochead__top .house { color: var(--nav-ink); }
.dochead__top .house b { font-weight: 500; color: var(--camel-ink); }

/* The nav was 11px warm grey at 0.24em, the widest tracking on the site.
   Wide tracking at a small size is what made it read as a caption rather than
   as navigation: the letters stop forming words at a glance. Bigger, tighter,
   and navy, which also takes it from 4.70:1 against the paper to 13.68:1. */
.dochead__nav a { font-size: 0.875rem; letter-spacing: 0.13em; font-weight: 500;
  text-transform: uppercase; color: var(--nav-ink); padding-bottom: 2px;
  border-bottom: 1px solid transparent; }
.dochead__nav a:hover, .dochead__nav a[aria-current="page"] { color: var(--nav-ink);
  border-bottom-color: var(--camel); }
.dochead__nav .grp { display: flex; gap: clamp(0.875rem, 2.4vw, 2.25rem); flex-wrap: wrap; }

/* The three part masthead does not fit on a phone. The centre line and the
   register are both nowrap, so at 375px they pushed the document to 657px
   wide and the whole site scrolled sideways. Below tablet the head keeps the
   house name and the register only, and labels are allowed to wrap. */
@media (max-width: 46rem) {
  .dochead__top { grid-template-columns: 1fr auto; }
  .dochead__top .micro--ink { display: none; }
  .micro { white-space: normal; }
  .register__cap { flex-wrap: wrap; }
}

/* ============================================================
   2. GRID
   Twelve columns. Content starts at two. Column one is the margin
   the whole composition hangs off, and it stays empty.
   ============================================================ */

.g12 { display: grid; grid-template-columns: repeat(12, 1fr); gap: 0 var(--colgap); }

/* on narrow screens the offset collapses, the grid does not */
.c2-12 { grid-column: 1 / -1; }
.c2-8  { grid-column: 1 / -1; }
.c7-13 { grid-column: 1 / -1; }
.c2-7  { grid-column: 1 / -1; }
.c8-13 { grid-column: 1 / -1; }
.c2-13 { grid-column: 1 / -1; }

@media (min-width: 56rem) {
  .c2-12 { grid-column: 2 / 12; }
  .c2-8  { grid-column: 2 / 8; }
  .c7-13 { grid-column: 7 / 13; }
  .c2-7  { grid-column: 2 / 7; }
  .c8-13 { grid-column: 8 / 13; }
  .c2-13 { grid-column: 2 / 13; }
}

.band { padding-block: clamp(2.5rem, 6vw, 5.5rem); }
.band--tight { padding-block: clamp(1.75rem, 3.5vw, 3rem); }

/* a navy strip runs the full width of the document, edge to edge */
.strip { margin-inline: calc(-1 * var(--pad)); padding: clamp(1.75rem, 4vw, 3.25rem) var(--pad); }
.strip .micro { color: var(--gold); }

/* ============================================================
   3. TYPE
   ============================================================ */

.kick { margin: 0 0 1rem; padding-top: 0.75rem; border-top: 1px solid var(--camel);
  font-size: var(--t-label); letter-spacing: 0.26em; text-transform: uppercase; color: var(--camel-ink);
  display: inline-block; }

.display {
  margin: 0; font-family: var(--serif); font-weight: 400;
  font-size: var(--t-d1); line-height: 0.99; letter-spacing: -0.028em;
}

.display em { font-style: italic; color: var(--camel-ink); }
.display--sm { font-size: var(--t-d2); line-height: 1.08; }
.display--xs { font-size: var(--t-d3); line-height: 1.25; }

.refuse { margin: 0; font-family: var(--serif); font-style: italic;
  font-size: var(--t-d3); color: var(--stone-ink); }

/* long form reads in Lora, the same as every finished guide */
.prose { max-width: var(--read); font-family: var(--serif); font-weight: 400;
  font-size: var(--t-read); line-height: 1.62; color: var(--char); }
.prose > * { margin-block: 0; }
.prose > * + * { margin-top: 1.125rem; }
.prose > h2 { margin-top: clamp(2.25rem, 4vw, 3rem); font-family: var(--serif); font-weight: 400;
  font-size: var(--t-d2); line-height: 1.14; letter-spacing: -0.015em; }
.prose > h3 { margin-top: 2rem; font-family: var(--sans); font-weight: 500; font-size: var(--t-label);
  letter-spacing: 0.3em; text-transform: uppercase; color: var(--camel-ink); }
.prose a { border-bottom: 1px solid var(--camel); }
.prose strong { font-weight: 500; }
.strip .prose, .navy .prose { color: var(--on-navy); }

/* the camel left rule. a definition, a quoted line, or a short list that
   is the spine of the section it sits in. */
.mark { border-left: 2px solid var(--camel); padding-left: clamp(1rem, 2vw, 1.5rem); }
.mark p { margin: 0; font-family: var(--serif); font-weight: 400;
  font-size: var(--t-d3); line-height: 1.35; }
.mark p + p { margin-top: 0.625rem; }
.strip .mark, .navy .mark { border-left-color: var(--gold); }

/* the small set block. Poppins, tight, used for asides and specs */
/* short annotation only. two or three lines. anything longer reads badly in
   a sans at this width and belongs in .prose or .cols, which are Lora. */
.set { margin: 0; font-size: var(--t-meta); line-height: 1.6; color: var(--set); max-width: 40ch; }
.strip .set { color: rgba(237, 231, 218, 0.74); }

/* ============================================================
   4. THE WATERMARK

   The DS mark is a permanent watermark, not a decoration dropped on
   one section. It is painted as a fixed background layer, so it holds
   still in the viewport while the bands scroll over it, and each band
   reveals only the part of it that it currently covers.

   That is also what makes it change lighting on its own. Paper bands
   paint the charcoal cut, navy bands paint the bone cut, so the mark
   reads dark on bone and light on blue and appears to shift as a strip
   passes across it. No script, no second element.

   Opacity is the wash layer, not the file, so it is tuned here:
   a higher wash alpha means a fainter mark.
   ============================================================ */

:root {
  --wm-size: auto 128vh;                       /* taller than the viewport, so it always crops */
  --wm-pos: right -22vw center;                /* bleeds off the right edge, as it did before */
  /* The wash sets how faint the mark is: higher alpha, fainter mark. The
     target is that you can see it and know it is there, and it never
     competes with type. Navy is pushed furthest because a bone mark on a
     navy ground sits in the same tonal register as bone text, which is the
     worst case on the site. */
  --wm-paper: rgba(244, 239, 230, 0.955);      /* mark reads at ~4.5% */
  --wm-paper-2: rgba(237, 231, 218, 0.958);     /* ~4% */
  --wm-navy: rgba(19, 35, 63, 0.979);          /* ~2%, faintest of the three */
}

body {
  background-image: linear-gradient(var(--wm-paper), var(--wm-paper)), var(--wm-mark);
  background-attachment: scroll, fixed;
  background-repeat: no-repeat, no-repeat;
  background-position: center, var(--wm-pos);
  background-size: cover, var(--wm-size);
}

/* .paper is the same ground as the document, so it stays transparent and
   lets the body watermark through rather than painting over it. */
.paper { background: transparent; }

/* The ground sets the text colour for everything inside it. This rule went
   missing in the watermark refactor and only showed up on headings, because
   every other element on navy happened to carry its own override. */
.strip, .navy { color: var(--on-navy); }

.paper-2 {
  background-color: var(--bone-2);
  background-image: linear-gradient(var(--wm-paper-2), var(--wm-paper-2)), var(--wm-mark);
  background-attachment: scroll, fixed;
  background-repeat: no-repeat, no-repeat;
  background-position: center, var(--wm-pos);
  background-size: cover, var(--wm-size);
}

.strip, .navy {
  background-color: var(--navy);
  background-image: linear-gradient(var(--wm-navy), var(--wm-navy)), url("/assets/wm-light.png");
  background-attachment: scroll, fixed;
  background-repeat: no-repeat, no-repeat;
  background-position: center, var(--wm-pos);
  background-size: cover, var(--wm-size);
}

/* iOS Safari treats fixed attachment as scroll and repaints badly with it,
   so below tablet the mark rides with the page instead of holding still. */
@media (max-width: 52rem) {
  body, .paper-2, .strip, .navy { background-attachment: scroll, scroll; }
  :root { --wm-size: auto 90vh; --wm-pos: right -30vw center; }
}

/* The ghosted numeral. Same idea as the watermark, flattened into a single
   section rather than the whole document. .stage is the positioning context
   it needs; the two only ever appear together. */

.stage { position: relative; overflow: hidden; }
.stage > *:not(.bignum) { position: relative; z-index: 1; }

.bignum {
  position: absolute; right: -0.06em; bottom: -0.3em; margin: 0;
  /* exception: decorative, not read */
  font-family: var(--serif); font-size: clamp(11rem, 26vw, 22rem); line-height: 0.7;
  color: rgba(38, 37, 31, 0.055); pointer-events: none; user-select: none;
}

.strip .bignum, .navy .bignum { color: rgba(237, 231, 218, 0.07); }

/* ============================================================
   5. THE REGISTER
   The ruled index. This is the workhorse and it replaces every card
   grid on the site.
   ============================================================ */

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

.register__cap {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  padding-bottom: 0.5rem; border-bottom: 1px solid var(--char);
}

.reg { display: grid; grid-template-columns: 2.25rem 1fr; gap: 0.25rem 0.875rem;
  padding: 0.75rem 0; border-bottom: 1px solid var(--rule); align-items: baseline; }

.reg__n { margin: 0; font-size: var(--t-label); letter-spacing: 0.14em; color: var(--camel-ink); }
.reg__t { margin: 0; font-family: var(--serif); font-weight: 400; font-size: var(--t-d3); line-height: 1.3; }
.reg__m { grid-column: 2; margin: 0; font-size: var(--t-label); letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--stone-ink); }

@media (min-width: 46rem) {
  .reg { grid-template-columns: 2.5rem 1fr auto; gap: 0.875rem; }
  .reg__m { grid-column: 3; text-align: right; }
}

a.reg:hover { background: rgba(156, 123, 74, 0.07); }
a.reg:hover .reg__t { color: var(--camel-ink); }

.strip .register__cap, .navy .register__cap { border-bottom-color: var(--on-navy); }
.strip .reg, .navy .reg { border-bottom-color: var(--rule-navy); }
.strip .reg__n, .navy .reg__n { color: var(--gold); }
.strip .reg__t, .navy .reg__t { color: var(--on-navy); }
.strip .reg__m, .navy .reg__m { color: rgba(237, 231, 218, 0.66); }

/* the wide register, used where a row carries a full sentence */
.reg--wide { grid-template-columns: 2.25rem 1fr; }
@media (min-width: 56rem) {
  .reg--wide { grid-template-columns: 2.5rem 17rem 1fr; }
  .reg--wide .reg__m { grid-column: 3; text-align: left; font-size: var(--t-meta);
    letter-spacing: 0; text-transform: none; color: var(--set); max-width: 62ch; }
  .strip .reg--wide .reg__m, .navy .reg--wide .reg__m { color: rgba(237, 231, 218, 0.7); }
}

/* ============================================================
   6. RULED ROW
   The B footer device. Flush columns divided by vertical hairlines,
   never boxes.
   ============================================================ */

.ruled { display: grid; grid-template-columns: 1fr; border-top: 1px solid var(--rule); }
@media (min-width: 52rem) { .ruled--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 52rem) { .ruled--4 { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 52rem) { .ruled--2 { grid-template-columns: repeat(2, 1fr); } }

.ruled > * { padding: 1.5rem 1.5rem 1.5rem 0; border-bottom: 1px solid var(--rule); }
@media (min-width: 52rem) {
  .ruled > * { border-right: 1px solid var(--rule); border-bottom: 0; }
  .ruled > *:last-child { border-right: 0; }
  .ruled > * + * { padding-left: 1.5rem; }
}

.ruled h3 { margin: 0.625rem 0 0.375rem; font-family: var(--serif); font-weight: 400;
  font-size: var(--t-d3); }
.ruled p { margin: 0; font-size: var(--t-meta); color: var(--stone-ink); max-width: 36ch; }
.ruled a:hover h3 { color: var(--camel-ink); }
.strip .ruled, .navy .ruled { border-top-color: var(--rule-navy); }
.strip .ruled > *, .navy .ruled > * { border-right-color: var(--rule-navy); border-bottom-color: var(--rule-navy); }
.strip .ruled p, .navy .ruled p { color: rgba(237, 231, 218, 0.6); }

/* ============================================================
   7. RECORD
   Ten era sheets, scrolled left to right. Each sheet is a ruled
   document carrying its two finished cards.
   ============================================================ */

.deck { display: grid; gap: clamp(2.5rem, 5vw, 3.5rem); }

@media (min-width: 62rem) {
  .deck {
    grid-auto-flow: column; grid-auto-columns: min(72rem, 86vw);
    overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity;
    margin-inline: calc(-1 * var(--pad)); padding: 0 var(--pad) 1.5rem;
    scrollbar-color: var(--rule) transparent;
  }
  .era { scroll-snap-align: start; }
}

.era { position: relative; overflow: hidden; }
.era__head { display: grid; grid-template-columns: 1fr auto; gap: 0.5rem 1rem; align-items: end;
  padding-bottom: 0.5rem; border-bottom: 2px solid var(--char); }
.era__sub { margin: 0.25rem 0 0; font-family: var(--serif); font-style: italic; color: var(--stone-ink); }

.era__cards { display: grid; gap: clamp(0.875rem, 2vw, 1.5rem); margin-top: clamp(1.25rem, 2.5vw, 2rem); }
@media (min-width: 46rem) { .era__cards { grid-template-columns: 1fr 1fr; } }

.card { margin: 0; }
.card img { width: 100%; height: auto; border: 1px solid var(--rule); background: var(--bone);
  transition: border-color 160ms ease; }
.card a:hover img { border-color: var(--camel); }
.card figcaption { margin-top: 0.5rem; font-family: var(--mono); font-size: var(--t-label);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--stone-ink); }

/* ============================================================
   8. CONTROLS
   A rule and a word. No filled pills, no icons.
   ============================================================ */

.act {
  display: inline-block; font-size: var(--t-label); font-weight: 500; letter-spacing: 0.24em;
  text-transform: uppercase; padding-bottom: 0.4375rem;
  border-bottom: 1px solid var(--camel); color: var(--char);
  transition: color 150ms ease, border-color 150ms ease;
}

.act:hover { color: var(--camel-ink); }
.act--solid { border: 1px solid var(--char); background: var(--char); color: var(--bone);
  padding: 0.875rem 1.5rem; }
.act--solid:hover { background: var(--camel); border-color: var(--camel); color: var(--bone); }
.strip .act, .navy .act { color: var(--on-navy); border-bottom-color: var(--gold); }
.strip .act:hover, .navy .act:hover { color: var(--gold); }
.strip .act--solid, .navy .act--solid { background: var(--on-navy); border-color: var(--on-navy); color: var(--navy); }
.strip .act--solid:hover, .navy .act--solid:hover { background: var(--gold); border-color: var(--gold); }

.acts { display: flex; gap: clamp(1.5rem, 3vw, 2.75rem); flex-wrap: wrap; align-items: center; }

.mailto { font-family: var(--serif); font-size: var(--t-d3);
  border-bottom: 1px solid var(--camel); padding-bottom: 3px; overflow-wrap: anywhere; }
.strip .mailto, .navy .mailto { border-bottom-color: var(--gold); }

/* ============================================================
   9. DOCUMENT FOOT
   ============================================================ */

.docfoot { border-top: 2px solid var(--char); padding-top: 1.25rem; margin-top: clamp(2.5rem, 5vw, 4rem); }
.docfoot__cols { display: grid; gap: 1.75rem; }
@media (min-width: 52rem) { .docfoot__cols { grid-template-columns: 1.7fr 1fr 1fr 1.1fr; gap: 2rem; } }
/* On one column the four groups keep their desktop max-widths, which leaves
   every block hugging the left edge with a third of the screen empty beside
   it. Centre the stack and let the capped paragraphs centre with it. */
@media (max-width: 52rem) {
  .docfoot__cols { text-align: center; }
  .docfoot__cols p, .docfoot__cols ul { margin-inline: auto; }
  .docfoot__base { text-align: center; }
}
.docfoot ul { list-style: none; margin: 0.75rem 0 0; padding: 0; }
.docfoot li + li { margin-top: 0.4375rem; }
.docfoot a { font-size: var(--t-meta); color: var(--char); }
.docfoot a:hover { color: var(--camel-ink); }
.docfoot__base { margin-top: 2rem; padding-top: 0.875rem; border-top: 1px solid var(--rule);
  display: grid; gap: 0.625rem; }

.disclosure { margin: 0; font-size: var(--t-meta); line-height: 1.55; color: var(--stone-ink); max-width: 78ch; }

/* ============================================================
   10. UTILITIES
   These are declared last on purpose. .inset has the same specificity
   as the component rules it has to beat, so order is what decides it.
   ============================================================ */

/* Everything on a page shares one left and one right edge. The stage sets
   it at column two, so registers and ruled rows have to match or the eye
   reads two competing margins down the page.

   Doubled selector on purpose. This is a utility that has to beat component
   rules, and components keep getting appended below it, which at equal
   specificity means the component wins and the block silently goes flush
   left. That happened three times before this. .inset.inset is specificity
   0,2,0 and cannot be undone by a single class rule wherever it sits in the
   file, so ordering stops mattering. */
@media (min-width: 56rem) {
  /* one track plus one gap: the exact left edge of column two, derived from
     the same numbers the grid uses. 8.333% was close but not equal, so an
     inset block and a .c2-* block sat two pixels apart, and the gap moved
     with the viewport because one was a percentage and the other was not. */
  .inset.inset { margin-inline: calc((100% - 11 * var(--colgap)) / 12 + var(--colgap)); }
}

.flush-r { text-align: right; }
.hr { border: 0; border-top: 1px solid var(--rule); margin: 0; }
.hr--heavy { border-top: 2px solid var(--char); }
.mt-1 { margin-top: 0.75rem; } .mt-2 { margin-top: 1.5rem; }
.mt-3 { margin-top: 2.25rem; } .mt-4 { margin-top: 3.25rem; }

/* ============================================================
   11. THE RECORD TIMELINE
   The century runs left to right. One rule, ten years on it, and the
   plates fan out from the year you are pointing at.
   ============================================================ */

.timeline {
  position: relative;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  margin-inline: calc(-1 * var(--pad));
  padding: clamp(15rem, 34vh, 22rem) var(--pad) clamp(4rem, 8vh, 6rem);
  scrollbar-width: none;
}

.timeline::-webkit-scrollbar { display: none; }

.timeline__inner { position: relative; display: flex; align-items: flex-start; width: max-content; }

/* The century draws itself in from the left. Note the order: everything
   here is VISIBLE by default and only hidden once JS has armed it. If the
   script never runs, or the page loads in a background tab where the first
   frame never paints, the timeline is still fully readable. */
.timeline__rule {
  position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: var(--rule-2); transform-origin: left center;
}

.timeline.is-armed .timeline__rule { transform: scaleX(0); }

.timeline.is-drawn .timeline__rule {
  transform: scaleX(1);
  transition: transform 1100ms cubic-bezier(.22, .9, .24, 1);
}

/* a year on the rule */
.yr {
  position: relative;
  flex: none;
  width: clamp(15rem, 23vw, 22rem);
  padding-top: 2.25rem;
  scroll-snap-align: center;
  display: block;
}

.yr::before {
  content: "";
  position: absolute; left: 0; top: 0; width: 1px; height: 1.25rem;
  background: var(--camel); transform-origin: top center;
}

.timeline.is-armed .yr::before { transform: scaleY(0); }
.timeline.is-ready .yr::before { transform: scaleY(1); transition: transform 420ms ease-out; }

.yr__no    { margin: 0; font-size: var(--t-label); letter-spacing: 0.26em; text-transform: uppercase; color: var(--stone-ink); }
.yr__year  { margin: 0.375rem 0 0; font-family: var(--serif); font-weight: 400;
             font-size: var(--t-d2); line-height: 1; letter-spacing: -0.02em;
             transition: color 220ms ease; }
.yr__sub   { margin: 0.5rem 0 0; font-family: var(--serif); font-style: italic;
             font-size: var(--t-read); color: var(--stone-ink); max-width: 22ch;
             opacity: 0; transform: translateY(6px);
             transition: opacity 320ms ease, transform 320ms ease; }
.yr__enter { margin: 0.875rem 0 0; font-size: var(--t-label); letter-spacing: 0.26em;
             text-transform: uppercase; color: var(--camel-ink);
             opacity: 0; transition: opacity 320ms ease 60ms; }

/* without JS there is no hover state to reveal them, so show them outright */
.timeline:not(.is-armed) .yr__sub,
.timeline:not(.is-armed) .yr__enter { opacity: 1; transform: none; }

.yr:hover .yr__year, .yr.is-open .yr__year { color: var(--camel-ink); }
.timeline .yr.is-open > .yr__sub { opacity: 1; transform: none; }
.timeline .yr.is-open > .yr__enter { opacity: 1; transform: none; }

/* The years rise onto the rule in sequence, once armed. Scoped to <p> so it
   never touches .stills, whose own opacity is driven by the hover state. */
.timeline.is-armed .yr > p { opacity: 0; transform: translateY(14px); }
.timeline.is-ready .yr > .yr__no,
.timeline.is-ready .yr > .yr__year {
  opacity: 1; transform: none;
  transition: opacity 620ms ease, transform 620ms cubic-bezier(.22,.9,.24,1);
}
.timeline.is-ready .yr > .yr__sub,
.timeline.is-ready .yr > .yr__enter { transform: none; }

.timeline.is-ready .yr:nth-child(1) > p  { transition-delay: 0ms; }
.timeline.is-ready .yr:nth-child(2) > p  { transition-delay: 70ms; }
.timeline.is-ready .yr:nth-child(3) > p  { transition-delay: 140ms; }
.timeline.is-ready .yr:nth-child(4) > p  { transition-delay: 210ms; }
.timeline.is-ready .yr:nth-child(5) > p  { transition-delay: 280ms; }
.timeline.is-ready .yr:nth-child(6) > p  { transition-delay: 350ms; }
.timeline.is-ready .yr:nth-child(7) > p  { transition-delay: 420ms; }
.timeline.is-ready .yr:nth-child(8) > p  { transition-delay: 490ms; }
.timeline.is-ready .yr:nth-child(9) > p  { transition-delay: 560ms; }
.timeline.is-ready .yr:nth-child(10) > p { transition-delay: 630ms; }

/* the plates, stacked above the rule until the year is pointed at */
.stills { position: absolute; left: 0; bottom: calc(100% + 1.5rem); width: clamp(9rem, 13vw, 12.5rem); }
.stills img {
  position: absolute; bottom: 0; left: 0; width: 100%; height: auto;
  border: 1px solid var(--rule); background: var(--bone);
  box-shadow: 0 1px 0 rgba(38,37,31,.06);
  opacity: 0; transform: translateY(26px) rotate(0deg);
  transition: opacity 480ms ease, transform 620ms cubic-bezier(.22,.9,.24,1);
}

.yr.is-open .stills img { opacity: 1; }
.yr.is-open .stills img:nth-child(1) { transform: translate(0, 0) rotate(-2.4deg); transition-delay: 0ms; }
.yr.is-open .stills img:nth-child(2) { transform: translate(5.5rem, -2.25rem) rotate(2.1deg); transition-delay: 90ms; }

.timeline__hint { display: flex; justify-content: space-between; gap: 1rem;
  padding-top: 0.75rem; border-top: 1px solid var(--rule); }

@media (max-width: 56rem) {
  .timeline { padding-top: clamp(11rem, 26vh, 15rem); }
  .yr { width: 14rem; }
  .stills { width: 7.5rem; }
}

/* ============================================================
   12. AN ERA PAGE
   The plate, at web scale. Set in that era's own typeface, because
   the decade's voice is part of what is being shown.
   ============================================================ */

.era-title {
  margin: 0; font-family: var(--era-display), var(--serif); font-weight: 400;
  /* exception: the decade's own face at its own plate size, one per page */
  font-size: clamp(2.5rem, 7vw, var(--era-size, 5.5rem)); line-height: 1;
  letter-spacing: var(--era-track, 0);
}

.era-sub { margin: 0.625rem 0 0; font-family: var(--serif); font-style: italic;
  font-size: var(--t-d3); color: var(--stone-ink); }

.era-body { font-family: var(--era-body), var(--sans); }

/* the record line under a plate */
.record { border-top: 1px solid var(--rule); padding-top: 0.875rem; }
.record__line { margin: 0.625rem 0 0; font-family: var(--era-display), var(--serif);
  font-size: var(--t-d3); line-height: 1.35; max-width: 34ch; }
.record__meta { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  margin-top: 1.25rem; padding-top: 0.75rem; border-top: 1px solid var(--rule); }

/* the lettered and numbered callouts, as they read on plate B */
.callout { list-style: none; margin: 0.875rem 0 0; padding: 0; }
.callout li { display: grid; grid-template-columns: 1.5rem 1fr; gap: 0.875rem;
  padding: 0.5rem 0; border-bottom: 1px solid var(--rule); align-items: baseline; }
.callout .k { font-family: var(--mono); font-size: var(--t-label); letter-spacing: 0.06em; color: var(--camel-ink); }
.callout .v { font-family: var(--era-body), var(--sans); font-size: var(--t-meta); color: var(--set); }

/* the six statements the room was making */
.statements { display: grid; gap: 0; border-top: 1px solid var(--rule); }
@media (min-width: 46rem) { .statements { grid-template-columns: repeat(3, 1fr); } }
.statements > div { padding: 1.125rem 1.25rem 1.125rem 0; border-bottom: 1px solid var(--rule); }
@media (min-width: 46rem) {
  .statements > div { border-right: 1px solid var(--rule); }
  .statements > div:nth-child(3n) { border-right: 0; }
  .statements > div:not(:nth-child(3n+1)) { padding-left: 1.25rem; }
}
.statements .l { margin: 0; font-size: var(--t-label); letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--camel-ink); }
.statements .v { margin: 0.5rem 0 0; font-family: var(--era-display), var(--serif);
  font-size: var(--t-d3); line-height: 1.4; }

.plate-fig { margin: 0; }
.plate-fig img { width: 100%; height: auto; border: 1px solid var(--rule); background: var(--bone); }
.plate-fig figcaption { margin-top: 0.5rem; font-family: var(--mono); font-size: var(--t-label);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--stone-ink); }

/* previous and next decade */
.eranav { display: grid; grid-template-columns: 1fr 1fr; border-top: 2px solid var(--char); }
.eranav a { padding: 1.5rem 0; }
.eranav a:last-child { text-align: right; padding-left: 1.5rem; }
.eranav .t { margin: 0.5rem 0 0; font-family: var(--serif); font-size: var(--t-d3); }
.eranav a:hover .t { color: var(--camel-ink); }

/* ============================================================
   13. COLUMNS
   Long form runs across the whole page in newspaper columns rather
   than sitting in one narrow strip with half the sheet empty. The
   column count is set by measure, not by number, so it lands on four
   on a wide screen and one on a phone without any breakpoints.
   ============================================================ */

.cols {
  /* A column always starts on a new paragraph, never mid-sentence. That is
     what break-inside does. The count is passed in per block as --cols and
     capped by column-width, so a three paragraph section makes three columns
     rather than four with one left empty, and a phone makes one. */
  column-count: var(--cols, 3);
  column-width: 15rem;
  column-gap: clamp(1.25rem, 2.4vw, 2.25rem);
  column-rule: 1px solid var(--rule);
  font-family: var(--era-body, var(--serif));
  font-size: var(--t-read);
  line-height: 1.6;
  color: var(--char);
}

.cols p { margin: 0 0 1.0625rem; break-inside: avoid; -webkit-column-break-inside: avoid; }
.cols p:last-child { margin-bottom: 0; }
.strip .cols { color: var(--on-navy); column-rule-color: var(--rule-navy); }

/* the serif reading variant, for pages with no era face of their own */
.cols--serif { font-family: var(--serif); }

/* ============================================================
   14. THE TIMELINE SCROLLBAR
   Always visible. Without it there is no way to know the century
   runs to the right, and a hidden native bar tells you nothing.
   Draggable, clickable, and it doubles as a progress read.
   ============================================================ */

.tlbar {
  position: relative;
  height: 3px;
  margin-top: 1.5rem;
  background: var(--rule);
  cursor: pointer;
  touch-action: none;
}

.tlbar__thumb {
  position: absolute; left: 0; top: -1px; height: 5px;
  background: var(--camel);
  min-width: 2.5rem;
  transition: background 150ms ease;
}

.tlbar:hover .tlbar__thumb, .tlbar.is-dragging .tlbar__thumb { background: var(--char); }

.tlbar__ends { display: flex; justify-content: space-between; gap: 1rem; margin-top: 0.625rem; }

/* ============================================================
   15. THE ROSE

   A four point navigation star, tall on the vertical axis, standing in
   the middle of the principles band with its north and south points
   breaking out through the top and bottom edges into the sections
   either side. The four principles sit close in around the waist.

   The layering is the whole trick. A section background paints early
   and a section's plain text paints just after it, and there is no
   z-index that lands between the two. So every section's content is
   lifted into a positioned layer at z-index 1. The star used to sit at
   0, above every background it crossed and below every word. On desktop
   it now sits at 3, above both, so the rules in the section below stop
   striping across it. See the note on the star itself.

   Because the points cross both grounds, the star is drawn in gold on
   both halves rather than bone. Bone would be invisible the moment a
   point left the navy.
   ============================================================ */

main > section > * { position: relative; z-index: 1; }

.rose-band {
  position: relative;
  min-height: clamp(30rem, 68vh, 46rem);
  display: grid;
  align-content: center;
}

/* Equal arms. All four points leave the band: north and south through the
   top and bottom edges, east and west out past the text columns to the
   page edges. Sized by width so the horizontal reach is the fixed thing;
   the vertical bleed follows from it.

   An earlier version elongated the vertical axis so the horizontal points
   would not collide with the copy. That was solving a problem that does
   not exist here, because the star is already beneath every word on the
   page, and it produced a dagger rather than a compass. */
.rose__star {
  position: absolute;
  z-index: 0;
  left: 50%; top: 50%;
  width: min(104vw, 88rem);
  height: auto;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

/* The star is opaque, and these are the two colours it is opaque IN.

   It used to be gold at 60% with a 50% hairline, which on the navy band
   composited to exactly these values. That worked while the star was a
   window: over navy it looked like this, and nowhere else mattered. It stops
   working the moment the star is meant to be an object sitting on top of the
   page, because a translucent point lets the column rules and the paper show
   straight through it and the whole illusion of height goes.

   So the composite is baked: #806f58 is var(--gold) at 0.6 over var(--navy),
   and #6e6254 is the same gold at 0.5. On the band nothing changes by a
   single pixel, which is the point. Everywhere else the point now carries
   the middle's colour instead of thinning out against whatever is behind it.

   Neither --gold nor --navy is remapped for night, so both hold in both
   themes. */
.rose-band { --rose-face: #806f58; --rose-edge: #6e6254; }

.rose__solid { fill: var(--rose-face); fill-opacity: 1; }
.rose__hair { fill: none; stroke: var(--rose-edge); stroke-width: 2; stroke-opacity: 1; }

/* ------------------------------------------------------------
   THE STAR AS AN OBJECT, not a window

   Four of the eight triangles were unfilled, which is what gives a compass
   rose its two-tone face. Unfilled means they show whatever is behind them,
   so inside the band they read as navy and the instant a point crossed onto
   the paper the same triangle turned bone. The star looked cut off at the
   band edge because it was: it was never carrying its own colour.

   Filling them with navy makes the whole silhouette opaque, so the star
   keeps its blue-and-gold face the entire way through, over the paper as
   well as over the band. Inside the band nothing changes at all, because
   navy on navy is what was already showing.

   Once it is opaque it can be lifted over the rules that used to stripe
   across it: the caption hairline and the column dividers in the four
   refusals below. Those are borders on elements the layering rule holds at
   z-index 1, so there is no way to hide them other than to put the star
   above. That does mean the star is now above every word as well, which is
   only safe because its points fall in the gutters. Checked at 1280, 1440
   and 1920: it crosses no text at any of them.

   Desktop only. Below 62rem the star is not a bleed at all, it is a small
   static mark sitting on navy, where a navy fill would be invisible and a
   drop shadow would be a smudge.
   ------------------------------------------------------------ */
@media (min-width: 62.0625rem) {
  .rose__hair { fill: var(--navy); fill-opacity: 1; }
  .rose__star {
    z-index: 3;
    filter: drop-shadow(0 12px 24px rgba(0, 0, 0, 0.45))
            drop-shadow(0 34px 64px rgba(0, 0, 0, 0.30));
  }
}

.rose {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  gap: clamp(2.25rem, 5vw, 3.5rem);
}

.rose__q { align-content: start; }
.rose__q h3 { max-width: 17ch; }
.rose__q .set { max-width: 30ch; }

@media (max-width: 62rem) {
  /* On one column there is no middle for a compass to sit in the middle of.
     Blown up to 150vw behind the stack it stopped being a mark and became a
     dark smear with the copy sitting on its arms. So below the two-column
     breakpoint it stops being a background and becomes what it is: a mark,
     small, centred, at the head of the four points it belongs to. */
  .rose-band { display: block; }
  .rose__star {
    position: static;
    transform: none;
    display: block;
    width: clamp(4.5rem, 20vw, 7rem);
    margin: 0 auto clamp(2.25rem, 8vw, 3.25rem);
    opacity: 1;
  }
  /* and the four become a register: a numeral, a rule, and the point.
     Capped and centred, because one column across a tablet runs the measure
     out to about ninety characters, which is half again what anyone reads
     comfortably. On a phone the cap is wider than the screen and does
     nothing. */
  .rose { gap: 0; max-width: 38rem; margin-inline: auto; }
  .rose__q { padding-block: clamp(1.5rem, 5vw, 2rem); }
  .rose__q + .rose__q { border-top: 1px solid rgba(244, 239, 230, 0.16); }
  .rose__q:first-child { padding-top: 0; }
  .rose__q:last-child { padding-bottom: 0; }
  .rose__q h3, .rose__q .set { max-width: none; }
}

@media (min-width: 62rem) {
  .rose {
    grid-template-columns: 1fr 1fr;
    /* equal tracks so the row boundary lands exactly on the rose's centre.
       Without this the taller quadrant sets row one's height, the boundary
       drifts off centre, and the horizontal arms cut through copy. */
    grid-template-rows: 1fr 1fr;
    column-gap: clamp(5.5rem, 10vw, 9.5rem);
    row-gap: clamp(4.5rem, 9vw, 8rem);
  }
  .rose__q--nw { grid-area: 1 / 1; }
  .rose__q--ne { grid-area: 1 / 2; }
  .rose__q--sw { grid-area: 2 / 1; }
  .rose__q--se { grid-area: 2 / 2; }

  /* Both sides have to hug the star equally. The columns are equal, but the
     copy inside them is left aligned, so without this the left blocks sit
     against the far edge of their column while the right blocks sit against
     the gap: one side a quarter of the page from the centre, the other
     touching it. The block is pushed to the column's inner edge; the text
     inside it stays left aligned, because that is about reading, not
     composition. */
  .rose__q--nw, .rose__q--sw { justify-self: end; }
  .rose__q--ne, .rose__q--se { justify-self: start; }
  .rose__q { max-width: 30ch; }

  /* Pushing the block to the inner edge was only half of it. Inside the
     block the type stayed left aligned, so the left pair met the star with a
     ragged edge while the right pair met it with a flush one, and the two
     sides read as different distances from the centre even though the boxes
     were symmetrical. The left pair now sets to the right, and every child
     with a max-width is pushed to the block's right edge, or an h3 capped at
     17ch would align to 17ch from the wrong side. */
  .rose__q--nw, .rose__q--sw { text-align: right; }
  .rose__q--nw > *, .rose__q--sw > * { margin-left: auto; }

  /* The headings run two lines or three depending on the principle, so the
     paragraph under a two line heading started a line above the paragraph
     next to it and the four blocks read as unaligned. Reserving three lines
     of heading puts every paragraph on the same line.

     Subgrid would express this better, but it needs each quadrant to span
     several parent tracks, and the rose's two rows have to stay equal or the
     boundary drifts off the star's centre and the horizontal arms cut
     through the copy. bin/check.py enforces that. Three lines it is: if a
     principle ever needs four, this number moves with it. */
  .rose__q h3 { min-height: 3.75em; }   /* 3 x the 1.25 line-height */
}

/* ============================================================
   16. THE DRAWER
   Phone navigation. Five items do not fit across a 393px screen, so
   below tablet the nav row is replaced by a burger and the menu slides
   in from the left.

   Sized for an iPhone 14 Pro, 393 x 852. Every target in here clears
   44px, which the desktop nav does not and cannot without wrecking the
   masthead.
   ============================================================ */

/* The drawer used to live entirely inside the phone breakpoint, because the
   burger was the only thing that could open it. The floating menu opens it at
   every width now, so the panel itself is unconditional and only the burger
   stays phone-only. Closed state is the `hidden` attribute, which a class
   selector would otherwise beat, hence the explicit [hidden] rule. */
.burger { display: none; }
.drawer[hidden], .scrim[hidden] { display: none; }

@media (max-width: 52rem) {
  .dochead__nav { display: none; }

  .burger {
    display: flex; align-items: center; gap: 0.75rem;
    width: 100%; min-height: 3rem;
    padding: 0.5rem 0; margin: 0;
    background: none; border: 0; border-bottom: 1px solid var(--rule);
    /* the burger IS the navigation on a phone, so it matches what the nav
       row became on a desktop rather than staying at the old caption size */
    color: var(--nav-ink); cursor: pointer;
    font-family: var(--sans); font-size: 0.875rem; font-weight: 500;
    letter-spacing: 0.13em; text-transform: uppercase;
  }

  .burger__bars { display: grid; gap: 4px; width: 1.125rem; }
  .burger__word { line-height: 1; }
  .burger__bars i { display: block; height: 1px; background: var(--nav-ink); transition: transform 260ms ease, opacity 200ms ease; }
  .burger[aria-expanded="true"] .burger__bars i:nth-child(1) { transform: translateY(5px) rotate(45deg); }
  .burger[aria-expanded="true"] .burger__bars i:nth-child(2) { opacity: 0; }
  .burger[aria-expanded="true"] .burger__bars i:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

}

.scrim {
  display: block; position: fixed; inset: 0; z-index: 90;
  background: rgba(18, 22, 28, 0.5);
  opacity: 0; transition: opacity 320ms ease;
}
.scrim.is-open { opacity: 1; }

/* left to right, and it holds its own scroll if the list ever grows */
.drawer {
  display: flex; flex-direction: column;
  position: fixed; z-index: 95;
  top: 0; bottom: 0; left: 0;
  width: min(20rem, 86vw);
  padding: max(1.25rem, env(safe-area-inset-top)) 1.5rem
           max(1.5rem, env(safe-area-inset-bottom));
  background: var(--navy); color: var(--on-navy);
  overflow-y: auto; overscroll-behavior: contain;
  transform: translateX(-100%);
  transition: transform 380ms cubic-bezier(.22, .9, .24, 1);
}
.drawer.is-open { transform: none; }
.drawer:focus { outline: none; }

.drawer__top { display: flex; justify-content: space-between; align-items: center;
  gap: 1rem; padding-bottom: 1rem; border-bottom: 1px solid var(--rule-navy); }
.drawer__top .micro { color: var(--on-navy); white-space: nowrap; }
.drawer__top .micro b { color: var(--gold); font-weight: 500; }

.drawer__close { min-height: 2.75rem; padding: 0 0.25rem; background: none; border: 0;
  color: var(--gold); font-family: var(--sans); font-size: var(--t-label);
  letter-spacing: 0.24em; text-transform: uppercase; cursor: pointer; }

.drawer__list { list-style: none; margin: 0; padding: 0; }
.drawer__list a {
  display: grid; grid-template-columns: 2rem 1fr; gap: 1rem; align-items: baseline;
  min-height: 3.5rem; padding: 1rem 0;
  border-bottom: 1px solid var(--rule-navy);
}
.drawer__n { font-family: var(--mono); font-size: var(--t-label); color: var(--gold); }
.drawer__t { font-family: var(--serif); font-size: var(--t-d3); line-height: 1.2; }
.drawer__list a[aria-current="page"] .drawer__t { color: var(--gold); }

.drawer__guide { display: block; margin-top: auto; padding-top: 1.5rem; }
.drawer__guide .micro { color: rgba(237, 231, 218, 0.66); }
.drawer__guide-t { margin: 0.5rem 0 0.375rem; font-family: var(--serif);
  font-size: var(--t-d3); color: var(--on-navy); }

/* the sequence runs off transitions, so honour the setting properly */
@media (prefers-reduced-motion: reduce) {
  .drawer, .scrim, .burger__bars i, .fl { transition: none; }
}

/* the page must not scroll behind an open drawer */
body.is-locked { overflow: hidden; }

/* ============================================================
   17. PHONE LEGIBILITY
   A phone gets read outdoors, one-handed, at whatever brightness the
   screen happens to be on. The mid tones that hold up on a monitor go
   milky in daylight, so the secondary text darkens below tablet.

   Tokens only. Nothing here changes a rule, so the composition is
   identical and only the ink gets heavier.
   ============================================================ */

@media (max-width: 52rem) {
  :root {
    --set: #33312b;        /* was #4a473f. 11.4:1 on bone, up from 8.0 */
    --stone-ink: #4f4b45;  /* was #6f6a5f. 7.6:1, up from 4.7 */
    --camel-ink: #5f4829;  /* was #7f6339. 7.5:1, up from 4.9 */
    --stone-lift: #b3ada0; /* secondary on navy, lifted for the same reason */
  }

  /* Poppins at 300 is thin on a phone. One step up costs nothing and it is
     the single biggest readability gain outdoors. */
  body { font-weight: 400; }
  .set, .ruled p, .disclosure, .reg--wide .reg__m { font-weight: 400; }
}


/* ============================================================
   18. THE ROOM PAGES

   Twelve pages, one per room, carrying a chapter of the guide in full. The
   whole point is that a man searching "what to wear to a funeral" lands on
   something he can read, rather than on a download.

   The download itself sits at the top right and the bottom right, so it is
   in reach whether he has decided in ten seconds or read the lot.
   ============================================================ */

/* the header: title left, download right, and they stack on a phone */
.rm-head { display: flex; flex-wrap: wrap; align-items: flex-end;
           justify-content: space-between; gap: 1.5rem clamp(1.5rem, 4vw, 3rem); }
.rm-h1 { font-size: clamp(2rem, 1.2rem + 3.2vw, 3.5rem); }
.rm-dl { margin: 0; flex-shrink: 0; }
.rm-what { font-size: var(--t-d3); font-family: var(--serif); color: var(--set); }
.rm-top .kick a { color: inherit; border-bottom: 1px solid var(--rule-2); }
.rm-top .kick a:hover { color: var(--camel-ink); }

/* the plates. Navy sheets on bone paper, so they carry their own edge. */
.rm-plate { margin: 0; }
.rm-plate + .rm-plate { margin-top: var(--colgap); }
@media (min-width: 56rem) { .rm-plate + .rm-plate { margin-top: 0; } }
.rm-plate img { display: block; width: 100%; height: auto;
                border: 1px solid var(--rule-2); background: var(--navy); }
.rm-plate figcaption { margin-top: 0.625rem; color: var(--stone-ink); }

/* the chapter itself */
.rm-body { max-width: 46rem; }
.rm-sec { padding-block: clamp(1.5rem, 3.5vw, 2.25rem); }
.rm-sec + .rm-sec { border-top: 1px solid var(--rule); }
.rm-sec__h { margin: 0 0 0.75rem; }
.rm-sec__b { font-family: var(--serif); font-size: var(--t-read); line-height: 1.62;
             color: var(--char); }
.rm-sec__b > * { margin: 0; }
.rm-sec__b > * + * { margin-top: 1rem; }
.rm-lede { font-size: var(--t-d3); line-height: 1.35; }
.rm-q { margin: 1.25rem 0 0; padding-left: 1.125rem; border-left: 2px solid var(--camel);
        font-style: italic; color: var(--set); }

/* How to act is a list of pairs, so it is set as one */
.rm-acts { display: grid; gap: 1.125rem; }
/* a label and its instruction are one thing. Do not let a print or a column
   split them apart. */
.rm-act { break-inside: avoid; margin: 0; }

/* Set the way the guide sets it: the label opens the sentence, inline, in the
   same serif, italic. The copy is written to continue out of it, so "Listen
   for the question behind the question" is one sentence and the lowercase
   word after the label is correct.

   It used to be sans, uppercase, on its own line. That turned every one of
   these into a heading followed by a paragraph that appeared to start in
   lowercase, which reads as a typo. It was also the only place on a room page
   where a label above a paragraph did not capitalise what followed. */
.rm-act__k { font-style: italic; color: var(--char); }

/* previous and next, because twelve rooms should feel like one thing */
.rm-near { display: grid; gap: 1px; background: var(--rule); border-block: 1px solid var(--rule); }
@media (min-width: 42rem) { .rm-near { grid-template-columns: 1fr 1fr; } }
.rm-near__a { display: grid; gap: 0.35rem; padding: 1.25rem 0.25rem; background: var(--bone);
              text-decoration: none; color: inherit; transition: background 0.2s ease; }
.rm-near__a:hover { background: var(--bone-2); }
.rm-near__a--n { text-align: left; }
@media (min-width: 42rem) { .rm-near__a--n { text-align: right; padding-inline: 0.25rem; } }
.rm-near__t { font-family: var(--serif); font-size: var(--t-d3); }

/* ============================================================
   19. NIGHT PAPER

   Dark mode is not a grey theme. The ground is the charcoal ink deepened,
   so it reads as the same paper at night, and the navy strips do not move
   at all. A navy plate on navy paper has nothing to sit against, and the
   twenty-four plates are the one asset here nothing else has.

   It is nothing but a token flip. That is deliberate: it is what lets the
   same values serve the system setting and the reader's own choice without
   a single rule being written twice. Sections 1 through 18 never learn that
   dark mode exists.

   Three ways in, in order of authority:
     data-theme="dark"    the reader chose night
     data-theme="light"   the reader chose day, and it beats the system
     the system setting   when the reader has expressed no preference
   ============================================================ */
:root {
  /* the night values, written once */
  --dk-bone: #14130e;      /* the char hue deepened, not a neutral grey */
  --dk-bone-2: #1a1913;
  --dk-rule: #34322a;
  --dk-rule-2: #47443a;
  --dk-char: #efe9dd;      /* what was the ground is now the ink */
  --dk-set: #cdc7b8;
  --dk-stone: #a09a8c;
  --dk-stone-ink: #a8a294;
  /* camel is a dark brown and disappears on dark paper. Gold, already the
     accent on every navy ground, takes over. */
  --dk-camel: #c9a268;
  /* The same 0.955 veil that makes the mark a whisper on bone lets it shout
     here, because a bone mark against near black is a far bigger jump than a
     charcoal mark against bone. */
  --dk-wm-paper: rgba(20, 19, 14, 0.975);
  --dk-wm-paper-2: rgba(26, 25, 19, 0.972);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bone: var(--dk-bone); --bone-2: var(--dk-bone-2);
    --rule: var(--dk-rule); --rule-2: var(--dk-rule-2);
    --char: var(--dk-char); --set: var(--dk-set);
    --stone: var(--dk-stone); --stone-ink: var(--dk-stone-ink);
    --camel: var(--dk-camel); --camel-ink: var(--dk-camel);
    --on-navy: var(--dk-char);
    --nav-ink: var(--dk-char);
    --wm-mark: url("/assets/wm-light.png");
    --wm-paper: var(--dk-wm-paper); --wm-paper-2: var(--dk-wm-paper-2);
  }
}

:root[data-theme="dark"] {
  --bone: var(--dk-bone); --bone-2: var(--dk-bone-2);
  --rule: var(--dk-rule); --rule-2: var(--dk-rule-2);
  --char: var(--dk-char); --set: var(--dk-set);
  --stone: var(--dk-stone); --stone-ink: var(--dk-stone-ink);
  --camel: var(--dk-camel); --camel-ink: var(--dk-camel);
  --on-navy: var(--dk-char);
  --nav-ink: var(--dk-char);
  --wm-mark: url("/assets/wm-light.png");
  --wm-paper: var(--dk-wm-paper); --wm-paper-2: var(--dk-wm-paper-2);
}

/* ============================================================
   20. THE TOGGLE

   Day and night, in the register's own voice: a small mark and a word. The
   word says what the button will DO, not what is currently on, because a
   control labelled with its own state is the oldest confusion in interface
   design.

   It appears twice, in the nav row and in the phone drawer, because the nav
   row is not on screen below tablet. Both are driven by the same handler.
   ============================================================ */
.tog {
  display: inline-flex; align-items: center; gap: 0.5rem;
  margin: 0 0 0 clamp(0.875rem, 2.4vw, 2.25rem); padding: 0 0 2px;
  background: none; border: 0; border-bottom: 1px solid transparent;
  font-family: var(--sans); font-size: 0.875rem; font-weight: 500;
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--nav-ink); cursor: pointer;
}
.tog:hover { border-bottom-color: var(--camel); }

/* half filled, which is the universal mark for contrast and is drawn rather
   than borrowed from an emoji font that renders differently everywhere */
.tog__m {
  width: 0.75rem; height: 0.75rem; border-radius: 50%;
  border: 1px solid currentColor;
  background: linear-gradient(90deg, currentColor 50%, transparent 50%);
}
[data-theme="dark"] .tog__m { transform: rotate(180deg); }

/* the word swaps between Day and Night, so it is held to the width of the
   longer one and the row does not jump when it changes */
.tog__w { min-width: 3.4em; text-align: left; }

/* Also unconditional now. Once the drawer is reachable from mid-page at any
   width, the header toggle has scrolled away, and the drawer is the only
   place left to change day or night. */
.drawer__tog { display: block; padding: 0.875rem 0 0; }
.drawer__tog .tog { margin: 0; color: var(--on-navy); }
.drawer__tog .tog:hover { border-bottom-color: var(--gold); }

/* every decade, on every decade page */
.decades { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; margin-top: 0.875rem; }
.decades a { font-family: var(--sans); font-size: var(--t-meta); font-weight: 400;
  letter-spacing: 0.06em; color: var(--stone-ink);
  padding-bottom: 2px; border-bottom: 1px solid transparent; }
.decades a:hover { color: var(--char); border-bottom-color: var(--camel); }
.decades a[aria-current="page"] { color: var(--char); border-bottom-color: var(--camel); }

/* ============================================================
   21. CONSENT

   Clarity records sessions, so it does not start until the reader says yes.
   The notice sits at the foot of the page rather than across the middle of
   it: this site does not put anything between a man and what he came to
   read, and a modal that blocks the page would be the first thing to
   contradict the argument the page is making.

   Allow and No thanks are the same size, the same weight and one tab apart.
   A decline that is harder to reach than an accept is not a choice.
   ============================================================ */
.consent {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 2147482000;          /* under the door, which lifts before this matters */
  background: var(--bone-2);
  border-top: 1px solid var(--rule-2);
  padding: clamp(0.875rem, 2vw, 1.25rem) var(--pad);
}
.consent[hidden] { display: none; }

.consent__in {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 0.875rem clamp(1.5rem, 4vw, 3rem);
  max-width: 72rem; margin-inline: auto;
}

.consent__t {
  margin: 0; max-width: 60ch;
  font-family: var(--sans); font-weight: 300;
  font-size: var(--t-meta); line-height: 1.55; color: var(--set);
}

.consent__acts { display: flex; gap: 0.75rem; margin: 0; flex-shrink: 0; }

.consent__b {
  font-family: var(--sans); font-size: var(--t-label); font-weight: 500;
  letter-spacing: 0.16em; text-transform: uppercase;
  padding: 0.6875rem 1.25rem; cursor: pointer;
  background: none; color: var(--char);
  border: 1px solid var(--rule-2);
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.consent__b:hover { border-color: var(--camel); color: var(--camel-ink); }
.consent__b--yes { background: var(--char); border-color: var(--char); color: var(--bone); }
.consent__b--yes:hover { background: var(--camel); border-color: var(--camel); color: var(--bone); }

.docfoot__base a { border-bottom: 1px solid var(--rule-2); }
.docfoot__base a:hover { color: var(--camel-ink); }

/* cache key d88ce34b was poisoned at the edge during a deploy race. See bin/verify_live.py */

/* ============================================================
   22. THE FLOATING MENU

   The header is sticky in intent but not in fact: body { overflow-x: hidden }
   further up makes the body a scroll container and silently kills position
   sticky. Rather than unpick that, the navigation comes back on its own
   terms. Once the masthead is well off screen a navy pill rises out of the
   bottom margin, and pressing it widens the pill until the whole nav row is
   sitting inside it.

   Bottom centre, not top centre. Top centre is exactly where the text column
   is, and anything parked there cuts a hole through the middle of a sentence.
   The bottom margin is empty by construction and it is where a thumb already
   is on a phone.

   The width is animated, which is normally a bad idea, but it is one element
   with nothing beneath it in flow, and width is the whole effect: the row
   has to look like it came out of the pill rather than appearing over it.
   overflow: hidden is what makes that read, by clipping the row until there
   is room for it.
   ============================================================ */

.fl {
  position: fixed; left: 50%; bottom: 1.75rem; z-index: 80;
  /* set from the trigger's real width on load, so the collapsed pill is
     exactly as wide as its contents in whatever font actually rendered */
  width: var(--fl-shut, 7rem);
  display: flex; align-items: center;
  background: var(--navy); color: var(--on-navy);
  border-radius: 999px; overflow: hidden;
  box-shadow: 0 6px 24px rgba(19, 35, 63, 0.28);
  opacity: 0; visibility: hidden; transform: translate(-50%, 2rem);
  transition: width 420ms cubic-bezier(.22, .9, .24, 1),
              transform 380ms cubic-bezier(.22, .9, .24, 1),
              opacity 300ms ease, visibility 380ms;
}
.fl.is-in { opacity: 1; visibility: visible; transform: translate(-50%, 0); }
.fl.is-open { width: min(78rem, calc(100vw - 2 * var(--pad))); }

/* the trigger keeps its own width so the mark never shifts as the pill grows */
.fl__t {
  flex: 0 0 auto; display: flex; align-items: center; gap: 0.5rem;
  padding: 0.5625rem 1.25rem 0.5625rem 0.875rem;
  background: none; border: 0; color: inherit; cursor: pointer;
  font-family: var(--sans); font-size: 0.6875rem; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase; white-space: nowrap;
}
.fl__m { display: block; width: 1.75rem; height: auto; opacity: 0.95; }
.fl__w { min-width: 3.2em; text-align: left; }
.fl__t:focus-visible { outline: 2px solid var(--gold); outline-offset: -4px; }

/* The row. visibility, not display, so it is out of the tab order and off the
   accessibility tree while it is shut without collapsing the layout the width
   animation is measured against. It fades in only once the pill has opened
   far enough to hold it, and leaves immediately on the way back. */
.fl__nav {
  display: flex; align-items: center; justify-content: space-between;
  flex: 1 1 auto; gap: clamp(0.875rem, 2.4vw, 2.25rem);
  padding-right: 1.5rem; white-space: nowrap;
  opacity: 0; visibility: hidden;
  transition: opacity 180ms ease, visibility 180ms;
}
.fl.is-open .fl__nav {
  opacity: 1; visibility: visible;
  transition: opacity 240ms ease 180ms, visibility 240ms 180ms;
}
.fl__grp { display: flex; align-items: center; gap: clamp(0.875rem, 2vw, 2rem); }

/* the nav row's own type, on navy instead of on paper */
.fl__nav a {
  font-size: 0.8125rem; letter-spacing: 0.13em; font-weight: 500;
  text-transform: uppercase; color: var(--on-navy);
  padding-bottom: 2px; border-bottom: 1px solid transparent;
}
.fl__nav a:hover, .fl__nav a[aria-current="page"] { border-bottom-color: var(--gold); }
.fl__nav a[aria-current="page"] { color: var(--gold); }
.fl__nav .tog { margin: 0; color: var(--on-navy); }
.fl__nav .tog:hover { border-bottom-color: var(--gold); }

/* At full size the row wants about 1130px, so on anything short of a large
   desktop it was being clipped by the pill's own overflow: hidden and the
   Night toggle simply fell off the end. It tightens instead of falling back,
   because falling back to the drawer on a 1200px laptop is not a desktop
   experience. Measured, not guessed: bin/check.py asserts it fits. */
@media (max-width: 82rem) {
  .fl__nav { gap: 1rem; padding-right: 1.125rem; }
  .fl__grp { gap: 1rem; }
  .fl__nav a { font-size: 0.75rem; letter-spacing: 0.09em; }
}

/* Below this even the tight row does not fit, so the pill goes back to being
   a button that opens the phone drawer. The JS reads the same breakpoint.

   This was 62rem until the Instagram link joined the row. The row got about
   70px wider and stopped fitting on the narrowest desktops, so the fallback
   moved up rather than letting it clip. Measured, not guessed: bin/check.py
   has no eye for this, so brand/../fit probe does. */
@media (max-width: 69rem) {
  .fl.is-open { width: var(--fl-shut, 7rem); }
  .fl__nav { display: none; }
}

@media (max-width: 52rem) {
  .fl { bottom: max(1.25rem, env(safe-area-inset-bottom)); }
}

/* an open drawer means the pill has done its job */
body.is-locked .fl { opacity: 0; visibility: hidden; }

/* On night paper the navy pill sits on near black and loses its edge, and a
   drop shadow does nothing on a dark ground. The gold hairline gives it a
   boundary instead. This is the one place dark mode needs more than the
   token flip, because the pill is the only navy element that floats over the
   paper rather than being a strip anchored to it. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .fl {
    border: 1px solid rgba(201, 162, 104, 0.42);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.55);
  }
}
:root[data-theme="dark"] .fl {
  border: 1px solid rgba(201, 162, 104, 0.42);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.55);
}

/* ------------------------------------------------------------
   THE PRINCIPLES CAPTION

   "Four principles" is in the source copy and was the one band on this page
   with no label on it, which left the four points reading as decoration
   rather than as a numbered set.

   The words only. It started as the same ruled caption pair the section
   below uses, and the rule was too much: it drew a second horizontal across
   a band that already has the star's east and west points running through
   it.

   It cannot simply sit in the band's flow. The band centres its content on
   itself and the star is centred on the band, so anything added above the
   list pushes the list down and the row boundary stops landing on the star's
   waist, which is the alignment the whole composition hangs off. Pinned to
   the top instead, so the centring is untouched.

   Only above the two-column breakpoint. Below it the star is a small static
   mark at the head of the stack and the caption belongs in the flow, where
   it reads as the heading for the list that follows.
   ------------------------------------------------------------ */
.rose-band__cap { display: block; margin: 0 0 clamp(1.5rem, 5vw, 2rem); }

/* Not gold. Every .micro on a navy strip goes gold by default, which put the
   label in the accent colour and made it read as a third voice next to the
   numerals. It takes the same value as the principle copy underneath it, so
   the label and the words it labels are the same ink. Kept in step with
   `.strip .set` above; if that value moves, this moves with it.

   .strip .micro is specificity 0,2,0, so this has to match it and sit later
   in the file, which it does. */
.strip .rose-band__cap { color: rgba(237, 231, 218, 0.74); }

@media (min-width: 62.0625rem) {
  /* Getting this to line up with the caption in the section below it takes
     two corrections, both from the same cause: an absolutely positioned box
     is laid out against its ancestor's PADDING box, and this strip is a
     full-bleed band whose padding box is two page margins wider than an
     ordinary section's content box.

     So left:0 sat a whole --pad too far left, and .inset's percentage margin,
     resolved against that wider base, then added another 2*--pad/12 on top.
     The offset is written out here against the correct width instead, and
     .inset's margin is cancelled. Doubled selector because .inset.inset is
     specificity 0,2,0 and a single class cannot undo it. */
  .rose-band__cap.rose-band__cap {
    position: absolute;
    left:  calc(var(--pad) + (100% - 2 * var(--pad) - 11 * var(--colgap)) / 12 + var(--colgap));
    right: calc(var(--pad) + (100% - 2 * var(--pad) - 11 * var(--colgap)) / 12 + var(--colgap));
    top: clamp(1.75rem, 4vw, 3.25rem);
    margin-inline: 0;
    margin-bottom: 0;
  }
}

/* In the floating row the toggle is the mark alone. The word is dropped, not
   hidden from everyone: nav.js already keeps an aria-label on the button that
   says what pressing it will do, so a screen reader still gets "switch to
   night" while the row gets its space back.

   The mark grows a little to stay a real target once the word is gone. The
   drawn button is 30px, which clears the 24px pointer guideline, but this row
   shows from 1105px up and a large tablet in landscape is both that wide and
   a touch screen. So the hit area is pushed out to 44px with a pseudo element
   instead of padding, which would have made the pill taller. The gap to the
   Instagram link beside it is 14px at its tightest, so a 7px reach each side
   cannot steal its clicks. */
.fl__nav .tog__w { display: none; }
.fl__nav .tog {
  gap: 0; padding: 0.5rem; margin-left: 0;
  border-bottom: 0; border-radius: 50%;
}
.fl__nav .tog__m { width: 0.875rem; height: 0.875rem; }
.fl__nav .tog { position: relative; }
.fl__nav .tog::after { content: ""; position: absolute; inset: -7px; }
.fl__nav .tog:hover { background: rgba(237, 231, 218, 0.12); }
.fl__nav .tog:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

/* A section caption that is also the section's heading. Promoting these from
   <p> to <h2> fixed a real hierarchy gap: /standard/ ran h1 straight to four
   h3s with nothing between, and so did the record pages. The class already
   carries the whole look; this only undoes what the browser adds to an h2. */
h2.micro { margin: 0; font-weight: 400; font-size: var(--t-label); }

/* Two sentences that must never break mid sentence. .set caps the measure at
   40ch, which is right for body copy and wrong here: it forced this closer to
   wrap after "This", leaving "one is a download" stranded on its own line.

   Wide enough, the two sentences sit on one line. Below the phone breakpoint
   they cannot, so each becomes its own block and the break lands where a
   full stop already is. */
.closer { max-width: 34rem; }
@media (max-width: 46rem) {
  .closer > span { display: block; }
}

/* cache key 72624000 was poisoned at the edge during deploy propagation, 2026-08-15. See bin/verify_live.py */
