/* ==========================================================================
   Laura Duty — v3
   Tokens and values follow the Claude Design handoff, plus the client's first
   review round (Simple Commenter, 2026-07-27/28). Changes traceable to a
   comment are marked `REVIEW #n` at the rule.
   Three radii only: 30px (cards/panels), 999px (buttons/pill), 0 (photos/solids).
   ========================================================================== */

:root {
  /* ------------------------------------------------------------------------
     v3 palette. Applied from brand/palette.html. Ratios there are measured,
     not estimated; the ones quoted in these comments were re-checked here.
     ------------------------------------------------------------------------ */

  /* Ground — unchanged. The paper stays out of the photography's way, and
     deepening it would push links below 4.5:1. */
  --ground:        #FDFBF7;
  --ground-grad:   #F7EFE6;
  --sand:          #F5EFE6;
  --sand-grad:     #EFE5D7;

  /* Accent solids: the squares that sit behind each photograph. Equal
     lightness (L* 79.9 / 80.6), opposite temperature, so the two doors carry
     the same visual weight and neither can outrank the other. SURFACES only,
     never text. --deep was 1.26:1 against cream, i.e. invisible; --deep-cool
     never rendered at all because a sage override won on specificity. */
  --deep:          #E1C0A8;
  --deep-cool:     #ADCCE4;

  /* Ink */
  --ink:           #3D3A36;
  --ink-2:         #5C5750;
  --ink-muted:     #6D665D;   /* was #8C857B — 3.53:1, failed as body text */
  --anchor:        #0E2654;   /* bluebonnet deep. Credentials band + footer. */
  --rule:          #ADA396;   /* was #CFC4B4 — hairlines now read at 2.40:1 */

  /* Action — the logo's own hue, one step down in lightness. Chroma 0.149 to
     0.184 AND contrast 5.01 to 5.47. Both axes at once, which is what the
     client meant by "pop". */
  --action:        #C13021;
  --action-hover:  #9E1E12;

  /* Coral — same hue and chroma as the logo file, lightness dropped so 29px
     Caveat kickers clear the 3:1 large-text floor (they were at 2.98:1).
     The logo image itself is untouched. Large display type only. */
  --coral:         #E64245;

  /* Marigold — value unchanged. It starts rendering once the sage override on
     .footer-head is removed: 6.81:1 on the new anchor. */
  --marigold:      #E9A23B;

  /* Sage — nudged 0.8 degrees onto the triad. Surface and hairline only. */
  --sage:          #ABC1AE;
  --sage-deep:     #55755B;

  /* The credentials band. v2 ran this light blue per the client's comment;
     v3 takes the study's recommendation and runs it deep, which keeps the
     white wave pattern the client asked for and gives the page back a dark
     band between two warm sections. White on this measures 14.75:1.
     A lighter alternative, #1E5578, is in the study at 8.00:1. */
  --band:          var(--anchor);
  --band-ink:      #FDFBF7;
  --band-ink-2:    rgba(253, 251, 247, .78);

  /* ----------------------------------------------------------------------
     v2d — the aspect colours from v2c, WITHOUT the textures.

     Same five colours and the same assignment; the accent blocks are flat
     fills here rather than colour-plus-texture. This is the variant that
     answers "is the colour system doing the work, or is the texture?".

       coaching   #EF8D01  bright, forward
       grief      #72ACAE  cool, held, quiet
       speaking   #5A8770  growth, rooms, groups
       nonprofit  #175E7C  institutional, structural
       welcome    #DB411D  the one act-now colour

     Coaching and grief sit 0.026 apart in OKLCH lightness and 135 degrees
     apart in hue: near-identical weight, opposite temperature. That is what
     lets the two doors stay level while still being told apart, and it is the
     rule the whole doors band is built on. Do not re-assign either of those
     two without re-checking that number.
     ---------------------------------------------------------------------- */
  /* Nav underline. Two full periods across a 120px tile, both ends left on the
     same tangent so repeat-x is seamless at any link width. */
  --nav-wave: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 8' preserveAspectRatio='none'%3E%3Cpath d='M0,4 C10,1.5 20,6.5 30,4 C40,1.5 50,6.5 60,4 C70,1.5 80,6.5 90,4 C100,1.5 110,6.5 120,4' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");


  --c-coaching:  #EF8D01;
  --c-grief:     #72ACAE;
  --c-speaking:  #5A8770;
  /* Badge-only. Same hue and saturation as --c-speaking, dark enough that
     white small text clears 4.5:1 on it (4.63:1 vs the token's 3.96:1). */
  --c-speaking-deep: #527B66;
  --c-nonprofit: #175E7C;
  --c-welcome:   #DB411D;

  /* The five textures. v2d leaves the accent solids flat — that is the whole
     point of it against v2c — so only --tex-welcome is actually used here, by
     the testimonial panel. The other four are declared so swapping that panel
     to another aspect colour is a one-word change. */
  --tex-coaching:  url('../images/components/textures/strokes-speckle-orange.svg');
  --tex-grief:     url('../images/components/textures/crosshatch-softteal.svg');
  --tex-speaking:  url('../images/components/textures/spiral-green.svg');
  --tex-nonprofit: url('../images/components/textures/strokes-bold-deepteal.svg');
  --tex-welcome:   url('../images/components/textures/hatch-fine-vermilion.svg');

  /* --olive retired. Zero references in the stylesheet. */

  /* Type — unchanged */
  --display: 'Sansita', Georgia, serif;
  --body:    'Source Sans 3', system-ui, -apple-system, sans-serif;
  --accent:  'Caveat', cursive;

  /* Shadow — unchanged except the band shadow, now warm-blue under the band */
  /* ---- spacing scale -------------------------------------------------
     Every band and every gap between blocks comes from these. Before this
     existed the pages carried loose one-off values (110, 120, 150, 30, 34,
     44, 56) that read as inconsistent rhythm from page to page. Change the
     rhythm here, not at the call site. */
  --pad-band: 120px;   /* the standard section, top and bottom */
  --pad-hero:  96px;   /* above a page hero, matching the homepage hero */
  --pad-strip: 90px;   /* the full-bleed camera strip, top and bottom */
  --gap-sm:    32px;
  --gap-md:    44px;
  --gap-lg:    56px;

  --sh-card:   0 18px 44px -22px rgba(61, 58, 54, .26);
  --sh-photo:  0 22px 52px -24px rgba(61, 58, 54, .36);
  --sh-hero:   0 26px 60px -26px rgba(61, 58, 54, .42);
  --sh-band:   0 26px 60px -28px rgba(14, 38, 84, .45);
  --sh-nav:    0 8px 26px -14px rgba(61, 58, 54, .22);
  --sh-panel:  0 20px 48px -22px rgba(61, 58, 54, .32);
  --sh-small:  0 18px 40px -18px rgba(61, 58, 54, .40);

  --container:  1300px;
  --gutter:     40px;
}

/* --------------------------------------------------------------- reset -- */

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

/* .shot wraps a single photograph with its own credit so the two travel
   together: the wrapper takes over the frame's positioning class and the
   credit hangs off its bottom edge. Absolute rather than in flow, so a
   credit can never push a composition around or eat into an aspect-ratio
   box. Every photograph on the site gets one. */
.shot { margin: 0; display: block; position: relative; }
.shot > img, .shot > .ph { display: block; width: 100%; height: 100%; object-fit: cover; }
.shot > .credit {
  position: absolute; left: 0; top: 100%;
  margin-top: 6px; white-space: nowrap; z-index: 5;
}
/* Frames that hang off the right edge of their cluster read better with the
   credit right-aligned under them. */
.shot--right > .credit { left: auto; right: 0; }
/* For a frame with smaller ones hung off both bottom corners, the only
   clear ground is the gap between them. */
.shot--center > .credit { left: 50%; right: auto; transform: translateX(-50%); }


html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--body);
  font-size: 19px;
  line-height: 1.7;               /* non-negotiable: audience is 45 to 70 */
  -webkit-font-smoothing: antialiased;
}

/* height:auto is load-bearing. Every <img> carries width/height attributes for
   CLS, and without this the attribute height wins as a used value and CSS
   aspect-ratio is ignored entirely. That is what stretched the hero portrait
   to 2400px and the door photos to 2000px. */
img { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 700;      /* Sansita 700. It has no 500, so nothing may ask for one. */
  color: var(--ink);
  margin: 0;
  text-wrap: pretty;
}

p { margin: 0 0 1em; max-width: 68ch; }   /* measure cap */
p:last-child { margin-bottom: 0; }

a { color: var(--action); }
a:hover { color: var(--action-hover); }

:focus-visible {
  outline: 2px solid var(--action);
  outline-offset: 2px;
  border-radius: 2px;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--action); color: var(--ground);
  padding: 14px 22px; border-radius: 0 0 8px 0;
  font-weight: 600; text-decoration: none;
}
.skip-link:focus { left: 0; }

/* ----------------------------------------------------------- scaffold -- */
/* Every band is section > .container > content. */

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

/* overflow-x: clip contains the decorative rings and offset solids, which are
   positioned in px and bleed past the viewport at intermediate widths. Unlike
   overflow: hidden it does not create a scroll container, so nothing vertical
   is affected and the credential band still straddles its seam. */
.section          { padding-block: var(--pad-band); position: relative; overflow-x: clip; }
/* Bands that set their own container padding must not also take the default
   section padding, or every value in the spec doubles. */
.section--own-pad { padding-block: 0; }
.section--cream   { background: linear-gradient(180deg, var(--ground-grad) 0%, var(--ground) 38%, var(--ground) 100%); }
.section--sand    { background: linear-gradient(180deg, var(--sand-grad) 0%, var(--sand) 34%, var(--sand) 100%); }
.section--flat-sand { background: var(--sand); }

/* Wave: filled with the colour ABOVE, first child of the section BELOW. */
.wave { display: block; width: 100%; height: 88px; margin-bottom: -1px; }
.section > .wave:first-child { margin-top: 0; }
.has-wave { padding-top: 0; }
.has-wave > .container { padding-top: var(--pad-band); }

/* The hand-drawn ring. Always decorative. */
.ring {
  position: absolute;
  object-fit: contain;
  mix-blend-mode: multiply;
  pointer-events: none;
  user-select: none;
}

/* Hand-drawn marks, masked so they take brand colour. */
.mark { position: absolute; pointer-events: none; }
.mark--swoosh {
  background: var(--coral); opacity: .85;
  -webkit-mask: url('../images/components/mark-swoosh.svg') left center/contain no-repeat;
          mask: url('../images/components/mark-swoosh.svg') left center/contain no-repeat;
}
.mark--arrow {
  background: var(--marigold);
  -webkit-mask: url('../images/components/mark-arrow.svg') center/contain no-repeat;
          mask: url('../images/components/mark-arrow.svg') center/contain no-repeat;
}
.mark--stroke {
  background: var(--deep);
  -webkit-mask: url('../images/components/mark-stroke.svg') center/contain no-repeat;
          mask: url('../images/components/mark-stroke.svg') center/contain no-repeat;
}

/* Square accent solid sitting behind a photograph, offset 54px.

   v2d — flat aspect colour. --c is inherited, so a section or a page sets it
   once on an ancestor and every solid inside picks it up; anything that does
   not set it falls back to the welcome vermilion. No texture layer here: that
   is the single difference between this build and v2c. */
.solid { position: absolute; background: var(--c, var(--c-welcome)); z-index: 0; }
/* .solid--cool no longer needs its own colour: the grief door sets --c. */
.solid--cool { background: var(--c, var(--c-welcome)); }

/* ---------------------------------------------------------- assignment --- */
.hero-stage     { --c: var(--c-coaching); }
.door--coaching { --c: var(--c-coaching); }
.door--grief    { --c: var(--c-grief); }
.speaking-stage { --c: var(--c-speaking); }
.bio-figure,
.freecall-stage { --c: var(--c-welcome); }

/* Internal pages take their service colour throughout, so a visitor who lands
   on Grief education from search meets the same block they would have met by
   walking through that door from the homepage. */
.page-life-coaching          { --c: var(--c-coaching); }
.page-grief-education        { --c: var(--c-grief); }
.page-speaking-workshops     { --c: var(--c-speaking); }
.page-nonprofit-facilitation { --c: var(--c-nonprofit); }

/* -------------------------------------------------------------- type --- */

.kicker {
  font-family: var(--accent);
  font-size: 29px;
  line-height: 1;
  color: var(--coral);
  margin-bottom: 2px;
}

.em { font-style: italic; }

.h1 { font-size: 84px; line-height: 1.04; max-width: 14ch; }  /* measure on the h1 itself */
.h2 { font-size: 48px; line-height: 1.12; }
.h2--md { font-size: 42px; }
.h2--sm { font-size: 38px; }
.h2--xs { font-size: 34px; }
.h3 { font-size: 29px; font-weight: 700; }

.lead { font-size: 21px; }
.small { font-size: 16px; }
.caption { font-size: 15px; color: var(--ink-2); }
.is-pending { color: var(--ink-muted); }

/* -------------------------------------------------------------- btns --- */

.btn {
  display: inline-block;
  background: var(--action);
  color: var(--ground);
  font-family: var(--body);
  font-weight: 600;
  font-size: 17px;
  line-height: 1.2;
  padding: 18px 36px;
  border-radius: 999px;
  text-decoration: none;
  border: 0;
  cursor: pointer;
  transition: transform 180ms ease, box-shadow 180ms ease, background-color 180ms ease;
}
.btn:hover {
  color: var(--ground);
  background: var(--action-hover);
  transform: translateY(-2px);
  box-shadow: var(--sh-card);
}
.btn--sm { font-size: 16px; padding: 14px 30px; }

.link {
  font-family: var(--body);
  font-weight: 600;
  font-size: 18px;
  color: var(--action);
  text-decoration: underline;
  text-underline-offset: 5px;
}

/* --------------------------------------------------------------- nav --- */

/* The nav sits on the hero's gradient start rather than on flat ground, so
   there is no colour seam under the pill and no orphan band above it. */
/* Sticky at every width (9/11 round). z-index clears the events dropdowns,
   which sit at 20 inside main. At rest the band paints exactly as before; once
   site.js marks the page scrolled the band goes transparent and stops taking
   taps, so only the pill (and an open mobile menu) floats and catches input. */
.nav-wrap {
  background-color: var(--ground-grad); padding-top: 16px;
  position: sticky; top: 0; z-index: 50;
  transition: background-color 220ms ease;
}
.nav-wrap.is-stuck { background-color: transparent; pointer-events: none; }
.nav-wrap.is-stuck .nav,
.nav-wrap.is-stuck .mobile-nav { pointer-events: auto; }
/* Anchor jumps and the skip link land below the floating pill, not under it. */
html { scroll-padding-top: 116px; }

.nav {
  background: #FFFFFF;                 /* the one white surface on the site */
  border-radius: 999px;
  padding: 6px 10px 6px 32px;
  box-shadow: var(--sh-nav);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 32px;
}

/* Nav type.

   It was body copy sitting in a bar: 17px, regular weight, default tracking —
   the same setting as a paragraph, which is why it read as unconsidered. It is
   a set of six short labels, not prose, so it can carry weight and tracking
   that a paragraph could not.

   It now takes the headline face. Sansita in the bar makes the nav read as
   part of the same voice as the H1 under it rather than as system furniture,
   which is the cheapest way to make a nav feel authored.

   Weight 400, not 600: Sansita has no 500, so the choice is regular or bold,
   and bold at nav size is a shout. Size goes UP to 19px because a serif at a
   given px reads smaller than a sans — 16px Sansita would have been quieter
   than the 17px sans it replaced, not more present. Tracking stays near zero;
   the face already has its own rhythm and adding to it makes it look stretched.

   The dropdown deliberately stays in the body face. Display type at 16px in a
   menu is where serifs start costing legibility, and keeping the two faces
   apart gives the bar and its menu a clear hierarchy. */
.nav-list {
  display: flex; align-items: center; gap: 34px;
  list-style: none; margin: 0; padding: 0;
  font-family: var(--display); font-size: 19px; font-weight: 400; letter-spacing: .005em;
}
.nav-list--right { justify-content: flex-end; }
.nav-list a { color: var(--ink); text-decoration: none; }
.nav-list a:hover { color: var(--action); }
.nav-list a[aria-current="page"] { color: var(--action); }

/* Nav links get a hand-drawn underline rather than a border.

   The rest of the site is drawn — the ring, the kicker script, the five
   textures — and a 1px underline was the one interaction that looked typed.
   This is the same wave the rules use, at nav scale.

   The stroke is masked, so it takes --action from the token rather than baking
   a colour. clip-path is kept as the reveal mechanism because it does not
   stretch the wave the way scaleX would, and because it is what a transition
   would hook into if the underline is ever animated again.

   Scoped with `>` so it belongs to the top-level items only; the dropdown
   below has its own, quieter treatment. */
.nav-list > li > a {
  position: relative;
  display: inline-flex; align-items: center;
}
.nav-list > li > a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -10px; height: 8px;
  background: var(--action);
  -webkit-mask: var(--nav-wave) repeat-x left center / 120px 8px;
          mask: var(--nav-wave) repeat-x left center / 120px 8px;
  clip-path: inset(0 100% 0 0);
  transition: clip-path 300ms cubic-bezier(.22, .61, .36, 1);
  /* The dropdown is a later sibling and opens at top: 100% of the same li, so
     with auto z-index it painted straight over the underline of the item that
     opened it. One step up is enough to keep the two visible together. */
  z-index: 1;
}
/* No hover reveal. The underline marks the page you are ON and nothing else,
   so it is state rather than feedback — hover still answers with colour, and
   keyboard focus still gets the global focus ring. A line that appeared under
   every item the pointer crossed was reading as decoration on a bar that has
   six of them. */
.nav-list > li > a[aria-current="page"]::after { clip-path: inset(0 0 0 0); }

/* The caret turns over while its menu is open, so the control says which
   state it is in rather than pointing down the whole time. */
.caret {
  margin-left: 6px; font-size: 12px; display: inline-block;
  transition: transform 220ms cubic-bezier(.22, .61, .36, 1);
}
.has-children:hover .caret,
.has-children:focus-within .caret { transform: rotate(180deg); }

.nav-list .has-children { position: relative; }
.subnav {
  position: absolute; left: -20px; top: 100%;
  margin: 0; padding: 14px 0; list-style: none;
  min-width: 250px;
  background: var(--ground);
  border-radius: 20px;
  box-shadow: var(--sh-card);
  opacity: 0; visibility: hidden;
  transform: translateY(6px);
  transition: opacity 180ms ease, transform 180ms ease, visibility 180ms;
}
/* The menu sits one step back from the bar, and back in the body face.

   No hover flourish here either. The rule that used to draw in from the left
   is gone, and the indent goes with it — that shift only existed to make room
   for the rule, so on its own it would have been text moving for no reason.
   Hover answers with colour, the same as the bar above. */
.subnav a {
  display: block; padding: 9px 26px;
  font-family: var(--body); font-size: 16px; font-weight: 500; letter-spacing: 0;
  transition: color 160ms ease;
}
.has-children:hover .subnav,
.has-children:focus-within .subnav { opacity: 1; visibility: visible; transform: translateY(0); }

.nav-logo { display: block; justify-self: center; }
/* The source JPEG carried a 66% white margin, so an 84px box only rendered a
   ~55px mark. The file is cropped to the mark now, which is why 70px here
   reads larger than 84px did while taking 28px off the bar.

   No mix-blend-mode any more: logo-mark.png carries real alpha, so the mark
   sits correctly on the white pill without borrowing the backdrop, and a
   filter or opacity on this element no longer leaves a grey box. */
.nav-logo img { height: 70px; width: auto; }

.nav-right { display: flex; align-items: center; justify-content: flex-end; gap: 30px; }

/* The nav CTA never wraps. A two-line label was adding 19px to the mobile bar,
   so the label itself shortens instead. */
.nav-cta { white-space: nowrap; font-size: 15px; letter-spacing: .015em; }
.nav-cta__short { display: none; }

.nav-toggle { display: none; background: none; border: 0; padding: 12px; cursor: pointer; }
.nav-toggle__bars { display: grid; gap: 5px; }
.nav-toggle__bars span { display: block; width: 26px; height: 2px; background: var(--ink); }

/* The menu travels with the floating pill, so it scrolls itself rather than
   running off the bottom of a short landscape screen. */
.mobile-nav {
  background: var(--ground); padding: 8px 0 24px;
  max-height: calc(100vh - 100px); overflow-y: auto; overscroll-behavior: contain;
}
.mobile-nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.mobile-nav a {
  display: block; padding: 14px 0; font-size: 19px;
  color: var(--ink); text-decoration: none; min-height: 48px;
}
.mobile-nav__child a { padding-left: 22px; font-size: 17px; color: var(--ink-2); }

/* -------------------------------------------------------------- hero --- */

/* The hero continues the nav's gradient start rather than restarting it, so
   the pill reads as sitting on the hero instead of on a band of its own. */
.hero { background: linear-gradient(180deg, var(--ground-grad) 0%, var(--ground) 42%, var(--ground) 100%); }
/* Bottom padding is load-bearing: the credential band is pulled up 106px, so
   this has to clear the copy panel's bottom edge or the band cuts the CTA. */
.hero > .container { padding-block: 96px 226px; position: relative; }
.hero-inner { position: relative; }

/* Type sits beside the portrait rather than inside it, so no headline ever
   lands on a photograph. The sand solid runs underneath both and does the
   layering instead. */
.hero-type {
  position: absolute; right: 0; top: 96px; z-index: 3;
  width: 46%; max-width: 540px;
}
/* One measure for the whole hero type block.

   The headline and the lead were capped independently — 13ch of a 60px serif
   and 44ch of a 19px sans — which are different physical widths, so the block
   had two different right edges and read as two stacked columns rather than
   one. `ch` cannot be shared between them because it is relative to each
   element's own font, so the measure is set once in px on the parent and both
   inherit it.

   453px is the headline's existing width, kept so its three-line break does
   not change; the lead now wraps inside the same column instead of running
   past it. */
.hero-type { --hero-measure: 453px; }
.hero-type .kicker { font-size: 31px; margin-bottom: 4px; max-width: var(--hero-measure); }
.h1 { font-size: 60px; line-height: 1.06; max-width: var(--hero-measure); }
.hero-lead { font-size: 19px; margin: 30px 0 0; max-width: var(--hero-measure); }
.hero-cta { margin-top: 26px; }

/* Collage. One dominant 2:3 portrait left of centre, a satellite card
   bleeding off each outer edge, and a low card tucked under the type. */
.hero-stage { position: relative; height: 646px; z-index: 1; }

/* The hero solid.

   It used to sit at left:96px / width:42%, which put ~72px of it outside the
   portrait on the left AND ~68px on the right, so it read as a slab framing
   the photograph rather than a block it was sitting on.

   Now it is pulled left and narrowed until its right edge is comfortably
   behind the portrait, leaving a single vertical strip down the left. The
   left offset is px and the portrait's is px, so that strip stays a constant
   ~124px; the 26% width only has to keep the right edge covered, which it
   does from 861px (where the solid hides entirely) up.

   The fill comes from --c on .hero-stage, which is the coaching orange. */
.hero-solid {
  left: 44px; top: 96px; width: 26%; height: 460px;
}

.hero-portrait {
  position: absolute; left: 168px; top: 0; width: 372px;
  aspect-ratio: 2/3; z-index: 2; box-shadow: var(--sh-hero);
}
.hero-portrait > img { object-position: 50% 34%; }

.hero-card { position: absolute; object-fit: cover; z-index: 3; box-shadow: var(--sh-small); }
.hero-card--left  { left: -104px; top: 168px; width: 196px; aspect-ratio: 4/5; }
.hero-card--right { right: -96px; top: 34px;  width: 216px; aspect-ratio: 3/2; }
/* Tucked into the gap between the portrait and the type column, overlapping
   the portrait's bottom-right corner. It must never land on the paragraph. */
.hero-card--low   { left: 418px;  top: 500px; width: 236px; aspect-ratio: 3/2; z-index: 4; }

/* ------------------------------------------------------- credentials --- */
/* Straddles the seam: pulled up and down by half its own height. */

/* REVIEW #12 — the band was near-black. It is a light blue field now, carrying
   a white wave pattern, which turns the one hard stop on the page into the one
   cool band and stops it reading as a slab dropped between two warm sections.
   Text colour flips with it: ink on light, not cream on dark. */

.credentials { position: relative; z-index: 5; margin-block: -106px; }
.credentials-band {
  background: var(--band);
  border-radius: 30px;
  padding: 52px 64px;
  position: relative;
  overflow: hidden;
  box-shadow: var(--sh-band);
}

/* The white line pattern is gone. The band carries the same texture-waves.svg
   the hero does, via .has-texture, so the two surfaces read as one material.

   It needs its own strength on this ground: .has-texture is tuned at 22% for
   a cream band, and a cream-toned artwork at 22% over deep bluebonnet is a
   smear rather than a texture. Screen keeps only the lightest strokes, and 9%
   is where it stops competing with the badges sitting on top of it. */
.credentials-band.has-texture::before {
  mix-blend-mode: screen;
  opacity: .09;
  background-size: cover;
  background-position: center;
}

.credentials-grid {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 64px;
}
.credentials-grid h2 { font-size: 23px; color: var(--band-ink); margin-bottom: 10px; }
.credentials-grid p  { font-size: 16px; color: var(--band-ink-2); max-width: none; }


/* ---------------------------------------------------------- two doors -- */

.doors > .container { padding-block: 210px 150px; }   /* clears the credential band */
.doors-head { text-align: center; margin-bottom: 96px; position: relative; z-index: 2; }
.doors-grid { display: grid; grid-template-columns: 1fr 1fr; column-gap: 96px; position: relative; z-index: 1; }
.door--grief { margin-top: 88px; }

.door-frame { position: relative; }
.door-frame .solid { inset: -54px -54px auto auto; width: 100%; height: 100%; }
.door--coaching .door-frame .solid { inset: -54px auto auto -54px; }
/* Square, per the handoff prose: "a square photograph over a square accent
   solid offset 54px". The prototype markup said 4/5, which at a 562px column
   renders 702px tall and dominates the band. Square is both the written spec
   and the better read. */
.door-frame img.door-photo {
  position: relative; z-index: 2; width: 100%;
  aspect-ratio: 1/1; object-fit: cover; display: block;
}
.door--coaching .door-photo > img { object-position: 50% 18%; }
.door--grief .door-photo    > img { object-position: 50% 15%; }
.door-frame .ring { z-index: 1; }

/* small nature frame overlapping the coaching door's lower edge */
.door-inset {
  position: absolute; right: -46px; bottom: -52px; z-index: 3;
  width: 168px; height: 168px; object-fit: cover; box-shadow: var(--sh-small);
}

.door-body { padding-top: 44px; }
.door-body h3 { margin-bottom: 14px; }
.door-body p { max-width: 52ch; margin-bottom: 20px; }

/* --------------------------------------------------------------- bio --- */

.bio > .container {
  display: grid; grid-template-columns: 5fr 7fr; gap: 96px; align-items: center;
  padding-bottom: 250px;          /* room under the copy before the drift band */
}
/* The figure anchors to the bottom of the row and then overshoots by 200px.
   130px of that is eaten by the container padding, so it breaks the section
   edge by roughly 70px. align-self is load-bearing: under align-items: center
   the negative margin just recentres the figure instead of pushing it out.
   overflow-x: clip on .section leaves the y axis visible, which is what lets
   it hang into the drift strip below. */
.bio-figure { align-self: end; margin-bottom: -30px; z-index: 3; }
.bio-figure { justify-self: center; position: relative; width: 356px; height: 454px; z-index: 1; }
.bio-figure .solid { left: -54px; top: 54px; width: 300px; height: 380px; }
.bio-figure .ring { z-index: 1; }
.bio-portrait {
  position: relative; z-index: 2; width: 302px; height: 454px;
  margin-left: 54px;
}
.bio-portrait > img { object-position: 44% 30%; }
/* added frame — a small garden square hung off the portrait's bottom-left */
.bio-inset {
  position: absolute; left: -30px; bottom: -54px; z-index: 3;
  width: 158px; height: 158px; object-fit: cover; box-shadow: var(--sh-small);
}

.bio-body h2 { margin-bottom: 22px; }
.bio-body p { max-width: 60ch; }
.signature { display: flex; align-items: center; gap: 24px; margin: 26px 0; }
.signature__script { font-family: var(--accent); font-size: 38px; line-height: 1; }
.signature__rule { width: 1px; height: 44px; background: var(--rule); }
.signature__certs { font-size: 15px; line-height: 1.5; color: var(--ink-2); }

/* ------------------------------------------------- transition / drift -- */
/* Full-bleed band of nature photographs only. No copy, no CTA.
   Each column drifts downward at its own rate as the band passes.
   Fully disabled under prefers-reduced-motion and on small screens. */

/* The drift band is pulled up into the bio band and its own background is
   transparent, so the sand-to-cream seam above it cuts through the middle of
   the photographs rather than sitting cleanly above them. */
.transition {
  background: transparent;
  padding-block: 0;
  overflow: hidden;
  position: relative;
  z-index: 2;
  margin-top: -272px;
}
.transition-inner {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 22px;
  padding-inline: 22px;
  align-items: start;
  /* headroom so the drifting columns never expose the band edge */
  padding-block: 96px 118px;
}
.drift { will-change: transform; }
/* No height here. The per-image aspect-ratio comes in inline from $TRANSITION,
   and an explicit height would beat it. */
.drift img {
  width: 100%; object-fit: cover; display: block;
}
.drift--tall  { margin-top: 0; }
.drift--mid   { margin-top: 54px; }
.drift--low   { margin-top: 104px; }

/* ---------------------------------------------------------- free call -- */

/* Flat ground. The gradient was fighting the drift band directly above it. */
.freecall { background: var(--ground); }
.freecall > .container {
  display: grid; grid-template-columns: 7fr 5fr; gap: 88px; align-items: center;
  position: relative;
}
.freecall .mark--stroke { right: 40px; top: 70px; width: 120px; height: 234px; }
.freecall-body { position: relative; z-index: 1; }
.freecall-body h2 { font-size: 46px; margin-bottom: 24px; }
.freecall-body p { font-size: 21px; max-width: 60ch; margin-bottom: 18px; }
/* .freecall-body p is more specific than .kicker, so the eyebrow needs its own
   line or it renders at body size instead of matching the other kickers. */
.freecall-body p.kicker { font-size: 29px; max-width: none; }
.freecall-promise { display: flex; align-items: center; gap: 20px; margin-bottom: 34px; }
.freecall-promise .kicker { font-size: 31px; margin: 0; }
.freecall-promise .mark--arrow { position: relative; width: 62px; height: 30px; flex: none; }

.figures { display: grid; gap: 26px; position: relative; z-index: 1; }
/* On the homepage the three figures sit in a row under the copy, on the left. */
.figures--row {
  grid-template-columns: repeat(3, auto);
  justify-content: start; gap: 48px;
  margin: 34px 0 30px; padding: 26px 0;
  border-top: 1px solid var(--sage); border-bottom: 1px solid var(--sage);
}
.figure__num { font-family: var(--display); font-size: 34px; line-height: 1; color: var(--action); margin-bottom: 6px; }
.figure__label { font-size: 17px; }
/* Image cluster on the right: one large frame with two smaller ones hung off
   its corners, offset solid behind. */
.freecall-stage { position: relative; z-index: 1; padding: 30px 0 70px; }
.freecall-stage .solid {
  background: var(--sage); right: -40px; top: -22px; width: 74%; height: 62%;
}
.freecall-photo {
  position: relative; z-index: 2; width: 100%; aspect-ratio: 4/3;
  object-fit: cover; box-shadow: var(--sh-photo);
}
.freecall-photo--sm {
  position: absolute; left: -58px; bottom: 6px; z-index: 3;
  width: 170px; aspect-ratio: 1/1; object-fit: cover; box-shadow: var(--sh-small);
}
.freecall-photo--xs {
  position: absolute; right: 12px; bottom: -34px; z-index: 3;
  width: 132px; aspect-ratio: 4/5; object-fit: cover; box-shadow: var(--sh-small);
}

/* ------------------------------------------------------ testimonials --- */

.quotes-head {
  position: relative; display: flex; align-items: flex-end;
  justify-content: space-between; gap: 32px; margin-bottom: 44px;
}
.quotes-head h2 { font-size: 42px; }
.quotes-nav { display: flex; align-items: center; gap: 12px; }
/* REVIEW #10 — with one quote on screen the reader loses the sense of how many
   there are, which the three-up rail gave away for free. The counter puts that
   back without showing the thinness. */
.quotes-count {
  font-size: 15px; color: var(--ink-2); font-variant-numeric: tabular-nums;
  min-width: 46px; text-align: center;
}
.quotes-btn {
  width: 52px; height: 52px; border-radius: 50%;
  border: 1.5px solid var(--action); background: transparent; color: var(--action);
  font-size: 20px; cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: background-color 180ms ease, color 180ms ease;
}
.quotes-btn--next { background: var(--action); color: var(--ground); }
.quotes-btn:hover { background: var(--action-hover); border-color: var(--action-hover); color: var(--ground); }

.quotes-viewport {
  position: relative; overflow: hidden;
  -webkit-mask: linear-gradient(90deg, #000 0%, #000 82%, rgba(0,0,0,.12) 100%);
          mask: linear-gradient(90deg, #000 0%, #000 82%, rgba(0,0,0,.12) 100%);
}

/* REVIEW #10 — one at a time. The card fills the viewport instead of sitting
   in a 400px rail, so nothing is sliced off at the right edge and there is no
   fade mask implying more cards just out of view. The JS measures its stride
   from the cards themselves, so widening them here is all that is required. */
.quotes-viewport--single {
  -webkit-mask: none;
          mask: none;
}
.quotes-viewport--single .quotes-track { gap: 48px; }
.quotes-viewport--single .quote-card {
  /* The basis stays 100% because it is also the carousel's stride — the JS
     measures offsetLeft between cards. The readable measure is set on the
     contents instead. */
  flex: 0 0 100%;
  padding: 64px 72px 56px;
  min-height: 0;
  transition: opacity 420ms ease;
  align-items: flex-start;
  /* All four cards stretch to the tallest, so space-between stranded the
     attribution at the foot of the card on the short quotes. Centring the
     quote and its attribution as one block keeps them together and keeps the
     card height stable between slides. */
  justify-content: center;
  /* Both are load-bearing: position for the texture panel, and overflow so
     that panel is trimmed by the card's own corner radius instead of
     squaring off the right-hand side of the box. */
  position: relative;
  overflow: hidden;
  border-radius: 30px;
  /* The base .quote-card carries margin: 19px 40px, which held the rail in
     from the container edge. At full width that 40px pushed the card out of
     line with the section heading above it. The vertical margin stays — it is
     what gives the drop shadow room. The carousel measures its stride from the
     cards themselves, so zeroing this stays in step automatically. */
  margin-inline: 0;
}

/* The quote sits left. Capped by whichever comes first, a comfortable measure
   or half the card, so a wide card never runs the line under the texture. */
.quotes-viewport--single .quote-card blockquote,
.quotes-viewport--single .quote-card figcaption {
  position: relative; z-index: 1;
  width: 100%; max-width: min(44ch, 50%);
}

/* Texture panel down the right-hand side, feathered on its left so it
   dissolves toward the quote rather than ending on a line. Two mask layers
   that must agree: the texture shape AND the feather. */
.quotes-viewport--single .quote-card::after {
  content: ''; position: absolute; z-index: 0; pointer-events: none;
  right: 0; top: 0; bottom: 0; width: 46%;
  background: var(--c-welcome);
  opacity: .17;
  -webkit-mask-image: var(--tex-welcome), linear-gradient(90deg, transparent 0%, rgba(0,0,0,.45) 32%, #000 70%);
          mask-image: var(--tex-welcome), linear-gradient(90deg, transparent 0%, rgba(0,0,0,.45) 32%, #000 70%);
  -webkit-mask-size: cover, 100% 100%;
          mask-size: cover, 100% 100%;
  -webkit-mask-position: right center, center;
          mask-position: right center, center;
  -webkit-mask-repeat: no-repeat, no-repeat;
          mask-repeat: no-repeat, no-repeat;
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
}
/* The cross-fade is gated on .is-live, which site.js adds once it has taken
   the carousel over. Without JS every card stays fully opaque and the viewport
   simply clips to the first one, rather than the whole section going blank. */
.quotes-viewport--single .quotes-track.is-live .quote-card { opacity: 0; }
.quotes-viewport--single .quotes-track.is-live .quote-card.is-current { opacity: 1; }
.quotes-viewport--single .quote-card p { font-size: 30px; line-height: 1.46; max-width: none; }
.quotes-viewport--single .quote-card cite { margin-top: 34px; }

.quotes-track {
  display: flex; gap: 32px;
  transition: transform 520ms cubic-bezier(.4, 0, .2, 1);
}
.quote-card {
  flex: 0 0 400px;
  background: var(--ground);
  border-radius: 30px;
  padding: 44px 40px 40px;
  box-shadow: var(--sh-card);
  display: flex; flex-direction: column; justify-content: space-between;
  min-height: 340px;
}
.quote-card blockquote { margin: 0; }
.quote-card p {
  font-family: var(--display); font-style: italic; font-size: 23px; line-height: 1.5;
  margin: 0; max-width: none;
}
.quote-card cite { display: block; font-style: normal; font-size: 15px; color: var(--ink-2); margin-top: 28px; }
.quotes-note { font-size: 14px; color: var(--ink-2); margin-top: 32px; max-width: 68ch; }

/* ---------------------------------------------------------- speaking --- */

.speaking > .container {
  display: grid; grid-template-columns: 6fr 6fr; gap: 96px; align-items: center;
}
.speaking-body { position: relative; z-index: 1; }
.speaking-body h2 { margin-bottom: 16px; }
.speaking-body p { font-size: 18px; max-width: 56ch; margin-bottom: 22px; }
.speaking-stage { position: relative; height: 420px; z-index: 1; }
.speaking-stage .solid { right: 0; bottom: -40px; width: 340px; height: 250px; }
.speaking-stage .ring { z-index: 1; }
.speaking-photo {
  position: absolute; left: 0; top: 0; width: 420px; aspect-ratio: 4/3;
  object-fit: cover; z-index: 2; box-shadow: var(--sh-photo);
}
.speaking-inset {
  position: absolute; right: 28px; bottom: 24px; width: 200px; height: 142px;
  object-fit: cover; z-index: 3; box-shadow: var(--sh-small);
}

/* ----------------------------------------------------------- closing --- */

.closing > .container { text-align: center; padding-block: var(--pad-band); }
.closing h2 { margin-bottom: 18px; }
.closing p { max-width: 52ch; margin: 0 auto 34px; }
.closing-actions {
  display: flex; align-items: center; justify-content: center;
  gap: 28px; flex-wrap: wrap; margin-bottom: 44px;
}
.closing-actions a:not(.btn) { font-size: 18px; text-decoration: underline; text-underline-offset: 5px; }
.closing-line {
  font-family: var(--accent); font-size: 46px; line-height: 1.2;
  color: var(--coral); margin: 0; max-width: none;
}

/* ------------------------------------------------------------ footer --- */

.footer { background: var(--anchor); color: var(--ground); }
.footer > .container { padding-block: 48px 28px; }
.footer-grid {
  display: grid; grid-template-columns: 4fr 2fr 3fr 3fr; gap: 56px; padding-bottom: 56px;
}
.footer-brand p { font-size: 16px; color: rgba(253, 251, 247, .68); max-width: 34ch; }

/* REVIEW #1 — the certification seals, under the Contact column.

   Height-matched rather than width-matched: the two seals are different
   shapes (one is a circle, the other a wreath-and-ribbon lockup wider than it
   is tall), and matching widths would make the circle read as the larger of
   the two.

   They wrap rather than overflow: the Contact column is 3fr of an 11fr grid,
   which is about 287px at full width, and two chips come to roughly 250px. It
   fits, but only just, so the row is allowed to break rather than push the
   column wider and unbalance the footer. */
/* Social, under the mark. Icons inherit currentColor from the link. */
.footer-social {
  list-style: none; margin: 26px 0 0; padding: 0;
  display: flex; gap: 12px;
}
.footer-social a {
  display: flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 50%;
  color: rgba(253, 251, 247, .82);
  background: rgba(253, 251, 247, .08);
  transition: background-color 160ms ease, color 160ms ease;
}
.footer-social a:hover { background: rgba(253, 251, 247, .18); color: var(--ground); }
.footer-social svg { width: 20px; height: 20px; display: block; }

/* The seals, stacked in the column Follow used to hold.

   Both were issued for light grounds and both are mostly mid-blue, so sitting
   straight on the dark footer they lost their outlines and read as two vague
   discs — a credential nobody can identify is not doing a credential's job.
   The pale chip gives them back the ground they were drawn for. Rounded
   rectangle rather than circle because only one of the two is circular; the
   other is a wreath-and-ribbon lockup wider than it is tall. */
.footer-seals {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 14px;
}
/* Both chips the same width. align-items: flex-start means the li shrinks to
   its content, so `width: 100%` on the button was resolving against the image
   inside it — and the two marks are different shapes, so the two chips came
   out different widths. An explicit width fixes them to each other.
   The images stay height-matched rather than width-matched: one is a circle,
   the other a wreath-and-ribbon lockup wider than it is tall, and matching
   their widths would make the circle read as the larger of the two. */
.footer-seals li { width: 100%; }
.footer-seals .seal {
  display: block; width: 190px; max-width: 100%;
  background: rgba(253, 251, 247, .94);
  border: 0; border-radius: 14px;
  padding: 14px 20px; cursor: pointer;
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.footer-seals .seal:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 28px -14px rgba(0, 0, 0, .55);
}
.footer-seals .seal:focus-visible { outline: 2px solid var(--marigold); outline-offset: 3px; }
.footer-seals img { height: 92px; width: auto; margin-inline: auto; }

/* ------------------------------------------------ certification modal --- */

.seal-modal {
  border: 0; border-radius: 22px; padding: 40px 44px 36px;
  max-width: 460px; width: calc(100vw - 40px);
  background: var(--ground); color: var(--ink);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .5);
  position: relative;
}
.seal-modal::backdrop { background: rgba(20, 18, 16, .62); }
.seal-modal__img { width: 190px; height: auto; margin: 0 auto 24px; display: block; }
.seal-modal__title { font-family: var(--display); font-size: 27px; text-align: center; margin: 0 0 10px; }
.seal-modal__body { font-size: 17px; color: var(--ink-2); text-align: center; margin: 0 auto; max-width: 34ch; }
.seal-modal__close {
  position: absolute; right: 14px; top: 12px;
  width: 40px; height: 40px; border: 0; border-radius: 50%;
  background: transparent; color: var(--ink-muted);
  font-size: 26px; line-height: 1; cursor: pointer;
}
.seal-modal__close:hover { background: var(--sand); color: var(--ink); }

@media (max-width: 1024px) {
  .footer-seals .seal { width: 168px; padding: 12px 16px; }
  .footer-seals img { height: 76px; }
}
@media (prefers-reduced-motion: reduce) {
  .footer-seals .seal, .footer-social a { transition: none; }
  .footer-seals .seal:hover { transform: none; }
}
/* One asset, two colourways: the nav takes logo-mark.png, the footer takes
   the all-white logo-mark-white.png. Nothing is reconstructed in live type
   here any more, so the two lockups cannot drift apart. */
.footer-lockup { margin-bottom: 22px; }
.footer-lockup img { display: block; height: 116px; width: auto; }
.footer-lockup__wordmark {
  font-family: var(--display); font-size: 24px; color: var(--ground);
}
.footer-head {
  font-family: var(--body); font-size: 13px; font-weight: 600;
  letter-spacing: 1.6px; text-transform: uppercase;
  color: var(--marigold); margin-bottom: 18px;
}
.footer-links { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; font-size: 16px; }
.footer-links a { color: rgba(253, 251, 247, .82); text-decoration: none; }
.footer-links a:hover { color: var(--ground); text-decoration: underline; }
.footer-links .is-pending { color: rgba(253, 251, 247, .55); }   /* was .45 — 4.02:1 */
.footer-legal {
  border-top: 1px solid rgba(253, 251, 247, .14);
  padding-top: 24px;
  display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap;
  font-size: 14px; color: rgba(253, 251, 247, .5);
}
.footer-photo-credit {
  font-size: 14px; line-height: 1.6; color: rgba(253, 251, 247, .5);
  margin: 0 0 22px; max-width: 70ch;
}
.footer-legal__links { display: flex; gap: 24px; flex-wrap: wrap; }
.footer-legal a { color: rgba(253, 251, 247, .6); text-decoration: none; }
.footer-legal a:hover { color: var(--ground); }

/* --------------------------------------------------------- reveal ------ */
/* Fade and rise, once, 16px travel. Nothing else. */

/* REVIEW #2 — "some animation/movement as you scroll down, doesn't have to be
   a lot." The mechanism already existed; it was set so low it was invisible
   (16px over 600ms) and only four blocks on the homepage used it. The travel
   is raised to 28px, the curve given a little more ease-out, and --d exposed
   so neighbouring elements in a band can stagger instead of arriving as one
   slab. Still one move per element, still never repeating, and still fully
   off under prefers-reduced-motion in the block below. */
.reveal { opacity: 0; transform: translateY(28px); }
.reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity 700ms ease, transform 700ms cubic-bezier(.22, .61, .36, 1);
  transition-delay: var(--d, 0ms);
}
/* Stagger steps. Applied on the element, read by the transition above. */
.reveal--d1 { --d:  90ms; }
.reveal--d2 { --d: 180ms; }
.reveal--d3 { --d: 270ms; }

/* ========================================================== responsive == */

@media (max-width: 1200px) {
  .h1 { font-size: 68px; }
  .hero-portrait { width: 340px; right: 4%; }
  .speaking-photo { width: 100%; max-width: 380px; }
}

@media (max-width: 1024px) {
  :root { --gutter: 28px; }
  html { scroll-padding-top: 96px; }   /* the pill is 66px tall here, plus its 16px inset */

  .nav { grid-template-columns: auto 1fr auto; padding-left: 16px; }
  .nav-list--left, .nav-list--right { display: none; }
  .nav-logo { justify-self: start; }
  .nav-logo img { height: 54px; }
  .nav-right { justify-self: end; }
  .nav-toggle { display: block; }

  .bio > .container,
  .freecall > .container,
  .speaking > .container { grid-template-columns: 1fr; gap: 56px; }

  .credentials-grid { grid-template-columns: 1fr; gap: 34px; }
  .credentials-band { padding: 40px 34px; }

  .transition-inner { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 860px) {
  body { font-size: 18px; }

  /* Mobile rhythm is set by token, not by restating .section here. A
     `.section { padding-block: 84px }` rule at this point sat after
     .section--own-pad and .has-wave at equal specificity and beat both: every
     own-pad band took 84px on top of its container's own padding (474px of
     nothing above the bio portrait at 375), and every wave floated 84px down
     inside its sand band instead of being the band's top edge. */
  :root { --pad-band: 72px; --pad-hero: 56px; --pad-strip: 60px; }
  .wave { height: 60px; }

  .h1 { font-size: 46px; max-width: none; }
  .h2 { font-size: 34px; }
  .h2--md { font-size: 32px; }
  .h2--sm, .h2--xs { font-size: 28px; }
  .h3 { font-size: 25px; }
  .lead { font-size: 19px; }
  .closing-line { font-size: 34px; }

  /* Hero: the collage unstacks into document order. Portraits are 2:3 and
     work natively in a single column, which is the one place the aspect
     ratio is an advantage. */
  .hero > .container { padding-block: 32px 0; }
  .hero-type { position: static; width: auto; max-width: none; }
  .hero-lead { margin-top: 22px; font-size: 19px; }
  /* The collage keeps its overlap on mobile rather than flattening into a
     stack. Flex order puts the portrait first, then each card is pulled up
     over the one above it and alternated left and right. The outward bleeds
     are contained by overflow-x: clip on .section, so nothing scrolls. */
  .hero-stage {
    height: auto; margin-top: 36px;
    display: flex; flex-direction: column; gap: 0;
  }
  .hero-stage .solid { display: none; }

  .hero-portrait {
    position: static; order: 1; width: 84%; align-self: flex-start;
    height: auto; aspect-ratio: 2/3; box-shadow: var(--sh-photo); z-index: 1;
  }
  /* inset: auto matters. The desktop rules set left/top/right in px, and under
     position: relative those still apply as offsets and fling the cards off
     the viewport. */
  .hero-card { position: relative; inset: auto; height: auto; box-shadow: var(--sh-small); }
  .hero-card--right {
    order: 2; width: 54%; align-self: flex-end; aspect-ratio: 3/2;
    margin-top: -26%; margin-right: -5%; z-index: 3;
  }
  .hero-card--low {
    order: 3; width: 47%; align-self: flex-start; aspect-ratio: 3/2;
    margin-top: -15%; margin-left: 7%; z-index: 4;
  }
  .hero-card--left {
    order: 4; width: 40%; align-self: flex-end; aspect-ratio: 4/5;
    margin-top: -7%; margin-right: 11%; z-index: 2;
  }

  .credentials { margin-block: 56px 0; }
  .doors > .container { padding-block: var(--pad-band); }
  .doors-head { margin-bottom: 48px; }
  .doors-grid { grid-template-columns: 1fr; row-gap: 72px; }
  .door--grief { margin-top: 0; }        /* stacks coaching first, equal weight */
  .door-frame .solid,
  .door--coaching .door-frame .solid { inset: -18px -18px auto auto; }
  .door--coaching .door-frame .solid { inset: -18px auto auto -18px; }
  .door-inset { width: 108px; height: 108px; right: -12px; bottom: -26px; }
  .door-frame .ring { display: none; }

  .bio-figure { width: 100%; height: auto; }
  .bio-figure .solid { display: none; }
  .bio-portrait { width: 100%; height: auto; aspect-ratio: 2/3; margin-left: 0; }
  .bio-inset { width: 116px; height: 116px; left: -8px; bottom: -30px; }

  .freecall .mark--stroke { display: none; }
  .freecall-promise { flex-wrap: wrap; gap: 12px; }

  .speaking-stage { height: auto; display: grid; gap: 16px; }
  .speaking-stage .solid, .speaking-stage .ring { display: none; }
  .speaking-photo, .speaking-inset {
    position: static; width: 100%; max-width: none; height: auto; aspect-ratio: 4/3;
  }
  .speaking-inset { aspect-ratio: 3/2; }

  .quote-card { flex: 0 0 min(400px, 82vw); padding: 32px 28px; min-height: 0; }
  .quotes-viewport { -webkit-mask: none; mask: none; }
  .quotes-head { flex-direction: column; align-items: flex-start; gap: 20px; }

  /* REVIEW #10 — the single-quote variant is more specific than the rule
     above, so it keeps its desktop 72px side padding here unless it is reset.
     On a 430px screen that left the text about 226px wide. */
  .quotes-viewport--single .quote-card { padding: 34px 26px 30px; }
  .quotes-viewport--single .quotes-track { gap: 24px; }
  .quotes-viewport--single .quote-card p { font-size: 22px; line-height: 1.5; }
  .quotes-viewport--single .quote-card cite { margin-top: 24px; }
  /* Full measure on a phone (9/11 round). The desktop cap of half the card
     leaves the quote a narrow column down the left of a 320px card. With the
     text running the full width the texture panel sits under the words, so it
     is muted here rather than removed. Same specificity as the base rules, so
     this block has to stay below them. */
  .quotes-viewport--single .quote-card blockquote,
  .quotes-viewport--single .quote-card figcaption { max-width: none; }
  .quotes-viewport--single .quote-card::after { opacity: .05; }

  .transition-inner {
    grid-template-columns: repeat(2, 1fr);
    gap: 14px; padding-inline: 14px; padding-block: 56px;
  }
  /* Drift is off below this width. Reset the staggered margins so the grid
     reads as an even gallery rather than a broken collage. */
  .drift--mid, .drift--low { margin-top: 0; }

  /* Decorative rings are sized for desktop and push the page 60px wide on a
     phone. They are decoration, so they come out rather than get scaled. */
  .section .ring { display: none; }

  .footer-grid { grid-template-columns: 1fr 1fr; gap: 40px; }
  .footer-legal { flex-direction: column; gap: 14px; }
}

@media (max-width: 560px) {
  :root { --pad-band: 56px; --pad-hero: 40px; --pad-strip: 48px; }
  .wave { height: 44px; }
  .footer-grid { grid-template-columns: 1fr; }
  .closing-actions { flex-direction: column; gap: 18px; }
  /* Scoped. A bare .btn rule here also caught the nav CTA, which wrapped its
     label onto two lines and made the mobile bar 16px taller than it needed
     to be. */
  .closing-actions .btn,
  .page-hero__cta .btn,
  .form .btn { width: 100%; text-align: center; }
}

/* ------------------------------------------------- reduced motion ------ */
/* Honored fully and by default. No toggle, no exception. On a site with a
   grief section this is not a nicety. */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  .reveal.is-in { transition-delay: 0ms; }   /* no staggered arrival either */
  /* The nav flair still shows, it just stops travelling. */
  .nav-list > li > a::after, .caret, .subnav a { transition: none; }
  .drift { transform: none !important; }
  .drift--mid, .drift--low { margin-top: 0; }
  .btn:hover { transform: none; }
}

/* ==========================================================================
   Internal pages
   Same design system as the homepage. No greyscale skin.
   ========================================================================== */

/* --------------------------------------------------------- page hero --- */

/* Was 48px, which put the H1 120px below the nav where the homepage puts it
   227px. The internal heroes now open on the same air the homepage hero does. */
.page-hero > .container { padding-block: var(--pad-hero) var(--pad-band); }
.page-hero__grid {
  display: grid; grid-template-columns: 58fr 42fr; gap: 80px; align-items: center;
}
.page-hero__type { position: relative; z-index: 2; }
.h1--page { font-size: 62px; max-width: 17ch; }
.page-hero__type .lead { margin-top: 22px; }
.page-hero__cta { margin-top: 30px; }
.page-hero__cta--below { margin: 56px 0 0; }

.page-hero__figure { position: relative; }
.page-hero__figure .solid {
  left: auto; right: -46px; top: -46px; width: 78%; height: 100%;
}
/* Capped so a tall portrait ratio cannot stretch the grid row and leave a void
   next to a short type block. */
.page-hero__figure { max-height: 520px; }
.page-hero__figure img:not(.ring),
.page-hero__figure .ph {
  position: relative; z-index: 2; width: 100%; height: 520px;
  object-fit: cover; display: block; box-shadow: var(--sh-photo);
}
@media (max-width: 1024px) {
  .page-hero__figure { max-height: none; }
  .page-hero__figure img:not(.ring),
  .page-hero__figure .ph { height: auto; }
}
.page-hero__figure .ring { z-index: 1; }

/* Grief register: the headline gets air and nothing crowds it. */
/* The Grief Education column split, now the standard for every page under
   What Laura Does: even columns and a 2:3 image rather than the 58/42 default. */
.page-hero--even .page-hero__grid { grid-template-columns: 6fr 6fr; gap: 96px; }
.page-hero--quiet > .container { padding-block: 112px 140px; }

/* ------------------------------------------------------ section head --- */

.sec-head { margin-bottom: 34px; }
.sec-head .kicker { margin-bottom: 4px; }

/* Vertical rhythm. Grief pages run 25 to 30 percent looser. */
.stack        { display: grid; gap: 72px; }
.stack--loose { gap: 104px; }

/* ------------------------------------------------------------ split --- */

.split      { display: grid; gap: 80px; align-items: center; }
.split--58  { grid-template-columns: 58fr 42fr; }
.split--42  { grid-template-columns: 42fr 58fr; }
.split--64  { grid-template-columns: 64fr 36fr; }
.split--even{ grid-template-columns: 1fr 1fr; align-items: start; }
.split--top { align-items: start; }
.offset-lo  { margin-top: 72px; }

/* ------------------------------------------------------------- figs --- */

.fig { position: relative; }
.fig .solid { width: 100%; height: 100%; top: -46px; }
.fig--left  .solid { left: -46px; right: auto; }
.fig--right .solid { right: -46px; left: auto; }
/* :not(.ring) matters. The ring is also an <img>, and a bare descendant rule
   overrides its position:absolute and drops it into flow, which stretches the
   whole grid row by the ring's height. */
.fig img:not(.ring) {
  position: relative; z-index: 2; width: 100%; object-fit: cover; display: block;
}
.fig .ring { z-index: 1; }

/* ------------------------------------------------------------ notes --- */
/* Preview annotations. These are review furniture, not site content, and
   they come out when the page is signed off. */

.note {
  font-family: var(--body); font-size: 15px; line-height: 1.65;
  color: var(--ink-2); background: var(--sand);
  border-left: 3px solid var(--rule); border-radius: 0 8px 8px 0;
  padding: 16px 20px; margin: var(--gap-sm) 0 24px; max-width: 74ch;
}
/* The tail container under About's closing band carries one review note and
   nothing else. With notes off it collapses rather than leaving a gap above
   the camera strip. */
.ld-tail:not(:has(.note)) { display: none; }
.ld-tail { padding-bottom: var(--gap-lg); }

/* A run of notes is one block, not several. */
.note + .note { margin-top: 0; }
.note--intent::before { content: '▸ '; color: var(--ink-muted); }
.note--gap { border-left-color: var(--action); color: var(--ink); }
.note--blocking { border-left-width: 5px; }
.note__label {
  display: block; font-family: var(--body); font-size: 11px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--action);
  margin-bottom: 6px;
}

/* ------------------------------------------------------------ lists --- */

.plain-list { list-style: none; margin: 0 0 26px; padding: 0; display: grid; gap: 0; max-width: 74ch; }
.plain-list li {
  border-bottom: 1px solid var(--rule); padding: 18px 0;
  font-size: 19px; line-height: 1.6;
}
.plain-list li:first-child { padding-top: 0; }
.plain-list li:last-child { border-bottom: 0; }

.plain-list--tight li { font-size: 18px; padding: 13px 0; }
.plain-list--cols { max-width: none; }

.resume-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.resume-list li {
  border-bottom: 1px solid var(--rule); padding: 13px 0; font-size: 17px; line-height: 1.55;
}
.resume-list li:last-child { border-bottom: 0; }

/* ------------------------------------------------------------ cards --- */

.cards { display: grid; gap: 28px; }
.cards--2 { grid-template-columns: 1fr 1fr; }
.cards--3 { grid-template-columns: repeat(3, 1fr); }
.card {
  background: var(--ground); border-radius: 30px; padding: 34px 32px;
  box-shadow: var(--sh-card);
}
.section--cream .card { background: var(--sand); box-shadow: none; }
.card h3 { margin-bottom: 12px; }
.card p { font-size: 18px; margin-bottom: 16px; }
.card p:last-child { margin-bottom: 0; }

.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; }

/* -------------------------------------------------------------- faq --- */

/* Hairlines take --rule. --deep is a shape now, not a rule: it was doing
   both jobs, was set to the hairline value, and the shapes disappeared. */
.faq { border-top: 1px solid var(--rule); max-width: none; }
.faq__item { border-bottom: 1px solid var(--rule); }
.faq__q {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 24px;
  background: none; border: 0; cursor: pointer; text-align: left;
  font-family: var(--display); font-size: 22px; font-weight: 700; color: var(--ink);
  padding: 24px 0; min-height: 48px;
}
.faq__q:hover { color: var(--action); }
.faq__icon {
  flex: none; width: 22px; height: 22px; position: relative;
}
.faq__icon::before, .faq__icon::after {
  content: ''; position: absolute; background: var(--action);
  left: 50%; top: 50%; transform: translate(-50%, -50%);
}
.faq__icon::before { width: 16px; height: 2px; }
.faq__icon::after  { width: 2px; height: 16px; transition: transform 200ms ease; }
.faq__q[aria-expanded="true"] .faq__icon::after { transform: translate(-50%, -50%) scaleY(0); }
/* Answers keep a readable measure even though the rule runs full width. */
.faq__a-inner { padding: 0 0 26px; max-width: 74ch; }
.faq__a-inner p { font-size: 18px; }

/* ------------------------------------------------------------ quote --- */

.quote-card--static { flex: none; min-height: 0; }

/* ------------------------------------------------------------- form --- */

.form { display: grid; gap: 22px; max-width: 620px; }
.field { display: grid; gap: 8px; }
.field label { font-size: 16px; font-weight: 600; }
.field .opt { font-weight: 400; color: var(--ink-2); }
.field input, .field select, .field textarea {
  font-family: var(--body); font-size: 18px; color: var(--ink);
  background: var(--sand); border: 1px solid var(--ink-muted); border-radius: 8px;
  padding: 14px 16px; min-height: 52px; width: 100%;
}
.section--sand .field input,
.section--sand .field select,
.section--sand .field textarea { background: var(--ground); }
.field textarea { min-height: 150px; resize: vertical; }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
  outline: 2px solid var(--action); outline-offset: 2px;
}

/* ------------------------------------------------- camera carousel ---- */
/* The internal pages' closing gallery (9/11 round). The homepage drift band's
   look (mixed frames, staggered tops, nature only) with a wave for a twist:
   each frame drops by --w, set per frame in ld_gallery() from a sine, so the
   tops ride a long gentle curve like the site's wave dividers. It is a native
   horizontal scroller with snap; site.js makes it glide on its own and, on
   desktop, adds a small sideways ease as the band scrolls past. */
.camera-scroller {
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity; scroll-padding-inline: var(--gutter);
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.camera-scroller::-webkit-scrollbar { display: none; }
.camera-scroller:focus-visible { outline: 2px solid var(--action); outline-offset: -4px; }
.camera-track {
  --wave-amp: 46px;            /* half the total rise and fall */
  display: flex; align-items: flex-start; gap: 22px;
  width: max-content; list-style: none; margin: 0;
  /* At least 40px each side: the desktop sideways ease travels 32px, and the
     strip must never pull away from its own edge. */
  padding: 0 max(var(--gutter), 40px);
}
.camera-item {
  flex: 0 0 auto; width: 250px; scroll-snap-align: start;
  margin-top: calc((1 - var(--w, 0)) * var(--wave-amp));
}
.camera-item .shot { margin: 0; }
.camera-item img { width: 100%; height: auto; object-fit: cover; display: block; }
/* Snap would pull the glide back to a frame edge on every step, so it is off
   while site.js drives the strip. It stays on when the glide never starts
   (reduced motion, or no script): then it is a plain swipeable row. */
.camera-scroller.is-auto { scroll-snap-type: none; }

/* ------------------------------------------------- internal responsive - */

@media (max-width: 1024px) {
  /* --even has to be named here. .page-hero--even .page-hero__grid is
     specificity (0,2,0) and beats a bare .page-hero__grid no matter that this
     rule sits inside a media query, so without it every internal hero stayed
     two columns on a phone and wedged the photograph in beside the H1. */
  .page-hero__grid,
  .page-hero--even .page-hero__grid,
  .page-hero--quiet .page-hero__grid,
  .split--58, .split--42, .split--64, .split--even { grid-template-columns: 1fr; gap: 44px; }
  .offset-lo { margin-top: 0; }
  .h1--page { font-size: 48px; max-width: none; }
  .cards--3 { grid-template-columns: 1fr 1fr; }
  .page-hero__figure .solid, .fig .solid { display: none; }
}

@media (max-width: 860px) {
  .h1--page { font-size: 34px; }
  .stack, .stack--loose { gap: 56px; }
  .cards--2, .cards--3 { grid-template-columns: 1fr; }
  .stat-row { grid-template-columns: 1fr; gap: 20px; }
  .faq__q { font-size: 19px; }
  .camera-track { --wave-amp: 22px; gap: 14px; padding-inline: var(--gutter); }
  /* The next frame always peeks in from the right edge: the cue to swipe. */
  .camera-item { width: 56vw; max-width: 250px; }
  .page-hero > .container,
  .page-hero--quiet > .container { padding-block: var(--pad-hero) var(--pad-band); }
}

/* The one deliberate fragment on the grief page. It needs air or it reads as
   a typo at body size. */
.pull-line {
  font-family: var(--display); font-size: 30px; line-height: 1.3;
  color: var(--ink); margin: 34px 0 0;
  /* Narrow enough that the break lands on the full stop rather than leaving
     "past." alone on its own line. text-wrap: balance holds the same shape
     where it is supported and if the wording ever changes. */
  max-width: 14ch;
  text-wrap: balance;
}

/* The grief page closes quietly: left aligned, no Caveat flourish. */
.closing--quiet > .container { text-align: left; }
.closing--quiet p { margin-left: 0; margin-right: 0; }
.closing--quiet .closing-actions { justify-content: flex-start; margin-bottom: 26px; }

@media (max-width: 860px) { .pull-line { font-size: 24px; } }

/* --------------------------------------------------- badges + archive -- */

.badge-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 32px;
  background: var(--sand); border-radius: 30px;
  padding: 26px 30px; margin-top: 34px;
  /* Hugs the seals rather than stretching the column. */
  width: fit-content; max-width: 100%;
}
.section--sand .badge-row { background: var(--ground); }
.badge-row img { height: 124px; width: auto; }  /* John 2026-09-25: was 78px, seal text too small to read */
/* About: the full seal set runs the width of the column, evenly spaced. */
.badge-row--spread { width: 100%; justify-content: space-evenly; }

/* Life coaching: three seals in view, auto-rotating, dots to jump.
   site.js adds .is-rotating and builds viewport > track > slots + dots;
   without it the row is the static spread above. */
.badge-row--rotate.is-rotating { display: block; padding-bottom: 14px; }
.badge-viewport { overflow: hidden; }
.badge-track {
  display: flex;
  transition: transform .7s cubic-bezier(.45, 0, .2, 1);
}
.badge-track.no-anim { transition: none; }
.badge-slot {
  flex: 0 0 calc(100% / 3);
  display: flex; align-items: center; justify-content: center;
  height: 124px;
}
.badge-slot img { height: auto; max-height: 124px; width: auto; max-width: 90%; }
.badge-dots { display: flex; justify-content: center; gap: 2px; margin-top: 12px; }
.badge-dots button {
  width: 24px; height: 24px; padding: 0; border: 0; background: none;
  cursor: pointer; display: grid; place-items: center; border-radius: 50%;
}
.badge-dots button::before {
  content: ''; width: 9px; height: 9px; border-radius: 50%;
  background: var(--rule); transition: background .2s, transform .2s;
}
.badge-dots button[aria-current="true"]::before { background: var(--action); transform: scale(1.2); }
.badge-dots button:hover::before { background: var(--ink-muted); }
.badge-dots button[aria-current="true"]:hover::before { background: var(--action-hover); }
.badge-dots button:focus-visible { outline: 2px solid var(--action); outline-offset: 1px; }

/* A seal that has been promised but not supplied. Deliberately outside the
   brand palette: it must read as a gap, not as artwork. */
.badge-ph {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 78px; min-width: 104px; padding: 0 14px; text-align: center;
  border: 1.5px dashed var(--ink-muted); border-radius: 10px;
  font-family: var(--body); line-height: 1.25; color: var(--ink-2);
}
.badge-ph__label { font-size: 13px; font-weight: 700; }
.badge-ph__note {
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-muted); margin-top: 3px;
}

@media (max-width: 860px) {
  .badge-row { gap: 20px; padding: 20px; }
  .badge-row--spread { gap: 18px 14px; justify-content: center; }
  .badge-slot { height: 96px; }
  .badge-slot img { max-height: 96px; }
  .badge-row img, .badge-ph { height: 96px; }
  .badge-ph { min-width: 88px; }
  .badge-ph__label { font-size: 12px; }
}

/* Post card. The thumbnail is edge to edge at the top of the card, so the
   photograph belongs to the card rather than floating inside its padding. */
.card--post { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.card--post .card__thumb { margin: 0; }
.card--post .card__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card--post .card__body { padding: 26px 30px 30px; }
.card--post .caption { margin-bottom: 6px; }

.filter-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 32px; }
.chip {
  font-family: var(--body); font-size: 15px; font-weight: 600;
  background: transparent; color: var(--ink-2);
  border: 1.5px solid var(--ink-muted); border-radius: 999px;
  padding: 9px 20px; min-height: 44px; cursor: pointer;
}
.chip:hover { border-color: var(--action); color: var(--action); }
.chip--on { background: var(--action); border-color: var(--action); color: var(--ground); }

.archive { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.archive li {
  border-bottom: 1px solid var(--rule); padding: 22px 0;
  display: grid; grid-template-columns: 200px 1fr; gap: 24px; align-items: baseline;
}
.archive__meta { font-size: 15px; color: var(--ink-2); }
.archive__title {
  font-family: var(--display); font-size: 23px; font-weight: 700;
  color: var(--ink); text-decoration: none;
}
.archive__title:hover { color: var(--action); text-decoration: underline; text-underline-offset: 5px; }

@media (max-width: 860px) {
  .archive li { grid-template-columns: 1fr; gap: 6px; }
  .archive__title { font-size: 20px; }
}

@media (max-width: 1024px) {
  /* Rings are sized for the desktop composition and push the page ~76px wide
     once the columns stack. Decoration, so they come out. */
  .page-hero__figure .ring, .fig .ring { display: none; }
}

@media (max-width: 620px) {
  .nav-cta__long  { display: none; }
  .nav-cta__short { display: inline; }
  .nav-cta { font-size: 15px; padding: 12px 20px; }
  .nav { padding-left: 14px; gap: 12px; }
}

/* The last sage override is gone. It used the `background` shorthand, which
   reset background-color and beat the --c assignment, so the bio solid stayed
   sage while every other solid took its aspect colour. Sage is now unused as a
   surface; it stays in the tokens for the wireframe skin. */

@media (max-width: 860px) {
  /* The desktop 250px is room for the drift band's overlap, which is off here.
     The section's own padding is the tail; the container adding more doubled it. */
  .bio > .container { padding-bottom: 0; }
  .bio-figure { margin-bottom: 0; }
  .transition { margin-top: 0; background: var(--ground); }
  .figures--row { grid-template-columns: 1fr; gap: 22px; }
  .freecall-stage { padding: 0; }
  .freecall-stage .solid { display: none; }
  .freecall-photo--sm, .freecall-photo--xs { position: static; width: 100%; margin-top: 14px; }
}

/* The closing band runs deep at the top and lightens into --sand, which is the
   house direction every other sand band uses.
   It had been reversed (cream at the top, deepening to --sand-grad at the
   footer) back when the band ran straight into the footer wave. It no longer
   does: the gallery sits between them on flat --sand, so ending the closing on
   --sand-grad put a step directly above the strip. Landing on --sand instead
   means closing band, gallery ground and footer wave are all one value and the
   bottom of every page runs continuous. */
.closing.section--sand {
  background: linear-gradient(180deg,
              var(--sand-grad) 0%,
              var(--sand) 32%,
              var(--sand) 100%);
}

/* The gallery is its own band, not a strip glued to the footer: real space
   above and below, on the page ground, so it reads as a section. */
/* One flat ground for the strip: #F5EFE6 (--sand). No gradient and no feathered
   edge — the band is a block of colour and the photographs sit squarely on it.
   The footer wave directly below is filled with this same value on every page
   that carries the strip, or the two would meet on a visible seam. */
.camera-band {
  background: var(--sand);
  padding-block: var(--pad-strip);
}
/* The band's name, and its accessible name. Sits on the container grid so it
   lines up with every other kicker on the page, while the strip below stays
   full bleed.
   The gap goes on the container, not on the kicker: the kicker is the only
   child of that container, so p:last-child zeroes any margin-bottom set on it.
   It needs to be generous — .kicker is 29px Caveat on line-height 1, so the box
   stops above the descenders and the strip drifts up under it by ~14px as the
   band crosses the viewport. */
.camera-band > .container:first-child { padding-bottom: 40px; }
.camera-kicker { max-width: none; text-align: center; }
/* Mobile padding comes from --pad-strip, set in the responsive blocks. */

/* The two-doors ring sits behind the headline now, not behind the photographs.
   The head needs its own stacking context so the ring lands under the type. */
.doors-head { position: relative; }
.doors-head .ring { z-index: 0; }
.doors-head .kicker, .doors-head .h2 { position: relative; z-index: 1; }

/* Accent circle behind the closing line. */
.closing-line { position: relative; }
.closing-line .ring { z-index: 0; }
.closing-line { z-index: 1; }

/* ---------------------------------------------------------- texture ---- */
/* Recoloured wavy-line texture on a brand ramp. Applied as a pseudo-element
   so its opacity never touches the content, and always behind everything.
   Placed once per band rather than tiled: the artwork is a composition, not a
   seamless pattern, and repeating it shows obvious seams.

   It is deliberately weak. If it is legible as a picture rather than felt as a
   surface, it is too strong. */

.has-texture { position: relative; isolation: isolate; }
/* The ::before sits behind on its own z-index rather than pushing every child
   to position: relative. That child rule was clobbering `position: absolute`
   on decorations like .ring, dropping them into flow and adding their full
   height to the band. */
.has-texture::before {
  content: '';
  position: absolute; inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: url('../images/components/texture-waves.svg');
  background-repeat: no-repeat;
  background-position: right -14% top -18%;
  background-size: auto 210%;   /* larger strokes read as surface, not linework */
  opacity: .22;
  /* Feathered on every edge so the artwork never cuts off against a band
     boundary. Applies wherever .has-texture is used. */
  -webkit-mask-image: radial-gradient(ellipse 78% 78% at 50% 50%,
                      rgba(0,0,0,1) 38%, rgba(0,0,0,.55) 66%, rgba(0,0,0,0) 92%);
          mask-image: radial-gradient(ellipse 78% 78% at 50% 50%,
                      rgba(0,0,0,1) 38%, rgba(0,0,0,.55) 66%, rgba(0,0,0,0) 92%);
}

/* Mirrored, so consecutive bands do not read as the same picture twice. */
.has-texture--left::before {
  background-position: left -12% bottom -18%;
  transform: scaleX(-1);
}

/* REVIEW #12 — the credentials band's texture override lives with the band
   itself, further up, since it needs its own strength on the dark ground. */

@media (max-width: 860px) {
  .has-texture::before { background-size: auto 160%; opacity: .16; }
}

@media (prefers-reduced-motion: reduce) { /* texture is static; nothing to do */ }

/* ==========================================================================
   Off-grid photo compositions
   ========================================================================== */

.comp { position: relative; }
.comp img, .comp .ph { display: block; width: 100%; object-fit: cover; }

/* REVIEW #47 — photo attribution. A quiet credit line under every photograph,
   small enough to read as metadata rather than caption. Placeholder text for
   now; the wording is driven from $PHOTO_CREDIT in config.php. */
.credit {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.4;
  letter-spacing: .04em;
  color: var(--ink-muted);
  text-align: left;
}
.comp .solid { z-index: 0; }

/* --- pair: large frame with a small one on a corner --------------------- */
.comp--pair .comp__big   { position: relative; z-index: 2; width: 84%; }
.comp--pair .comp__small { position: absolute; z-index: 3; width: 42%; box-shadow: var(--sh-small); }
.comp--pair .solid { width: 74%; height: 72%; }

.comp--pair-br .comp__big   { margin-left: 0; }
.comp--pair-br .comp__small { right: 0; bottom: -14%; }
.comp--pair-br .solid       { right: 0; top: -34px; }

.comp--pair-bl .comp__big   { margin-left: 16%; }
.comp--pair-bl .comp__small { left: 0; bottom: -12%; }
.comp--pair-bl .solid       { left: 0; bottom: -34px; }

.comp--pair-tr .comp__big   { margin-left: 0; margin-top: 12%; }
.comp--pair-tr .comp__small { right: 0; top: 0; }
.comp--pair-tr .solid       { right: 6%; bottom: -30px; }

.comp--pair-tl .comp__big   { margin-left: 16%; margin-top: 10%; }
.comp--pair-tl .comp__small { left: 0; top: 0; }
.comp--pair-tl .solid       { left: 4%; bottom: -30px; }

/* --- escape: breaks the container edge ---------------------------------- */
.comp--escape { width: calc(100% + var(--gutter) + 80px); }
.comp--escape-right { margin-right: calc((var(--gutter) + 80px) * -1); }
.comp--escape-left  { margin-left:  calc((var(--gutter) + 80px) * -1); }
.comp--escape img, .comp--escape .ph { box-shadow: var(--sh-photo); }

/* --- trio: staggered three-frame cluster -------------------------------- */
.comp--trio { min-height: 480px; }
.comp--trio .comp__a { position: relative; z-index: 2; width: 56%; }
.comp--trio .comp__b { position: absolute; z-index: 3; width: 46%; box-shadow: var(--sh-small); }
.comp--trio .comp__c { position: absolute; z-index: 1; width: 34%; }
.comp--trio .solid   { width: 46%; height: 56%; }

.comp--trio-right .comp__a { margin-left: 8%; }
.comp--trio-right .comp__b { right: 0; top: 14%; }
.comp--trio-right .comp__c { left: 0; bottom: -6%; }
.comp--trio-right .solid   { right: 4%; bottom: 4%; }

.comp--trio-left .comp__a { margin-left: 34%; }
.comp--trio-left .comp__b { left: 0; top: 10%; }
.comp--trio-left .comp__c { right: 0; bottom: -6%; }
.comp--trio-left .solid   { left: 2%; bottom: 6%; }

/* --- stack: vertically offset pair, no overlap -------------------------- */
.comp--stack { display: grid; gap: 22px; }
.comp--stack .comp__one { width: 74%; }
.comp--stack .comp__two { width: 62%; }
.comp--stack-right .comp__one { justify-self: start; }
.comp--stack-right .comp__two { justify-self: end; margin-top: -8%; }
.comp--stack-left  .comp__one { justify-self: end; }
.comp--stack-left  .comp__two { justify-self: start; margin-top: -8%; }

/* Reduced scale. The frames keep their ratios and their overlap; the block just
   takes up less of the column. Released at 860px, where every composition is
   already a plain single column and a cap would only make it narrow. */
.comp--sm { max-width: 64%; }
@media (max-width: 860px) { .comp--sm { max-width: 100%; } }

/* --- bleed: full-width band --------------------------------------------- */
.comp-bleed { display: block; }
.comp-bleed img, .comp-bleed .ph { width: 100%; display: block; object-fit: cover; }

@media (max-width: 1024px) {
  .comp--escape { width: 100%; margin-inline: 0; }
  .comp--trio { min-height: 0; }
}

@media (max-width: 860px) {
  /* Every composition collapses to a plain column. Overlaps that read as
     composition on desktop read as collision on a phone. */
  .comp--pair .comp__big,
  .comp--pair .comp__small,
  .comp--trio .comp__a,
  .comp--trio .comp__b,
  .comp--trio .comp__c,
  .comp--stack .comp__one,
  .comp--stack .comp__two {
    position: static; width: 100%; margin: 0; inset: auto;
    justify-self: stretch;
  }
  .comp--pair, .comp--trio { display: grid; gap: 16px; }
  .comp--pair .solid, .comp--trio .solid { display: none; }
  .comp--stack .comp__two { margin-top: 0; }
}


/* --------------------------------------------------- ring anchoring ---- */
/* Rings were positioned with percentage offsets against containers that
   resize, so they drifted relative to the words as the viewport changed.
   .ring-anchor shrink-wraps the text and becomes the positioning context, so
   a px offset is measured from the text box itself and stays put at every
   width. */
.ring-anchor { display: inline-block; position: relative; }
.ring-anchor > .ring { z-index: 0; }
.ring-anchor > h1, .ring-anchor > h2, .ring-anchor > h3 { position: relative; z-index: 1; }

/* The closing line shrink-wraps for the same reason: it is a centred <p> that
   spanned the full container, so a right: % offset moved with the viewport. */
.closing-line { display: inline-block; }

/* ------------------------------------------------- widows and orphans -- */
/* text-wrap: pretty rebalances the last lines so a headline never leaves a
   single word stranded. The nbsp fallback below handles engines without it. */
.page-hero__type h1,
.page-hero__type .h1,
.page-hero__type p,
.page-hero__type .lead,
.hero-type h1,
.hero-type .h1,
.hero-type p,
.hero-type .hero-lead,
.hero-type .kicker {
  text-wrap: pretty;
  -webkit-hyphens: none;
  hyphens: none;
}

/* Headlines get the tighter balancing: short enough that the browser can
   even out every line rather than only the last. */
.page-hero__type .h1,
.hero-type .h1,
.page-hero__type .kicker,
.sec-head .h2 {
  text-wrap: balance;
}

/* ==========================================================================
   REVIEW #9 — events (Speaking and workshops)
   Built to the Hope's Door events-page pattern: a text hero, then a stack of
   cards, each one a date badge, a body and a thumbnail. Rows were the earlier
   treatment; cards give the thumbnail somewhere to live and let the date read
   as a badge rather than a column heading.
   ========================================================================== */


/* ---------------------------------------------------- events list rows ---
   Built to the list view The Events Calendar renders for Hope's Door: a month
   rule, then one row per event. Rows, not cards — no panel, no shadow, no
   hover lift. The page ground carries them and the month rules do the
   dividing, which is what makes a long list scannable. */

.ev-list { margin-top: 4px; }

/* Month rule. The label sits left and the hairline runs out to the container
   edge, so a new month reads as a break rather than as another heading. */
.ev-month-sep {
  display: flex; align-items: center; gap: 24px;
  font-family: var(--display); font-size: 21px; font-weight: 700;
  color: var(--ink); margin: 56px 0 32px;
}
.ev-list > .ev-month-sep:first-child { margin-top: 8px; }
.ev-month-sep::after {
  content: ''; flex: 1 1 auto; height: 1px; background: var(--rule);
}

.ev-row {
  display: grid;
  grid-template-columns: 78px minmax(0, 1fr) 340px;
  gap: 36px;
  align-items: start;
  padding-bottom: 52px;
}
.ev-row--no-media { grid-template-columns: 78px minmax(0, 1fr); }

/* Date block. Day-of-week over the number, the number in the action colour,
   which is the one place on this page that carries the accent. */
.ev-row__date { margin: 0; text-align: center; line-height: 1.05; }
.ev-row__dow {
  display: block; font-size: 12px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-muted); margin-bottom: 3px;
}
.ev-row__day {
  display: block; font-family: var(--display); font-size: 32px; color: var(--action);
}

.ev-row__meta {
  font-size: 15px; font-weight: 600; color: var(--action);
  margin: 0 0 8px; max-width: none;
}
.ev-row__title { font-size: 27px; line-height: 1.2; margin: 0 0 6px; }
.ev-row__title a { color: var(--action); text-decoration: none; }
.ev-row__title a:hover { text-decoration: underline; }
.ev-row__meta-host {
  font-size: 14px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-muted); margin: 0 0 12px; max-width: none;
}
.ev-row__body p { max-width: 62ch; }
.ev-row__closed {
  font-size: 15px; color: var(--ink-muted); font-style: italic; margin-top: 14px;
}

/* Square corners, like every other photograph on the site. */
.ev-row__media { margin: 0; position: relative; }
.ev-row__media img {
  width: 100%; display: block; object-fit: cover; aspect-ratio: 3 / 2;
  box-shadow: var(--sh-photo);
}

/* ------------------------------------------------- single event page --- */
/* Built to the single-event view The Events Calendar renders: title, when,
   photograph, description, add to calendar, a details table, then previous and
   next across the rest of the list. One measured column, not the full 1300. */

.ev-single { max-width: 760px; }
.ev-single__back { font-size: 15px; margin: 0 0 18px; }
.ev-single__back a { text-decoration: none; }
.ev-single__back a:hover { text-decoration: underline; }
.ev-single__title { margin: 0 0 14px; max-width: none; }
.ev-single__when {
  font-size: 19px; font-weight: 600; color: var(--action);
  margin: 0 0 30px; max-width: none;
}
.ev-single__media { margin: 0 0 30px; }
.ev-single__media img {
  width: 100%; display: block; object-fit: cover; aspect-ratio: 3 / 2;
  box-shadow: var(--sh-photo);
}
.ev-single__body p { max-width: 66ch; }
.ev-single__actions { margin: 26px 0 0; }

/* Add to calendar. Both options are live links, so the control does what it
   says: a Google template URL and an .ics the browser downloads. */
.ev-addcal { position: relative; margin: 30px 0 44px; width: fit-content; }
.ev-addcal > summary {
  display: inline-flex; align-items: center; gap: 12px;
  cursor: pointer; list-style: none; min-height: 48px;
  padding: 0 24px; border: 1.5px solid var(--ink-muted); border-radius: 999px;
  font-family: var(--body); font-size: 16px; font-weight: 600; color: var(--ink);
}
.ev-addcal > summary::-webkit-details-marker { display: none; }
.ev-addcal > summary:hover { border-color: var(--action); color: var(--action); }
.ev-addcal__caret {
  width: 9px; height: 9px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
}
.ev-addcal[open] > summary .ev-addcal__caret { transform: rotate(-135deg) translate(-3px, -3px); }
.ev-addcal ul {
  position: absolute; z-index: 20; left: 0; top: calc(100% + 6px);
  list-style: none; margin: 0; padding: 8px; min-width: 230px;
  background: var(--ground); border-radius: 14px; box-shadow: var(--sh-panel);
}
.ev-addcal ul a {
  display: block; padding: 11px 14px; border-radius: 8px;
  font-size: 16px; color: var(--ink); text-decoration: none;
}
.ev-addcal ul a:hover { background: var(--sand); color: var(--action); }

.ev-details { border-top: 1px solid var(--rule); padding-top: 26px; }
.ev-details__head {
  font-family: var(--body); font-size: 13px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-2);
  margin: 0 0 18px;
}
.ev-details dl {
  margin: 0; display: grid; grid-template-columns: max-content 1fr;
  gap: 10px 30px; font-size: 16px;
}
.ev-details dt { font-weight: 700; color: var(--ink); }
.ev-details dd { margin: 0; color: var(--ink-2); }

.ev-single__nav {
  display: flex; justify-content: space-between; gap: 30px;
  border-top: 1px solid var(--rule); margin-top: 40px; padding-top: 24px;
  font-size: 16px;
}
.ev-single__nav a { text-decoration: none; }
.ev-single__nav a:hover { text-decoration: underline; }

@media (max-width: 560px) {
  .ev-details dl { grid-template-columns: 1fr; gap: 4px 0; }
  .ev-details dd { margin-bottom: 12px; }
  .ev-single__nav { flex-direction: column; gap: 14px; }
}

/* ------------------------------------------------------- list nav row --- */

.ev-listnav {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 10px;
}
.ev-listnav .ev-nav__today { margin-left: 6px; }
.ev-nav__arrow.is-off { opacity: .3; cursor: default; }

/* The range label. It is a disclosure button rather than a heading whenever
   there is a month to jump to, because a caret that opens nothing is a control
   pretending to be one. */
.ev-jump { position: relative; margin-left: 12px; }
.ev-jump > summary {
  display: inline-flex; align-items: center; gap: 10px;
  cursor: pointer; list-style: none; min-height: 44px;
}
.ev-jump > summary::-webkit-details-marker { display: none; }
.ev-jump__label {
  font-family: var(--display); font-size: 30px; font-weight: 700; color: var(--ink);
  margin: 0;
}
.ev-jump__label--plain { margin-left: 18px; }
.ev-jump__caret {
  width: 11px; height: 11px; border-right: 2px solid var(--ink-2);
  border-bottom: 2px solid var(--ink-2); transform: rotate(45deg) translate(-2px, -2px);
}
.ev-jump[open] > summary .ev-jump__caret { transform: rotate(-135deg) translate(-3px, -3px); }
.ev-jump__menu {
  position: absolute; z-index: 20; left: 0; top: calc(100% + 6px);
  list-style: none; margin: 0; padding: 8px;
  background: var(--ground); border-radius: 14px; box-shadow: var(--sh-panel);
  min-width: 190px;
}
.ev-jump__menu a {
  display: block; padding: 10px 14px; border-radius: 8px;
  font-size: 16px; color: var(--ink); text-decoration: none;
}
.ev-jump__menu a:hover { background: var(--sand); color: var(--action); }
/* Below 560 the nav row wraps and the label can land anywhere on the second
   line, so a menu anchored to the label opened 1px past a 430px screen. The
   row is the anchor instead: the menu opens flush with the content edge. */
@media (max-width: 560px) {
  .ev-listnav { position: relative; }
  .ev-jump { position: static; }
}

/* Example rows exist so the layout is reviewable before real dates land. */
.ev-row--example .ev-row__media img { opacity: .8; }
/* The placeholder tag. It has to be unmistakable at a glance: a reviewer must
   never read one of these rows as a real booking. Deliberately not brand
   colour — this is review furniture, not design. */
.event-example {
  font-family: var(--body); font-size: 12px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-2); background: var(--sand);
  border: 1px solid var(--rule); border-radius: 999px;
  padding: 3px 10px; margin-left: 8px; white-space: nowrap;
  vertical-align: middle;
}
.ev-day__event .event-example { font-size: 10px; padding: 1px 6px; margin-left: 4px; }
.events-empty { max-width: 64ch; }

/* ------------------------------------------- events bar / month grid --- */
/* Built to the shape of The Events Calendar month view Hope's Door runs.
   Everything is drawn from tokens, so the wireframe skin greys it out with
   the rest of the page and no rule here has to know about that. */


.ev-bar {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  background: var(--ground);
  border-radius: 999px;
  box-shadow: var(--sh-card);
  padding: 12px 12px 12px 26px;
  margin-bottom: 34px;
}
.ev-bar__search { flex: 1 1 240px; min-width: 0; }
.ev-bar__search input {
  width: 100%; border: 0; background: transparent;
  font-family: var(--body); font-size: 17px; color: var(--ink);
  padding: 10px 0; min-height: 44px;
}
.ev-bar__search input::placeholder { color: var(--ink-muted); }

.ev-views ul { display: flex; gap: 4px; list-style: none; margin: 0; padding: 0; }
.ev-view {
  display: block; padding: 10px 16px; min-height: 44px;
  font-size: 16px; font-weight: 600; color: var(--ink-2);
  text-decoration: none; border-radius: 999px;
  border-bottom: 2px solid transparent;
}
.ev-view:hover { color: var(--action); }
.ev-view.is-on { color: var(--ink); border-bottom-color: var(--action); border-radius: 0; }

.ev-nav { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 22px; }
.ev-nav__today {
  font-size: 15px; font-weight: 600; color: var(--ink-2); text-decoration: none;
  border: 1px solid var(--rule); border-radius: 999px; padding: 9px 18px; min-height: 44px;
  display: inline-flex; align-items: center;
}
.ev-nav__today:hover { border-color: var(--action); color: var(--action); }
.ev-nav__arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%;
  color: var(--ink-2); text-decoration: none; font-size: 26px; line-height: 1;
}
.ev-nav__arrow:hover { background: var(--sand); color: var(--action); }
.ev-nav__label { font-family: var(--display); font-size: 30px; margin-left: 6px; }

.ev-notice {
  background: var(--sand); border-radius: 14px;
  padding: 18px 24px; margin-bottom: 26px; max-width: none;
  font-size: 16px; color: var(--ink-2);
}

.ev-cal__head {
  display: grid; grid-template-columns: repeat(7, 1fr);
  font-size: 13px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-muted); padding-bottom: 8px;
}
.ev-cal__head span { padding-inline: 12px; }

/* Single-pixel gaps rather than borders on each cell, so the grid never
   doubles a line where two cells meet. */
.ev-cal__grid {
  display: grid; grid-template-columns: repeat(7, 1fr);
  gap: 1px; background: var(--rule);
  border-top: 1px solid var(--rule);
  border-left: 1px solid var(--rule);
}
.ev-day {
  background: var(--ground);
  min-height: 124px;
  padding: 10px 12px 14px;
}
.ev-day.is-outside { background: var(--sand); }
.ev-day.is-outside .ev-day__num { color: var(--ink-muted); }
.ev-day__num { font-family: var(--display); font-size: 19px; margin: 0 0 6px; }
.ev-day.is-today .ev-day__num {
  color: var(--action); font-weight: 700;
}
.ev-day__event { font-size: 14px; line-height: 1.35; margin: 0 0 6px; max-width: none; }
.ev-day__event a { text-decoration: none; }
.ev-day__event a:hover { text-decoration: underline; }
.ev-day__event.is-closed { color: var(--ink-muted); font-style: italic; }

.ev-day-head { font-family: var(--display); font-size: 30px; margin-bottom: 20px; }

@media (max-width: 860px) {
  .ev-bar { border-radius: 24px; padding: 14px; }
  .ev-nav__label { font-size: 25px; }
  /* A seven-column grid at phone width gives each day about 45px, which is
     narrower than a single word. The grid becomes a list of the days that
     actually have something in them. */
  .ev-cal__head { display: none; }
  .ev-cal__grid { grid-template-columns: 1fr; border-left: 0; }
  .ev-day { min-height: 0; display: none; }
  .ev-day:has(.ev-day__event) { display: block; }
  .ev-day.is-outside { display: none; }
}

@media (max-width: 900px) {
  /* The photograph goes above the text rather than beside it; a 340px frame
     next to a 300px text column reads as two narrow strips. */
  .ev-row, .ev-row--no-media { grid-template-columns: 78px minmax(0, 1fr); gap: 24px; }
  .ev-row__media { grid-column: 2; grid-row: 1; margin-bottom: 20px; }
  .ev-row__body { grid-column: 2; grid-row: 2; }
  .ev-row__date { grid-column: 1; grid-row: 1; }
  .ev-row__title { font-size: 24px; }
  .ev-month-sep { margin: 44px 0 26px; }
}
@media (max-width: 560px) {
  .ev-row, .ev-row--no-media { grid-template-columns: 1fr; gap: 14px; }
  .ev-row__media, .ev-row__body, .ev-row__date { grid-column: 1; grid-row: auto; }
  .ev-row__date { text-align: left; display: flex; align-items: baseline; gap: 10px; }
  .ev-row__day { font-size: 26px; }
  .ev-jump__label { font-size: 25px; }
}

/* ==========================================================================
   Preview version switcher — REVIEW TOOL, NOT PART OF THE DESIGN
   Literal hex on purpose: it must look identical across all three builds and
   must not change when the wireframe skin re-points the brand tokens. Delete
   this block and $SHOW_VERSION_SWITCHER together when the palette is settled.
   ========================================================================== */

.vswitch {
  position: fixed; left: 18px; bottom: 18px; z-index: 9000;
  background: rgba(28, 27, 25, .93);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border-radius: 14px; padding: 10px 10px 8px;
  box-shadow: 0 12px 34px -12px rgba(0, 0, 0, .55);
  font-family: var(--body);
}
.vswitch__label {
  margin: 0 0 7px 4px; max-width: none;
  font-size: 10px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255, 255, 255, .5);
}
.vswitch__list { list-style: none; margin: 0; padding: 0; display: flex; gap: 5px; }
.vswitch__item {
  display: flex; flex-direction: column; gap: 1px;
  padding: 7px 11px; border-radius: 9px;
  text-decoration: none; color: rgba(255, 255, 255, .72);
  background: rgba(255, 255, 255, .07);
  transition: background-color 150ms ease, color 150ms ease;
}
.vswitch__item:hover { background: rgba(255, 255, 255, .16); color: #fff; }
.vswitch__item.is-on { background: #E9A23B; color: #23211E; }
.vswitch__v    { font-size: 14px; font-weight: 700; line-height: 1.1; }
.vswitch__note { font-size: 10px; line-height: 1.2; opacity: .82; white-space: nowrap; }
/* Four entries now. Wrap rather than run off the viewport on small screens. */
.vswitch { max-width: calc(100vw - 36px); }
.vswitch__list { flex-wrap: wrap; }
.vswitch__item:focus-visible { outline: 2px solid #E9A23B; outline-offset: 2px; }
.vswitch__item.is-on:focus-visible { outline-color: #fff; }

/* Collapses to just the version numbers where there is no room for the notes. */
@media (max-width: 620px) {
  .vswitch { left: 10px; bottom: 10px; padding: 8px; }
  .vswitch__label, .vswitch__note { display: none; }
  .vswitch__item { padding: 9px 12px; }
}
@media (prefers-reduced-motion: reduce) { .vswitch__item { transition: none; } }
