/* ==========================================================================
   RUBY FREMON — COMPONENTS
   Every component is built in the plate's vocabulary. A stock component
   inside a committed form is a lapse, so nav, buttons, inputs, and links
   are all rebuilt here.

   Layer 3 of the token architecture: component tokens are declared at the
   top of each block and resolve to semantic tokens, never to primitives.
   ========================================================================== */

/* ==========================================================================
   LAYOUT
   ========================================================================== */

/* Any `display` declaration beats the hidden attribute's UA `display:none`, so
   a component that sets `display: grid` and is then marked hidden stays on
   screen. That is how the contact form's success message shipped visible under
   the form. One line, everywhere, no exceptions. */
[hidden] { display: none !important; }

/* ==========================================================================
   INLINE LINK
   A link inside prose. Unclassed anchors only, so no component that styles its
   own anchors — .btn, .nav__link, .footer__link, .episode, .brandmark — can be
   caught by it.

   Colour is currentColor, never a hue: a link takes the colour of the text
   around it and therefore flips pole with everything else, and it already
   passes contrast wherever that text does. The underline is what carries the
   affordance, drawn as a hairline like every other line in this system.
   Browser-default blue is not a styling oversight here, it is a palette
   violation — there is no hue in this system.
   ========================================================================== */

a:not([class]),
.link {
  color: currentColor;
  text-decoration: underline;
  text-decoration-thickness: var(--p-line-hair);
  text-underline-offset: 0.22em;
  text-decoration-color: var(--accent-warm);
  transition: text-decoration-color var(--p-dur-fast) var(--p-ease-ink);
}

a:not([class]):hover,
.link:hover { text-decoration-color: currentColor; text-decoration-thickness: var(--p-line-thin); }

a:not([class]):focus-visible,
.link:focus-visible {
  outline: var(--p-line-thin) solid var(--focus-ring);
  outline-offset: 3px;
  text-decoration-color: currentColor;
}

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--text { max-width: var(--container-text); }

.stack > * + * { margin-block-start: var(--p-space-5); }
.stack--tight > * + * { margin-block-start: var(--p-space-3); }
.stack--loose > * + * { margin-block-start: var(--p-space-7); }

/* More space above a heading than below it. One rhythm, no exceptions. */
.prose > * + * { margin-block-start: var(--p-space-5); }
.prose > * + :is(h2, h3, h4) { margin-block-start: var(--p-space-8); }
.prose > :is(h2, h3, h4) + * { margin-block-start: var(--p-space-4); }
.prose { max-width: var(--p-measure); }

/* ==========================================================================
   TYPE
   ========================================================================== */

/* Headings are a grotesque set heavy and tracked in hard. The face it
   replaces was a didone, whose hairlines dissolved at exactly these sizes on
   a black ground — legibility is the reason for the family, and the tight
   tracking is what makes a grotesque read as considered rather than default. */
.display {
  font-family: var(--p-font-display);
  font-weight: var(--p-weight-semibold);
  line-height: var(--p-leading-tight);
  letter-spacing: var(--p-tracking-display);
  text-wrap: balance;
}

.display--1 {
  font-size: clamp(var(--p-size-3xl), 9vw, var(--p-size-5xl));
  letter-spacing: var(--p-tracking-display-tight);
  font-weight: var(--p-weight-bold);
}
.display--2 {
  font-size: clamp(var(--p-size-2xl), 6vw, var(--p-size-4xl));
  letter-spacing: var(--p-tracking-display-tight);
  font-weight: var(--p-weight-bold);
}
.display--3 { font-size: clamp(var(--p-size-xl), 4vw, var(--p-size-3xl)); }
.display--4 {
  font-size: clamp(var(--p-size-lg), 3vw, var(--p-size-2xl));
  line-height: var(--p-leading-snug);
}

/* Ruby's voice, and only her voice. The serif never sets a heading. */
.display em,
.voice {
  font-family: var(--p-font-voice);
  font-weight: var(--p-weight-regular);
  font-style: italic;
  letter-spacing: var(--p-tracking-voice);
}

.lead {
  font-size: var(--p-size-lg);
  line-height: var(--p-leading-normal);
  color: var(--text-secondary);
  max-width: var(--p-measure-tight);
}

/* The key. Every plate has one: small, tracked caps naming what you are
   looking at. This is the system's connective tissue. */
.key {
  font-family: var(--p-font-text);
  font-size: var(--p-size-2xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  text-transform: uppercase;
  line-height: var(--p-leading-normal);
  color: var(--text-secondary);
}

.key--action { color: var(--accent); }
.key--marked { color: var(--marker); }
.key--annotate { color: var(--accent); }
/* Warm accent. Ground-side only: 4.96:1 there, but 3.99:1 on a white plate. */
.key--warm { color: var(--accent-warm); }
.key--on-plate { color: var(--text-on-plate-secondary); }

/* Figure numbers. Tracked open like a key, not a UI counter. */
.figure-no {
  font-family: var(--p-font-display);
  font-size: var(--p-size-3xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--accent-warm);
  /* A figure number is one token. "PLATE I" breaking across two lines reads
     as two labels. */
  white-space: nowrap;
}

/* On a lifted plate the ground-calibrated muted stop drops to 3.8:1.
   Anything muted re-resolves against the surface it actually sits on. */
.plate .caption { color: var(--text-on-plate-muted); }

.caption {
  font-size: var(--p-size-2xs);
  line-height: var(--p-leading-normal);
  color: var(--text-muted);
  letter-spacing: 0.01em;
}

/* ==========================================================================
   RULE
   The hairline is structural. Three weights, and the ruled field.
   ========================================================================== */

.rule {
  border: 0;
  border-block-start: var(--p-line-hair) solid var(--rule-hair);
  margin: 0;
}

.rule--strong { border-block-start-color: var(--rule-hair-strong); }
.rule--heavy { border-block-start-width: var(--p-line-thin); border-block-start-color: var(--rule-hair-strong); }
.rule--on-plate { border-block-start-color: var(--rule-on-plate); }

/* A ruled field: the engraver's hatching, at true density. */
.ruled-field {
  --ruled-gap: 6px;
  background-image: repeating-linear-gradient(
    to bottom,
    var(--rule-hair) 0,
    var(--rule-hair) var(--p-line-hair),
    transparent var(--p-line-hair),
    transparent var(--ruled-gap)
  );
}

.ruled-field--on-plate {
  background-image: repeating-linear-gradient(
    to bottom,
    var(--rule-on-plate) 0,
    var(--rule-on-plate) var(--p-line-hair),
    transparent var(--p-line-hair),
    transparent var(--ruled-gap)
  );
}

/* ==========================================================================
   PLATE
   The signature object, and the black-and-white move: the plate inverts to
   white against the black ground.

   Because the surface flips, every value token flips with it. Anything
   nested inside a plate reads the same semantic names and resolves to the
   opposite pole automatically — no component needs an on-plate variant.
   ========================================================================== */

.plate {
  --plate-pad: var(--p-space-5);
  --plate-bg: var(--surface-plate);
  --surface-raised: var(--p-n-050);   /* the white plate's own lift */
  --plate-mark-inset: var(--p-space-2);

  /* The pole flip. */
  --accent: var(--p-n-950);
  --accent-hover: var(--p-black);
  --accent-fill: var(--p-n-950);
  --accent-fill-hover: var(--p-n-800);
  --accent-fill-press: var(--p-n-700);
  --accent-quiet: rgba(0, 0, 0, 0.06);
  --marker: var(--p-n-950);
  --marker-quiet: rgba(0, 0, 0, 0.06);
  --text-inverse: var(--p-white);
  --focus-ring: var(--p-n-950);
  --rule-hair: rgba(0, 0, 0, 0.16);
  --rule-hair-strong: rgba(0, 0, 0, 0.38);
  --text-primary: var(--text-on-plate);
  --text-secondary: var(--text-on-plate-secondary);
  --text-muted: var(--text-on-plate-muted);
  --status-error: var(--p-n-950);
  /* The warm accent flips too: olive is 4.96:1 on the ground but only
     3.99:1 here, so the white plate takes the derived taupe instead. */
  --accent-warm: var(--p-taupe-700);   /* 6.68:1 on white */
  --text-warm: var(--p-taupe-700);
  --rule-warm: rgba(0, 0, 0, 0.35);

  position: relative;
  background-color: var(--plate-bg);
  color: var(--text-on-plate);
  padding: var(--plate-pad);
  border-radius: var(--p-radius-none);
  box-shadow: var(--impression-md);
  isolation: isolate;
}

/* The plate mark: the debossed rectangle the copperplate presses into the
   sheet, always inset from the paper's edge. */
.plate::before {
  content: "";
  position: absolute;
  inset: var(--plate-mark-inset);
  border: var(--p-line-hair) solid var(--rule-on-plate-strong);
  pointer-events: none;
  z-index: -1;
}

.plate--bright { --plate-bg: var(--surface-plate-bright); }
.plate--shade { --plate-bg: var(--surface-plate-shade); }
.plate--sheet, .plate--slate { box-shadow: var(--impression-md); }
.plate--flush { --plate-pad: var(--p-space-4); --plate-mark-inset: var(--p-space-2); }
.plate--generous { --plate-pad: var(--p-space-6); --plate-mark-inset: var(--p-space-3); }

/* Plate padding is a proportion of the sheet, not a fixed inset. At 400px a
   4rem pad plus a 1.5rem plate mark leaves a measure too narrow to set type in. */
@media (min-width: 48rem) {
  .plate { --plate-pad: var(--p-space-6); --plate-mark-inset: var(--p-space-3); }
  .plate--generous { --plate-pad: var(--p-space-8); --plate-mark-inset: var(--p-space-5); }
}

/* And the same principle at the other end: below 26rem there is no such thing
   as a generous plate, because the sheet is not big enough to be generous
   with. At a 320px viewport the container is 272px, so a 2rem pad each side
   leaves 208px — and `.tag` is nowrap by design, so a long one like "+ ONE
   MONTH OF SUPPORT" needs 218px and cannot give any of it back. Grid then
   refuses to shrink the item below its min-content and the whole document
   goes 18px wide. Both plate steps collapse to 1rem here, which leaves 240px
   and puts the distinction back at 26rem where there is room for it. */
@media (max-width: 25.99rem) {
  .plate { --plate-pad: var(--p-space-4); --plate-mark-inset: var(--p-space-2); }
  .plate--generous { --plate-pad: var(--p-space-4); --plate-mark-inset: var(--p-space-2); }
}

/* --- Brand surfaces -------------------------------------------------------
   Two plate variants in the secondary palette. Both set their own pole, the
   same way .plate and .plate--proof do, so nested components keep working
   without variants. */

/* Slate. A middle surface between the black ground and the white plate —
   the one place a panel can sit without going all the way to paper. */
.plate--slate {
  --plate-bg: var(--surface-slate);
  --surface-raised: var(--surface-raised-slate);
  --accent: var(--p-white);
  --accent-hover: var(--p-white);
  --accent-fill: var(--p-white);
  --accent-fill-hover: var(--p-n-100);
  --accent-fill-press: var(--p-n-200);
  --accent-quiet: rgba(255, 255, 255, 0.1);
  --marker: var(--p-white);
  --marker-quiet: rgba(255, 255, 255, 0.08);
  --text-inverse: var(--p-slate-700);
  --focus-ring: var(--p-white);
  --rule-hair: rgba(255, 255, 255, 0.18);
  --rule-hair-strong: rgba(255, 255, 255, 0.38);
  --rule-on-plate: rgba(255, 255, 255, 0.18);
  --rule-on-plate-strong: rgba(255, 255, 255, 0.38);
  --text-primary: var(--p-white);        /* 12.40:1 on slate */
  --text-secondary: var(--p-n-200);      /*  8.36:1 on slate (measured) */
  --text-muted: var(--p-n-300);          /*  5.72:1 on slate (measured) */
  --text-on-plate: var(--p-white);
  --text-on-plate-secondary: var(--p-n-200);
  --text-on-plate-muted: var(--p-n-300);
  --status-error: var(--p-white);
  /* Olive collapses to 3.11:1 on slate; sand holds at 9.39:1. */
  --accent-warm: var(--p-sand-100);
  --text-warm: var(--p-sand-100);
  --rule-warm: rgba(231, 223, 212, 0.45);

  color: var(--p-white);
}

/* Sheet. The warm pole. Near-black on it measures 14.99:1, and the readable
   taupe carries secondary text at 5.06:1 — note that is taupe-700, not the
   taupe used for rules, which only reaches 4.04:1 here. */
.plate--sheet {
  --plate-bg: var(--surface-sheet);
  --surface-raised: var(--surface-raised-sheet);
  --accent: var(--p-n-950);
  --accent-fill: var(--p-n-950);
  --accent-fill-hover: var(--p-n-800);
  --accent-fill-press: var(--p-n-700);
  --accent-quiet: rgba(0, 0, 0, 0.06);
  --marker: var(--p-n-950);
  --marker-quiet: rgba(0, 0, 0, 0.06);
  --text-inverse: var(--p-sand-100);
  --focus-ring: var(--p-n-950);
  --rule-hair: rgba(44, 54, 57, 0.2);
  --rule-hair-strong: rgba(44, 54, 57, 0.45);
  --rule-on-plate: rgba(44, 54, 57, 0.2);
  --rule-on-plate-strong: rgba(44, 54, 57, 0.45);
  --text-primary: var(--p-n-950);              /* 14.99:1 on sheet */
  --text-secondary: var(--p-taupe-700);        /*  5.06:1 on sheet */
  --text-muted: var(--p-taupe-700);            /*  5.06:1 — no third stop clears AA here */
  --text-on-plate: var(--p-n-950);
  --text-on-plate-secondary: var(--p-taupe-700);
  --text-on-plate-muted: var(--p-taupe-700);
  --status-error: var(--p-n-950);
  --accent-warm: var(--p-taupe-700);   /* 5.06:1 on sheet */
  --text-warm: var(--p-taupe-700);
  --rule-warm: rgba(44, 54, 57, 0.35);

  color: var(--p-n-950);
}

/* A plate ruled directly onto the black ground, holding no paper: the
   engraved line alone. Used where a white field would blow a hole in a dense
   passage. It stays on the dark pole, so it undoes the flip above. */
.plate--proof {
  --plate-bg: transparent;
  --accent-warm: var(--p-olive-500);
  --text-warm: var(--p-sand-100);
  --accent: var(--p-white);
  --accent-hover: var(--p-white);
  --accent-fill: var(--p-white);
  --accent-fill-hover: var(--p-n-100);
  --accent-fill-press: var(--p-n-200);
  --accent-quiet: rgba(255, 255, 255, 0.1);
  --marker: var(--p-white);
  --marker-quiet: rgba(255, 255, 255, 0.08);
  --text-inverse: var(--p-n-950);
  --focus-ring: var(--p-white);
  --rule-hair: rgba(255, 255, 255, 0.16);
  --rule-hair-strong: rgba(255, 255, 255, 0.34);
  --text-primary: var(--p-white);
  --text-secondary: var(--p-n-300);
  --text-muted: var(--p-n-400);
  --status-error: var(--p-white);

  color: var(--p-white);
  box-shadow: none;
  border: var(--p-line-hair) solid var(--rule-hair-strong);
}

.plate--proof::before { border-color: var(--rule-hair); }

.plate--proof .plate__caption,
.plate--proof .figure-no,
.plate--proof .caption { color: var(--p-n-400); }

.plate__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--p-space-2) var(--p-space-4);
  padding-block-end: var(--p-space-3);
  border-block-end: var(--p-line-hair) solid var(--rule-on-plate);
  margin-block-end: var(--p-space-5);
}

.plate--proof .plate__head { border-block-end-color: var(--rule-hair); }

.plate__caption {
  margin-block-start: var(--p-space-5);
  padding-block-start: var(--p-space-3);
  border-block-start: var(--p-line-hair) solid var(--rule-on-plate);
  font-size: var(--p-size-2xs);
  line-height: var(--p-leading-normal);
  color: var(--text-on-plate-muted);
}

.plate--proof .plate__caption {
  border-block-start-color: var(--rule-hair);
  color: var(--text-muted);
}

/* ==========================================================================
   CALLOUT
   The signature interaction. A hairline leader runs from a label to the
   thing it names, and draws itself when the plate comes into view.
   ========================================================================== */

.callout {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--p-space-3);
}

.callout__leader {
  position: relative;
  block-size: var(--p-line-hair);
  min-inline-size: var(--p-space-7);
  background-color: currentColor;
  opacity: 0.5;
  transform-origin: left center;
}

/* The draw is the build's one authored motion moment, and it sits ~2,000px
   down the page. Running it on load meant it completed before anyone could
   reach it — it existed in the stylesheet and never in the experience. It is
   now driven by entry, and only when scripting is available: without JS the
   leaders render drawn rather than invisible. */
.js .callout__leader {
  transform: scaleX(0);
  transition: transform var(--p-dur-draw) var(--p-ease-ink);
}

.js .callout__leader[data-drawn] { transform: scaleX(1); }

/* The leader terminates in a dot, the way an engraved callout does. */
.callout__leader::after {
  content: "";
  position: absolute;
  inset-inline-end: 0;
  inset-block-start: 50%;
  inline-size: 4px;
  block-size: 4px;
  border-radius: 50%;
  background-color: currentColor;
  transform: translate(50%, -50%);
}

.callout--reverse { grid-template-columns: 1fr auto; }
.callout--reverse .callout__leader { transform-origin: right center; }
.callout--reverse .callout__leader::after {
  inset-inline-end: auto;
  inset-inline-start: 0;
  transform: translate(-50%, -50%);
}

/* ==========================================================================
   NAV
   ========================================================================== */

.nav {
  position: sticky;
  inset-block-start: 0;
  z-index: 50;
  background-color: color-mix(in srgb, var(--surface-base) 88%, transparent);
  backdrop-filter: blur(12px);
  border-block-end: var(--p-line-hair) solid var(--rule-hair);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--p-space-4);
  min-block-size: 4rem;
}

.nav__mark {
  font-family: var(--p-font-voice);
  font-style: italic;
  font-size: var(--p-size-lg);
  letter-spacing: var(--p-tracking-voice);
  color: var(--text-primary);
  text-decoration: none;
  white-space: nowrap;
  flex: none;
}

/* The nav carries seven items on the real site. Below the breakpoint the list
   scrolls horizontally rather than clipping or wrapping into the mark —
   scrollbar hidden, because the overflow is the affordance, not the bar. */
.nav__inner > nav { min-inline-size: 0; }

.nav__list {
  display: flex;
  align-items: center;
  gap: var(--p-space-4);
  list-style: none;
  min-inline-size: 0;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* Keep the drawn underline from being clipped by the scroll container. */
  padding-block-end: var(--p-line-medium);
}

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

.nav__link {
  position: relative;
  display: inline-block;
  white-space: nowrap;
  padding-block: var(--p-space-2);
  font-size: var(--p-size-3xs);
  font-weight: var(--p-weight-medium);
  letter-spacing: var(--p-tracking-wide);
  text-transform: uppercase;
  color: var(--text-secondary);
  text-decoration: none;
  transition: color var(--p-dur-fast) var(--p-ease-ink);
}

/* The underline is a ruled leader, drawn on approach — not a generic
   hover underline. */
.nav__link::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: var(--p-line-thin);
  background-color: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--p-dur-base) var(--p-ease-press);
}

.nav__link:hover { color: var(--text-primary); }
.nav__link:hover::after,
.nav__link[aria-current]::after { transform: scaleX(1); }
.nav__link[aria-current] { color: var(--text-primary); }

/* Mobile disclosure. The horizontally scrolling strip that preceded this
   hid Contact — the stated primary conversion — behind an invisible scroll
   with no affordance at all. A menu that cannot be seen is not navigation. */
.nav__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--p-space-3);
  min-block-size: 2.75rem;
  padding-inline: var(--p-space-3);
  background: transparent;
  border: var(--p-line-thin) solid var(--rule-hair-strong);
  color: var(--text-primary);
  font-size: var(--p-size-3xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  text-transform: uppercase;
  cursor: pointer;
}

.nav__toggle-bars { display: grid; gap: 4px; inline-size: 1rem; }
.nav__toggle-bars i {
  display: block;
  block-size: var(--p-line-thin);
  background: currentColor;
  transition: transform var(--p-dur-fast) var(--p-ease-ink);
}
.nav__toggle[aria-expanded="true"] .nav__toggle-bars i:first-child { transform: translateY(2.5px) rotate(20deg); }
.nav__toggle[aria-expanded="true"] .nav__toggle-bars i:last-child  { transform: translateY(-2.5px) rotate(-20deg); }

/* --- NAV GROUP -----------------------------------------------------------
   A nav item that is a SET rather than a page. "Retreats" covers two
   offerings, and putting both in the row would make it six items — the row
   fits five with 143px spare at 1000px, and the disclosure breakpoint is
   measured against that count. A group costs the row a caret instead.

   The trigger is a <button>, not a link, because it goes nowhere: both
   destinations are inside it. With JavaScript off the submenu is not
   reachable from the header, which is why every page's footer lists both
   retreats — that is the no-JS path and it was there before this. */
/* "Retreats" is a set, and the WHOLE LABEL opens it — client instruction,
   5 Sep 2026, after a version where only a caret beside the link did. A target
   the size of one glyph is a target people miss, and the two destinations
   inside are the only things this item was ever for.

   It is a <button>, not a link with its click intercepted: a control announced
   as a link and behaving as a disclosure lies to a screen reader. The cost is
   that Retreats no longer navigates and, with JavaScript off, the group cannot
   be opened from the header — which is survivable only because every page's
   footer lists both retreats by name. */
.nav__group {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

.nav__disclose {
  display: inline-flex;
  align-items: center;
  gap: var(--p-space-2);
  padding-inline: 0;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: inherit;
}

/* Drawn, not fetched. It rotates rather than swapping glyphs so the control
   reads as one thing in two states. */
.nav__caret {
  flex: none;
  inline-size: 0;
  block-size: 0;
  border-inline: 0.26rem solid transparent;
  border-block-start: 0.3rem solid currentColor;
  transition: transform var(--p-dur-fast) var(--p-ease-ink);
}
.nav__disclose[aria-expanded="true"] .nav__caret { transform: rotate(180deg); }

/* flex-basis so the open submenu takes its own line inside the mobile panel;
   on the desktop row it is absolutely positioned and this does nothing. */
.nav__sub { flex-basis: 100%; list-style: none; display: none; }
.nav__sub[data-open] { display: block; }

.nav__sublink {
  position: relative;
  display: block;
  white-space: nowrap;
  padding-block: var(--p-space-2);
  font-size: var(--p-size-3xs);
  font-weight: var(--p-weight-medium);
  letter-spacing: var(--p-tracking-wide);
  text-transform: uppercase;
  color: var(--text-secondary);
  text-decoration: none;
  transition: color var(--p-dur-fast) var(--p-ease-ink);
}
.nav__sublink:hover,
.nav__sublink[aria-current] { color: var(--text-primary); }

/* Inside the mobile panel the submenu is a nested indent on the same rules as
   the rest of the list, not a floating card. */
.nav__menu[data-open] .nav__sub[data-open] { padding-inline-start: var(--p-space-5); }
.nav__menu[data-open] .nav__sublink {
  padding-block: var(--p-space-4);
  font-size: var(--p-size-xs);
  border-block-end: var(--p-line-hair) solid var(--rule-hair);
}
/* In the panel the control spans the row and pushes its caret to the far edge,
   so the whole width of the row is the target. */
.nav__menu[data-open] .nav__disclose { inline-size: 100%; justify-content: space-between; }

.nav__menu { display: none; }
.nav__menu[data-open] {
  display: block;
  position: absolute;
  inset-inline: 0;
  inset-block-start: 100%;
  padding: var(--p-space-5) var(--gutter) var(--p-space-6);
  background: var(--surface-sunken);
  border-block-end: var(--p-line-thin) solid var(--rule-warm);
}
.nav__menu[data-open] .nav__list { flex-direction: column; align-items: stretch; gap: 0; overflow: visible; }
.nav__menu[data-open] .nav__link {
  display: block;
  padding-block: var(--p-space-4);
  font-size: var(--p-size-xs);
  border-block-end: var(--p-line-hair) solid var(--rule-hair);
}
.nav__menu[data-open] .nav__cta { display: inline-flex; margin-block-start: var(--p-space-5); }
.nav__cta { display: none; }
/* The label sets on one line everywhere else on the page; inside the flex row
   it was being squeezed into two and became the tallest object in the bar. */
.nav__cta { white-space: nowrap; flex: none; }

.nav { position: sticky; }
.nav__inner { position: relative; }

/* 64rem, not 48. The disclosure holds until the row genuinely fits, and the
   fit point moves with the item count. At seven links it was 69rem: the links
   overflowed their own list below that and the CTA painted straight over them
   — at 784px, 282px of "Contact", "Free Training" and "Community" sat
   underneath it, and document width never changed, so an overflow check could
   not see it. At five links the row needs 881px and comes clean at 1000px, so
   the threshold drops to the site's own desktop breakpoint with 143px spare.
   Re-measure this number whenever a nav item is added or removed.

   RE-MEASURED 5 Sep 2026, twice in one day. "Client Praise" took the row to
   six links and 598px, which does not come clean until 1180 — at 1024 the list
   was CLIPPED BY 104px and "Contact" sat underneath the CTA, the exact failure
   described above and invisible to a document-overflow check because
   .nav__list scrolls inside itself. Then "Book" became "The Book" and the CTA
   became "Remembrance Retreat", taking the row to 631px and the fit point to
   1240. The threshold is 80rem, which clears it by 40px.

   THE ROW IS AT ITS PRACTICAL LIMIT. Six links, a group caret and a
   nineteen-character CTA. Anything longer pushes the hamburger past the width
   of a common laptop, and the next addition should replace something rather
   than join it. */
@media (min-width: 80rem) {
  .nav__toggle { display: none; }
  /* flex, not block: as a block the wrapper stacked the CTA beneath the link
     row and made the header two rows tall, misplacing the primary conversion. */
  .nav__menu { display: flex; align-items: center; gap: var(--p-space-5); }
  .nav__list { flex-wrap: nowrap; }
  .nav__cta { display: inline-flex; }
  .nav__inner { min-block-size: 4.5rem; gap: var(--p-space-5); }
  .nav__mark { font-size: var(--p-size-lg); }
  .nav__list { gap: var(--p-space-5); overflow-x: visible; }
  .nav__link { font-size: var(--p-size-xs); }

  /* On the row, the submenu hangs off its own item as a plate. The nav is
     sticky at z-index 50, so the panel has to clear it. */
  .nav__sub[data-open] {
    position: absolute;
    inset-block-start: calc(100% + var(--p-space-3));
    inset-inline-start: calc(var(--p-space-4) * -1);
    z-index: 60;
    min-inline-size: 14rem;
    padding: var(--p-space-3) var(--p-space-4);
    background-color: var(--surface-sunken);
    border: var(--p-line-hair) solid var(--rule-hair);
    border-block-start: var(--p-line-thin) solid var(--rule-warm);
    box-shadow: var(--impression-md);
  }
  .nav__sub[data-open] li + li { border-block-start: var(--p-line-hair) solid var(--rule-hair); }
  .nav__sublink { padding-block: var(--p-space-3); font-size: var(--p-size-xs); }

}

/* ==========================================================================
   BUTTON
   Rebuilt in the plate's vocabulary: a pressed rectangle with a debossed
   mark, never a rounded pill.
   ========================================================================== */

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text-primary);
  --btn-line: var(--rule-hair-strong);

  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--p-space-3);
  min-block-size: 3rem;
  padding-inline: var(--p-space-6);
  padding-block: var(--p-space-3);
  border: var(--p-line-thin) solid var(--btn-line);
  border-radius: var(--p-radius-none);
  background-color: var(--btn-bg);
  color: var(--btn-fg);
  font-size: var(--p-size-xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--p-dur-fast) var(--p-ease-ink),
    border-color var(--p-dur-fast) var(--p-ease-ink),
    color var(--p-dur-fast) var(--p-ease-ink),
    transform var(--p-dur-instant) var(--p-ease-press);
}

/* The inner plate mark, so a button is unmistakably part of this world. */
.btn::before {
  content: "";
  position: absolute;
  inset: 3px;
  border: var(--p-line-hair) solid currentColor;
  opacity: 0.28;
  pointer-events: none;
}

/* The press. A plate meets paper: it travels down, it does not bounce. */
.btn:active { transform: translateY(1px); }

.btn--primary {
  --btn-bg: var(--accent-fill);
  --btn-fg: var(--text-inverse);
  --btn-line: var(--accent-fill);
}
.btn--primary:hover {
  --btn-bg: var(--accent-fill-hover);
  --btn-line: var(--accent-fill-hover);
}
.btn--primary:active {
  --btn-bg: var(--accent-fill-press);
  --btn-line: var(--accent-fill-press);
}

.btn--secondary { --btn-line: var(--rule-hair-strong); }
.btn--secondary:hover {
  --btn-bg: var(--surface-raised);
  --btn-line: var(--text-secondary);
}

.btn--on-plate {
  --btn-fg: var(--text-on-plate);
  --btn-line: var(--rule-on-plate-strong);
}
.btn--on-plate:hover { --btn-bg: var(--marker-quiet); }

/* Tertiary: a ruled link with a leader that extends on hover. */
.btn--quiet {
  /* 2.75rem, not auto. This variant drops the border and the background so it
     reads as a text CTA — but with padding zeroed its hit area was the height
     of the type itself, 21px, against the 24px WCAG 2.2 target minimum and a
     long way under a comfortable thumb. The box grows; nothing about it looks
     any different, because there is no border or fill to grow with it. */
  min-block-size: 2.75rem;
  padding: 0;
  border: 0;
  --btn-fg: var(--accent);
  letter-spacing: var(--p-tracking-wide);
}
.btn--quiet::before { display: none; }
.btn--quiet::after {
  content: "";
  inline-size: var(--p-space-5);
  block-size: var(--p-line-thin);
  background-color: currentColor;
  transition: inline-size var(--p-dur-base) var(--p-ease-press);
}
.btn--quiet:hover::after { inline-size: var(--p-space-7); }
.btn--quiet:active { transform: none; }

.btn[disabled],
.btn[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
}

/* ==========================================================================
   SECTION HEAD
   Every section is a numbered plate in the volume.
   ========================================================================== */

/* Section rhythm scales with the viewport. A 12rem band that reads as
   composed silence at 1440 reads as a loading failure at 400. */
.section { padding-block: var(--p-space-8); }
.section--tight { padding-block: var(--p-space-7); }
.section--vast { padding-block: var(--p-space-9); }

@media (min-width: 48rem) {
  .section { padding-block: var(--p-space-9); }
  .section--tight { padding-block: var(--p-space-8); }
  .section--vast { padding-block: var(--p-space-10); }
}

@media (min-width: 75rem) {
  .section--vast { padding-block: var(--p-space-11); }
}


.section__head {
  display: flex;
  align-items: baseline;
  gap: var(--p-space-4);
  padding-block-end: var(--p-space-4);
  /* The heavy structural rule is the one place a warm line reads at page
     scale. 3.71:1 on the ground clears the 3:1 floor for a non-text boundary. */
  border-block-end: var(--p-line-thin) solid var(--rule-warm);
  margin-block-end: var(--p-space-7);
}

.section__head .figure-no { flex: none; }
.section__head .rule { flex: 1; }

/* ==========================================================================
   OFFERING
   The nine offerings, each a numbered figure on the plate.
   ========================================================================== */

.offering {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--p-space-4) var(--p-space-5);
  padding-block: var(--p-space-5);
  border-block-end: var(--p-line-hair) solid var(--rule-hair);
  transition: background-color var(--p-dur-fast) var(--p-ease-ink);
}

.offering:hover { background-color: var(--surface-raised); }

.offering__no {
  font-family: var(--p-font-display);
  font-size: var(--p-size-xl);
  line-height: 1;
  color: var(--accent-warm);
  font-variant-numeric: lining-nums tabular-nums;
}

.offering__body { min-inline-size: 0; }

.offering__title {
  font-family: var(--p-font-display);
  font-size: var(--p-size-xl);
  line-height: var(--p-leading-snug);
  color: var(--text-primary);
}

/* The offering's own line — "For leaders seeking deep and lasting
   transformation." It is a subtitle, not a tag and not the description: it
   states who the offering is for in one sentence, and it reads at lead scale
   because it is the thing scanned before the paragraph beneath it. */
.offering__tagline {
  margin-block-start: var(--p-space-2);
  font-size: var(--p-size-lg);
  line-height: var(--p-leading-normal);
  color: var(--text-warm);
  max-width: 52ch;
  /* One sentence that mostly fits one line. `pretty` rather than `balance`:
     when it does wrap, the failure to avoid is the single word left alone on
     line two, not uneven line lengths. */
  text-wrap: pretty;
}

.offering__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--p-space-2) var(--p-space-4);
  margin-block-start: var(--p-space-2);
}

.offering__desc {
  margin-block-start: var(--p-space-3);
  color: var(--text-secondary);
  max-width: var(--p-measure);
}

.offering__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--p-space-5);
  margin-block-start: var(--p-space-4);
}

/* ==========================================================================
   TAG
   ========================================================================== */

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--p-space-2);
  padding-inline: var(--p-space-3);
  padding-block: var(--p-space-1);
  border: var(--p-line-hair) solid var(--rule-hair-strong);
  font-size: var(--p-size-3xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  text-transform: uppercase;
  color: var(--text-secondary);
  white-space: nowrap;
}

.tag--marked {
  border-color: var(--marker);
  color: var(--marker);
  background-color: var(--marker-quiet);
}

.tag--warm {
  border-color: var(--accent-warm);
  color: var(--accent-warm);
}

.tag--action {
  border-color: var(--accent);
  color: var(--accent);
  background-color: var(--accent-quiet);
}

/* ==========================================================================
   TESTIMONIAL
   ========================================================================== */

.testimonial {
  display: flex;
  flex-direction: column;
  gap: var(--p-space-5);
  block-size: 100%;
}

.testimonial__quote {
  font-family: var(--p-font-voice);
  /* Sized for the real quotes, which run 26-36 words, not the one-liners this
     component was first built against. At 26px a card this width gave a 24
     character measure and nine-line columns; 20px buys back roughly a third of
     the line and keeps the voice serif at quote scale. */
  font-size: var(--p-size-lg);
  font-style: italic;
  line-height: var(--p-leading-normal);
  letter-spacing: var(--p-tracking-voice);
  color: var(--text-on-plate);
  text-wrap: pretty;
}

/* Engraved quotation: the mark hangs outside the measure, as it would be
   set on a plate. */
.testimonial__quote::before {
  content: "\201C";
  float: left;
  margin-inline-start: -0.42em;
  font-size: 1.6em;
  line-height: 0.85;
  color: var(--accent-fill);
}

.testimonial__attr {
  margin-block-start: auto;
  padding-block-start: var(--p-space-4);
  border-block-start: var(--p-line-hair) solid var(--rule-on-plate);
}

.testimonial__name {
  display: block;
  font-weight: var(--p-weight-semibold);
  font-size: var(--p-size-sm);
  color: var(--text-on-plate);
}

.testimonial__role {
  display: block;
  font-size: var(--p-size-2xs);
  letter-spacing: var(--p-tracking-wide);
  text-transform: uppercase;
  color: var(--text-on-plate-muted);
  margin-block-start: var(--p-space-1);
}

/* ==========================================================================
   PULL QUOTE
   ========================================================================== */

.pullquote {
  /* A <blockquote> arrives with a 40px UA inline margin, so every pull quote on
     this site has been sitting 40px inside its column's left edge — with a
     warm rule drawn down that false edge, which is the one place the offset is
     impossible to miss once seen. The rule IS the left edge; it has to start
     where the text above it starts. Reset here rather than per page: four
     pages use this object and all four had it. */
  margin-inline: 0;
  border-inline-start: var(--p-line-medium) solid var(--rule-warm);
  padding-inline-start: var(--p-space-6);
  font-family: var(--p-font-voice);
  font-style: italic;
  font-size: clamp(var(--p-size-2xl), 5vw, var(--p-size-4xl));
  line-height: var(--p-leading-snug);
  letter-spacing: var(--p-tracking-voice);
  color: var(--text-primary);
  text-wrap: balance;
}

.pullquote__attr {
  display: block;
  margin-block-start: var(--p-space-5);
  font-family: var(--p-font-text);
  font-style: normal;
  font-size: var(--p-size-2xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ==========================================================================
   DATELINE
   The strip under the nav on a page that is an EVENT: what it is, when, and
   who it is for, in three keys on one hairline. Shared by the two retreat
   pages, which is why it lives here rather than in either of them.
   ========================================================================== */

.dateline { border-block-end: var(--p-line-hair) solid var(--rule-hair); }

.dateline__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--p-space-2) var(--p-space-5);
  padding-block: var(--p-space-4);
}

/* The last item pushes right once there is a row to push across. */
@media (min-width: 48rem) {
  .dateline__inner > :last-child { margin-inline-start: auto; }
}

/* ==========================================================================
   INCLUDED
   What an offering contains, as a ruled two-column list. Each item is one
   line of a manifest, not a sentence, so the marker is a warm rule rather
   than a bullet and the rows are separated rather than spaced.
   ========================================================================== */

.included { list-style: none; margin-block-start: var(--p-space-6); }

@media (min-width: 48rem) {
  .included { columns: 2; column-gap: var(--p-space-8); }
  .included li { break-inside: avoid; }
}

.included li {
  display: grid;
  grid-template-columns: var(--p-space-4) minmax(0, 1fr);
  gap: var(--p-space-4);
  align-items: baseline;
  padding-block: var(--p-space-4);
  border-block-start: var(--p-line-hair) solid var(--rule-hair);
  color: var(--text-secondary);
}

/* Baseline alignment has nothing to sit on inside an empty box, so the rule is
   nudged onto the cap line of the type beside it. */
.included li::before {
  content: "";
  block-size: var(--p-line-thin);
  background-color: var(--accent-warm);
  transform: translateY(-0.35em);
}

/* ==========================================================================
   PRICE TIER
   Equìa publishes three tiers. They are set as a rate table, the way a
   plate would carry one.
   ========================================================================== */

.tiers {
  display: grid;
  gap: var(--p-line-thin);
  background-color: var(--rule-warm);
  border: var(--p-line-thin) solid var(--rule-warm);
}

@media (min-width: 40rem) {
  .tiers { grid-template-columns: repeat(3, 1fr); }
}

.tier {
  background-color: var(--surface-sheet);
  color: var(--p-n-950);
  padding: var(--p-space-5);
  display: flex;
  flex-direction: column;
  gap: var(--p-space-2);
}

.tier__label {
  font-size: var(--p-size-3xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  text-transform: uppercase;
  color: var(--p-taupe-700);   /* 5.06:1 on sheet */
}

.tier__rate {
  font-family: var(--p-font-display);
  font-size: var(--p-size-2xl);
  line-height: 1;
  color: var(--p-n-950);
  font-variant-numeric: lining-nums tabular-nums;
}

.tier__note {
  font-size: var(--p-size-2xs);
  color: var(--p-taupe-700);
}

/* ==========================================================================
   FIELD
   Inputs rebuilt as ruled entry lines, not boxes. A ledger is filled on a
   rule, and a box here would be a stock component in a committed form.
   ========================================================================== */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--p-space-2);
}

.field__label {
  font-size: var(--p-size-3xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.field__control {
  inline-size: 100%;
  padding-block: var(--p-space-3);
  padding-inline: 0;
  background-color: transparent;
  border: 0;
  border-block-end: var(--p-line-thin) solid var(--rule-hair-strong);
  border-radius: var(--p-radius-none);
  color: var(--text-primary);
  font-size: var(--p-size-md);
  transition: border-color var(--p-dur-fast) var(--p-ease-ink);
}

.field__control::placeholder { color: var(--text-muted); }

.field__control:hover { border-block-end-color: var(--text-secondary); }

/* The ruled line thickens and tints on focus, and the chrome focus ring is
   kept on top of it — the tint alone is a colour-only signal. */
.field__control:focus-visible {
  border-block-end-color: var(--accent);
  border-block-end-width: var(--p-line-medium);
}

.field:focus-within .field__label { color: var(--accent); }

textarea.field__control {
  min-block-size: 7rem;
  resize: vertical;
  border: var(--p-line-thin) solid var(--rule-hair-strong);
  padding-inline: var(--p-space-4);
}

.field__hint {
  font-size: var(--p-size-2xs);
  color: var(--text-muted);
}

.field__error {
  font-size: var(--p-size-2xs);
  color: var(--status-error);
}

.field[data-invalid="true"] .field__control {
  border-block-end-color: var(--status-error);
}

/* ==========================================================================
   CREED
   A list of short declarative statements, each on its own rule behind a warm
   tick. Not a bullet list and not a register: a register is a row of fields
   about a thing, a creed is a sequence of sentences that each stand alone.

   /remembrance sets the reader's own habits with it ("When there's a problem,
   you solve it.") and the home page sets Ruby's five "I want you to..." lines.
   Two pages, so it lives here.

   The measure is deliberately NOT capped in the component — one page wants
   34ch beside a photograph and the other wants 52ch across a band, and that
   is composition, not the object.
   ========================================================================== */

.creed { list-style: none; }

.creed li {
  display: grid;
  grid-template-columns: var(--p-space-5) minmax(0, 1fr);
  align-items: baseline;
  gap: var(--p-space-4);
  padding-block: var(--p-space-4);
  border-block-start: var(--p-line-hair) solid var(--rule-hair);
  font-family: var(--p-font-display);
  font-size: clamp(var(--p-size-lg), 2.6vw, var(--p-size-xl));
  font-weight: var(--p-weight-semibold);
  line-height: var(--p-leading-snug);
  letter-spacing: var(--p-tracking-display);
}

/* Baseline alignment has nothing to sit on inside an empty box, so the tick is
   nudged onto the cap line of the type beside it. */
.creed li::before {
  content: "";
  block-size: var(--p-line-thin);
  background-color: var(--accent-warm);
  transform: translateY(-0.4em);
}

/* ==========================================================================
   ACCOUNT — long testimony
   A testimonial card and an account are different objects, and the difference
   is length. The card sets its quote in the voice serif at 20px italic, which
   is right for the twenty-six to thirty-six words it was measured against and
   punishing at a hundred and fifty. So testimony past roughly a hundred words
   gets an account instead: a left rail holding an 80px square avatar, a
   tabular index and the name, and beside it the words in the READING face at
   reading measure. An account carries its voice in the rail and the rule above
   it, not in italics.

   Two pages need it — /journey runs three and /praise runs the whole roll of
   nine — so it lives here rather than in either of them.

   Truncating an account is not an option. A card may carry a shortened quote,
   across contiguous sentences and stopping at a full stop; an account exists
   precisely because that shortening would destroy it.
   ========================================================================== */

.accounts { border-block-start: var(--p-line-thin) solid var(--rule-warm); }

.account {
  display: grid;
  gap: var(--p-space-5);
  padding-block: var(--p-space-7);
  border-block-end: var(--p-line-hair) solid var(--rule-hair);
}

.account__head { display: flex; align-items: center; gap: var(--p-space-4); }
.account__head .avatar { --avatar-size: 4rem; }

.account__n {
  display: block;
  font-family: var(--p-font-display);
  font-size: var(--p-size-2xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-wide);
  color: var(--accent-warm);
  font-variant-numeric: tabular-nums;
  margin-block-end: var(--p-space-1);
}

/* The name is an h3 and the body a blockquote: both arrive with UA margins
   this project's reset does not clear, so both are zeroed here. */
.account__name {
  margin: 0;
  font-family: var(--p-font-display);
  font-size: var(--p-size-lg);
  font-weight: var(--p-weight-medium);
  letter-spacing: var(--p-tracking-display);
  line-height: var(--p-leading-snug);
  color: var(--text-primary);
}

.account__role {
  display: block;
  margin-block-start: var(--p-space-2);
  font-size: var(--p-size-2xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  text-transform: uppercase;
  color: var(--text-muted);
}

.account__body { display: grid; gap: var(--p-space-4); margin: 0; max-width: var(--p-measure); color: var(--text-secondary); }
/* The opening line carries the weight, so it is set at lead scale. Nothing
   else in the account is styled — 250 words want to be left alone. */
.account__body p:first-child { font-size: var(--p-size-md); color: var(--text-primary); }

@media (min-width: 64rem) {
  .account { grid-template-columns: minmax(0, 17rem) minmax(0, 1fr); gap: var(--p-space-8); align-items: start; }
  .account__head { flex-direction: column; align-items: flex-start; gap: var(--p-space-4); }
  .account__head .avatar { --avatar-size: 5rem; }
}

/* ==========================================================================
   DISCLOSURE
   A folded row. The itinerary and the FAQ both need one, which is why it is
   here rather than in a page.

   It is a REGISTER, not an accordion: hairline-separated rows, no container,
   no gap, no background at rest, taking the pole's lift on hover — the same
   object as .offering and .episode, folded. Reaching for a bordered card with
   a chevron would be reaching outside the system twice over.

   The mark is a ruled cross drawn from two hairlines, and the vertical stroke
   scales to nothing when the row opens. A chevron is a stock affordance; a
   plus drawn in rules is the one this world already owns.

   Rows do not animate open. `details` has no native height transition, and
   the alternatives all animate a fixed max-height that either clips long
   answers or eases into empty space. An instant open is also the right
   default for an audience working with nervous-system dysregulation.
   ========================================================================== */

.disclosure {
  border-block-end: var(--p-line-hair) solid var(--rule-hair);
  transition: background-color var(--p-dur-fast) var(--p-ease-ink);
}

.disclosure:hover { background-color: var(--surface-raised); }

.disclosure__summary {
  display: flex;
  align-items: baseline;
  gap: var(--p-space-4) var(--p-space-5);
  padding-block: var(--p-space-5);
  padding-inline: var(--p-space-4);
  cursor: pointer;
  list-style: none;
}

/* Both spellings: the pseudo-element in WebKit, the display value elsewhere. */
.disclosure__summary::-webkit-details-marker { display: none; }
.disclosure__summary::marker { content: ""; }

.disclosure__summary:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: calc(var(--focus-ring-offset) * -1);
}

/* The left column: a figure number, a day numeral, a date. Optional. */
.disclosure__lead { flex: none; }

.disclosure__title {
  font-family: var(--p-font-display);
  font-size: var(--p-size-lg);
  font-weight: var(--p-weight-semibold);
  line-height: var(--p-leading-snug);
  letter-spacing: var(--p-tracking-display);
  color: var(--text-primary);
  min-inline-size: 0;
}

/* The mark. Two hairlines crossed; the upright retracts when the row opens.
   It sits on its own baseline-independent line, so align-self keeps it level
   with the first line of the title rather than with the row's last baseline. */
.disclosure__mark {
  flex: none;
  position: relative;
  align-self: center;
  margin-inline-start: auto;
  inline-size: 1.125rem;
  block-size: 1.125rem;
}

.disclosure__mark::before,
.disclosure__mark::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 0;
  inline-size: 100%;
  block-size: var(--p-line-thin);
  background-color: var(--text-secondary);
  transition:
    transform var(--p-dur-fast) var(--p-ease-press),
    background-color var(--p-dur-fast) var(--p-ease-ink);
}

.disclosure__mark::before { transform: translateY(-50%); }
.disclosure__mark::after  { transform: translateY(-50%) rotate(90deg); }

.disclosure[open] .disclosure__mark::after { transform: translateY(-50%) rotate(90deg) scaleX(0); }

.disclosure:hover .disclosure__mark::before,
.disclosure:hover .disclosure__mark::after,
.disclosure[open] .disclosure__mark::before,
.disclosure[open] .disclosure__mark::after { background-color: var(--text-primary); }

/* On a full-width register the 20px title is the only thing carrying a row
   1120px wide, and it reads as a caption. This is a size step, the way
   .plate--generous is — not a pole variant. */
.disclosure--lg .disclosure__title { font-size: clamp(var(--p-size-lg), 2.4vw, var(--p-size-xl)); }

.disclosure:hover .disclosure__title { color: var(--accent); }

.disclosure__body {
  padding-inline: var(--p-space-4);
  padding-block-end: var(--p-space-5);
  color: var(--text-secondary);
  max-width: var(--p-measure);
}

.disclosure__body > * + * { margin-block-start: var(--p-space-4); }

/* Indent the answer under the title once there is room for the two columns to
   read as columns. Below that the lead sits on its own line and an indent
   would only narrow the measure. */
@media (min-width: 48rem) {
  .disclosure--indent .disclosure__body {
    padding-inline-start: calc(var(--disclosure-indent, 6rem) + var(--p-space-5) + var(--p-space-4));
  }
}

/* ==========================================================================
   EPISODE
   The podcast index, set as a ruled register.
   ========================================================================== */

.episode {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: var(--p-space-4);
  padding-block: var(--p-space-4);
  border-block-end: var(--p-line-hair) solid var(--rule-hair);
  text-decoration: none;
  color: inherit;
  transition: background-color var(--p-dur-fast) var(--p-ease-ink);
}

.episode:hover { background-color: var(--surface-raised); }
.episode:hover .episode__title { color: var(--accent); }

.episode__no {
  font-family: var(--p-font-display);
  font-size: var(--p-size-xs);
  color: var(--accent-warm);
  font-variant-numeric: tabular-nums lining-nums;
}

.episode__title {
  font-size: var(--p-size-md);
  color: var(--text-primary);
  transition: color var(--p-dur-fast) var(--p-ease-ink);
  text-wrap: pretty;
}

.episode__meta {
  font-size: var(--p-size-2xs);
  letter-spacing: var(--p-tracking-wide);
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}

/* ==========================================================================
   FOOTER
   ========================================================================== */

.footer {
  padding-block: var(--p-space-8) var(--p-space-6);
  border-block-start: var(--p-line-thin) solid var(--rule-warm);
  background-color: var(--surface-slate);
  /* Slate footer: the warm tones flip here the same way they do on a plate. */
  --accent-warm: var(--p-sand-100);   /* 9.39:1 on slate */
  --text-warm: var(--p-sand-100);
  --text-secondary: var(--p-n-200);   /* 9.4:1 on slate */
  --text-muted: var(--p-n-300);       /* 5.7:1 on slate */
  --rule-hair: rgba(255, 255, 255, 0.18);
}

.footer__grid {
  display: grid;
  gap: var(--p-space-7);
}

@media (min-width: 48rem) {
  .footer__grid { grid-template-columns: 2fr 1fr 1fr; }
}

.footer__list { list-style: none; display: grid; gap: var(--p-space-3); }

.footer__link {
  font-size: var(--p-size-sm);
  color: var(--text-secondary);
  text-decoration: none;
  transition: color var(--p-dur-fast) var(--p-ease-ink);
}

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

.footer__base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--p-space-4);
  margin-block-start: var(--p-space-8);
  padding-block-start: var(--p-space-4);
  border-block-start: var(--p-line-hair) solid var(--rule-hair);
}

/* ==========================================================================
   GRID HELPERS
   ========================================================================== */

.grid { display: grid; gap: var(--p-space-5); }

/* Two equal reading columns, wider gutter, and no split until there is room
   for two real measures. .grid--2 breaks at 40rem, which is right for cards
   and much too early for body copy. */
.split { display: grid; gap: var(--p-space-7); }

@media (min-width: 64rem) {
  .split { grid-template-columns: 1fr 1fr; gap: var(--p-space-9); align-items: start; }
}

@media (min-width: 40rem) {
  .grid--2 { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 64rem) {
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .grid--sidebar { grid-template-columns: 2fr 1fr; gap: var(--p-space-8); }
}

.visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   SKIP LINK
   .visually-hidden never reveals itself, so a skip link wearing it is invisible
   even when focused: a keyboard user tabs onto nothing, presses Enter, and gets
   no signal that anything happened. It was that on all five pages, and it was
   also the last unstyled anchor on the site — rendering in browser-default blue
   for the split second it existed.

   No transition. A skip link should be there the instant it is focused, and
   this audience is working with nervous-system dysregulation.
   ========================================================================== */

.skip-link {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: var(--gutter);
  z-index: 100;                 /* the nav is sticky at 50 */
  transform: translateY(-200%);
  padding: var(--p-space-3) var(--p-space-5);
  background-color: var(--p-white);
  color: var(--p-n-950);         /* 19.8:1 */
  font-family: var(--p-font-display);
  font-size: var(--p-size-2xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  text-transform: uppercase;
  text-decoration: none;
}

.skip-link:focus,
.skip-link:focus-visible {
  transform: translateY(0);
  outline: var(--p-line-medium) solid var(--p-n-950);
  outline-offset: 2px;
}

/* ==========================================================================
   PHOTOGRAPHY

   The governing rule: photographs are ALWAYS in colour, and they are the only
   colour on the page. That is what the monochrome palette is for. Every
   surface stays black, white, or grey so that Ruby and the horses are the one
   place colour appears, and they carry the whole emotional load unopposed.

   There is deliberately no grayscale or duotone treatment in this system.
   Draining a photograph would remove the only colour the design has. Restraint
   comes from how OFTEN a photograph appears and at what scale — never from
   desaturating it.
   ========================================================================== */

.photo {
  --photo-ratio: 3 / 2;
  /* Focal point. `center` is a default, not an answer: cropping these
     photographs to centre puts the frame on empty sky and on the horses'
     ears, cutting Ruby out of her own portrait. Every instance sets this. */
  --photo-focus: 50% 50%;

  position: relative;
  display: block;
  aspect-ratio: var(--photo-ratio);
  overflow: hidden;
  background-color: var(--surface-raised);
  isolation: isolate;
}

.photo > img,
.photo > picture > img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: var(--photo-focus);
}

.photo > picture { display: contents; }

.photo--portrait { --photo-ratio: 4 / 5; }
.photo--square   { --photo-ratio: 1 / 1; }
.photo--wide     { --photo-ratio: 16 / 9; }
.photo--band     { --photo-ratio: 21 / 9; }
/* The hero plate. Shallower than 16:9 so a landscape source keeps its full
   height, and only 11% comes off the width — enough to hold a centred
   three-up subject intact. This is the ratio index.html's hero runs at. */
.photo--plate    { --photo-ratio: 4 / 3; }

/* The plate mark, carried onto the image so a photograph belongs to this
   world rather than sitting in it. */
.photo--marked::after {
  content: "";
  position: absolute;
  inset: var(--p-space-3);
  border: var(--p-line-hair) solid rgba(255, 255, 255, 0.55);
  pointer-events: none;
}

/* --- Text over image ------------------------------------------------------
   Never set type straight onto a photograph. The scrim is a graded wash in
   the ground colour, and its alpha was measured rather than eyeballed.

   Sampling the bottom third of the supplied photographs, where scrim type
   sits: ruby-fremon-hero-1 averages #B5A17A (white on it is only 2.52:1,
   a clear fail) and ruby-fremon-and-horses averages #6C584B (6.70:1).
   Compositing #0A0A0A over the worse of the two gives white 9.7:1 at 0.62
   alpha and 15.2:1 at 0.82. Rendered and sampled on ruby-fremon-and-horses
   at 16:9, the headline band comes out #2F251E — 14.95:1 against white, and
   4.72:1 on its single lightest pixel; the caption band never drops below
   10.8:1. Publish the lightest-pixel figure, not the mean: contrast on a
   photograph is a per-pixel property and the mean hides the failure.

   The wash is weighted hard to the foot and released fast, so it buys
   legibility for the type band without draining colour out of the subject.

   State the stops in rem wherever the frame's height is fluid. The stops
   below are percentages because .photo boxes hold a fixed aspect ratio, so
   a percentage IS a fixed distance. The home page hero's frame is the
   viewport: there the same percentages held 6.5:1 at 1440 and 3.06:1 at 390,
   and only rem-anchored stops gave the headline the same protection at every
   width. Percent follows the frame; rem follows the type.
   An even wash across the frame is how a scrim quietly turns a colour
   photograph grey — the exact thing this system must not do.
   Re-measure before lowering the foot alpha on new art. */
.photo__scrim {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: var(--p-space-5);
  background: linear-gradient(
    to top,
    rgba(10, 10, 10, 0.88) 0%,
    rgba(10, 10, 10, 0.72) 14%,
    rgba(10, 10, 10, 0.28) 32%,
    rgba(10, 10, 10, 0) 52%
  );
  color: var(--p-white);
}

/* A scrim sits on the dark pole even inside a white plate: it is over the
   photograph, not over the sheet. */
.plate .photo__scrim {
  --text-primary: var(--p-white);
  --text-secondary: var(--p-n-200);
  --accent: var(--p-white);
  --rule-hair: rgba(255, 255, 255, 0.34);
  color: var(--p-white);
}

.photo__scrim .figure-no,
.photo__scrim .caption { color: var(--p-n-200); }

/* --- Figure ---------------------------------------------------------------
   A photograph with its number and caption, set like a plate in a volume. */
/* A <figure> arrives with a 1em/40px UA margin. Every use of this class so far
   has been either a <div>, which has none, or a <figure> carrying an inline
   margin that happened to zero it — so the first plain <figure class="figure">
   on the site came out 80px narrower than its container and nobody had ever
   seen it. Same bug as .pullquote's 40px indent, same fix. */
.figure { display: grid; gap: var(--p-space-3); align-content: start; margin: 0; }

.figure__caption {
  display: flex;
  align-items: baseline;
  gap: var(--p-space-3);
  padding-block-start: var(--p-space-2);
  border-block-start: var(--p-line-hair) solid var(--rule-hair);
  font-size: var(--p-size-2xs);
  line-height: var(--p-leading-normal);
  color: var(--text-muted);
}

.figure__caption .figure-no { flex: none; }

/* ==========================================================================
   BRANDMARK

   The logo is one piece of artwork in two inks: slate #2C3639 and white.
   Which ink you use is not a preference — the surface forces it. The slate
   mark measures 1.60:1 on the black ground, the same reading that makes
   surface-slate a surface and never text. It is invisible there.

     black ground / slate  ->  LIGHT mark   (19.8:1 / 12.40:1)
     white plate / sheet   ->  DARK mark    (12.40:1 / 9.39:1)

   A logo is a graphical object, so 3:1 is its floor under WCAG 1.4.11. Both
   correct pairings clear it several times over; both wrong ones fail.
   ========================================================================== */

.brandmark { display: inline-block; line-height: 0; }

.brandmark img {
  block-size: var(--brandmark-size, 1.75rem);
  inline-size: auto;
}

.brandmark--lg { --brandmark-size: 2.75rem; }
.brandmark--sm { --brandmark-size: 1.375rem; }

@media (min-width: 48rem) {
  .brandmark { --brandmark-size: 2rem; }
  .brandmark--lg { --brandmark-size: 3.25rem; }
  .brandmark--sm { --brandmark-size: 1.5rem; }
}

/* ==========================================================================
   AVATAR

   Square, because nothing in this world rounds — the circular headshot is
   the one convention this system does not inherit.

   The placeholder is initials, never a stand-in face. These are real named
   people; substituting a generated or stock likeness for a real person is
   not a placeholder, it is a fabrication. The empty state says it is empty.
   ========================================================================== */

.avatar {
  --avatar-size: 3rem;

  position: relative;
  flex: none;
  inline-size: var(--avatar-size);
  block-size: var(--avatar-size);
  border-radius: var(--p-radius-none);
  overflow: hidden;
  background-color: var(--surface-slate);
  display: grid;
  place-items: center;
  isolation: isolate;
}

/* The avatar is a grid box, so a <picture> wrapper would become the grid item
   and the image inside it would size to content instead of the box. */
.avatar picture { display: contents; }

.avatar img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: var(--avatar-focus, 50% 30%);
}

/* Sand on slate measures 9.39:1. */
.avatar__initials {
  font-family: var(--p-font-display);
  font-size: var(--p-size-2xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-wide);
  color: var(--p-sand-100);
  user-select: none;
}

/* Marks it as awaiting real art. Drop the class when a photograph lands. */
.avatar--placeholder::after {
  content: "";
  position: absolute;
  inset: 0;
  border: var(--p-line-thin) dashed rgba(231, 223, 212, 0.4);
  pointer-events: none;
}

.avatar--lg { --avatar-size: 4rem; }

/* Attribution row: avatar beside name and role. */
.testimonial__attr {
  display: flex;
  align-items: center;
  gap: var(--p-space-4);
  /* Clear the plate mark. The mark is inset 12px and the plate pads 32px, so a
     role that wraps to three lines lands on the hairline. This buys the space
     back rather than hoping the role stays short. */
  padding-block-end: var(--p-space-2);
}

.testimonial__role { text-wrap: pretty; }

.testimonial__who { min-inline-size: 0; }

/* ==========================================================================
   BANDS — full-width grounds that flip pole
   A band is a plate the width of the page. It reassigns the same semantic
   tokens a plate does, so identical markup resolves correctly inside it and
   no component needs an on-band variant.

   These lived inline in index.html, equia.html and journey.html as three
   byte-identical copies, which is how --surface-raised came to be missing
   from all three: .offering:hover paints --surface-raised, that token stayed
   at n-850 on a cream band, and the description text measured 2.68:1 under
   the cursor. One definition, one place to fix it.
   ========================================================================== */

.band { background: var(--surface-sunken); }

.band--slate { background: var(--surface-slate); --surface-raised: var(--surface-raised-slate); --accent-warm: var(--p-sand-100); --text-warm: var(--p-sand-100); --text-primary: var(--p-white); --text-secondary: var(--p-n-200); --text-muted: var(--p-n-300); --rule-hair: rgba(255,255,255,0.18); --rule-warm: rgba(231,223,212,0.45); --accent-fill: var(--p-white); --accent-fill-hover: var(--p-n-100); --accent-fill-press: var(--p-n-200); --text-inverse: var(--p-slate-700); --accent: var(--p-white); --focus-ring: var(--p-white); color: var(--p-white); }

.band--sheet { background: var(--surface-sheet); --surface-raised: var(--surface-raised-sheet); --accent-warm: var(--p-taupe-700); --text-warm: var(--p-taupe-700); --text-primary: var(--p-n-950); --text-secondary: var(--p-taupe-700); --text-muted: var(--p-taupe-700); --rule-hair: rgba(44,54,57,0.2); --rule-hair-strong: rgba(44,54,57,0.45); --rule-warm: rgba(44,54,57,0.35); --accent-fill: var(--p-n-950); --accent-fill-hover: var(--p-n-800); --accent-fill-press: var(--p-n-700); --text-inverse: var(--p-sand-100); --accent: var(--p-n-950); --focus-ring: var(--p-n-950); color: var(--p-n-950); }

.band--edge { border-block-start: var(--p-line-hair) solid var(--rule-hair); }

/* --- THE LEGAL DOCUMENT ------------------------------------------------
   Shared by /privacy and /terms-conditions, and deliberately shared. The
   page-composition rule on this site is that arrangements must not repeat —
   but that rule exists so pages do not read as one page with the words
   swapped. Legal instruments are the exception that proves it: they are a
   SET, and a reader who has met the privacy policy should recognise the terms
   page as its sibling on sight. Varying them would be decoration, and
   decoration is the last thing either document needs.

   The composition is "the instrument": the page opens the way a legal
   document opens — issuing entity, title, effective date, and the numbered
   contents itself in the first viewport, so the whole shape of what is being
   agreed to is visible before a line of it is read. Both open on PAPER, which
   /book is the only other page to do, and for the same reason: they are
   printed objects. */
.doc { padding-block: var(--p-space-9) var(--p-space-8); }

@media (min-width: 48rem) { .doc { padding-block: var(--p-space-10) var(--p-space-9); } }

.doc__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--p-space-3) var(--p-space-6);
  margin-block-start: var(--p-space-6);
  padding-block-start: var(--p-space-4);
  border-block-start: var(--p-line-thin) solid var(--rule-warm);
}

/* Tabular figures so a date reads as a date. */
.doc__date { font-variant-numeric: tabular-nums; }

/* The shallowest frame on the site. The standing rule here is that a hero
   always carries an image; a legal page has to obey it without pretending to
   be a brochure, so the band reads as a rule with texture rather than a view. */
.doc__band { --photo-ratio: 32 / 9; --photo-focus: 50% 50%; }

@media (max-width: 47.99rem) { .doc__band { --photo-ratio: 16 / 9; } }

/* THE CONTENTS — a numbered register, not a bulleted list. A legal document
   is navigated, not read start to finish, so the numbers are the interface. */
.toc { margin-block-start: var(--p-space-7); border-block-start: var(--p-line-hair) solid var(--rule-hair); }

.toc a {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: var(--p-space-4);
  align-items: baseline;
  padding-block: var(--p-space-4);
  border-block-end: var(--p-line-hair) solid var(--rule-hair);
  color: inherit;
  text-decoration: none;
}

.toc a:hover .toc__name { text-decoration: underline; text-underline-offset: 0.2em; }

.toc__n {
  font-size: var(--p-size-2xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  color: var(--text-warm);
  font-variant-numeric: tabular-nums;
}

.toc__name { font-weight: var(--p-weight-semibold); }

@media (min-width: 48rem) {
  .toc--split { columns: 2; column-gap: var(--p-space-8); }
  .toc--split a { break-inside: avoid; }
}

/* THE CLAUSES — one column at one measure, numbered to match the contents.
   Nothing here is set in two columns: a reader looking for clause 7 should
   never have to work out which way the page runs. */
.clause { padding-block-start: var(--p-space-7); }
.clause + .clause { margin-block-start: var(--p-space-8); border-block-start: var(--p-line-thin) solid var(--rule-warm); }

/* The number sits ABOVE the heading, not beside it. Beside it on a baseline
   the heading starts 36px in from the body text below and the clause has two
   left edges. */
.clause__head > .toc__n { display: block; margin-block-end: var(--p-space-3); }

.clause__body { max-width: 68ch; margin-block-start: var(--p-space-5); }
.clause__body > * + * { margin-block-start: var(--p-space-4); }

/* A .pending note inside a clause takes the wider gap, stated rather than left
   to cascade order: it is a dashed aside about what is missing, not the next
   paragraph, and 1rem is not enough to say so. */
.clause__body > .pending { margin-block-start: var(--p-space-6); }
.clause__body p, .clause__body li { color: var(--text-secondary); }
.clause__body strong { color: var(--text-primary); font-weight: var(--p-weight-semibold); }

/* Definition rows, for anything in a legal document that is enumerable. */
.defs { margin-block-start: var(--p-space-5); border-block-start: var(--p-line-hair) solid var(--rule-hair); }

.defs > div {
  display: grid;
  gap: var(--p-space-1) var(--p-space-5);
  padding-block: var(--p-space-4);
  border-block-end: var(--p-line-hair) solid var(--rule-hair);
}

@media (min-width: 48rem) {
  .defs > div { grid-template-columns: 14rem minmax(0, 1fr); align-items: baseline; }
}

.defs dt { font-weight: var(--p-weight-semibold); color: var(--text-primary); }
.defs dd { margin: 0; color: var(--text-secondary); }

/* Numbered sub-clauses inside a clause. The numeral is in the margin so the
   text keeps one left edge with the paragraphs above it. */
.subs { list-style: none; margin-block-start: var(--p-space-4); }

.subs > li {
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr);
  gap: var(--p-space-3);
  align-items: baseline;
}

.subs > li + li { margin-block-start: var(--p-space-4); }

.subs__n {
  font-size: var(--p-size-2xs);
  font-weight: var(--p-weight-semibold);
  letter-spacing: var(--p-tracking-key);
  color: var(--text-warm);
  font-variant-numeric: tabular-nums;
}

/* --- PENDING -------------------------------------------------------------
   A ruled editorial note, dashed top and bottom, naming what is genuinely not
   decided yet. It wears the same dashed edge as .avatar--placeholder so the
   whole site has one placeholder language, and it is deliberately NOT a
   reserved empty box: a placeholder should say what is missing, not hold open
   the space the missing thing will occupy. Used by /remembrance for unshot
   photography and by /privacy for clauses that are the client's to decide. */
.pending {
  display: grid;
  gap: var(--p-space-2);
  margin-block-start: var(--p-space-6);
  padding-block: var(--p-space-4);
  border-block: var(--p-line-hair) dashed var(--rule-hair-strong);
}

.pending p { color: var(--text-secondary); max-width: 52ch; }

@media (min-width: 48rem) {
  .pending { grid-template-columns: 12rem minmax(0, 1fr); gap: var(--p-space-5); align-items: baseline; }
}
