/* =========================================================================
   The MLD Register - main.css
   ONE source-of-truth stylesheet. Design tokens first, then base,
   components, utilities, page-specific sections. All style edits go here.

   Identity: "The Living Ledger" (see DESIGN.md). Committed bottle-green on
   warm bone paper with aged-brass detail; Source Serif 4 display over
   Hanken Grotesk body; ledger-entry captions, index numbering and the
   scalloped verification seal as signature motifs. Mobile-first.
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. Design tokens
   ------------------------------------------------------------------------- */
:root {
  /* Palette (OKLCH; neutrals tinted toward the brand hues, never #000/#fff) */
  --ink: oklch(0.24 0.02 165);
  --ink-soft: oklch(0.42 0.02 165);
  --ink-mute: oklch(0.50 0.016 165); /* >=4.5:1 on paper, paper-2 and green-wash */
  --paper: oklch(0.972 0.008 95);
  --paper-2: oklch(0.943 0.012 95);
  --surface: oklch(0.99 0.004 95);
  /* Filter-panel cards. Rick's specified value (25 Jul 2026), kept as the
     authored hex so it is exactly the colour he picked; it sits in the same
     warm hue-95 family as paper/surface, a shade lighter than paper-2 so the
     cards lift off the panel behind them. */
  --filter-card: #fcfaf1;
  --line: oklch(0.9 0.012 110);
  --line-strong: oklch(0.8 0.02 110);
  --green: oklch(0.36 0.055 165);
  --green-deep: oklch(0.27 0.045 168);
  --green-wash: oklch(0.93 0.02 160);
  /* Brass is context-split (Rick, 17 Aug 2026): #DFA33A on light surfaces,
     #E4B349 on the dark jade bands. Rules INSIDE dark containers
     (.section-green, .site-footer, .cta-band) use --brass-on-dark; brand
     theme.css files that retune --brass must retune --brass-on-dark too.
     --brass-deep stays a darkened text-safe tone (white-on-brass buttons
     need >=4.5:1, which the display brass cannot give). */
  --brass: #DFA33A;
  --brass-on-dark: #E4B349;
  --brass-deep: oklch(0.52 0.085 80);
  --brass-soft: #D3AE71;
  --verified: oklch(0.5 0.09 160);
  --verified-wash: oklch(0.94 0.025 160);
  --danger: oklch(0.5 0.13 25);
  --danger-wash: oklch(0.95 0.02 25);
  --focus: oklch(0.55 0.13 250);

  /* On-green (light text on the committed colour needs +line-height too) */
  --on-green: oklch(0.96 0.01 120);
  --on-green-soft: oklch(0.83 0.02 140);

  /* Typography */
  --font-serif: 'Source Serif 4', Georgia, 'Times New Roman', serif;
  --font-sans: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI',
               Roboto, 'Helvetica Neue', Arial, sans-serif;

  /* Rhythm */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: clamp(3.5rem, 8vw, 6rem);
  --radius: 4px;
  --radius-lg: 12px;
  --shadow-1: 0 1px 2px oklch(0.27 0.045 168 / 0.07), 0 1px 8px oklch(0.27 0.045 168 / 0.05);
  --shadow-2: 0 2px 8px oklch(0.27 0.045 168 / 0.09), 0 12px 32px oklch(0.27 0.045 168 / 0.08);
  /* 80rem = 1280px, the common modern page shell (Tailwind's 7xl; Bootstrap
     sits either side at 1140 and 1320). The old 74rem was undocumented and
     inside the normal range, but it was costing the one page that needs the
     room: almost all the extra goes to the finder's results column, because
     the map beside it is a fixed 22rem. Prose is unaffected either way -
     .prose, guides and forms cap themselves at 46-52rem and every paragraph
     at 70ch, so this widens listings and admin tables, not reading measure. */
  --container: 80rem;
  /* 60rem = 960px. The middle shell, for a long FORM that is neither a
     listing nor prose: the concierge profile preview, where 46rem squeezed
     paired fields (phone + second phone, fee label + minutes + price) into
     columns too narrow to read while 80rem left a single-column form
     stranded across 1280px. Rick, 16 Aug 2026, reviewing his own profile.
     Paragraphs still cap at 70ch, so this widens the CONTROLS, not the
     reading measure. */
  --container-medium: 60rem;
  --container-narrow: 46rem;
  --ease-out: cubic-bezier(0.165, 0.84, 0.44, 1); /* ease-out-quart */

  /* Component tones: every literal a component rule needs, hoisted so a
     per-brand theme.css can re-skin without touching component CSS.
     Values are the engine's Living Ledger defaults. */
  /* Dark-jade header (18 Aug 2026 rebuild). The band is the brand's own
     deep bottle green - the footer's colour, so the page sits inside one
     frame. Heights per the approved spec: 86px desktop resting, 66px
     scrolled; 64px/58px on a phone. --header-offset is what OTHER sticky
     elements (finder bar, sticky map, profile rail) add to their top so
     they park under the pinned compact header, and what scroll-padding
     uses so anchor jumps never land hidden behind it. */
  --header-bg: var(--green-deep);
  --header-ink: var(--on-green);
  --header-ink-soft: var(--on-green-soft);
  --header-accent: var(--brass-on-dark);
  --header-cta-bg: #DCA23A;
  --header-cta-ink: var(--green-deep);
  --header-h: 5.375rem;
  --header-h-scrolled: 4.125rem;
  --header-offset: var(--header-h-scrolled);
  --link-underline: oklch(0.62 0.09 85 / 0.75);
  --on-green-hairline: oklch(0.96 0.01 120 / 0.16);
  --on-green-hairline-strong: oklch(0.96 0.01 120 / 0.18);
  --on-green-mute: oklch(0.72 0.02 150);
  --btn-secondary-border: oklch(0.36 0.055 165 / 0.45);
  --off-white: oklch(0.99 0.004 95);
  --tone-danger-border: oklch(0.7 0.08 25);
  --tone-danger-ink: oklch(0.38 0.12 25);
  --tone-success-border: oklch(0.65 0.08 160);
  --tone-success-ink: oklch(0.35 0.08 160);
  /* One real green for completed-step ticks on every directory (Rick, 28 Sep
     2026). Brand themes restyle --green and --verified (navy on MLD, blue on
     WhatCounsellor), so the ticks take these instead. The only green in
     the official WHAT palette (Rick, 28 Sep 2026): WhatNutritionist's
     primary and accent, #3F6B50 on #D9E2CE. Brightened on 18 Oct 2026
     (Rick, after joining MLD: "a tasteful bright green"): white on the
     solid tick 5.02:1, the tick on its wash 4.55:1, the tick on MLD's
     Porcelain 4.50:1, so every text use stays AA. */
  --tick-green: #15803D;
  --tick-green-wash: #EAF7EE;
  /* The ring round a member's profile photo follows the brand's primary
     colour (--green in every theme). MLD sets its own in its theme. */
  --photo-ring: var(--green);
  --photo-ring-halo: color-mix(in srgb, var(--photo-ring) 14%, transparent);
  /* Membership and Featured offer cards (.offer-card): the "months free"
     line and the total panel follow the brand. MLD sets its own in its
     theme. */
  --offer-free-ink: var(--green);
  --offer-addon-ink: var(--offer-free-ink);
  --offer-total-bg: var(--green-wash);
  /* Hint text on every directory (Rick, 28 Sep 2026): larger and a touch
     darker than each brand's --ink-mute. */
  --hint-ink: #515e6c;
  --tone-verified-border: oklch(0.6 0.08 160);
  --tone-verified-ink: oklch(0.35 0.09 160);
  --tone-neutral-border: oklch(0.55 0.06 165);
  --tone-warn-ink: oklch(0.42 0.08 80);
  --notice-border: oklch(0.7 0.04 160);
  --search-keyline: #92afa4;
  --filter-ink: #727272;
  --filter-line: #a8a8a8;
  --cta-ring: oklch(0.62 0.09 85 / 0.35);
  --cta-ring-soft: oklch(0.62 0.09 85 / 0.2);
  --cta-outline: oklch(0.96 0.01 120 / 0.5);
  --cta-outline-wash: oklch(0.96 0.01 120 / 0.1);
  --radius-stamp: 3px;
  --flourish-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20360%20240'%3E%3Cg%20fill='none'%20stroke='%23F2EFE4'%20stroke-width='2.5'%20stroke-linecap='round'%3E%3Cpath%20d='M-10,120C60,70,140,170,220,120S350,70,380,110'/%3E%3Cpath%20d='M-10,150C60,100,140,200,220,150S350,100,380,140'/%3E%3Cpath%20d='M-10,180C60,130,140,230,220,180S350,130,380,170'/%3E%3C/g%3E%3C/svg%3E");
  --select-chevron: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23727272' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* -------------------------------------------------------------------------
   2. Font faces (self-hosted variable files, exactly two - no CDN)
   ------------------------------------------------------------------------- */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/source-serif-4-var.woff2') format('woff2');
}

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/hanken-grotesk-var.woff2') format('woff2');
}

/* -------------------------------------------------------------------------
   3. Reset and base
   ------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* The header is sticky, so every anchor jump, :target and scrollIntoView
   must clear it or the landing content starts hidden under the band. Since
   the profile round 2 (22 Oct 2026) main.js measures the header's REAL
   height into --header-real on load, on resize and whenever the header
   changes size (an admin bar, a zoomed page, the compact state); the static
   --header-offset is the fallback without the script. */
html { scroll-padding-top: calc(var(--header-real, var(--header-offset)) + var(--space-4)); }

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 1.125rem;
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  text-rendering: optimizeLegibility;
}

/* .shot-title and .shot-heading are headings by APPEARANCE ONLY, for the
   laptop product shot in section 13c. A shot is a picture of another page,
   so real h1/h2/h3 tags inside it would put a second h1 and a run of
   out-of-order sections into the outline of the page carrying the picture.
   The specimen uses paragraphs and borrows the styling - the same trick, for
   the same reason, as .preview-frame .result-name. Never use either class
   outside a shot: a real heading must be a real heading. */
h1, h2, h3, h4, .shot-title, .shot-heading {
  font-family: var(--font-serif);
  font-weight: 600;
  line-height: 1.14;
  color: var(--ink);
  margin: 0 0 var(--space-4);
  letter-spacing: -0.015em;
  text-wrap: balance;
}

/* One h1 size on every page and every brand (Rick, 19 Oct 2026): the
   hero size from his 17 Aug doc. Page headers, the finder and the hero no
   longer set their own. */
h1 { font-size: clamp(2.2rem, 5vw, 3rem); }
h2 { font-size: clamp(1.6rem, 3.2vw, 2.3rem); margin-top: var(--space-6); }
h3 { font-size: clamp(1.25rem, 2vw, 1.5rem); margin-top: var(--space-5); }
h4 { font-size: 1.1rem; }

p { margin: 0 0 var(--space-4); max-width: 70ch; text-wrap: pretty; }
li { text-wrap: pretty; }

a {
  color: var(--green);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2.5px;
  text-decoration-color: var(--link-underline);
  transition: color 160ms var(--ease-out), text-decoration-color 160ms var(--ease-out);
}

a:hover { color: var(--green-deep); text-decoration-color: currentColor; }

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: 2px;
}

img { max-width: 100%; height: auto; display: block; }

ul, ol { padding-left: 1.4rem; margin: 0 0 var(--space-4); }
li { margin-bottom: var(--space-2); }

hr { border: 0; border-top: 1px solid var(--line); margin: var(--space-6) 0; }

blockquote {
  margin: var(--space-5) 0;
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-soft);
  font-family: var(--font-serif);
  font-style: italic;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 var(--space-5);
  font-size: 1.1rem;
}

th, td {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

th {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ink-soft);
  border-bottom: 2px solid var(--brass);
}

::selection { background: var(--brass-soft); color: var(--ink); }

/* -------------------------------------------------------------------------
   4. Layout primitives
   ------------------------------------------------------------------------- */
.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 4vw, 2.5rem);
}

.container-medium {
  max-width: var(--container-medium);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 4vw, 2.5rem);
}

.container-narrow {
  max-width: var(--container-narrow);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 4vw, 2.5rem);
}

.section { padding-block: var(--space-8); }
.section-tint { background: var(--paper-2); }
/* White, for a band that must separate itself from the paper above it (the
   homepage's "Why verification matters", which otherwise ran straight on
   from the hero). */
.section-surface { background: var(--surface); }
/* Rick's specified shell tone for the For Therapists badge/certificate band
   (18 Aug 2026), kept as the authored hex so it is exactly the colour he
   picked - the same warm family as paper-2, a shade deeper. */
.section-shell { background: #EEECE3; }
/* Collapse the top padding when a section follows another of the SAME
   background (e.g. two paper sections in a row), so the shared background
   does not read as one enormous empty gap. Applied per instance, never
   blanket, because colour-banded sections need their own top padding. */
.section-flush-top { padding-block-start: 0; }
.section-green {
  background: var(--green-deep);
  color: var(--on-green-soft);
}
.section-green h2, .section-green h3 { color: var(--on-green); }
.section-green p { line-height: 1.75; }
.section-green a { color: var(--on-green); text-decoration-color: var(--brass-on-dark); }
.section-green a:hover { color: var(--brass-soft); }
.section-green .text-muted { color: var(--on-green-soft); }

/* Quiet corner flourish: the logo's flow-wave lines, whisper-faint in the
   bottom-right of a green band. Opt-in per section via .section-flourish. */
.section-flourish { position: relative; overflow: hidden; }

.section-flourish > .container { position: relative; z-index: 1; }

.section-flourish::after {
  content: '';
  position: absolute;
  right: -5rem;
  bottom: -3rem;
  width: 30rem;
  height: 20rem;
  background: var(--flourish-image) no-repeat;
  background-size: contain;
  opacity: 0.12;
  pointer-events: none;
}

/* Light surfaces inside a green section keep the ink palette */
.section-green .verification-box,
.section-green .card { color: var(--ink-soft); }
.section-green .verification-box h2, .section-green .verification-box h3,
.section-green .card h2, .section-green .card h3 { color: var(--ink); }
.section-green .verification-box a:not(.chip),
.section-green .card a:not(.chip) { color: var(--green); text-decoration-color: var(--link-underline); }
.section-green .verification-box a:not(.chip):hover,
.section-green .card a:not(.chip):hover { color: var(--green-deep); }
.section-green .card .text-muted { color: var(--ink-mute); }
/* The featured card's Verified stamp is a plain .chip like every other one on
   the site now; keep its ink readable against the card on the green band. */
.section-green .card a.chip { color: var(--ink-soft); }

.section-lead {
  max-width: 44rem;
  color: var(--ink-soft);
  font-size: 1.2rem;
  font-family: var(--font-serif);
  line-height: 1.6;
}

.section-green .section-lead { color: var(--on-green-soft); }

.grid-2, .grid-3, .grid-4 {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .grid-2 { grid-template-columns: repeat(2, 1fr); }
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  /* Media column on the LEFT. A visual swap, not a DOM reorder, so the single
     phone column still reads heading, argument, photograph. */
  .grid-2-media-first > :first-child { order: 2; }
  .grid-2-media-first > :nth-child(2) { order: 1; }
}
/* A two-column grid that stays one column until 960px, for a column holding
   something wide such as the profile specimen card (/how-we-differ, 23 Sep 2026:
   at about 740px the specimen's chips pushed the page sideways). */
@media (min-width: 640px) and (max-width: 959.98px) {
  .grid-2.grid-2-late { grid-template-columns: 1fr; }
}

/* The "Why verification matters" media half: one picture from 640px up, the
   same three claims as REAL TEXT below it. The reasoning, and the measurements
   that forced it, are in brands/mld/views/pages/home.php. Only one of the two
   is ever in the document flow, so neither can be read twice. */
.why-infographic { display: none; }

.why-checks {
  display: grid;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.why-checks > li {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}

/* .ledger-photo img above sets width:100% with a shadow, which is right for a
   photograph and wrong for a 56px line drawing. Same specificity, so this wins
   on source order - keep it below that rule. */
.ledger-photo .why-checks img {
  width: 56px;
  height: 56px;
  border-radius: 0;
  box-shadow: none;
}

.why-checks h3 { margin: 0 0 var(--space-2); font-size: 1.05rem; }
.why-checks p { margin: 0; max-width: none; }

@media (min-width: 640px) {
  .why-infographic { display: block; }
  .why-checks { display: none; }
  /* EXCEPT where the infographic was not rendered at all (31 Aug 2026). Panel
     3 of that artwork has "Massage therapists are not regulated by law in the
     UK" BAKED INTO THE PIXELS, which no template can edit, so a country where
     that is untrue gets no infographic and these cards carry the band at every
     width instead. The class is set in home.php beside the same condition that
     drops the image, so the two can never disagree. */
  .why-checks-always { display: grid; }
}

/* A band whose media half is an image with TEXT BAKED INTO IT holds off the
   two-column split until 960px. In a half-width column at 768px the image is
   only ~330px wide - NARROWER than the ~360px it gets in the single phone
   column - so the normal 640px split makes such an image least readable on
   exactly the device that most needs it readable. One opt-in class, because
   this is wrong for every band whose media half is a photograph. */
@media (max-width: 959.98px) {
  .grid-2.infographic-band { grid-template-columns: 1fr; }
}

@media (min-width: 960px) {
  .grid-3 { grid-template-columns: repeat(3, 1fr); }
  .grid-4 { grid-template-columns: repeat(4, 1fr); }
}

/* -------------------------------------------------------------------------
   5. Header
   ------------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--green-deep);
  color: var(--on-green);
  padding: var(--space-3) var(--space-5);
  z-index: 700; /* above the sticky header (600) */
}

.skip-link:focus { left: 0; color: var(--on-green); }

/* Site header, rebuilt 18 Aug 2026 (report section 5): one full dark-jade
   band, sticky at the top of the viewport. The founding strip (.notice-bar)
   above it stays in normal flow and scrolls away; main.js adds .is-scrolled
   past ~90px of scroll and the band compacts (86px -> 66px desktop,
   64px -> 58px phone), animated below unless the visitor prefers reduced
   motion. z-index 600 beats the finder bar (500); the skip link sits above
   both. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 600;
  background: var(--header-bg);
  color: var(--header-ink);
  border-bottom: 1px solid var(--on-green-hairline);
}

/* The compact state earns a whisper of shadow so the pinned band separates
   from content sliding under it; resting at page top it has none. */
.site-header.is-scrolled { box-shadow: 0 2px 10px oklch(0.27 0.045 168 / 0.25); }

.site-header-grid {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  height: var(--header-h);
  transition: height 200ms var(--ease-out);
}

.site-header.is-scrolled .site-header-grid { height: var(--header-h-scrolled); }

.wordmark { display: inline-flex; align-items: center; flex: none; }

/* Cream-on-dark lockup, mark + wordmark only (the strapline lives in the
   footer sign-off where it has room to be read). Width is the animated
   dimension; height follows the artwork's aspect. */
.wordmark-lockup {
  display: block;
  width: 255px;
  max-width: 100%;
  height: auto;
  transition: width 200ms var(--ease-out);
}

.site-header.is-scrolled .wordmark-lockup { width: 210px; }

/* The WHAT brands size the header lockup by HEIGHT (polish pass, 30 Sep
   2026), so every WHAT brand's logo stands the same height whatever its
   artwork's shape: WhatCounsellor's lockup is about 5:1 and WhatHypno's
   about 4:1, so the same width left them 52px and 48px tall. header.php
   prints .wordmark-lockup-what only on a brand with a design, so MLD keeps
   its width-sized strip above. The heights follow the engine's bands. */
.wordmark-lockup.wordmark-lockup-what {
  width: auto;
  max-width: none;
  height: 3rem;
  transition: height 200ms var(--ease-out);
}
.site-header.is-scrolled .wordmark-lockup.wordmark-lockup-what { width: auto; height: 2.625rem; }
@media (min-width: 1200px) and (max-width: 1279.98px) {
  .wordmark-lockup.wordmark-lockup-what { height: 2.75rem; }
  .site-header.is-scrolled .wordmark-lockup.wordmark-lockup-what { height: 2.5rem; }
}
@media (min-width: 1024px) and (max-width: 1199.98px) {
  .wordmark-lockup.wordmark-lockup-what { height: 2.375rem; }
  .site-header.is-scrolled .wordmark-lockup.wordmark-lockup-what { height: 2.25rem; }
}
@media (max-width: 1023.98px) {
  .wordmark-lockup.wordmark-lockup-what { height: 2.5rem; }
  .site-header.is-scrolled .wordmark-lockup.wordmark-lockup-what { height: 2.25rem; }
}
@media (prefers-reduced-motion: reduce) {
  .wordmark-lockup.wordmark-lockup-what { transition: none; }
}

.footer-brand img { max-width: min(420px, 100%); height: auto; }

/* Primary nav: pushed right against the utility cluster. */
.site-nav { margin-left: auto; }

.nav-list {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-list li { margin: 0; }

/* Shared item typography (links and dropdown triggers alike). The 2px
   transparent bottom border is the gold-underline slot: 8px below the text
   via padding, revealed on hover/active, never a filled pill.

   NOWRAP, 31 Aug 2026. A nav label is a name, not prose: "Find a Therapist"
   broken across two lines reads as a cramped mistake and made the row two
   different heights. It happened because these are flex items with no
   nowrap, so once the row ran short of space the browser shrank them and
   wrapped the words INSIDE each item rather than letting the whole menu
   wrap - the flexible spend it found first. Both countries did it, the UK
   sooner because it carries a sixth item (Guides) the US does not.
   Wrapping the words is never the right answer here: the squeeze
   breakpoints below buy the room instead, and below 1024px the phone menu
   takes over. Rick's standing ruling is that a menu WRAPS and never scrolls
   sideways, so every width was measured for overflow, not just for looks. */
.nav-item > a,
.nav-sub-toggle {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  gap: 0.4rem;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: var(--space-2) 0;
  font: inherit;
  font-size: 0.97rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--header-ink);
  text-decoration: none;
  cursor: pointer;
  transition: color 160ms, border-color 160ms;
}

.nav-item > a:hover,
.nav-sub-toggle:hover,
.nav-item.is-active > a,
.nav-item.is-active > .nav-sub-toggle {
  color: var(--off-white);
  border-bottom-color: var(--header-accent);
}

/* Focus on the dark band: the site's blue focus ring drowns in jade, so
   header controls carry a gold ring instead. */
.nav-item > a:focus-visible,
.nav-sub-toggle:focus-visible,
.nav-sub a:focus-visible,
.header-login:focus-visible,
.header-cta:focus-visible,
.nav-toggle:focus-visible {
  outline: 2px solid var(--header-accent);
  outline-offset: 3px;
}

.nav-chevron { flex: none; transition: transform 160ms; }

.has-children.open > .nav-sub-toggle .nav-chevron { transform: rotate(180deg); }

/* Desktop utility cluster: a hairline separates the log-in link (quiet text
   utility) and the one persistent primary button from the content nav. */
.site-header-utility {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin-left: var(--space-5);
  padding-left: var(--space-5);
  border-left: 1px solid var(--on-green-hairline-strong);
}

.header-login {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  text-decoration: none;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--header-ink);
}

/* The log-out icon (partial icon_logout) scales with its link's text and
   never shrinks it. */
.icon-logout { width: 1em; height: 1em; flex: none; }

.header-login:hover,
.header-login[aria-current="page"] {
  color: var(--off-white);
  text-decoration: underline;
  text-decoration-color: var(--header-accent);
  text-underline-offset: 0.3em;
}

/* The only persistent primary button in the header: cream fill, jade text,
   46px resting and 40px in the compact state. Hover warms toward gold
   without losing the dark-on-light contrast. */
.header-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.875rem;
  padding-inline: 1.625rem;
  border-radius: var(--radius);
  background: var(--header-cta-bg);
  color: var(--header-cta-ink);
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: background 160ms, height 200ms var(--ease-out);
}

.header-cta:hover { background: #c98f28; color: var(--header-cta-ink); }

.site-header.is-scrolled .header-cta { height: 2.5rem; }

/* Burger (phone only; desktop hides it below). 44px target. */
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-left: auto;
  background: none;
  border: 0;
  border-radius: var(--radius);
  color: var(--header-ink);
  cursor: pointer;
}

.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 1px;
  background: currentColor;
  position: relative;
  content: '';
  transition: transform 160ms, background 160ms;
}

.nav-toggle-bars::before { position: absolute; top: -6px; }
.nav-toggle-bars::after { position: absolute; top: 6px; }

/* Open state: the bars become the X (spec: burger swaps for a close icon). */
.nav-toggle[aria-expanded="true"] .nav-toggle-bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after { transform: translateY(-6px) rotate(-45deg); }

/* ------------------------------ desktop ------------------------------- */
@media (min-width: 1024px) {
  /* Panel-only slots stay out of the desktop row. */
  .nav-panel-cta,
  .nav-panel-foot { display: none; }

  .has-children { position: relative; }

  /* Dropdown: cream panel, jade text, 10px under the trigger, restrained
     shadow. Hidden until main.js opens it (hover, click or keyboard); the
     no-JS fallback below shows it on :hover/:focus-within with no offset
     gap, so a pointer can always reach it. */
  .nav-sub {
    display: none;
    position: absolute;
    top: calc(100% + 10px);
    left: 50%;
    transform: translateX(-50%);
    min-width: 240px;
    margin: 0;
    padding: 8px;
    list-style: none;
    background: var(--surface);
    color: var(--green-deep);
    border-radius: 10px;
    box-shadow: 0 2px 6px oklch(0.27 0.045 168 / 0.12), 0 12px 28px oklch(0.27 0.045 168 / 0.18);
    z-index: 10;
  }

  .js .has-children.open > .nav-sub { display: block; }

  html:not(.js) .has-children:hover > .nav-sub,
  html:not(.js) .has-children:focus-within > .nav-sub {
    display: block;
    top: 100%;
  }

  .nav-sub a {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0.4rem 0.9rem;
    border-radius: 7px;
    color: var(--green-deep);
    font-size: 0.95rem;
    font-weight: 600;
    text-decoration: none;
  }

  .nav-sub a:hover,
  .nav-sub a:focus-visible,
  .nav-sub a[aria-current="page"] { background: var(--green-wash); }

  /* Dropdown links sit on the CREAM panel, not the dark band: the gold focus
     ring the shared rule gives them is ~1.9:1 on cream and fails WCAG 1.4.11.
     The blue focus ring is the site's default and reads clearly here. The
     trigger itself stays gold - it lives on the dark band. */
  .nav-sub a:focus-visible { outline-color: var(--focus); }

  /* The join action inside a dropdown separates from the informational
     links with a hairline (partial marks it nav-sub-cta). */
  .nav-sub .nav-sub-cta { border-top: 1px solid var(--line); margin-top: 4px; padding-top: 4px; }
  .nav-sub .nav-sub-cta a { font-weight: 700; }
}

/* Tablet-to-small-desktop squeeze (1024-1199px): the full row must fit
   without wrapping, so the flexible spends shrink first - never the item
   count, never below-readable text. */
@media (min-width: 1024px) and (max-width: 1199.98px) {
  .wordmark-lockup { width: 204px; }
  .site-header.is-scrolled .wordmark-lockup { width: 190px; }
  .nav-list { gap: var(--space-3); }
  .site-header-utility { gap: var(--space-3); margin-left: var(--space-3); padding-left: var(--space-3); }
  .header-cta { padding-inline: 0.9rem; }
  .nav-item > a, .nav-sub-toggle { font-size: 0.9rem; }
}

/* Small-desktop squeeze (1200-1279px), added 31 Aug 2026. This band had no
   rules at all and did not need any while nav labels were allowed to wrap
   inside themselves. Now they hold one line, the row is 26px wider than the
   space here, so the same flexible spends give it back - a milder dose than
   the band above, which is 176px narrower. Measured, not guessed: with the
   labels on one line the UK row overflowed at 1200px and 1024px and fitted
   at 1280px, so those are the two bands that needed buying and 1280 up is
   left alone. */
@media (min-width: 1200px) and (max-width: 1279.98px) {
  .wordmark-lockup { width: 216px; }
  .site-header.is-scrolled .wordmark-lockup { width: 198px; }
  .nav-list { gap: var(--space-4); }
  .site-header-utility { gap: var(--space-4); margin-left: var(--space-4); padding-left: var(--space-4); }
  .header-cta { padding-inline: 1rem; }
  .nav-item > a, .nav-sub-toggle { font-size: 0.92rem; }
}

/* MLD's 16px header (features.text_min_16, 16 Oct 2026) needs a deeper
   squeeze, added 16 Oct 2026. With nav labels at 16px, "Log in" wrapped onto
   two lines at about 1024-1045px, and a signed-in member's row ("Log out" plus
   "Your dashboard") ran past the edge and scrolled sideways at about
   1024-1110px. Measured every 2-4px from 1024 to 1320px, signed in and out:
   these spends fit every width. Scoped to MLD's 16px body so the WHAT brands'
   header is untouched. */
.text-min-16:not(.design-what) .header-login { white-space: nowrap; }
@media (min-width: 1024px) and (max-width: 1199.98px) {
  .text-min-16:not(.design-what) .wordmark-lockup { width: 172px; }
  .text-min-16:not(.design-what) .site-header.is-scrolled .wordmark-lockup { width: 164px; }
  .text-min-16:not(.design-what) .site-header-grid { gap: var(--space-4); }
  .text-min-16:not(.design-what) .site-header-utility { gap: var(--space-2); margin-left: var(--space-2); padding-left: var(--space-2); }
  .text-min-16:not(.design-what) .header-cta { padding-inline: 0.75rem; }
}
@media (min-width: 1024px) and (max-width: 1299.98px) {
  .text-min-16:not(.design-what) .site-header-utility .icon-logout { display: none; }
}

/* ------------------------------- phone -------------------------------- */
@media (max-width: 1023.98px) {
  :root {
    --header-h: 4rem;
    --header-h-scrolled: 3.625rem;
    --header-offset: 3.625rem;
  }

  .site-header-grid { gap: var(--space-3); }

  .wordmark-lockup { width: 192px; }
  .site-header.is-scrolled .wordmark-lockup { width: 176px; }

  /* THE 29px SIDEWAYS SCROLL, fixed 1 Sep 2026, and the fix is about WHICH
     item gives way rather than about hiding anything.

     Measured on /about at a 320px viewport before the fix: clientWidth 320,
     scrollWidth 349. The phone row asks for 192 (lockup) + 12 + 73 (country
     switcher) + 12 + 8 + 44 (burger) = 341px inside a 280px content box, so
     it is 61px short. The lockup carried `flex: none`, so the browser took
     the shortfall out of the only item that WOULD shrink - the burger, which
     was rendering 32px wide instead of its designed 44px. So the overflow
     and a sub-minimum finger target were the same bug.

     Two rules settle it, and no page needs overflow-x: hidden (which would
     hide the symptom and break position: sticky):
       - the burger never shrinks. 44px is a finger target, not a preference.
       - the lockup is the one item allowed to shrink, so the row can never
         be wider than its container whatever else lands in it (a longer
         country label, a third control). It scales on its own aspect
         because the img is width + max-width: 100% + height: auto.
     Deliberately no min-width floor on the lockup: a floor is a number that
     goes stale the moment anything beside it changes width. */
  .nav-toggle { flex: none; }
  .wordmark { flex: 0 1 auto; min-width: 0; }

  /* Collapsed phone header is logo + burger ONLY (spec 5D): the login and
     CTA live inside the menu panel instead. */
  .site-header-utility { display: none; }

  .js .nav-toggle { display: inline-flex; }

  /* The open menu: a full-width warm off-white panel pinned directly under
     the header (main.js measures the header's bottom edge into
     --nav-panel-top at open), scrollable, body scroll locked behind it. */
  .js .site-nav {
    display: none;
    position: fixed;
    top: var(--nav-panel-top, var(--header-h));
    left: 0;
    right: 0;
    bottom: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--paper);
    color: var(--ink);
    padding: var(--space-5) var(--space-5) var(--space-7);
    z-index: 590;
  }

  .js .site-nav.open { display: block; }

  /* Without JS there is no burger, so the nav renders inline in the band,
     wrapped onto its own rows; the grid's fixed height gives way so
     nothing clips. */
  html:not(.js) .site-header-grid { height: auto; min-height: var(--header-h); flex-wrap: wrap; padding-block: var(--space-3); }
  html:not(.js) .site-nav { flex-basis: 100%; }
  html:not(.js) .nav-panel-cta,
  html:not(.js) .nav-panel-foot { padding-block: var(--space-2); }

  .nav-panel-cta { margin-bottom: var(--space-4); }

  /* Full-width on the panel, but the same gold Apply to join button as the
     desktop header - one brand action colour everywhere, and gold reads
     clearly on the warm off-white panel. */
  .nav-panel-cta .header-cta {
    display: flex;
    width: 100%;
    height: 3rem;
  }

  /* Panel colours: jade text on the warm panel (scoped to .js so the no-JS
     in-band nav keeps the band's light-on-dark palette). */
  .js .nav-list { display: block; }

  /* No JS: the nav renders inline in the band. Stack the items instead of a
     nowrap flex row, which would run off a 320-430px screen and scroll the
     page sideways (the house rule: menus wrap, never scroll). Desktop is
     unaffected - this only fires below 1024px. */
  html:not(.js) .nav-list { display: block; }

  .js .nav-item { border-bottom: 1px solid var(--line); }
  /* The foot below the list draws its own top rule (.nav-panel-foot), so the
     last item's bottom rule made a doubled line with an empty band between
     (browser review, 22 Sep 2026). One rule, the foot's. */
  .js .nav-list > .nav-item:last-child { border-bottom: 0; }

  .js .nav-item > a,
  .js .nav-sub-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    min-height: 54px;
    padding: 0.6rem var(--space-2);
    border-bottom: 0;
    color: var(--green-deep);
    font-size: 1.05rem;
  }

  /* One restrained active marker: the gold left rule. */
  .js .nav-item.is-active > a,
  .js .nav-item.is-active > .nav-sub-toggle {
    box-shadow: inset 3px 0 0 var(--brass);
    padding-left: 0.85rem;
    color: var(--green-deep);
  }

  .js .nav-item > a:hover,
  .js .nav-sub-toggle:hover { color: var(--green); }

  .js .nav-item > a:focus-visible,
  .js .nav-sub-toggle:focus-visible,
  .js .nav-sub a:focus-visible,
  .js .nav-panel-foot .header-login:focus-visible,
  .js .nav-panel-cta .header-cta:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
  }

  /* Accordion children: indented, quieter, 46px targets. Closed until the
     trigger opens them; always open without JS. */
  .js .nav-sub {
    display: none;
    margin: 0;
    padding: 0 0 var(--space-3);
    list-style: none;
  }

  .js .has-children.open > .nav-sub { display: block; }

  html:not(.js) .nav-sub { list-style: none; margin: 0; padding-left: var(--space-4); }

  /* The panel already leads with Apply to join, so the accordion never
     repeats it (spec 5F) - the /join child is desktop-dropdown only. */
  .nav-sub .nav-sub-cta { display: none; }

  .js .nav-sub a {
    display: flex;
    align-items: center;
    min-height: 46px;
    padding: 0.35rem var(--space-2) 0.35rem 1.1rem;
    color: var(--ink-soft);
    font-size: 0.98rem;
    font-weight: 600;
    text-decoration: none;
  }

  .js .nav-sub a:hover { color: var(--green-deep); }

  .js .nav-sub a[aria-current="page"] { color: var(--green-deep); font-weight: 700; }

  /* Member login separated at the panel foot. */
  .nav-panel-foot {
    margin-top: var(--space-5);
    padding-top: var(--space-5);
    border-top: 1px solid var(--line-strong);
  }

  .js .nav-panel-foot .header-login {
    display: flex;
    align-items: center;
    min-height: 48px; /* was a ~25px text-line target, half the other rows */
    color: var(--green-deep);
    font-size: 1rem;
  }

  /* Body scroll locks while the menu is open (class set by main.js). */
  html.nav-locked, html.nav-locked body { overflow: hidden; }
}

@media (prefers-reduced-motion: reduce) {
  .site-header-grid,
  .wordmark-lockup,
  .header-cta,
  .nav-chevron,
  .nav-toggle-bars,
  .nav-toggle-bars::before,
  .nav-toggle-bars::after { transition: none; }
}

/* Founding announcement strip (operator setting notice_bar_text; empty =
   hidden). One line, never a multi-line banner: past the fit it ellipsises
   rather than wraps (spec 5A/5D). It sits above the sticky header in
   normal flow, so it scrolls away first. */
.notice-bar {
  background: #254338;
  color: var(--on-green);
  border-bottom: 1px solid var(--on-green-hairline);
}

.notice-bar p {
  max-width: none; /* centred <p> gotcha: the base 70ch cap pins it left */
  margin: 0;
  padding-block: 0.3rem;
  text-align: center;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.notice-bar a { color: inherit; }

/* Full line on tablet/desktop, short line on phones. Only one is ever in
   flow, so the strip stays one line. The short variant is allowed to wrap
   to a second line on the very narrowest phones rather than clip - it is
   short by design, so it never becomes a tall banner, and never losing the
   deadline beats a tidy ellipsis. */
.notice-bar-short { display: none; }
@media (max-width: 700px) {
  /* p.notice-bar-* to outrank the base .notice-bar p (nowrap+ellipsis):
     a lower-specificity class alone loses to it and the short line clips. */
  .notice-bar p.notice-bar-full { display: none; }
  .notice-bar p.notice-bar-short {
    display: block;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }
}

/* -------------------------------------------------------------------------
   5C. Country controls (Phase 1 step 5, 29 Aug 2026)

   Two things, both of which render NOTHING while one country is live, so on
   a single-country brand not one byte of this ever reaches the page:

   .country-switch  the manual switcher, in the header and in the footer.
   .country-banner  the strip on every page except the homepage, which
                    redirects instead.

   The switcher is a native <details>, so it opens, closes and takes keyboard
   focus with no JavaScript at all. That matters more here than anywhere else
   on the site: this is the control that rescues a visitor the country guess
   got wrong, so it must not depend on a script having loaded.
   ------------------------------------------------------------------------- */

.country-switch {
  /* inline-block, because <details> is block by default and in the footer that
     made the control a full-width strip with a 48px label floating at its left
     end (measured at 1280px). In the header's flex row it makes no difference. */
  display: inline-block;
  position: relative;
  flex: none;
}

/* The trigger. SHORT LABEL ONLY ("UK"), which is what lets this sit in a
   375px header row beside a 192px lockup and the burger.

   OUTLINED, AND WITH A GLOBE, 31 Aug 2026 (Rick: the plain "UK" beside a
   chevron is easy to miss). The border is the part that does the work: it
   is what makes two characters read as a control rather than as a stray
   label. currentColor at 35% so the one rule serves both surfaces, the
   header's dark navy and the footer's paper, with no second colour to keep
   in step.

   DELIBERATELY NOT A FLAG. Windows renders no country-flag emoji at all, so
   a flag would show Rick's own visitors the bare letters "GB" and read as a
   broken image; and a flag names a nationality, while this control chooses a
   market. A globe says "somewhere else" without claiming either. */
.country-switch > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.55rem;
  border: 1px solid color-mix(in oklab, currentColor 35%, transparent);
  border-radius: var(--radius);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  list-style: none;          /* Firefox draws a marker without this */
  white-space: nowrap;
}

.country-switch > summary::-webkit-details-marker { display: none; }

.country-switch > summary:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.country-switch > summary:hover { border-color: currentColor; }

.country-switch-globe { flex: none; opacity: 0.85; }
.country-switch > summary:hover .country-switch-globe { opacity: 1; }

.country-switch-chevron { flex: none; transition: transform 160ms; }
.country-switch[open] > summary .country-switch-chevron { transform: rotate(180deg); }

/* The panel. Anchored to the trigger and lifted above the sticky header's
   own stacking context so it is not clipped by the band. */
.country-switch-list {
  position: absolute;
  right: 0;
  z-index: 20;
  min-width: 11rem;
  margin: 0.4rem 0 0;
  padding: 0.35rem;
  list-style: none;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.16);
}

.country-switch-footer .country-switch-list { right: auto; left: 0; bottom: 100%; margin: 0 0 0.4rem; }

.country-switch-list li { margin: 0; }

.country-switch-list a {
  display: block;
  padding: 0.45rem 0.6rem;
  border-radius: 4px;
  font-size: 0.9375rem;
  text-decoration: none;
  color: inherit;
}

.country-switch-list a:hover,
.country-switch-list a:focus-visible { background: var(--paper-2); }

.country-switch-list a[aria-current="true"] { font-weight: 700; }

/* In the dark header band the trigger is quiet cream text, like the login
   link beside it. The open panel stays light, because it is a menu. */
.site-header .country-switch > summary { color: var(--header-ink); }
.site-header .country-switch > summary:hover { color: var(--off-white); }

/* Two slots, one shown at a time, the same pattern the header's login link
   and call to action already use. Desktop shows the copy inside the utility
   cluster and hides the phone slot; phone hides the whole utility cluster and
   shows this one instead, beside the burger.

   BOTH RULES LIVE HERE, base first and the media query straight after. The
   phone override used to sit up in the header's own phone block, which is
   EARLIER in this file, so the base rule below it won at 375px and the control
   vanished on exactly the device it matters most on. Same specificity means
   source order decides (measured at 375px, 29 Aug 2026). */
.site-header-country { display: none; }

@media (max-width: 1023.98px) {
  /* margin-left: auto pushes the control and the burger to the right edge. */
  .site-header-country { display: block; margin-left: auto; }
  .site-header-country + .nav-toggle { margin-left: var(--space-2); }
  /* A finger-sized target, matching the 44px burger beside it. The label
     stays small; only the hit area grows. */
  .site-header-country .country-switch > summary { min-height: 44px; }
}

/* ------------------------------ the banner ---------------------------- */

/* One quiet line above the header, in normal flow like the founding strip,
   so it scrolls away and never covers content. Two links: go there, or stay
   here for good. "Stay here" writes the same cookie the switcher writes,
   which is what lets a visitor answer once and never be asked again. */
.country-banner {
  background: var(--green-wash);
  border-bottom: 1px solid var(--line);
  color: var(--ink);
}

.country-banner-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.4rem 1rem;
  padding-block: 0.45rem;
}

.country-banner p {
  max-width: none;  /* the base 70ch cap pins a centred <p> to the left */
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.4;
}

.country-banner-actions { display: flex; gap: 1rem; }

.country-banner a { color: inherit; }
.country-banner-go { font-weight: 700; }
.country-banner-stay { opacity: 0.75; }

/* Print: the dark-jade header prints as a cream-on-white smear (browsers
   drop backgrounds, the lockup is cream artwork, the nav text is near-white),
   so drop the site chrome on every printed page. The certificate page has its
   own print block; this covers guides, profiles and check results, which are
   the pages people actually print. */
@media print {
  .site-header,
  .country-banner,
  .notice-bar { display: none !important; }
}

/* -------------------------------------------------------------------------
   6. Footer
   ------------------------------------------------------------------------- */
/* No margin above the footer: every page ends in a .section, whose own bottom
   padding is the gap, and the margin showed as a bare cream bar between the
   last band and the footer (Rick, 18 Aug 2026). */
.site-footer {
  background: var(--green-deep);
  color: var(--on-green-soft);
  padding-block: var(--space-7) var(--space-6);
  font-size: 0.95rem;
  line-height: 1.75;
}

.footer-brand {
  padding-bottom: var(--space-6);
  margin-bottom: var(--space-6);
  border-bottom: 1px solid var(--on-green-hairline);
}

.footer-brand a { text-decoration: none; display: inline-block; }

.footer-columns {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--on-green-hairline);
}

@media (min-width: 640px) {
  .footer-columns { grid-template-columns: repeat(2, 1fr); }
}

/* Wide: one track per column the brand actually has (MLD ships four since
   the 18 Aug regroup, WhatCounsellor three) - auto-fit collapses the rest. */
@media (min-width: 960px) {
  .footer-columns { grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); }
}

.footer-heading {
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--brass-soft);
  margin: 0 0 var(--space-4);
}

.footer-col ul { list-style: none; margin: 0; padding: 0; }
.footer-col li { margin-bottom: var(--space-3); }

.footer-col a { color: var(--on-green-soft); text-decoration: none; }
.footer-col a:hover { color: var(--on-green); text-decoration: underline; text-decoration-color: var(--brass-on-dark); }

/* Social links (24 Aug 2026): inline-drawn icons above the legal block.
   Renders only when the operator has set the URLs, so brands without
   accounts show nothing. currentColor keeps them on the footer palette. */
.footer-social {
  display: flex;
  gap: var(--space-4);
  margin-top: var(--space-5);
}
.footer-social a {
  color: var(--on-green-soft);
  display: inline-flex;
  padding: 0.25rem;
}
.footer-social a:hover { color: var(--brass-on-dark); }

.footer-legal {
  padding-top: var(--space-5);
  color: var(--on-green-mute);
  font-size: 0.85rem;
}

.footer-legal p { max-width: none; }
.footer-disclaimer { margin-bottom: 0; }

/* A LINK IN HERE WAS INVISIBLE, on every page of the site.
   These paragraphs sit on the dark footer, but their links had no colour of
   their own, so they fell back to the global a { color: var(--ink) } - which
   is #0F2137, the exact colour of the footer behind them. The underline
   showed and the words did not.
   The one that matters is the GeoNames attribution: postal code data is used
   under a Creative Commons Attribution licence, and an attribution nobody can
   read is not an attribution. Found 1 Sep 2026 in one of Rick's phone
   screenshots, where the line reads "Postal code data from ______". */
.footer-disclaimer a {
  color: var(--on-green-soft);
  text-decoration: underline;
}

.footer-disclaimer a:hover,
.footer-disclaimer a:focus-visible { color: var(--on-green); }

/* Phone number in the footer: a visible trust signal, a touch brighter than
   the surrounding legal text. */
.footer-phone {
  font-size: 1rem;
  color: var(--on-green-soft);
  margin-bottom: var(--space-4);
}
.footer-phone strong { color: var(--on-green); }
.footer-phone a { color: var(--on-green); text-decoration-color: var(--brass-on-dark); }

/* WHATSAPP, the lead contact where a country declares a number (the US,
   22 Sep 2026; country_whatsapp() and partial icon_whatsapp). The glyph is
   a filled icon that takes its link's colour and sits a touch below the
   baseline so it reads as part of the word; inside the header's flex links
   the link's own gap spaces it, so the margin comes off there. The landline
   under the footer's WhatsApp line steps down to the legal size and closes
   up to it, so WhatsApp reads first and the two read as one block. */
.icon-whatsapp { width: 1.1em; height: 1.1em; flex: none; vertical-align: -0.2em; margin-right: 0.35em; }
.header-whatsapp .icon-whatsapp { width: 1.15em; height: 1.15em; margin-right: 0; }
/* nowrap: a phone number must never break mid-number ("+44" orphaned on one
   line, "7887 731638" on the next, seen in the footer at 375 on 22 Sep 2026);
   the whole link drops to the next line as one piece instead. */
.whatsapp-link { white-space: nowrap; }
.footer-whatsapp { margin-bottom: var(--space-1); }
.footer-phone-secondary { font-size: 0.85rem; color: var(--on-green-mute); }
.footer-phone-secondary a { color: var(--on-green-soft); }

/* LIGHT FOOTER (the WHAT master footer, app/views/what/partials/footer.php;
   Rick, 29 Sep 2026, decision 11 as he changed it). The brand's pale, deep
   ink text, links in the brand's primary, the full-colour lockup and a thin
   top rule. The brand line (lockup, tagline, phone) sits beside the link
   columns on a wide screen and above them on a phone. Tokens only: the
   pale is --paper, the primary is --brand-primary where a theme keeps the
   exact primary apart from its button colour, otherwise --green. The
   lockup is set by HEIGHT so every brand's logo is the same size whatever
   the length of its profession word. MLD's dark footer is unchanged. */
.site-footer-light {
  --footer-link: var(--brand-primary, var(--green));
  background: var(--paper);
  color: var(--ink);
  border-top: 1px solid var(--line-strong);
}
.site-footer-light .footer-main {
  display: grid;
  gap: var(--space-6);
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--line);
}
@media (min-width: 960px) {
  .site-footer-light .footer-main { grid-template-columns: minmax(15rem, 1fr) minmax(0, 2.6fr); gap: var(--space-7); }
}
.site-footer-light .footer-brand { padding: 0; margin: 0; border: 0; }
.site-footer-light .footer-brand img { display: block; height: 3rem; width: auto; max-width: 100%; }
.site-footer-light .footer-tagline { margin: var(--space-4) 0 var(--space-4); color: var(--ink-soft); max-width: 22rem; }
.site-footer-light .footer-columns { padding-bottom: 0; border-bottom: 0; }
@media (min-width: 960px) {
  .site-footer-light .footer-columns { grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); }
}
.site-footer-light .footer-heading { color: var(--ink); font-size: 0.85rem; }
.site-footer-light .footer-col a { color: var(--footer-link); }
.site-footer-light .footer-col a:hover,
.site-footer-light .footer-col a:focus-visible { color: var(--ink); text-decoration: underline; text-decoration-color: currentColor; }
.site-footer-light .footer-phone { color: var(--ink); margin-bottom: 0; }
.site-footer-light .footer-phone strong { color: var(--ink); }
.site-footer-light .footer-phone a { color: var(--footer-link); text-decoration-color: currentColor; white-space: nowrap; }
.site-footer-light .footer-phone-secondary { color: var(--ink-mute); }
.site-footer-light .footer-social a { color: var(--ink-soft); }
.site-footer-light .footer-social a:hover { color: var(--footer-link); }
.site-footer-light .footer-legal { color: var(--ink-mute); }
.site-footer-light .footer-disclaimer a { color: var(--footer-link); }
.site-footer-light .footer-disclaimer a:hover,
.site-footer-light .footer-disclaimer a:focus-visible { color: var(--ink); }

/* -------------------------------------------------------------------------
   7. Buttons
   ------------------------------------------------------------------------- */
.btn {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.01em;
  text-align: center;
  text-decoration: none;
  padding: 0.85rem 1.7rem;
  border-radius: var(--radius);
  border: 2px solid transparent;
  cursor: pointer;
  transition: background-color 180ms var(--ease-out), color 180ms var(--ease-out),
              border-color 180ms var(--ease-out), transform 180ms var(--ease-out);
}

.btn:active { transform: translateY(1px); }

.btn-primary {
  background: var(--green);
  color: var(--on-green);
}

.btn-primary:hover { background: var(--green-deep); color: var(--on-green); }

.btn-secondary {
  background: transparent;
  color: var(--green);
  border-color: var(--btn-secondary-border);
}

.btn-secondary:hover { border-color: var(--green); background: var(--green-wash); color: var(--green-deep); }

.btn-brass {
  background: var(--brass); /* Rick 17 Aug 2026: brass buttons are display brass with BLACK text (black on #DFA33A is ~9:1) */
  color: #000;
}

.btn-brass:hover { background: color-mix(in oklab, var(--brass), #000 12%); color: #000; }

.btn-sm { padding: 0.55rem 1.1rem; font-size: 0.92rem; }
.btn-lg { padding: 1.05rem 2.2rem; font-size: 1.08rem; }
.btn-block { display: block; width: 100%; }

.btn[disabled] { opacity: 0.55; cursor: not-allowed; }

.btn-row { display: flex; gap: var(--space-4); flex-wrap: wrap; margin-top: var(--space-5); }

/* -------------------------------------------------------------------------
   8. Forms
   ------------------------------------------------------------------------- */
.field { margin-bottom: var(--space-5); }

.field label {
  display: block;
  font-weight: 700;
  font-size: 1.1rem;
  margin-bottom: var(--space-2);
  color: var(--ink);
}

/* Hints follow any inline error and keep space before the next field. */
.field-hint {
  font-size: 1.125rem;
  color: var(--hint-ink);
  margin-top: var(--space-1);
  margin-bottom: 1.25rem;
}

/* The green tick under a file input once a file is chosen (Rick, 2 Sep
   2026): the browser's own filename did not read as "it worked". Written by
   main.js, so a page with JavaScript off keeps the browser's filename. */
.field-chosen {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--tone-success-ink);
  margin: var(--space-1) 0 0;
}
.field-chosen .field-chosen-tick { margin-right: 0.35em; }

/* List form of the same hint. A hint that makes three separate points reads
   as a wall when it is one paragraph - Rick, 16 Aug 2026, reviewing his own
   profile. It keeps the .field-hint class so the size, colour and spacing are
   identical to the paragraph form: only the layout differs, so the two never
   look like different components. */
ul.field-hint {
  list-style: disc;
  padding-left: 1.25rem;
}

ul.field-hint li + li { margin-top: 0.35rem; }

/* Required-field asterisk and the inline validation message under a field. */
.req { color: var(--danger); font-weight: 700; margin-left: 0.1rem; }

.field-error {
  color: var(--danger);
  font-size: 0.9rem;
  font-weight: 600;
  margin: var(--space-2) 0 0;
}

/* An invalid field gets a danger-toned border so the eye lands on it. */
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] {
  border-color: var(--danger);
}

.join-required-note { margin-bottom: var(--space-5); }

input[type="text"], input[type="email"], input[type="tel"], input[type="url"],
input[type="password"], input[type="search"], input[type="number"], input[type="date"],
select, textarea {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--ink-mute); /* >=3:1 boundary vs surface and paper (WCAG 1.4.11) */
  border-radius: var(--radius);
  padding: 0.75rem 0.95rem;
  transition: border-color 160ms var(--ease-out);
}

/* ONE select treatment for the whole site (Rick, 25 Jul 2026). There were
   three - the base rule's native arrow at 18px/400, the filter row at
   15.52px/600 grey with a chevron inset 14.4px, and the sort control at
   15.2px/600 with it inset 12.8px - which is exactly the inconsistency he
   spotted. Everything below now inherits font, weight and colour from the
   shared input rule above; only the chevron and the room made for it live
   here, so a component can never quietly re-style its dropdowns again.
   Component rules may still set width or height (the hero search field is
   deliberately taller); they must not set font-size, colour or the chevron. */
select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding-right: 2.75rem;
  background-image: var(--select-chevron);
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: 0.7rem auto;
}

/* The native option list is drawn by the browser and ignores CSS; Chromium's
   appearance: base-select opts into an in-page picker that does not, so the
   grey/white OS highlight becomes the brand green. Guarded, because Safari
   and Firefox have not shipped it - there the picker stays native, which is
   the same experience the site has always had, not a broken one. */
@supports (appearance: base-select) {
 /* Desktop pointers only. On a phone the native picker is a well-tuned
    bottom sheet and replacing it with an in-page list is a downgrade - and
    the whole point of opting in is the HOVER colour, which touch does not
    have. So phones keep the native control and lose nothing. */
 @media (hover: hover) and (pointer: fine) {
  select, ::picker(select) { appearance: base-select; }
  /* We draw our own chevron; suppress the one base-select adds. */
  select::picker-icon { display: none; }

  ::picker(select) {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-2);
    padding: var(--space-1);
  }

  /* Options are real DOM children, so they are styled directly - NOT as
     descendants of the ::picker() pseudo-element, which does not match. */
  select option {
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius);
    color: var(--ink);
    background: transparent;
  }

  /* Rick: the OS grey-with-white-text highlight should read as brand. */
  select option:hover,
  select option:focus {
    background: var(--green);
    color: var(--on-green);
  }

  /* The value currently held, shown quietly so it is not mistaken for hover. */
  select option:checked {
    background: var(--green-wash);
    color: var(--green-deep);
  }
  select option:checked:hover {
    background: var(--green);
    color: var(--on-green);
  }

  /* The tick base-select puts against the chosen row, toned to the brand. */
  select option::checkmark { color: var(--green); }
 }
}

input:hover, select:hover, textarea:hover { border-color: var(--ink-soft); }

input:focus, select:focus, textarea:focus {
  outline: 3px solid var(--focus);
  outline-offset: 0;
  border-color: var(--focus);
}

textarea { min-height: 8.5rem; resize: vertical; }

/* File inputs: the native "Choose file" button gets a small accent-coloured
   button style, matched across the app (member dashboard, onboarding, preview,
   admin). Two rules (standard + webkit) because a browser drops a whole rule if
   it does not understand one selector in a group. */
input[type="file"] { font: inherit; color: var(--ink-soft); max-width: 100%; }
input[type="file"]::file-selector-button {
  font: inherit;
  font-weight: 700;
  font-size: 0.9rem;
  padding: 0.45rem 0.95rem;
  margin-right: var(--space-3);
  border: 0;
  border-radius: var(--radius);
  background: var(--brass); /* Rick 17 Jul: file buttons read as the ACCENT, not the same green as real buttons; 17 Aug: display brass with black text */
  color: #000;
  cursor: pointer;
  transition: background-color 160ms var(--ease-out);
}
input[type="file"]::file-selector-button:hover { background: color-mix(in oklab, var(--brass), #000 12%); color: #000; }
input[type="file"]::-webkit-file-upload-button {
  font: inherit;
  font-weight: 700;
  font-size: 0.9rem;
  padding: 0.45rem 0.95rem;
  margin-right: var(--space-3);
  border: 0;
  border-radius: var(--radius);
  background: var(--brass);
  color: #000;
  cursor: pointer;
}

.checkbox-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.checkbox-row input[type="checkbox"] {
  width: 1.2rem;
  height: 1.2rem;
  margin-top: 0.2rem;
  flex: none;
  accent-color: var(--green);
}

.checkbox-row label { font-weight: 400; margin: 0; }

.form-error {
  background: var(--danger-wash);
  border: 1px solid var(--tone-danger-border);
  border-radius: var(--radius);
  color: var(--tone-danger-ink);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5);
}

.form-success {
  background: var(--verified-wash);
  border: 1px solid var(--tone-success-border);
  border-radius: var(--radius);
  color: var(--tone-success-ink);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5);
}

/* Honeypot: visually removed, still present for bots */
.hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* -------------------------------------------------------------------------
   9. Chips (styled as inked stamps)
   ------------------------------------------------------------------------- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  line-height: 1;
  padding: 0.42rem 0.7rem;
  /* Pill, not stamp (Rick, 21 Sep 2026): square corners made every chip
     look like a button. */
  border-radius: 100px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink-soft);
  white-space: nowrap;
}

.chip-verified { background: var(--verified-wash); border-color: var(--tone-verified-border); color: var(--tone-verified-ink); }
.chip-revalidated { background: var(--green-wash); border-color: var(--tone-neutral-border); color: var(--green-deep); }
.chip-available { background: var(--green-wash); border-color: var(--tone-neutral-border); color: var(--green-deep); }
.chip-founding, .chip-featured { background: var(--brass-soft); border-color: var(--brass); color: var(--tone-warn-ink); }
.chip-lapsed { background: var(--paper-2); border-color: var(--line-strong); color: var(--ink-mute); }
/* Admin field markers (Rick, 21 Sep 2026: "make it easy for me to see what
   i should absolutely be filling in"). Three states, one look each:
   Required = the operator must fill it before "Verify & send" will run;
   Automatic = the system writes it, the box exists only to correct it;
   nothing = optional detail. The marker sits after the label, and a
   Required field's box carries the same colour on its left edge so it
   reads at a glance down a long form. */
.chip-required { background: var(--danger-wash); border-color: var(--tone-danger-border); color: var(--danger); }
.chip-auto { background: var(--verified-wash); border-color: var(--tone-verified-border); color: var(--tone-verified-ink); }
.field-mark { margin-left: 0.5rem; vertical-align: middle; font-size: 0.66rem; padding: 0.3rem 0.5rem; }
.field-required > input, .field-required > select, .field-required > textarea { border-left: 4px solid var(--danger); }
.field-auto > input, .field-auto > select { border-left: 4px solid var(--tone-verified-border); background: var(--verified-wash); }
.field-key { display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem; align-items: center; margin: 0 0 var(--space-4); font-size: 0.92rem; color: var(--ink-soft); }
.field-key .chip { margin-right: 0.35rem; }
.chip-removed { background: var(--danger-wash); border-color: var(--tone-danger-border); color: var(--danger); }

.chip svg { flex: none; }

/* THE QUIET TAG (22 Oct 2026, the profile decision card job; first used for
   a profile's Areas and Approaches): a .chip in plain sentence case at body
   size, neutral keyline on the page's pale ground, so a list of 25 topics
   reads as a calm set of labels, never as buttons, filters or a status.
   Not interactive: a topic with a published guide keeps its link inside the
   tag as underlined text. Lives in a .profile-tags list (a real ul, so a
   screen reader still hears a list and its count). The second selector
   outranks the WHAT 16px chip rule wherever it sits in this file. */
.profile-tags { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.profile-tags > li { margin: 0; }
.chip.chip-quiet,
:is(.design-what, .text-min-16) .chip.chip-quiet {
  display: inline-block;
  max-width: 100%;
  padding: 0.3rem 0.8rem;
  border-color: var(--line);
  background: var(--paper);
  color: var(--ink);
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.4;
  text-transform: none;
  white-space: normal;
  overflow-wrap: break-word;
}
.chip-quiet a { color: inherit; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
.chip-quiet a:hover { text-decoration-color: currentColor; }

/* -------------------------------------------------------------------------
   10. Ledger motifs: index lists, entry captions, dotted leaders
   ------------------------------------------------------------------------- */

/* Numbered index list (trust points, steps): 01-04 in serif over hairlines */
.index-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0;
  grid-template-columns: 1fr;
}

@media (min-width: 860px) {
  .index-list { grid-template-columns: repeat(2, 1fr); column-gap: var(--space-7); }
}

.index-list > li {
  display: flex;
  gap: var(--space-5);
  align-items: baseline;
  padding-block: var(--space-5);
  border-top: 1px solid var(--line);
  margin: 0;
}

.index-num {
  font-family: var(--font-serif);
  font-size: 1.7rem;
  font-weight: 600;
  color: var(--brass);
  flex: none;
  min-width: 2.4rem;
  font-variant-numeric: tabular-nums;
}

.index-list p { margin: 0; color: var(--ink-soft); font-size: 1.1rem; }
.index-list strong { display: block; color: var(--ink); font-size: 1.3rem; margin-bottom: 0.2rem; }

.section-green .index-list > li { border-top-color: var(--on-green-hairline-strong); }
.section-green .index-list p { color: var(--on-green-soft); }
.section-green .index-list strong { color: var(--on-green); }

/* Three items in one row on desktop (Rick, 13 Oct 2026: the /check page's
   "What a check shows you"). */
@media (min-width: 860px) {
  .index-list-3 { grid-template-columns: repeat(3, 1fr); column-gap: var(--space-6); }
}

/* A left-to-right flow of steps (Rick, 13 Oct 2026: "From application to
   live profile ... 3 items on 1 row and look like a flow"). Each step is a
   column, number on top, with an arrow to the next step; on a phone the
   steps stack and the arrow points down. */
.index-list-flow > li { flex-direction: column; gap: var(--space-4); position: relative; }
.index-list-flow > li:has(> .bubble-frame) > p { padding-top: 0; }
.index-list-flow > li:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 1.2rem;
  bottom: calc(var(--space-2) * -1);
  width: 0.7rem;
  height: 0.7rem;
  border-right: 2px solid var(--brass-on-dark, var(--brass));
  border-bottom: 2px solid var(--brass-on-dark, var(--brass));
  transform: rotate(45deg);
}
@media (min-width: 860px) {
  .index-list-flow { grid-template-columns: repeat(3, 1fr); column-gap: var(--space-8); }
  .index-list-flow > li { border-top: 0; padding-block: var(--space-4) 0; }
  .index-list-flow > li:not(:last-child)::after {
    left: auto;
    right: calc(var(--space-8) / -2 - 0.5rem);
    top: 1.7rem;
    bottom: auto;
    width: 0.9rem;
    height: 0.9rem;
    transform: rotate(-45deg);
  }
  /* The line the arrows sit on, joining the numbers. */
  .index-list-flow > li:not(:last-child)::before {
    content: '';
    position: absolute;
    top: 2.15rem;
    left: 4.2rem;
    right: calc(var(--space-8) / -2);
    border-top: 2px dashed var(--on-green-hairline-strong, var(--line));
  }
}
.section-green .index-num { color: var(--brass-soft); }

/* Ledger caption bar under photographs */
.ledger-photo { position: relative; }

.ledger-photo img {
  width: 100%;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-2);
}

/* The rule sits beside the FIRST line, so a caption that wraps on a phone
   never has it floating between its lines (review, 28 Sep 2026). One line
   renders exactly as before: half the line height, less half the rule. */
.ledger-caption {
  display: inline-flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin-top: var(--space-3);
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

.ledger-caption::before {
  content: '';
  display: block;
  flex: none;
  width: 2rem;
  height: 1px;
  margin-top: 0.75em;
  margin-top: calc(0.5lh - 0.5px);
  background: var(--brass);
}

/* Dotted leader rows (verification box, certificate) */
.leader-row {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin-bottom: var(--space-3);
  font-size: 0.97rem;
}

.leader-row .leader-label { font-weight: 600; color: var(--ink-soft); flex: none; }

.leader-row .leader-dots {
  flex: 1;
  border-bottom: 2px dotted var(--line-strong);
  transform: translateY(-4px);
  min-width: 1.5rem;
}

.leader-row .leader-value { font-weight: 600; color: var(--ink); text-align: right; }

/* A quieter second line inside a leader value - the training provider under
   its course (24 Aug 2026), so one row carries "what" and "where" without a
   repeated label pair per training. */
.leader-value-sub {
  display: block;
  font-weight: 400;
  font-size: 0.92em;
  color: var(--ink-mute);
}

/* The Verification card's one Training row (Rick, 29 Sep 2026: three rows
   each saying "Training" and naming the same school read as tiling). A list,
   so it stacks at every width, as every leader row already does under 420px:
   the label above, each school named once in the value's weight, its courses
   under it in body weight on a quiet rule, a little air between schools. A
   training with no school to group by keeps the value's weight, unruled. */
.leader-row-training { flex-wrap: wrap; row-gap: 0.35rem; }
.leader-row-training .leader-dots { display: none; }
.leader-row-training .leader-value { flex: 1 1 100%; text-align: left; }
.leader-row-training .training-group { display: block; }
.leader-row-training .training-group + .training-group { margin-top: var(--space-2); }
.leader-row-training .training-school { display: block; }
.leader-row-training .training-course {
  display: block;
  font-weight: 400;
  margin-top: 0.2rem;
  padding-left: 0.75rem;
  border-left: 2px solid var(--line-strong);
}
.leader-row-training .training-group-plain .training-course { font-weight: 600; margin-top: 0; padding-left: 0; border-left: 0; }
.leader-row-training .training-course + .leader-value-sub { padding-left: 0.75rem; border-left: 2px solid var(--line-strong); }

/* -------------------------------------------------------------------------
   11. Hero (asymmetric editorial split)
   ------------------------------------------------------------------------- */
.hero {
  background: var(--paper);
  overflow: hidden;
}

.hero-grid {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
  align-items: center;
  padding-block: var(--space-7);
}

@media (min-width: 960px) {
  .hero-grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: var(--space-8);
    padding-block: var(--space-8);
  }
}

/* A hero whose picture needs more room than its words (.hero-grid-media-wide,
   the WHAT practitioners hero's laptop and phone, 14 Oct 2026): the picture
   column is the wider one, so the laptop's screen is large enough to read
   as a page. One column below 960px, as every hero grid. */
@media (min-width: 960px) {
  .hero-grid.hero-grid-media-wide { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); }
}

.hero h1 { margin-bottom: var(--space-4); max-width: 13em; }

/* REVERSED 31 Aug 2026 (Rick's call): on a phone the paragraph reads ABOVE
   the search box again. The 14 Aug 2026 rule that lifted the box over the
   paragraph is DELETED rather than re-numbered, because the wanted visual
   order (eyebrow, heading, paragraph, form) is now the DOM order, so there
   is nothing left for it to do. Its flex column went with it: no other rule
   depended on it, and .hero-copy stacks the same as a block. */

/* Positioning line above the hero h1. Same voice as .welcome-eyebrow; its
   own rule because the hero sits on paper, not the welcome surface, and the
   welcome variant carries spacing this slot does not want. */
.hero-eyebrow {
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--green);
  max-width: none;
  margin-bottom: var(--space-3);
}

.hero-subhead {
  font-size: 1.3rem;
  font-family: var(--font-serif);
  color: var(--ink-soft);
  max-width: 44rem;
  margin-bottom: var(--space-6);
  line-height: 1.6;
}

/* ---- Full-bleed hero variant, added 20 Aug 2026 -------------------------
   The photograph runs edge to edge instead of sitting in a box beside the
   copy, which is what .hero-grid gives.

   OPT-IN AND ADDITIVE. A page keeps .hero-grid or .hero-stack unless it
   asks for .hero-bleed, so WhatCounsellor's homepage, the For Therapists
   hero and every other brand's hero are untouched by this block.

   Three art-directed frames, one per band (16:9 desktop, 4:3 tablet, 9:16
   phone), each composed with the therapist to one side of a soft empty
   field. The scrim below is INSURANCE for the widths in between - measured
   20 Aug 2026, a first attempt without enough of it laid the subhead
   across the therapist's body at 768px. Copy width is capped per band for
   the same reason: a paragraph allowed to run the full container always
   reaches her.

   THE PHONE DOES NOT OVERLAY, and that is deliberate. Measured at 390px:
   the eyebrow, heading and search box together are about 560px tall, while
   the pale field in the portrait frame is only ever about 48% of the hero,
   so the subhead - which sits LAST on a phone under the 14 Aug 2026 search
   box order rule - always landed on the therapist, at every hero height
   tried. Overlaying anyway would have meant either an unreadable paragraph
   or a wash so heavy the photograph disappeared. So on a phone the copy
   keeps clean paper and the photograph runs full width BELOW it. The
   portrait frame is still the right source there: at 390px it crops only
   vertically, so the therapist stays whole. */
.hero-bleed {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  min-height: 34rem;
  padding-block: var(--space-7);
}

.hero-bleed > .container {
  position: relative;
  z-index: 2;
  width: 100%;
}

.hero-bleed-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero-bleed-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 70% 50%;
}

/* Paper washing over the copy and clearing before the therapist.
   color-mix rather than a second hex keeps --paper the only definition of
   the colour, and mixing in oklab avoids the grey haze plain `transparent`
   gives when a gradient interpolates through transparent black. */
.hero-bleed-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    var(--paper) 0%,
    var(--paper) 30%,
    color-mix(in oklab, var(--paper) 70%, transparent) 55%,
    color-mix(in oklab, var(--paper) 0%, transparent) 78%
  );
}

.hero-bleed .hero-copy { max-width: 30rem; }

@media (min-width: 960px) {
  .hero-bleed {
    min-height: 40rem;
    padding-block: var(--space-8);
  }
  /* Wash strengthened to 80% paper at 44%, Rick's own gradient, 31 Aug 2026.
     The literal #f6f2ed first stop is his too; it is the value of --paper and
     sits at the same 0% position as the token, so it paints nothing. */
  .hero-bleed-media::after {
    background: linear-gradient(
      100deg,
      #f6f2ed 0%,
      var(--paper) 0%,
      color-mix(in oklab, var(--paper) 80%, transparent) 44%,
      color-mix(in oklab, var(--paper) 0%, transparent) 64%
    );
  }
  .hero-bleed .hero-copy { max-width: 36rem; }
}

/* PHONE: copy on paper, photograph full width beneath it. The media block
   is a sibling of .container, not inside it, so it still bleeds to both
   edges. Its DOM position is first, so order puts it second here. */
@media (max-width: 719px) {
  .hero-bleed {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
    padding-block: var(--space-6) 0;
  }
  .hero-bleed > .container { order: 1; }
  .hero-bleed-media {
    position: static;
    order: 2;
    height: 30rem;
    margin-top: var(--space-6);
  }
  .hero-bleed-media::after { content: none; }
  .hero-bleed-media img { object-position: 50% 88%; }
  .hero-bleed .hero-copy { max-width: none; }

  /* Rick, 20 Aug 2026: on a phone the eyebrow and heading CENTRE over the
     left-aligned paragraph and search card below them. A deliberate
     exception to the site-wide "mobile = all left" heading rule (16 Jul),
     scoped to .hero-bleed so no other page or brand moves. The h1 needs
     margin-inline too: it carries max-width 13em, and a narrower box with
     no auto margins stays pinned left however the text inside is aligned -
     the same trap that has now caught four separate centring jobs. */
  .hero-bleed .hero-eyebrow,
  .hero-bleed h1 { text-align: center; }
  .hero-bleed h1 { margin-inline: auto; }
}

.search-box {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-2);
  max-width: 38rem;
}

.search-box label {
  display: block;
  font-weight: 700;
  margin-bottom: var(--space-3);
}

.search-box-row {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.search-box-row input[type="search"],
.search-box-row input[type="text"] {
  flex: 1 1 14rem;
  font-size: 1.05rem;
}

.search-box-row .btn { flex: none; }

/* A location input wrapped for suggestions (.location-input-wrap) takes the
   input's flex slot, and the input's own flex rule fills it. Moved here from
   brands/mld/theme.css on 23 Sep 2026 because every brand's hero uses the
   wrap: without it the box shrinks to its content beside the reason select. */
.location-input-wrap { position: relative; }
.search-box-row .location-input-wrap { flex: 1 1 14rem; min-width: 0; display: flex; }

/* The hero's "Need help with?" select (home.php): since 26 Aug 2026 (Rick's
   layout) it SHARES the row with the location input, and the submit button
   sits underneath on its own line (.search-box-submit). Type size matches
   the input; the chevron and everything else still come from the shared
   select rules - the one-select-treatment rule (25 Jul 2026) bars a
   component from restyling them. The colour pair below keeps the two
   fields' resting text the same shade: the input's placeholder and the
   select's unchosen "Any reason" state are both ink-mute, and each darkens
   to full ink once it holds a real value. */
.search-box-row .search-box-reason {
  flex: 1 1 12rem;
  font-size: 1.05rem;
}

.search-box-submit { margin-top: var(--space-3); }

.search-box-row input::placeholder { color: var(--ink-mute); opacity: 1; }

.search-box-row .search-box-reason:has(option[value=""]:checked) {
  color: var(--ink-mute);
}

/* Search fields wear the sage keyline (requested: 3px solid #92afa4).
   On the finder it marks the two controls that define the SEARCH - where and
   how far - against the filters that refine it, now that both sit on one bar. */
.search-box-row input[type="search"],
.search-box-row input[type="text"],
.search-box-row input[type="email"],
.search-box-reason,
.finder-field-loc input[type="search"],
.finder-field-radius select {
  border: 3px solid var(--search-keyline);
}

.search-microcopy {
  font-size: 0.9rem;
  color: var(--ink-mute);
  margin: var(--space-3) 0 0;
}

/* -------------------------------------------------------------------------
   12. Editorial image trio (no card chrome; hairline-ruled columns)
   ------------------------------------------------------------------------- */
.editorial-trio {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
}

@media (min-width: 860px) {
  .editorial-trio { grid-template-columns: repeat(3, 1fr); }
}

.editorial-item { border-top: 2px solid var(--green); padding-top: var(--space-4); }

.editorial-item img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-lg);
  margin-bottom: var(--space-4);
}

.editorial-item h3 { margin-top: 0; font-size: 1.5rem; }
.editorial-item p { color: var(--ink-soft); font-size: 1.1rem; margin-bottom: 0; }

/* -------------------------------------------------------------------------
   13. Cards (kept for result entries and tier cards only)
   ------------------------------------------------------------------------- */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-1);
}

.card h3 { margin-top: 0; }

.card-link-list { list-style: none; padding: 0; margin: 0; }
.card-link-list li { margin-bottom: var(--space-3); }

/* -------------------------------------------------------------------------
   13b. Product preview frame (marketing pages)
   ------------------------------------------------------------------------- */
/* A labelled specimen of a real product surface - a search result card, the
   patient's filter options - shown on a sales page so a prospective member
   sees the thing itself instead of a description of it.

   RULE: build the inside from the REAL component classes (.result-card and
   its children), never a redrawn mock. A hand-drawn imitation drifts the
   moment the real component changes, and then the sales page is advertising
   a product we do not ship. Every frame carries a visible label saying the
   contents are an example, because the names, numbers and reviews inside a
   specimen are illustrative and must never read as a real member's record. */
.preview-frame {
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  box-shadow: var(--shadow-1);
}

/* On a tinted band the warm frame is the same tone as the band behind it and
   the chrome disappears. Flip to the white surface there so the frame still
   reads as a frame. */
.section-tint .preview-frame { background: var(--surface); }

/* Sentence case, never uppercase: this is a label a visitor reads, and the
   house rule bans shouting in anything outward-facing. */
.preview-frame-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink-mute);
}

.preview-frame .result-card { margin-bottom: 0; flex-wrap: wrap; }

/* The specimen's name is a <p>, not the h3 the real card uses (a heading
   inside a hero picture would skip an outline level under the h1). The serif
   comes from the heading rule, so it has to be restated here. */
.preview-frame .result-name { font-family: var(--font-serif); }

/* A frame is always narrow (a hero column, half a two-column band), so the
   floating View profile button unfloats here exactly as it does on a phone.
   It must also WRAP to its own row: .result-card is a flex row, so merely
   returning the button to the flow turns it into a third column and starves
   the text column (it measured 157px of a 519px card). Keep the clearance
   list in step with the 540px rule in section 18 - if a line gains the
   clearance there it needs releasing here too. */
.preview-frame .result-cta { position: static; transform: none; flex-basis: 100%; margin-top: var(--space-4); }
.preview-frame .result-cta .btn { display: block; width: 100%; }
.preview-frame .result-main .result-name,
.preview-frame .result-main .result-meta,
.preview-frame .result-main .result-rating,
.preview-frame .result-main .result-google-note,
.preview-frame .result-main .result-fee { padding-right: 0; }

/* Controls inside a frame are part of the picture, not working controls, so
   they never carry a pointer cursor. The specimen markup uses a span rather
   than an anchor for the same reason: a specimen must not offer a link to a
   profile that does not exist. */
.preview-frame .btn { cursor: default; }

/* A specimen chip longer than a phone-width frame's text column (the WHAT
   practitioners page's "Taking new clients, confirmed 26 Sep", 29 Sep 2026)
   wraps inside the card. Without this the one-line chip set the width of the
   card's wrapped flex line, so the chip and the View profile button ran past
   the card's edge. Phones only, where the column is narrowest; a chip that
   fits prints exactly as before. */
@media (max-width: 480px) {
  .preview-frame .chip { white-space: normal; }
}

.preview-frame-note {
  font-size: 0.85rem;
  color: var(--ink-mute);
  margin: var(--space-4) 0 0;
}

/* Row list inside a frame: the patient's filter options, one per line. */
.preview-list { list-style: none; margin: 0; padding: 0; }
.preview-list li { padding: var(--space-3) 0; border-top: 1px solid var(--line); }
.preview-list li:first-child { border-top: 0; padding-top: 0; }
/* Ticks beside each item (Rick, 13 Oct 2026, the practitioners page's
   "Help clients see you're the right fit"): the pricing page's tick. */
.preview-list-ticks li { position: relative; padding-left: 1.75rem; }
.preview-list-ticks li::before {
  content: '';
  position: absolute;
  left: 0.1rem;
  top: calc(var(--space-3) + 0.42rem);
  width: 0.85rem;
  height: 0.45rem;
  border-left: 2px solid var(--verified);
  border-bottom: 2px solid var(--verified);
  transform: rotate(-45deg);
}
.preview-list-ticks li:first-child::before { top: 0.42rem; }
.preview-list li:last-child { padding-bottom: 0; }

/* -------------------------------------------------------------------------
   13c. Laptop product shot (.device-macbook)
   ------------------------------------------------------------------------- */
/* A marketing product shot: a REAL page of this site, rendered at a real
   desktop width and photographed inside a laptop lid. Same rule as the
   preview frame above and for the same reason - the inside is built from the
   real component classes, never a redrawn mock, so it cannot drift into
   advertising a product we do not ship. The shot carries a visible caption
   saying the contents are an example, because every name, number and review
   inside a specimen is illustrative.

   HOW THE SCALING WORKS, and why it is not JavaScript. The screen holds the
   page at a real desktop width and shrinks it with a transform. Rendering at
   a real width is the whole point: the page inside lays out exactly as a
   visitor's own screen lays it out, including the 960px breakpoint that
   gives the profile its two columns.

   THE SCALE IS THE FIXED NUMBER AND THE INNER WIDTH FOLLOWS IT. The screen
   is whatever width the hero column leaves, and .device-screen-inner takes
   100% / scale of that, so the scaled page lands on the screen's own edges
   at any width. Sizing the two independently is what crops a shot: a
   narrower lid against an unchanged inner width cuts the right-hand third -
   the price and the whole Verification panel - off inside the screen.
   Nothing is measured and nothing is scripted, so the shot still renders
   correctly with scripting off.

   KEEP THE DERIVED INNER WIDTH ABOVE 960px, the profile's own two-column
   breakpoint, because a shot of the one-column phone layout is not what
   this is advertising. In the 552px hero column the screen is 464px, so
   0.46 derives 1009px. Lowering the scale RAISES the derived width.

   BELOW 1200px THERE IS NO SHOT. A laptop shrunk to a phone column is a grey
   smudge: at 360px the body text lands under 4px. The page shows the plain
   .preview-frame card there instead, and hides this. Pair the two with
   .device-shot-only / .device-shot-fallback so exactly one is in the
   document at any width - display:none, so a screen reader is never read
   both. */
/* THE WHOLE LAPTOP FITS INSIDE ITS HERO COLUMN (Rick, 19 Aug 2026: the hero
   read as pushed to the right). It used to be a fixed 760px lid in a 552px
   column, bleeding 200px past the container while the copy column started on
   the container's left edge - so at 1920px the page carried 352px of margin
   on the left and 115px on the right. The padding is exactly what the base's
   -30px side margins spend, so the BASE - the widest part of the laptop -
   lands on the column edge and mirrors the copy column opposite it. */
.device-macbook {
  --device-scale: 0.46;
  width: 100%;
  padding-inline: 30px;
}

.device-lid {
  position: relative;
  background: #2b2d31;
  border-radius: 16px;
  padding: 14px;
  box-shadow: 0 26px 50px oklch(0.27 0.045 168 / 0.20), 0 4px 12px oklch(0.27 0.045 168 / 0.14);
}

/* The camera, and the only detail the lid needs. A drawn notch, keyboard or
   trackpad reads as a picture OF a laptop; this reads as a laptop. */
.device-lid::before {
  content: "";
  position: absolute;
  top: 5px;
  left: 50%;
  transform: translateX(-50%);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #45484d;
}

/* 16:10.4 is the MacBook Pro screen, near enough that nobody reads it as a
   television. The overflow crop is what makes it a photograph of a page
   rather than a boxed-in copy of one: content continues past the bottom
   edge exactly as it does on a real screen. */
.device-screen {
  background: var(--paper);
  border-radius: 4px;
  overflow: hidden;
  aspect-ratio: 16 / 10.4;
}

/* The inner page width is DERIVED from the screen, never authored: 100% of
   the screen divided by the scale, scaled back by the scale, is the screen
   width again at any column width. See the scale note at the top of this
   block before changing either number. */
.device-screen-inner {
  width: calc(100% / var(--device-scale));
  transform: scale(var(--device-scale));
  transform-origin: top left;
}

/* The base is wider than the lid, which is the one proportion that makes a
   laptop read as a laptop rather than a framed picture. */
.device-base {
  height: 13px;
  margin: 0 -30px;
  background: linear-gradient(180deg, #d5d8dc 0%, #b6bbc1 55%, #91969c 100%);
  border-radius: 0 0 12px 12px;
  position: relative;
  box-shadow: 0 8px 14px oklch(0.27 0.045 168 / 0.16);
}

.device-base::after {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 110px;
  height: 7px;
  background: #9aa0a6;
  border-radius: 0 0 7px 7px;
}

/* Default sizes for the paragraph stand-ins declared with the global heading
   rule. Containers that already size their own headings (the profile
   masthead, the verification box head, a profile section) override these,
   exactly as they override h1/h2/h3. A shot heading is never a measure of
   text, so the 70ch paragraph cap has to come off. */
.shot-title { font-size: clamp(1.6rem, 3.2vw, 2.3rem); margin-top: var(--space-6); max-width: none; }
.shot-heading { font-size: clamp(1.25rem, 2vw, 1.5rem); margin-top: var(--space-5); max-width: none; }

/* Same job and same voice as .preview-frame-caption: sentence case, quiet,
   and OUTSIDE the shot so it cannot be cropped away with it. */
.device-caption {
  margin: var(--space-4) 0 0;
  font-size: 0.85rem;
  color: var(--ink-mute);
}

/* The responsive pair. Neither is decoration: below the swap the fallback
   card IS the specimen, so it carries the same caption and the same
   fictional registration number. */
.device-shot-only { display: none; }

@media (min-width: 1200px) {
  .device-shot-only { display: block; }
  .device-shot-fallback { display: none; }
}

/* The lid needs no size bands any more - it is its column. The one band left
   is below 1280px, where the container has not yet reached its 1280px cap, so
   the hero column is under 552px and the derived inner width would fall
   through the profile's 960px two-column breakpoint. A slightly smaller scale
   buys it back: at the 1200px worst case the screen is 424px, and 0.44
   derives 964px. */
@media (min-width: 1200px) and (max-width: 1279.98px) {
  .device-macbook { --device-scale: 0.44; }
}

/* -------------------------------------------------------------------------
   13d. Laptop and phone pair (.device-pair)
   ------------------------------------------------------------------------- */
/* A page of this site photographed at a laptop width and a phone width,
   shown as a laptop with a phone standing in front of its lower right
   corner (the WHAT practitioners hero, Rick 14 Oct 2026: the brand's own
   /sample-profile, the two pictures made by
   scripts/capture-sample-profile.sh). The laptop is the 13c lid, screen and
   base around a picture instead of a live page; the phone is drawn here.
   PICTURES, NOT LIVE PAGES, because two scaled live pages would be two more
   pages' worth of markup in the hero, and a page shrunk to a phone's width
   inside a phone would be unreadable anyway. The caption saying it is an
   example sits OUTSIDE the pair (figcaption), so nothing crops it.

   Both devices sit in ONE grid cell: the laptop at the top left, the phone
   at the bottom right. The phone hangs below the laptop's base by its
   negative bottom margin, and the pair's bottom padding is that same
   overhang, so the phone never covers what follows. The margin resolves
   against the pair's width and the padding against its column's, which are
   the same until the pair reaches its 40rem cap in a wider column; there the
   padding is a little larger, a slightly bigger gap and never an overlap.

   Sizes are a real laptop beside a real phone: the phone is about a fifth of
   the laptop's width and three quarters of its height. Below 640px the
   laptop would be too small to read, so the phone shows alone, centred. */
.device-pair {
  display: grid;
  width: 100%;
  max-width: 40rem;
  margin-inline: auto;
  padding-bottom: 6%;
}

.device-pair > * { grid-area: 1 / 1; min-width: 0; }
.device-pair > .device-macbook { width: 88%; align-self: start; justify-self: start; }

.device-pair .device-screen > img,
.device-phone-screen > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}

.device-phone {
  position: relative;
  width: 21%;
  justify-self: end;
  align-self: end;
  margin-bottom: -6%;
  padding: 0.4rem;
  background: #2b2d31;
  border-radius: 1.5rem;
  box-shadow: 0 22px 44px oklch(0.27 0.045 168 / 0.24), 0 4px 12px oklch(0.27 0.045 168 / 0.16);
}

/* The camera, in the bezel above the screen, as the laptop's lid has. */
.device-phone::before {
  content: "";
  position: absolute;
  top: calc(0.2rem - 2px);
  left: 50%;
  transform: translateX(-50%);
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: #45484d;
}

/* 375 by 812 is the phone width the picture is taken at, so the screen
   shows the picture whole. */
.device-phone-screen {
  border-radius: 1.1rem;
  overflow: hidden;
  aspect-ratio: 375 / 812;
  background: var(--surface);
}

.device-pair-figure { margin: 0; }
.device-pair-figure figcaption a { white-space: nowrap; }

@media (max-width: 639.98px) {
  .device-pair { padding-bottom: 0; }
  .device-pair > .device-macbook { display: none; }
  .device-pair > .device-phone { width: min(13rem, 64%); justify-self: center; margin-bottom: 0; }
}

/* -------------------------------------------------------------------------
   14. Notices, disclaimers, verification box
   ------------------------------------------------------------------------- */
.notice {
  background: var(--green-wash);
  border: 1px solid var(--notice-border);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  margin: var(--space-5) 0;
  font-size: 1.125rem;
}

.disclaimer-box {
  background: var(--paper-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  margin: var(--space-6) 0 var(--space-5);
  font-size: 0.95rem;
  color: var(--ink-soft);
}

.verification-box {
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-1);
}

.verification-box-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--line);
}

.verification-box-head h2, .verification-box-head h3,
.verification-box-head .shot-heading {
  margin: 0;
  font-size: 1.5rem; /* card-heading size, 19 Oct 2026 */
  /* Match the 34px seal height so seal-headed and text-only box heads
     rule at the same baseline in a two-box row. */
  min-height: 2.125rem;
  display: flex;
  align-items: center;
}

.verification-box-head .seal { color: var(--green); }

.verification-box-footer {
  font-size: 0.85rem;
  color: var(--ink-mute);
  border-top: 1px solid var(--line);
  padding-top: var(--space-3);
  margin-bottom: 0;
}
/* The footnote folded behind "What does Verified mean?" (Rick, 21 Sep 2026).
   Same look as the bio's "Read more" toggle; the paragraph keeps its own
   hairline once opened. */
.verification-more { border-top: 1px solid var(--line); margin-top: var(--space-3); padding-top: var(--space-2); }
.verification-more > summary {
  cursor: pointer;
  list-style: none;
  display: inline-block;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--green-deep);
  text-decoration: underline;
  text-decoration-color: var(--brass);
}
.verification-more > summary::-webkit-details-marker { display: none; }
.verification-more > .verification-box-footer { border-top: 0; padding-top: var(--space-2); }

/* -------------------------------------------------------------------------
   15. FAQ (details/summary)
   ------------------------------------------------------------------------- */
.faq-item { border-bottom: 1px solid var(--line); }

.faq-item summary {
  cursor: pointer;
  font-weight: 600;
  font-family: var(--font-serif);
  font-size: 1.3rem;
  padding: var(--space-4) var(--space-6) var(--space-4) 0;
  position: relative;
  list-style: none;
}

.faq-item summary:hover, .filter-sheet summary:hover { color: var(--green-deep); }

.faq-item summary::-webkit-details-marker { display: none; }

.faq-item summary::after {
  content: '+';
  position: absolute;
  right: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-serif);
  font-size: 1.5rem;
  color: var(--brass);
}

.faq-item[open] summary::after { content: '\2212'; }

.faq-item .faq-answer { padding: 0 0 var(--space-4); color: var(--ink-soft); }

/* -------------------------------------------------------------------------
   16. Breadcrumbs
   ------------------------------------------------------------------------- */
.breadcrumbs {
  font-size: 0.9rem;
  color: var(--ink-mute);
  padding-block: var(--space-4);
}

.breadcrumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0; padding: 0; }
/* baseline, not centre (Latest News, 16 Oct 2026): a long last crumb that
   wraps keeps its separator on its first line. */
.breadcrumbs li { margin: 0; display: flex; gap: var(--space-2); align-items: baseline; }
.breadcrumbs li + li::before { content: '·'; color: var(--brass); }
.breadcrumbs a { color: var(--ink-mute); text-decoration: none; }
.breadcrumbs a:hover { color: var(--green); text-decoration: underline; }

/* -------------------------------------------------------------------------
   17. CTA band
   ------------------------------------------------------------------------- */
.cta-band {
  background: var(--green-deep);
  color: var(--on-green-soft);
  border-radius: var(--radius-lg);
  padding: clamp(2rem, 5vw, 3.5rem);
  position: relative;
  overflow: hidden;
}

/* Watermark: the logo's own flow-wave lines in the top-right corner, in
   place of the two abstract rings that used to sit there (Rick, 18 Aug
   2026). Same --flourish-image the green bands already use, so the mark on
   the page is the mark in the logo and there is no second version of it. */
.cta-band::after {
  content: '';
  position: absolute;
  right: -3rem;
  top: -2.5rem;
  width: 26rem;
  height: 17rem;
  background: var(--flourish-image) no-repeat right top;
  background-size: contain;
  opacity: 0.16;
  pointer-events: none;
}

.cta-band > * { position: relative; z-index: 1; }

.cta-band h2, .cta-band h3 { color: var(--on-green); margin-top: 0; }
.cta-band p { max-width: 44rem; line-height: 1.75; }

.cta-band .btn-primary { background: #DBA239; color: #000; } /* Rick's exact values, 17 Aug 2026 */
.cta-band .btn-primary:hover { background: color-mix(in oklab, #DBA239, #000 12%); color: #000; }
.cta-band .btn-secondary { color: var(--on-green); border-color: var(--cta-outline); }
.cta-band .btn-secondary:hover { background: var(--cta-outline-wash); color: var(--on-green); border-color: var(--on-green); }

/* -------------------------------------------------------------------------
   18. Result entries (search, town pages) - ledger entry styling
   ------------------------------------------------------------------------- */
.result-card {
  display: flex;
  gap: var(--space-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-1);
  margin-bottom: var(--space-4);
  transition: box-shadow 200ms var(--ease-out), border-color 200ms var(--ease-out);
}

.result-card:hover { box-shadow: var(--shadow-2); border-color: var(--line-strong); }

.result-card.featured { border-color: var(--brass); }

.result-photo {
  flex: none;
  width: 8rem;
  height: 8rem;
  border-radius: 50%;
  overflow: hidden;
  background: var(--green-wash);
  display: grid;
  place-items: center;
  color: var(--green);
  font-family: var(--font-serif);
  font-size: 2.2rem;
}

.result-photo img { width: 100%; height: 100%; object-fit: cover; }

.result-main { flex: 1; min-width: 0; }

.result-name { font-size: 1.6rem; margin: 0 0 var(--space-1); }
.result-name a { text-decoration: none; color: var(--ink); }
.result-name a:hover { text-decoration: underline; text-decoration-color: var(--brass); }

.result-meta {
  font-size: 0.85rem;
  color: var(--ink-mute);
  margin-bottom: var(--space-3);
  font-variant-numeric: tabular-nums;
}

.result-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }

/* "Sessions from ..." on every result card (build run 2, job 4, 29 Sep 2026:
   Rick's decision 4, a fee on every result on every directory). One weight
   heavier than the details line above it, because it is the fact a visitor
   compares across cards; the member's own figure, in their own currency. */
.result-fee {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-3);
  font-variant-numeric: tabular-nums;
}

/* Provenance block (partials/provenance_chips.php): "Checked by us" over one
   row of stamps, "Told to us by the therapist" over another. Every chip inside
   keeps the plain .chip style deliberately - see the partial's header for why
   colour must not carry this distinction. The label is sentence case and quiet
   so it reads as a caption against the uppercase stamps it introduces. */
.provenance { display: flex; flex-direction: column; gap: var(--space-3); margin-bottom: var(--space-3); }
.prov-row { display: flex; flex-direction: column; gap: 0.4rem; }
.prov-label {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--ink-mute);
  line-height: 1.2;
}
.prov-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }

@media (max-width: 540px) {
  .result-card { flex-direction: column; }
}

/* -------------------------------------------------------------------------
   19. Map
   ------------------------------------------------------------------------- */
.map-frame {
  height: 26rem;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  overflow: hidden;
  background: var(--paper-2);
  /* Leaflet's own sheet puts controls at z-index 1000 and its marker and
     popup panes at 600/700. Without a stacking context here those numbers
     escape into the root and beat anything the page pins over the map - this
     is the third time that has bitten this page. One line ends the argument
     permanently: everything Leaflet does is now sealed inside the frame. */
  isolation: isolate;
}

/* Results stack in one column: map banner on top, then the full-width list. */
.search-layout {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
}

.search-layout .map-sticky { order: -1; }
/* 22rem in a ~1100px-wide banner is a 3:1 letterbox, and fitBounds satisfies
   both axes - so the short side chose the zoom and the long side filled the
   slack with France. Every doubling of height buys a zoom level; 28rem is
   enough to move a typical 50-mile search from zoom 8 to 9 without the map
   dominating the page. */
.search-layout .map-frame { height: 22rem; }

/* Only wide viewports have the problem: a narrow phone map has no excess
   width to fill, so it keeps the shorter banner rather than eating half the
   screen. */
@media (min-width: 720px) {
  .search-layout .map-frame { height: 28rem; }
}

/* --- The FINDER's map: a column beside the results, not a banner over them
       (Rick, 26 Jul 2026) ---------------------------------------------------
   Measured at 1440x800, the banner's top edge landed at 798px with the fold
   at 800: a sliver of something large and colourful peeking at the bottom of
   the screen is the strongest scroll cue an interface has, and it is what
   sent the first patient who tested this page past the filters entirely.
   Beside the results the map cannot do that, and it also finishes the
   over-zoom fix - the 3.1:1 letterbox was why fitBounds' short axis chose the
   zoom and the spare width filled with 260 miles of coastline.
   SCOPED to the finder: .search-layout is shared with town and lander pages,
   which have no filter bar and keep their single-column banner. */
@media (min-width: 960px) {
  .search-layout.search-layout-finder {
    grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
    /* start, not the default stretch: a stretched grid item fills the row
       height, which leaves a sticky child with zero travel. Same pattern as
       .profile-layout. */
    align-items: start;
  }
  /* Second in DOM and second visually, so focus order matches what is seen. */
  .search-layout.search-layout-finder .map-sticky {
    order: 0;
    position: sticky;
    /* Parked BELOW the pinned filter bar, not at the top of the viewport.
       The bar is opaque and sticks at top:0, so a map parked at --space-4
       had its top strip buried - Leaflet's +/- zoom buttons included, which
       made them unclickable for the whole scroll. The bar's height is not a
       constant (the active-filter chips live in it and it re-wraps), so
       main.js measures it into --finder-bar-h; the fallback is the measured
       one-row height for the no-JS case, where the bar still sticks. */
    top: calc(var(--header-offset) + var(--finder-bar-h, 8rem) + var(--space-4));
  }
  .search-layout.search-layout-finder .map-frame { height: min(34rem, calc(100vh - var(--header-offset) - 8rem)); }
}

/* Below the column breakpoint the map goes AFTER the results rather than
   above them. On a 375px phone the banner alone pushed the first therapist
   past 1600px; the point of the page is the therapists. */
@media (max-width: 959.98px) {
  .search-layout.search-layout-finder .map-sticky { order: 1; }
}

/* -------------------------------------------------------------------------
   20. Pricing tiers
   ------------------------------------------------------------------------- */
.tier-grid {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: 1fr;
  align-items: start;
}

@media (min-width: 720px) { .tier-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .tier-grid { grid-template-columns: repeat(4, 1fr); } }

.tier-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-1);
  display: flex;
  flex-direction: column;
  height: 100%;
  position: relative;
}

.tier-card.best-value { border: 2px solid var(--brass); }

.tier-flag {
  position: absolute;
  top: -0.85rem;
  left: var(--space-5);
  background: var(--brass-deep); /* white text needs >=4.5:1: brass-deep = 5.4:1 */
  color: var(--off-white);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.28rem 0.7rem;
  border-radius: var(--radius-stamp);
}

/* Self-sufficient so span.tier-name (/join) and h2.tier-name (/pricing)
   render identically; also lifts tier names into the 1.3rem heading step. */
.tier-name {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 1.3rem;
  color: var(--ink);
  line-height: 1.14;
  margin: 0 0 var(--space-3);
}

.tier-price {
  font-family: var(--font-serif);
  font-size: 2.1rem;
  font-weight: 700;
  color: var(--green-deep);
  margin-bottom: var(--space-1);
  font-variant-numeric: tabular-nums;
}

.tier-price-note { font-size: 0.9rem; color: var(--ink-mute); margin-bottom: var(--space-4); }

/* Card scale is scoped to cards; verification boxes and profiles inherit
   body size so the tick lists read as one system with their neighbours. */
.tier-features { list-style: none; padding: 0; margin: 0 0 var(--space-5); }
.tier-card .tier-features { font-size: 0.95rem; }
.verification-box .tier-features li { margin-bottom: var(--space-3); }

.tier-features li {
  padding-left: 1.5rem;
  position: relative;
  margin-bottom: var(--space-2);
}

.tier-features li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.42rem;
  width: 0.85rem;
  height: 0.45rem;
  border-left: 2px solid var(--verified);
  border-bottom: 2px solid var(--verified);
  transform: rotate(-45deg);
}

.tier-card .btn { margin-top: auto; }

/* -------------------------------------------------------------------------
   21. Prose (long-form legal/guide content)
   ------------------------------------------------------------------------- */
.prose { max-width: var(--container-narrow); margin-inline: auto; }
.prose h2 { margin-top: var(--space-7); }
.prose h3 { margin-top: var(--space-6); }
.prose li { margin-bottom: var(--space-3); }
/* An opening heading gets its top gap from the section padding, not an extra
   margin: without this, a prose block that starts with an h2 has a bigger gap
   above the heading than below it. */
.prose > :first-child { margin-top: 0; }

.prose-meta {
  font-size: 0.9rem;
  color: var(--ink-mute);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-6);
}

/* A version line inside a centred page header (Verification Standard, Badge
   Terms) is part of the title block, not a prose rule: no hairline, tighter,
   and margin-inline auto because the global p max-width would otherwise pin
   its box left while the header centres everything else. */
.page-header .prose-meta {
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: var(--space-3);
  margin-inline: auto;
}

/* -------------------------------------------------------------------------
   22. Page headers (interior pages)
   ------------------------------------------------------------------------- */
.page-header {
  padding-block: var(--space-7) var(--space-6);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.page-header h1 { margin-bottom: var(--space-3); }
.page-header .lead {
  font-size: 1.2rem;
  font-family: var(--font-serif);
  color: var(--ink-soft);
  max-width: 46rem;
  margin-bottom: 0;
}

/* Page titles (Rick, 16 Jul 2026): on desktop EVERY page-title block is
   centred (the homepage hero is its own component, not a .page-header, so it
   keeps its layout; admin pages keep their functional left alignment). On
   mobile all page titles read left-aligned - the base state below the
   breakpoint. */
@media (min-width: 640px) {
  body:not(.page-admin) .page-header { text-align: center; }
  body:not(.page-admin) .page-header .lead { margin-inline: auto; }
}

/* Compact variant, used by the finder once a search has run (Rick, 26 Jul
   2026). The full block is 218px of a 800px screen restating what the visitor
   already typed, and it pushed the map's top edge to within two pixels of the
   fold - which is what made people scroll straight past the filters. The h1
   keeps the one site-wide size (19 Oct 2026); only the padding is tighter.
   A modifier on the element, not a body class: .page-header is used by 41
   templates and the body class does not vary with search state. */
.page-header-compact { padding-block: var(--space-5) var(--space-4); }
.page-header-compact h1 { margin-bottom: var(--space-2); }
.page-header-compact .lead { font-size: 1.02rem; }
/* Compact spacing, but a headline that still outranks the section headings
   below it (h2 is 2.3rem). Used on /how-we-differ, 23 Sep 2026. */
.page-header-headline { padding-bottom: var(--space-7); }
.page-header-headline h1 { margin-bottom: var(--space-5); }
.page-header-headline .lead { color: oklch(0.32 0.02 165); } /* a shade darker than --ink-soft (Rick, 23 Sep 2026) */
/* Headline and intro stay centred on phones too (Rick, 23 Sep 2026); .hero-stack-text otherwise turns left below 640px. */
@media (max-width: 639.98px) {
  .page-header-headline h1, .page-header-headline .lead { text-align: center; }
}

/* -------------------------------------------------------------------------
   23. Dashboard and admin (functional, same tokens)
   ------------------------------------------------------------------------- */
.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  margin-bottom: var(--space-5);
}

.panel h2 { margin-top: 0; font-size: 1.5rem; } /* Rick 17 Jul: larger section titles, dashboard + admin */

.stat-row { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); }

.stat {
  background: var(--green-wash);
  border-radius: var(--radius);
  padding: var(--space-4);
  text-align: center;
}

.stat-number {
  font-family: var(--font-serif);
  font-size: 1.9rem;
  font-weight: 700;
  color: var(--green-deep);
  display: block;
  font-variant-numeric: tabular-nums;
}

.stat-label { font-size: 0.85rem; color: var(--ink-soft); }

.table-scroll { overflow-x: auto; }

.status-pill {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.25rem 0.6rem;
  border-radius: var(--radius-stamp);
  background: var(--paper-2);
  color: var(--ink-soft);
}

.status-pill.ok { background: var(--verified-wash); color: var(--tone-verified-ink); }
/* True green, literal values on purpose: --verified-* and --green-* are brand palette
   tokens and a brand may repaint them (MLD's are navy-blue), so a pill that must read
   green cannot borrow them. Used for "Approved. Waiting for public launch day",
   "Approved. First charge in flight" and "Live on the register" (Rick, 4 Oct 2026). */
.status-pill.go { background: oklch(0.92 0.06 150); color: oklch(0.34 0.09 150); }
/* Violet, literal for the same reason as .go: "Sent to them for approval", the one stage
   that is with the member to approve (Rick, 4 Oct 2026). Not blue, because blue is the
   Payment column's Reserved pill. */
.status-pill.sent { background: oklch(0.93 0.05 300); color: oklch(0.38 0.13 300); }
.status-pill.warn { background: var(--brass-soft); color: var(--tone-warn-ink); }
.status-pill.bad { background: var(--danger-wash); color: var(--danger); }

/* -------------------------------------------------------------------------
   24. Error pages
   ------------------------------------------------------------------------- */
.error-page { text-align: center; padding-block: var(--space-8); }

.error-code {
  font-family: var(--font-serif);
  font-size: 5rem;
  font-weight: 700;
  color: var(--brass);
  line-height: 1;
  margin-bottom: var(--space-4);
}

.error-page .search-box { margin-inline: auto; text-align: left; margin-top: var(--space-6); }
.error-page p { margin-inline: auto; }

.error-detail {
  text-align: left;
  overflow: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4);
  font-size: 0.85rem;
}

/* -------------------------------------------------------------------------
   25. Reveal-on-scroll (progressive enhancement; JS adds .reveal-ready)
   ------------------------------------------------------------------------- */
.reveal { opacity: 1; transform: none; }

.js.reveal-ready .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out);
}

.js.reveal-ready .reveal.revealed { opacity: 1; transform: none; }

.js.reveal-ready .reveal:nth-child(2) { transition-delay: 70ms; }
.js.reveal-ready .reveal:nth-child(3) { transition-delay: 140ms; }
.js.reveal-ready .reveal:nth-child(4) { transition-delay: 210ms; }

@media (prefers-reduced-motion: reduce) {
  .js.reveal-ready .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
  .btn, a, input, select, textarea, .result-card { transition: none !important; }
}

/* -------------------------------------------------------------------------
   26. Utilities
   ------------------------------------------------------------------------- */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.text-muted { color: var(--ink-mute); }
.text-small { font-size: 1.1rem; }
.text-nowrap { white-space: nowrap; }

/* Wider column gap for two-column editorial sections */
@media (min-width: 640px) {
  .grid-gap-lg { gap: var(--space-8); }
}
.text-center { text-align: center; }
.text-left { text-align: left; }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.mt-4 { margin-top: var(--space-4); }
.mt-6 { margin-top: var(--space-6); }
.mt-7 { margin-top: var(--space-7); }

/* Secret-field state badge (admin settings): shows whether a password/API key
   is stored, without ever revealing it. */
.secret-badge {
  display: inline-block;
  margin-left: var(--space-2);
  padding: 0.12em 0.6em;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1.5;
  vertical-align: middle;
}
.secret-badge.is-set { background: var(--green-wash); color: var(--green); }
.secret-badge.is-unset { background: var(--line); color: var(--ink-mute); }

/* Editable long-text setting (e.g. the AI drafting instructions). */
.settings-textarea {
  width: 100%;
  min-height: 12rem;
  font-size: 0.9rem;
  line-height: 1.55;
  resize: vertical;
}
.mx-auto { margin-inline: auto; }

/* =========================================================================
   Page-specific sections are appended below by the relevant build package.
   Keep every addition token-driven: no new colours, no new fonts.
   ========================================================================= */

/* --- Homepage --- */
/* The hero search prompt reads as a small title above the field. */
.page-home .search-box label { font-size: 1.25rem; }

.trust-strip {
  background: var(--surface);
  border-block: 1px solid var(--line);
  padding-block: var(--space-5);
}

/* First row of the trust strip needs no hairline above it on desktop */
@media (min-width: 860px) {
  .trust-strip .index-list > li:nth-child(-n+2) { border-top: 0; }
}

/* Mobile (single column): only the very first row drops its hairline, so the
   strip's own top border is not doubled by a stray rule above "01". */
.trust-strip .index-list > li:first-child { border-top: 0; }

/* Featured members band: cards centre in the committed-green surface at any
   count (one card at launch must not strand two empty columns), and the
   entries carry the ledger scale used in search/town results. */
.featured-grid {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .featured-grid {
    grid-template-columns: repeat(auto-fit, minmax(16rem, 24rem));
    justify-content: center;
  }
}

.featured-name { margin-top: 0; font-size: 1.3rem; }
.featured-name a { text-decoration: none; color: var(--ink); }
.featured-name a:hover { text-decoration: underline; text-decoration-color: var(--brass); }

.featured-meta {
  font-size: 0.85rem;
  color: var(--ink-mute);
  margin-bottom: var(--space-3);
  font-variant-numeric: tabular-nums;
}

/* A Featured card as a small listing (the WHAT master home, visual review
   30 Sep 2026: a name and a number alone read as a placeholder for a paid
   placement). The member's portrait is the search card's photo circle at a
   card's scale, beside the name, the meta line and View profile; the cards
   start on the heading's text line instead of centring away from it. Both
   classes are opt-in, so MLD's centred Featured cards are unchanged. */
@media (min-width: 640px) {
  .featured-grid-start { justify-content: start; }
}
.featured-card { display: flex; align-items: center; gap: var(--space-4); }
.featured-card .result-photo { width: 5.5rem; height: 5.5rem; font-size: 1.6rem; }
.featured-card-body { min-width: 0; }

.guide-link {
  display: block;
  font-family: var(--font-serif);
  font-size: 1.6rem; /* Rick, 2 Sep 2026 */
  font-weight: 600;
  text-decoration: none;
  color: var(--ink);
  padding: var(--space-4) var(--space-6) var(--space-4) 0;
  position: relative;
}

.guide-link::after {
  content: '\2192';
  position: absolute;
  right: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  color: var(--brass);
  transition: transform 200ms var(--ease-out);
}

.guide-link:hover { color: var(--green); }
.guide-link:hover::after { transform: translate(4px, -50%); }

li.faq-item { list-style: none; margin: 0; }

/* --- Admin navigation --- */
.admin-nav {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-6);
}

.admin-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: var(--space-3) 0;
}

.admin-nav li { margin: 0; }

.admin-nav a {
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink-soft);
  padding: var(--space-2) 0;
  border-bottom: 2px solid transparent;
}

.admin-nav a:hover, .admin-nav a[aria-current="page"] {
  color: var(--green-deep);
  border-bottom-color: var(--brass);
}

.admin-nav-logout { margin-left: auto; }

/* --- Guides hub and articles --- */
.guides-hub-list { max-width: 52rem; margin-block: var(--space-6); margin-inline: auto; }
.guides-hub-list + .disclaimer-box { max-width: 52rem; margin-inline: auto; }
.guide-link-desc { margin: -0.4rem 0 var(--space-4); max-width: 46rem; font-size: 1.125rem; } /* 18px at the 16px root (Rick, 2 Sep 2026) */

.guide-article { padding-block: var(--space-6) var(--space-7); } /* phone top gap doubled, Rick 2 Sep 2026: it sat too tight under the header */

@media (min-width: 640px) {
  .guide-article { padding-block: var(--space-8) var(--space-7); }
}

/* Guide titles follow the site-wide rule: centred on desktop, left on
   mobile; the article body stays editorial left at every width. */
@media (min-width: 640px) {
  .guide-article > h1 { text-align: center; }
}

.guide-intro {
  font-family: var(--font-serif);
  font-size: 1.2rem;
  line-height: 1.65;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--space-5);
  margin-bottom: var(--space-5);
}

/* --- Package: static-pages (B5 /for-therapists, B6 /pricing,
       B7 /verification-standard, B9 /about, B16 /faq) ---
   Token-driven only: existing custom properties, no new colours or fonts. */

/* For-therapists hero, on white (crisper than the warm-bone interior). MLD
   uses the two-column .hero-grid below; WhatCounsellor still uses the older
   centred .hero-stack, so BOTH sets of rules stay live. Everything specific
   to the two-column version is keyed off .hero-grid rather than the page
   class, so a WhatCounsellor deploy inherits none of it by accident. */
/* Rick's specified hero tone for this page (18 Aug 2026), kept as the
   authored hex so it is exactly the colour he picked. */
.page-for-therapists .hero { background: #F7F6F0; }

/* Report section 13 asks for roughly 52% copy / 48% preview, against the
   home hero's 7/5. An even split gives the product-preview column the width
   a real .result-card needs (8rem photo plus a readable text column) without
   squeezing the headline. */
@media (min-width: 960px) {
  .page-for-therapists .hero-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

/* From 1200px the preview column stops holding a result card and starts
   holding the laptop shot, which fits its column exactly - so the column
   width IS the shot size, and every pixel the gap gives back buys screen.
   The 6rem gap is sized for two columns of TEXT; a laptop carries its own
   drop shadow and needs less air beside it, and the shot is short enough at
   an even split that it stops before the Verification panel - the one part
   of the profile this page is selling. 3rem widens BOTH columns by 24px, so
   the headline gets more room rather than less.
   Uneven splits were tried first and all of them cost the headline its
   second line: it breaks to three below a 526px column. */
@media (min-width: 1200px) {
  .page-for-therapists .hero-grid { gap: var(--space-7); }
}

/* The stacked hero wants a 3rem gap under the subhead before its lone CTA.
   The two-column version carries buttons AND the founding price in the same
   column, so it takes the standard rhythm instead. */
.page-for-therapists .hero-grid .hero-subhead { margin-bottom: var(--space-5); }

/* Report section 13 wants the three hero proof points in three desktop
   columns. The shared .index-list is two columns, which would strand the
   third on a row of its own, so this strip takes three - and the rule that
   drops the hairline above the first ROW has to count to three here too,
   or 03 grows a stray line above it. Scoped to the page, and only where a
   .hero-grid proves this is the two-column MLD version of the page. */
@media (min-width: 860px) {
  .page-for-therapists .trust-strip .index-list { grid-template-columns: repeat(3, 1fr); }
  .page-for-therapists .trust-strip .index-list > li:nth-child(-n+3) { border-top: 0; }
}

/* The two plan cards here are a straight side-by-side comparison, so they
   match height and their Apply buttons line up on the same line. Boxes that
   carry a billing radio group keep the shared align-items:start, because
   stretching those strands the controls in mid-air.
   WhatCounsellor's For Therapists page has no plan cards, so it inherits
   nothing from this. */
@media (min-width: 800px) {
  .page-for-therapists .join-two-boxes { align-items: stretch; }
  .page-for-therapists .tier-box { display: flex; flex-direction: column; }
  .page-for-therapists .tier-box .tier-features { flex: 1 0 auto; }
}

/* /pricing joined the equal-height rule on 18 Aug 2026 (report section 14)
   once MLD's rate boxes moved out of the cards and the newly qualified rate
   became a banner beneath them.
   THE CONDITION IS THE RATE BOXES, NOT THE PAGE. /pricing is one shared
   controller and one shared body class, and WhatCounsellor has its own
   pricing view whose cards DO still carry .tier-billing groups - a
   .page-pricing scope would have stretched them and stranded their controls,
   which is the exact failure the block above avoids. :has() states the real
   invariant instead, and self-corrects if either brand's cards change.
   Kept in its own block on purpose: a selector list is dropped whole when one
   of its selectors will not parse, so pairing this with the rule above would
   cost For Therapists its equal-height cards on any engine without :has().
   Without :has() this simply does not apply and the cards fall back to the
   shared align-items:start, which is the pre-18-Aug layout. */
@media (min-width: 800px) {
  .page-pricing .join-two-boxes:not(:has(.tier-billing)) { align-items: stretch; }
  .page-pricing .join-two-boxes:not(:has(.tier-billing)) .tier-box { display: flex; flex-direction: column; }
  .page-pricing .join-two-boxes:not(:has(.tier-billing)) .tier-features { flex: 1 0 auto; }
}

.hero-stack { padding-block: var(--space-7); }

.hero-stack-text {
  max-width: 46rem;
  margin-inline: auto;
  text-align: center;
}

.hero-stack-text h1,
.hero-stack-text .hero-subhead,
.hero-stack-text p { margin-inline: auto; }

/* For-therapists hero: a wider measure than the home hero so the subhead
   holds fewer, more confident lines. */
.page-for-therapists .hero-stack-text { max-width: 53rem; }
.page-for-therapists .hero-subhead { max-width: 53rem; margin-bottom: var(--space-7); }

.hero-stack-text .btn-row { justify-content: center; }

/* Mobile: sales-hero text reads left like every other title block. */
@media (max-width: 639.98px) {
  .hero-stack-text { text-align: left; }
  .hero-stack-text .btn-row { justify-content: flex-start; }
  .hero-stack-text .hero-secondary-link { align-self: flex-start; }
}
.hero-stack-photo { margin-top: var(--space-6); }
.hero-stack-photo img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }

.hero-secondary-link {
  align-self: center;
  font-weight: 600;
}

.under-hero {
  font-size: 0.9rem;
  color: var(--ink-mute);
  margin: var(--space-4) 0 0;
}

#what-you-get { scroll-margin-top: var(--space-6); }

/* Comparison table: the register column reads as the committed entry */
.compare-table th:last-child,
.compare-table td:last-child { background: var(--green-wash); }
.compare-table td:last-child { color: var(--ink); font-weight: 500; }
.compare-table td:first-child { color: var(--ink-mute); }
.compare-table th:last-child { color: var(--green-deep); border-bottom-color: var(--green); }
/* A feature table: the first column names the feature, so it keeps the main
   text colour instead of the muted row-label grey (/how-we-differ, 23 Sep 2026). */
.compare-table-feature td:first-child { color: var(--ink); }
@media (min-width: 640px) {
  .compare-table-feature th:first-child, .compare-table-feature td:first-child { width: 38%; }
  .compare-table-feature td { padding-block: var(--space-4); } /* Rick, 23 Sep 2026 */
}
/* A centred measure a little wider than --container-narrow, for a feature table under a stacked header. */
.measure-wide { max-width: 62rem; margin-inline: auto; } /* 62rem, Rick 23 Sep 2026 */
/* Tick and cross marks for a comparison table (/how-we-differ, 23 Sep 2026).
 Every mark carries a visually-hidden Yes or No beside it for screen readers. */
.cmp-mark {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1;
}
/* A true green on purpose (Rick, 23 Sep 2026): the brand's --green and --verified render teal-navy. A brand may retune --mark-yes. */
.cmp-mark-yes { background: var(--mark-yes, oklch(0.56 0.15 148)); color: #fff; }
.cmp-mark-no { background: var(--danger); color: #fff; }
/* Not determined from outside: a neutral dash, never a cross. */
.cmp-mark-unknown { background: var(--line-strong); color: var(--ink); }
.cmp-cell { display: flex; gap: var(--space-3); align-items: flex-start; }
.cmp-cell .cmp-mark { margin-top: 0.125rem; }
.compare-table-marks .cmp-col-mark { text-align: center; background: var(--danger-wash); } /* its own tone, apart from the Features column; grey hid the rules (Rick, 23 Sep 2026) */
/* Placed as a box, not on the text baseline, so it levels with the Register tick in every font. */
.compare-table-marks .cmp-col-mark .cmp-mark { display: grid; margin: 0.125rem auto 0; }
@media (min-width: 640px) {
  .compare-table-marks th:first-child, .compare-table-marks td:first-child { width: 34%; }
  .compare-table-marks .cmp-col-mark { width: 9rem; }
  /* A framed table with a rule either side of the mark column (Rick, 23 Sep 2026). */
  /* Rounded 20px frame (Rick, 23 Sep 2026): separate borders so the radius takes,
     and the corner cells are rounded too so their backgrounds stay inside it. */
  .compare-table-marks { border: 1px solid oklch(0.72 0.02 110); border-collapse: separate; border-spacing: 0; border-radius: 20px; }
  .compare-table-marks thead th:first-child { border-top-left-radius: 19px; }
  .compare-table-marks thead th:last-child { border-top-right-radius: 19px; }
  .compare-table-marks tbody tr:last-child td { border-bottom: 0; }
  .compare-table-marks tbody tr:last-child td:first-child { border-bottom-left-radius: 19px; }
  .compare-table-marks tbody tr:last-child td:last-child { border-bottom-right-radius: 19px; }
  /* The Features column on white (Rick, 23 Sep 2026). */
  .compare-table-marks th:first-child, .compare-table-marks td:first-child { background: #ffffff; }
  .compare-table-marks .cmp-col-mark { border-inline: 1px solid oklch(0.72 0.02 110); }
}
/* Phones: the mark sits under its column name, in line with the Register's tick. */
@media (max-width: 639.98px) {
  .compare-table-marks td.cmp-col-mark { text-align: left; }
  /* Each row card clearly framed on phones (Rick, 23 Sep 2026). */
  .compare-table.compare-table-marks tr { border-color: oklch(0.72 0.02 110); border-radius: var(--radius-lg); }
  .compare-table-marks td.cmp-col-mark .cmp-mark { margin-inline: 0; }
}

/* Phones: each row becomes its own small card, the first cell as its title and
   every other cell under the column name from its data-label (added 23 Sep
   2026 for /how-we-differ; three columns in 335px left one or two words a line). */
@media (max-width: 639.98px) {
  .compare-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .compare-table, .compare-table tbody, .compare-table tr, .compare-table td { display: block; width: 100%; }
  .compare-table tr {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    overflow: hidden;
    margin-bottom: var(--space-4);
  }
  .compare-table td { border-bottom: 0; padding: var(--space-3) var(--space-4); }
  .compare-table td:first-child { color: var(--ink); font-weight: 700; padding-bottom: 0; }
  .compare-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--ink-soft);
    margin-bottom: 0.2rem;
  }
  .compare-table td:last-child[data-label]::before { color: var(--green-deep); }
  /* A feature table's card title keeps a gap above its tinted text. */
  .compare-table-feature td:first-child { padding-bottom: var(--space-3); }
}

.compare-note {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--ink-soft);
  max-width: 62ch;
  margin-top: var(--space-5);
  margin-bottom: 0;
}

/* Founding offer table */
.offer-table strong { color: var(--green-deep); }

/* The founding offer table explains each tier via a "?" tooltip in column 1
   instead of a heavy paragraph block. No scroll wrapper (short content wraps
   on mobile), so the bubbles are never clipped. */
.tier-cell {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.offer-table .tip-icon {
  width: 1.35rem;
  height: 1.35rem;
  min-width: 1.35rem;
  min-height: 1.35rem;
  font-size: 0.75rem;
}

.offer-table .tip-bubble { text-transform: none; letter-spacing: normal; width: 18rem; }

@media (max-width: 560px) {
  .offer-table { font-size: 0.9rem; }
  .offer-table th, .offer-table td { padding: var(--space-2) var(--space-3); }
}

/* Verification standard page */
@media (min-width: 860px) {
  .index-list-stack { grid-template-columns: 1fr; }
}

.means-not-list { list-style: none; padding: 0; margin: 0; }

.means-not-list li {
  padding-left: 1.5rem;
  position: relative;
  margin-bottom: var(--space-3);
}

.means-not-list li::before {
  content: '';
  position: absolute;
  left: 0.1rem;
  top: 0.68rem;
  width: 0.75rem;
  height: 2px;
  background: var(--ink-mute);
}

.school-list { list-style: none; padding: 0; margin: var(--space-5) 0; max-width: 46rem; }

.school-list li {
  margin: 0;
  padding: var(--space-4) 0;
  border-top: 1px solid var(--line);
}

.school-list li:last-child { border-bottom: 1px solid var(--line); }

.school-list strong {
  font-family: var(--font-serif);
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--ink);
}

.school-list .school-detail { color: var(--ink-soft); }

/* Pricing page */
.tier-note {
  font-size: 0.85rem;
  color: var(--ink-mute);
  margin: var(--space-3) 0 0;
}

.tier-card .tier-note { margin-top: var(--space-3); }

.pricing-foot {
  border-top: 2px solid var(--brass);
  padding-top: var(--space-5);
  max-width: 60rem;
  margin-inline: auto;
}

.pricing-foot ul { list-style: none; padding: 0; margin: 0; }

.pricing-foot li {
  font-size: 0.95rem;
  color: var(--ink-soft);
  margin-bottom: var(--space-3);
  max-width: 75ch;
}

/* About page: founder sign-off styled as a ledger signature line */
.founder-sig {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-family: var(--font-serif);
  font-size: 1.2rem;
  margin-top: var(--space-5);
}

/* The name and the role are two LINES. They used to be two flex items with a
   <br> between them, which flex discards, so they sat side by side. */
.founder-sig-lines { display: block; }
.founder-sig-role { display: block; font-size: 0.95rem; color: var(--ink-soft); }

.founder-sig::before {
  content: '';
  display: block;
  width: 2rem;
  height: 1px;
  /* Sits on the NAME's optical centre now the byline is two lines. */
  margin-top: 0.85em;
  background: var(--brass);
  flex: none;
}

/* -------------------------------------------------------------------------
   Package: legal-contact (contact page routes list + form panel).
   Legal pages reuse the existing .prose layout and need no new styles.
   Token-driven only: no new colours, no new fonts.
   ------------------------------------------------------------------------- */

.contact-grid { align-items: start; }

/* Ruled list of contact routes, in the ledger hairline idiom. */
.contact-routes {
  list-style: none;
  margin: 0;
  padding: 0;
}

.contact-routes li {
  margin: 0;
  padding-block: var(--space-5);
  border-top: 1px solid var(--line);
}

.contact-routes li:first-child {
  border-top: 0;
  padding-top: 0;
}

.contact-routes li:last-child {
  border-top: 1px solid var(--brass-soft);
}

.contact-routes p {
  margin: 0;
  color: var(--ink-soft);
}

.contact-routes p strong { color: var(--ink); }

/* The form panel mirrors the verification-box treatment. */
.contact-form-panel {
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-1);
}

/* Both form panels (contact + profile enquiry) share one heading size and
   run the heading straight into the form, no internal rule. */
.contact-form-panel h2, .enquiry-section h2 {
  margin-top: 0;
  font-size: 1.5rem;
  margin-bottom: var(--space-5);
}

/* Inline field validation message. */
.field-error { color: var(--danger); }

/* =========================================================================
   Package: search-towns
   Find a Therapist search page (/find-a-therapist) and town pages
   (/mld-therapist/[town]). Merged into main.css by the orchestrator.
   Token-driven only: existing custom properties, no new colours, no fonts.
   ========================================================================= */

.finder-field label {
  display: block;
  font-weight: 700;
  font-size: 0.95rem;
  margin-bottom: var(--space-2);
}

/* The location field is the ONLY growing item on the bar, and that is what
   keeps the row honest: whatever width is left over goes into it, so the bar
   always ends exactly where it should. Two rows could not do that - one of
   them always had slack, which became either an empty gap or an 848px box
   for an eight-character postcode. Its basis is small so it yields to the
   fixed controls first and only then takes the remainder - CRUCIALLY, flex
   line-breaking uses these basis sizes, so the basis total (not the grown
   widths) is what decides whether the row stays on one line. */
.finder-field-loc { flex: 1 1 6rem; min-width: 0; }
.finder-field-radius { flex: 0 0 auto; width: 8rem; }
.finder-filters-row > .btn { flex: 0 0 auto; }

/* Orientation line between the landing bar and the landing photo, centred on
   the same 60rem column so the three read as one composed block. Explicit
   max-width:none because the base p{max-width:70ch} pins a text-align:center
   paragraph left of centre (the recurring centred-paragraph gotcha). */
/* Check a Therapist utility strip (18 Aug 2026, report 5G): its home in
   the find journey now it is out of the global header. One quiet tinted
   row under the search card, in every search state, visually below the
   Search button in priority. On the landing state it sits on the same
   60rem column as the bar and photo. */
.check-strip {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  max-width: 60rem;
  margin: var(--space-4) auto 0;
  padding: var(--space-2) var(--space-4);
}

.check-strip-text {
  max-width: none; /* centred <p> gotcha */
  margin: 0;
  font-size: 0.92rem;
  color: var(--ink-soft);
}

.check-strip-link {
  flex: none;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--green-deep);
  text-decoration: underline;
  text-decoration-color: var(--link-underline);
  text-underline-offset: 0.2em;
}

.check-strip-link:hover { color: var(--green); }

@media (max-width: 599.98px) {
  .check-strip { flex-direction: column; text-align: center; padding-block: var(--space-3); }
}

/* --- Landing state photo: matches the landing bar's 60rem (Rick, 26 Jul) --- */
/* FOUNDING WINDOW: THE NOTICE AND THE PHOTOGRAPH AS ONE BAND (Rick, 2 Sep
   2026). Notice left, portrait photograph right, equal height: the copy sets
   the box's height and the photograph is cover-fitted to match it, so the
   two edges always line up whatever the wording does. Below 960px they stack
   as they always did. The row only exists while the window is open; the
   public page keeps the full-width landing photograph below, untouched. */
@media (min-width: 960px) {
  .finder-prelaunch-row {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: var(--space-6);
    align-items: stretch;
    margin-block: var(--space-6) var(--space-7);
  }
  .finder-prelaunch-row .prelaunch-notice { max-width: none; margin: 0; }
  .finder-prelaunch-row .finder-landing-side {
    max-width: none;
    margin: 0;
    display: flex;
    flex-direction: column;
  }
  .finder-prelaunch-row .finder-landing-side img {
    flex: 1 1 0;
    min-height: 0;
    height: auto;
    object-fit: cover;
  }
}

.finder-landing {
  max-width: 60rem;
  margin-block: var(--space-5) var(--space-7);
  margin-inline: auto;
}
.finder-landing img { aspect-ratio: 21 / 9; object-fit: cover; object-position: center 40%; } /* both WHAT sites show the same frame (Rick, 7 Oct 2026) */
.finder-landing .ledger-caption { display: flex; justify-content: center; max-width: none; }
.finder-landing .ledger-caption::after {
  content: '';
  display: block;
  flex: none;
  width: 2rem;
  height: 1px;
  margin-top: 0.75em;
  margin-top: calc(0.5lh - 0.5px);
  background: var(--brass);
}

/* --- Layout: filters live in the search panel; results own the full width --- */
.finder-layout {
  margin-bottom: var(--space-7);
}

/* --- The sticky filter bar ------------------------------------------------
   The bar has to keep up with the results, or a visitor who scrolls loses
   every control and has no way back short of scrolling to the top - which is
   exactly what happened to the first patient who tested the page.
   position: sticky only travels inside its own containing block, so the bar
   sits in .finder (which spans the controls AND the results) rather than
   inside the search form, which ends a few pixels below it. Its controls stay
   wired to the form with form="search-form".
   The z-index is not decorative: Leaflet's panes sit at 400+, and this file
   already records two shipped bugs from losing that stacking fight. */
.finder {
  position: relative;
}

.finder-bar {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  padding: var(--space-4) var(--space-5);
  margin-block: var(--space-5) var(--space-6);
}

/* Before a search has run the bar is the page's hero: 60rem = the 960px Rick
   specified (26 Jul), controls at the site's hero-search height rather than
   the compact toolbar height, and the landing photo matches its width so the
   two read as one composed block. */
.finder-bar-landing { max-width: 60rem; margin-inline: auto; --filter-control-h: 3.4rem; }

/* It sticks only while COLLAPSED. Open, it is 670px of panel, and pinning
   that to the top of the viewport would bury the results it exists to
   narrow; so it drops back into flow and main.js scrolls it into view, which
   also stops the button opening a panel the visitor cannot see.
   Gated on BOTH :has() and the js-finder class main.js sets, because each
   guard covers a way the bar could otherwise strand the panel: without
   :has() the panel is always open, so the bar would be permanently pinned at
   full height; without JS nothing scrolls the panel into view, so opening it
   while scrolled would render it off-screen above the visitor. In either
   case a bar that does not stick is the honest degradation. */
/* Not below 720px. There the seven controls wrap to about 400px of bar, and
   pinning half a phone screen costs more than it saves - the bar now starts
   at 469px on a 375px-wide phone, so it is on screen when you arrive without
   needing to be nailed there. A compact stuck state (condition + All filters
   only) would earn stickiness back on a phone; that needs stuck-detection
   and is its own piece of work. */
@media (min-width: 720px) {
  @supports selector(:has(*)) {
    .js-finder .finder:has(.finder-more:not([open])) .finder-bar {
      position: sticky;
      /* Parked under the pinned compact site header, not at the viewport
         top, where the header band would bury it (18 Aug 2026). */
      top: var(--header-offset);
      z-index: 500;
    }
  }
}

/* --- Filter sheet: a details element, collapsed by default so it works
       everywhere without JS; main.js opens it on wide viewports --- */
.filter-sheet {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}

.filter-sheet summary {
  cursor: pointer;
  list-style: none;
  font-weight: 700;
  padding: var(--space-4) var(--space-5);
  position: relative;
}

.filter-sheet summary::-webkit-details-marker { display: none; }

.filter-sheet summary::after {
  content: '+';
  position: absolute;
  right: var(--space-5);
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-serif);
  font-size: 1.4rem;
  color: var(--brass);
}

.filter-sheet[open] summary::after { content: '\2212'; }
.filter-sheet[open] summary { border-bottom: 1px solid var(--line); }

.filter-body { padding: var(--space-5); }

.filter-group {
  border: 0;
  padding: 0;
  margin: 0 0 var(--space-5);
  min-width: 0;
}

/* A fieldset's legend is anchored to the top EDGE of the border box and
   ignores the fieldset's top padding, so inside a padded card it rendered
   sitting on the card's rim rather than within it. Floating takes it out of
   that special rendering model and into normal flow, where the 20px padding
   contains it like everything else. */
.filter-group legend {
  float: left;
  width: 100%;
  font-weight: 700;
  font-size: 1.25rem;
  line-height: 1.3;
  padding: 0;
  margin-bottom: var(--space-3);
}

/* The float needs clearing, or the first sibling's box starts alongside it. */
.filter-group legend + * { clear: both; }

.filter-group .checkbox-row {
  margin-bottom: var(--space-3);
  align-items: center;
  gap: var(--space-2);
}

.filter-group .checkbox-row input[type="radio"] {
  width: 1.1rem;
  height: 1.1rem;
  flex: none;
  margin: 0;
  accent-color: var(--green);
}

.filter-group .checkbox-row input[type="checkbox"] { margin-top: 0; }
.filter-group .checkbox-row label { font-size: 0.95rem; }

.filter-reset { margin: var(--space-4) 0 0; }

/* --- Tooltips (filter toggles, Featured label): CSS-only bubble --- */
.tip {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.tip-icon {
  display: inline-grid;
  place-items: center;
  width: 1.5rem;   /* 24px min target (WCAG 2.5.8) */
  height: 1.5rem;
  min-width: 24px;
  min-height: 24px;
  border: 1px solid var(--ink-mute);
  border-radius: 50%;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 0.8rem;
  line-height: 1;
  color: var(--ink-mute);
  cursor: help;
}

.tip-bubble {
  position: absolute;
  z-index: 30;
  bottom: calc(100% + 0.55rem);
  left: 50%;
  transform: translateX(-50%);
  width: 15rem;
  max-width: 74vw;
  background: var(--green-deep);
  color: var(--on-green);
  font-family: var(--font-sans);
  font-size: 0.92rem;
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: normal;
  text-transform: none;
  white-space: normal;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
  opacity: 0;
  visibility: hidden;
  /* display:none as well as hidden (21 Sep 2026): an absolutely positioned
     bubble that is merely invisible still widens the page, and on a phone
     the three Services bubbles pushed the profile to 603px of scrollable
     width at a 375px viewport. Gone from layout until shown. */
  display: none;
  transition: opacity 160ms var(--ease-out);
  pointer-events: none;
}

.tip:hover .tip-bubble,
.tip:focus .tip-bubble,
.tip:focus-within .tip-bubble {
  display: block;
  opacity: 1;
  visibility: visible;
}

/* Escape-dismissed (WCAG 1.4.13); re-arms on pointer/focus leave via main.js */
.tip.tip-dismissed .tip-bubble { display: none !important; opacity: 0 !important; visibility: hidden !important; }

/* --- Results microcopy --- */
/* Count on the left, sort on the right: a sort is not a filter, so it belongs
   with the results it orders rather than in the filter panel. */
.results-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-5);
  margin-bottom: var(--space-5);
}

.results-count {
  font-family: var(--font-serif);
  font-size: 1.3rem;
  font-weight: 600;
  margin-bottom: 0;
  font-variant-numeric: tabular-nums;
}

.results-sort-control {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.results-sort-control label {
  font-weight: 700;
  font-size: 0.95rem;
  white-space: nowrap;
}

/* Width only - see the one select rule; height + centring match the finder
   bar controls exactly, so "Nearest first" is the same species of control
   as "Need help with?". */
.results-sort-control select {
  width: auto;
  height: var(--filter-control-h, 2.75rem);
  padding-block: 0;
  align-items: center;
  align-content: center;
  white-space: nowrap;
}

/* Wraps to its own line inside the head, so the head's gap owns the spacing. */
.results-sort { flex-basis: 100%; margin: 0; }

/* --- Result card extras (shared partial) --- */
/* View profile floats at the right, centred on the photo's band, without
   reserving a full-height column - so the chips tile the full card width. */
.result-card { position: relative; }

.result-cta {
  position: absolute;
  right: var(--space-6);
  top: calc(var(--space-6) + 4rem); /* padding + half the 8rem photo */
  transform: translateY(-50%);
}

/* Keep every line that shares the floating button's vertical band clear of it.
   The rating and the Google note belong here too: they sit in the same band and
   only ever escaped because they were short. Both lists must stay in step, or a
   line gets the clearance on desktop and keeps it once the button unfloats. */
.result-main .result-name,
.result-main .result-meta,
.result-main .result-rating,
.result-main .result-google-note,
.result-main .result-fee { padding-right: 10.5rem; }

@media (max-width: 540px) {
  .result-cta { position: static; transform: none; margin-top: var(--space-3); }
  .result-cta .btn { display: block; width: 100%; }
  .result-main .result-name,
  .result-main .result-meta,
  .result-main .result-rating,
  .result-main .result-google-note,
  .result-main .result-fee { padding-right: 0; }
}

a.chip { text-decoration: none; }
a.chip:hover { border-color: var(--verified); }

/* "Matches your search: ..." - the one line that says why this member is in
   these results. Its own line rather than more chips, and quieter than the
   chip row above it: the dated verification chip is the strongest claim on
   the card and nothing added later may out-shout it. Full width, because it
   sits below the floating View profile button's band. */
.result-matches {
  margin: var(--space-2) 0 0;
  max-width: none;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

.result-matches-label {
  font-weight: 600;
  color: var(--ink);
}

/* Shortlist tick. Ships hidden (the `hidden` attribute) and main.js reveals
   it, so a no-JS visitor never meets a control that would do nothing. Sits
   under the floating View profile button in the same column, which is why it
   needs no positioning of its own and follows that button's mobile collapse
   for free. */
.compare-tick {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin-top: var(--space-2);
  font-size: 0.85rem;
  color: var(--ink-soft);
  cursor: pointer;
  user-select: none;
}

/* A class selector beats the user agent's [hidden] { display: none }, so
   `display: flex` above silently defeated the attribute the markup and the
   gate both rely on: the tick rendered for a no-JS visitor and beside a
   two-result search, which is exactly what it must never do. Any component
   that sets display and ships hidden needs this line. */
.compare-tick[hidden] { display: none; }

.compare-tick input { cursor: pointer; }
.compare-tick.is-disabled { opacity: 0.45; cursor: default; }
.compare-tick.is-disabled input { cursor: default; }

/* The tray. Fixed to the bottom so it stays reachable while the visitor keeps
   scrolling results, and translated out of the way entirely when the
   shortlist is empty - a permanently parked bar over the last result row is
   just lost screen. */
.compare-tray {
  position: fixed;
  z-index: 500; /* above the Leaflet map, which sits at 400+ */
  left: 50%;
  bottom: var(--space-4);
  transform: translate(-50%, calc(100% + var(--space-6)));
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  transition: transform 0.2s var(--ease-out);
  max-width: calc(100vw - var(--space-4) * 2);
}

.compare-tray.is-open { transform: translate(-50%, 0); }

.compare-tray-count {
  margin: 0;
  max-width: none;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink);
}

.compare-tray-clear {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 0.85rem;
  color: var(--ink-mute);
  text-decoration: underline;
  cursor: pointer;
}

/* One selected is not a comparison, so the button reads as not-yet rather
   than broken (main.js also blocks the click). */
.compare-tray-go.is-disabled {
  opacity: 0.5;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .compare-tray { transition: none; }
}

.result-featured-flag { margin-bottom: var(--space-2); }

/* The Featured chip sits at the card's left edge; anchor its bubble left so
   the disclosure never clips off-screen on narrow phones. */
.result-featured-flag .tip-bubble { left: 0; transform: none; }

/* Trust-strip tip (the Aftercare recognition note): the icon ends its line,
   so a bubble anchored to the ICON depends on where the line happens to
   wrap - centred it poked past the right edge of a phone screen (a hidden
   bubble still widens the scrollable area, which showed as a sideways-
   scroll gap on Rick's phone, 18 Aug 2026), and icon-right-anchored it
   clipped off the LEFT edge instead. Anchor it to the LIST ITEM, whose
   left edge is always on screen and whose width always fits the bubble. */
.trust-strip .index-list > li { position: relative; }
.trust-strip .tip { position: static; }
/* The li is still the horizontal anchor - its left edge is always on screen
   and its width always fits the bubble, which is what stopped the sideways
   scroll on Rick's phone. But it was ALSO the vertical anchor, and
   bottom:100% on a tall two-column row put the bubble above the whole row,
   roughly 300px from the icon that opened it (Rick, 18 Aug 2026). Opening
   DOWNWARD from the row's baseline puts it back under the icon, which ends
   the row's last line, and it still cannot clip at either edge. */
.trust-strip .tip-bubble {
  left: 0;
  right: auto;
  top: calc(100% - var(--space-4));
  bottom: auto;
  transform: none;
  max-width: 100%;
}

/* --- Notify-me block (reuses the cta-band component) --- */
.notify-block {
  margin-block: var(--space-6);
  margin-inline: auto;
  max-width: 52rem;
  scroll-margin-top: var(--space-5);
}

.notify-block .notify-form { max-width: 34rem; }
.notify-block .search-box-row { margin-top: var(--space-2); }
.notify-block .notify-consent { color: var(--on-green-soft); }
.notify-block .notify-consent a { color: var(--on-green); text-decoration-color: var(--brass-on-dark); }
.notify-block .form-success { border-color: var(--brass-on-dark); }

/* --- Pre-launch search notice (app/lib/prelaunch.php) ---------------------
   Sits inside .cta-band.notify-block, so it inherits the green band, the
   brass button and the max-width. Only three things are new: two labelled
   fields side by side, the label colour, and the Follow row.

   THE LABELS NEED THE OVERRIDE. Global .field label is var(--ink), which is
   near-black on a dark green band - the very failure the brass ruling of
   22 Aug caught on the badge. --on-green is the band's own foreground. */
.prelaunch-notice .prelaunch-fields,
.notify-block .prelaunch-fields {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.prelaunch-notice .field,
.notify-block .field { margin-bottom: 0; }
.prelaunch-notice .field label,
.notify-block .field label { color: var(--on-green); }

/* The submit sits in its own paragraph, whose top margin is 0 by default -
   which put the button's edge flat against the bottom of the First name box
   with no gap at all (measured in Chrome, 22 Aug 2026). It needs more air
   than the gap BETWEEN the two fields, not less, or the button reads as a
   third field. */
.prelaunch-notice .prelaunch-submit,
.notify-block .prelaunch-submit { margin-top: var(--space-4); }

/* Two columns only where both fields still hold a real name and a real
   email side by side. Below that they stack, which is also what every
   phone width gets. */
@media (min-width: 34rem) {
  .prelaunch-notice .prelaunch-fields,
  .notify-block .prelaunch-fields { grid-template-columns: 1fr 1fr; }
}

/* The Follow links: a small icon plus the words, never an icon alone -
   "an icon with no label is a guess" and these two are the only outbound
   links on the block. Drawn inline (social_icon_path), so nothing is
   requested from Instagram or Facebook and no visitor is reported to them.
   44px of vertical hit area for a thumb, and wrap rather than scroll. */
.prelaunch-social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
}

.prelaunch-social a {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  color: var(--on-green);
  text-decoration-color: var(--brass-on-dark);
}

.prelaunch-social a:hover,
.prelaunch-social a:focus-visible { text-decoration-color: var(--on-green); }

.prelaunch-social svg { flex: none; }

/* One shared control height for every finder control, INCLUDING the sort
   dropdown beside the result count - it sat at 55px against the bar's 44px
   and read as a different species (Rick, 26 Jul). On .finder so the landing
   variant can override it for the hero. */
.finder { --filter-control-h: 2.75rem; }

/* THE bar: where, how far, what for, the quick toggles, More filters, and
   Search always at the far right (Rick, 26 Jul). One shared control height is
   what makes seven controls read as one bar rather than a search box with
   filters bolted underneath - which is how the old two-row version read, and
   why it got skipped entirely. The 12px gap is deliberate: it is what keeps
   the row on ONE line at the container width even with the badge showing and
   "Lymphoedema management" selected - the two states that used to tile
   "All filters" onto a second row. */
.finder-filters-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
}

/* Fixed-height controls need their block padding REMOVED, not fought. The
   base input rule carries 12px top and bottom; inside a 44px border-box that
   left a ~15px window for a 30px line, so the text rendered dropped and
   clipped (Rick's 26 Jul screenshot). With no block padding the fixed height
   centres a single line natively in inputs, and align-content centres the
   option text that base-select renders as real DOM. */
.finder-filters-row input[type="search"],
.finder-filters-row select,
.finder-filters-row > .btn {
  height: var(--filter-control-h);
  padding-block: 0;
}

.finder-filters-row > .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* base-select gotchas, MEASURED not assumed (26 Jul): the select renders as
   inline-FLEX, so vertical centring needs align-ITEMS - align-content alone
   leaves the value slot at the top, which is the "still not centred" bug
   Rick caught twice. And the selected option is real DOM, so in a
   width-capped select a long label WRAPS and paints below the border box.
   One line, centred, always. */
.finder-filters-row select {
  align-items: center;
  align-content: center;
  white-space: nowrap;
}

/* Sizes to its content (the label or the selected option, whichever is
   wider), because ellipsising the site's most important filter would be
   worse than letting the location field give up some slack. */
.finder-field-condition { flex: 0 0 auto; }
.finder-field-condition select { width: 100%; min-width: 11rem; }
.finder-field-condition label { white-space: nowrap; }

/* The bar's tooltips open DOWNWARD. Pinned to the top of the viewport there
   is nothing above the bar to open into. Scoped to the bar, because .tip is
   shared with result cards and both brands' pricing tables. */
.finder-bar .tip-bubble {
  bottom: auto;
  top: calc(100% + 0.55rem);
}

/* NOTE: the two surface toggles are NOT hidden on narrow viewports, however
   tempting the ~40px of sticky-bar height is. Their real <input> lives here
   and the panel copies are bare mirror labels, so a display:none here takes
   the only focusable control for Home visits and Taking new clients out of
   the tab order entirely - pointer-operable only, WCAG 2.1.1. The row already
   wraps, so on a phone they simply take their own line. */

/* On a phone every field takes its own full-width line - the standard calm
   mobile form - except the two toggles, which pair up. A first attempt kept
   desktop-ish widths and left the radius stranded alone at 128px, which is
   the exact stranded-control sin the design rules ban. */
@media (max-width: 559.98px) {
  .finder-field-loc,
  .finder-field-condition,
  .finder-more,
  .finder-filters-row > .btn { flex: 1 1 100%; }
  .finder-field-radius { flex: 1 1 100%; width: auto; }
  .finder-field-condition select { min-width: 0; }
  .finder-more > summary { width: 100%; justify-content: center; }
}

/* Labelled filter control: the label is visible now (an unlabelled dropdown
   reading "Any reason" tells you nothing about what it filters). */
.finder-filter-field label {
  display: block;
  font-weight: 700;
  font-size: 0.95rem;
  margin-bottom: var(--space-2);
}

.finder-filters-row > .tip { height: var(--filter-control-h); }

/* More filters expands IN FLOW, on its own full-width line of the filter row.
   It was an overlay anchored to the button; that was wrong twice over. The
   map's Leaflet panes sit at z-index 400+, so an overlay under them can never
   win a stacking fight, and a panel anchored to a control halfway down the
   page runs off the bottom of the viewport as soon as it holds more than a
   few filters - which is the exact direction this list is meant to grow.
   In flow it costs a downward push of the map and results, and in exchange it
   can never underlap anything, never leaves the viewport, and behaves
   identically at every width with no JS at all. */
/* Sits at the right-hand end of the SAME row as the other controls. The panel
   it opens is a sibling of that row, not a child of this element, so the
   button can be inline while the panel spans the full width beneath - see the
   :has() rules below. */
/* NO margin-left:auto. An auto margin eats free space BEFORE flex-grow gets
   a look in, so pushing this button to the right edge would starve the
   location field of the slack it is there to absorb - and put the gap back
   between the last chip and the button, which is what it looked like before
   (535px of nothing at 1280). It sits where it falls, next to the filters it
   opens. */
.finder-more {
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}

/* The button keeps its place at the right of the panel; only the body below
   it is full width, so opening the panel never moves the control you clicked. */
.finder-more > summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: fit-content;
  height: var(--filter-control-h);
  padding: 0 2.2rem 0 var(--space-4);
  border: 1px solid var(--filter-line);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: 0.97rem;
  white-space: nowrap;
}

.finder-more[open] > summary { border-color: var(--green); }
.finder-more[open] > summary { border-bottom: 1px solid var(--green); }

.finder-more > summary::after { right: var(--space-4); }

.filter-count {
  display: inline-grid;
  place-items: center;
  min-width: 1.4rem;
  height: 1.4rem;
  padding-inline: 0.35rem;
  border-radius: var(--radius-stamp);
  background: var(--green);
  color: var(--on-green);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}

/* The badge SLOT is always rendered and merely invisible at zero, so the
   button is the same width whether or not filters are applied. When it
   appeared from nowhere it widened the button, tipped the row past the
   container, and tiled "All filters" onto its own line (Rick, 26 Jul). */
.filter-count-empty { visibility: hidden; }

/* The panel: a sibling of the filter row, revealed by :has() when the details
   above is open. Progressive enhancement in the honest direction - a browser
   without :has() never hides it, so every filter stays reachable rather than
   being sealed behind a toggle that does nothing.
   ONE flat panel, no headed sub-sections (Rick, 26 Jul: with five controls
   plus the treatments band, "Your therapist" and "Appointments" were
   furniture): a row of tick filters, a row of dropdowns, the treatments
   band, the provenance line. */
.finder-bar > .filter-body {
  margin-top: var(--space-4);
  padding: var(--space-5) 0 0;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

@supports selector(:has(*)) {
  .finder-bar:has(.finder-more:not([open])) > .filter-body { display: none; }
}

/* --- Pre-launch notice dialog (layout.php + main.js) ---
   Native <dialog>: the browser centres it and paints ::backdrop; these rules
   only dress it in the .welcome-* single-message vocabulary. No transition,
   so prefers-reduced-motion needs no override. z-index is irrelevant to a
   modal dialog (top layer), so Leaflet's 400+ and the bar's 500 cannot sit
   over it. */
/* Browsers without <dialog> support have no UA rule hiding a closed dialog,
   so without this the element renders as a permanent inline box (and its
   method="dialog" button degrades to a query-stripping GET). Supporting
   browsers are unaffected: showModal() sets the open attribute. */
dialog:not([open]) { display: none; }

.notice-modal {
  /* Rick, 23 Aug 2026: 40rem wide. min() so a phone never scrolls sideways. */
  min-width: min(40rem, calc(100vw - 2 * var(--space-5)));
  max-width: min(40rem, calc(100vw - 2 * var(--space-5)));
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-2, var(--shadow-1));
  padding: clamp(1.5rem, 4vw, 2.5rem);
  text-align: center;
}

.notice-modal::backdrop { background: rgba(26, 34, 30, 0.55); }

.notice-modal h2 { margin: 0 0 var(--space-3); font-size: 1.5rem; } /* every dialog title one size, 19 Oct 2026 */

/* 1.1rem, Rick 23 Aug 2026 (supersedes his 17 Aug 16px call), left-aligned. */
.notice-modal p {
  max-width: none;
  margin: 0 0 var(--space-4);
  font-size: 1.1rem;
  line-height: 1.6;
  text-align: left;
}

.notice-modal p:last-of-type { margin-bottom: var(--space-5); }

.notice-modal form { margin: 0; }

/* CTA link + close button pair (rendered when the dialog has a link set):
   centred in the dialog, no inherited top margin. */
.notice-modal-actions { justify-content: center; margin-top: 0; }

/* The X close: the standard escape hatch in the standard corner. The dialog
   is position:fixed by UA default, so it is its own containing block; 44px
   square keeps the target phone-sized without crowding the heading. */
.notice-modal-x { position: absolute; top: var(--space-2); right: var(--space-2); }
.notice-modal-x button {
  width: 44px;
  height: 44px;
  border: 0;
  background: none;
  color: var(--ink-soft, var(--ink));
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  border-radius: var(--radius-sm, 6px);
}
.notice-modal-x button:hover, .notice-modal-x button:focus-visible { color: var(--ink); background: var(--tint, rgba(0, 0, 0, 0.05)); }

/* --- Image dialog (26 Aug 2026): an inline "i" button that opens an
   example image in a modal. First use: the reviews-badge example on the
   membership cards (partials/reviews_badge_tip.php). Same native <dialog>
   primitive as the notice dialog above - the browser centres it, paints
   ::backdrop, and carries Escape and the focus trap; main.js opens it from
   data-dialog-open and closes it on a backdrop click. --- */

/* The trigger reuses the .tip-icon circle as a real <button>: strip the
   UA button chrome, keep the circle. Sits inline after a tick-list line. */
button.img-dialog-open {
  background: none;
  padding: 0;
  margin-left: var(--space-1);
  vertical-align: text-bottom;
  cursor: pointer;
  font-style: italic; /* <button> does not inherit .tip-icon's serif italic look by default */
}

.img-dialog {
  max-width: min(32rem, calc(100vw - 2 * var(--space-5)));
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-2, var(--shadow-1));
  padding: clamp(1.25rem, 4vw, 2rem);
  text-align: center;
}

.img-dialog::backdrop { background: rgba(26, 34, 30, 0.55); }

/* Room on the right so the title never sits under the X. */
.img-dialog h2 {
  margin: 0 0 var(--space-4);
  font-size: 1.5rem;
  padding: 0 2.25rem;
}

.img-dialog img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius);
}

/* The X close, same shape as the notice dialog's. */
.img-dialog-x { position: absolute; top: var(--space-2); right: var(--space-2); margin: 0; }
.img-dialog-x button {
  width: 44px;
  height: 44px;
  border: 0;
  background: none;
  color: var(--ink-soft, var(--ink));
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  border-radius: var(--radius-sm, 6px);
}
.img-dialog-x button:hover, .img-dialog-x button:focus-visible { color: var(--ink); background: var(--tint, rgba(0, 0, 0, 0.05)); }

/* --- Member photo gallery (1 Sep 2026): the grid on a public profile and
   the lightbox it opens. Standard members show up to six photographs,
   Featured up to twenty; the grid draws six tiles and turns the last one
   into "+N more" when there are more behind it.

   The gallery EXTENDS .img-dialog rather than replacing it: the dialog
   markup carries both classes, so the border, the backdrop, the padding
   and the X are inherited and only the wider frame and the paging controls
   are new. There is no lightbox library on this site and this is why one
   was never needed. --- */

/* --- The profile contents menu (1 Sep 2026): a quiet row of jump links
   directly under the masthead, on profiles long enough to be worth a map.

   NOT STICKY, on purpose. The site header is already pinned and, below
   960px, so is the Book online bar at the foot of the screen; a third fixed
   strip would close a phone screen in from both ends. This scrolls away with
   the masthead, which is where a reader looks for a contents list.

   IT WRAPS, it never scrolls sideways. That is the standing rule for every
   menu here, and a horizontal scroller is exactly what a row of five links
   turns into on a narrow screen if you let it. --- */
.profile-nav {
  /* A BAND OF ITS OWN. This was --surface, which is exactly what the
     masthead above it uses, so the two ran together as one pale block
     divided by a hairline and the menu could be missed entirely. That also
     broke the standing rule that no two consecutive bands may share a
     background (Rick, 25 Aug 2026); he caught it by eye on the live page.

     The fallback is --paper-2 rather than a literal, so a brand with no sand
     in its pack gets its own neutral rather than inheriting this one. */
  background: var(--band-sand, var(--paper-2, #eaeaea));
  border-bottom: 1px solid var(--line);
}

.profile-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* space-2, not space-4, since 2 Sep 2026: Rick found the band too thick,
     and every pixel here is a pixel of the action card under the fold. */
  gap: var(--space-1) var(--space-6);
  padding-block: var(--space-2);
}

.profile-nav li { margin: 0; }

/* The span is the pitch page's laptop specimen, where nothing may be a real
   link but the menu still has to look like the menu it stands in for. */
.profile-nav a,
.profile-nav li > span {
  display: inline-block;
  /* 44px of height for a thumb, made of padding rather than a set height, so
     a wrapped second line still reads as one row of links. */
  padding: 0.6rem 0;
  font-size: 0.95rem;
  /* The FULL ink, not the soft grey. On sand the soft grey is about 6:1 and
     reads washed out; the full ink is about 11:1 and is what makes weight
     600 look deliberate rather than merely heavy. */
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 2px solid transparent;
}

/* On a desktop the links are a mouse target, so the 44px thumb height above
   is not needed and the band slims to one comfortable row. AFTER the base
   rule on purpose: same specificity, so the later one wins. */
@media (min-width: 960px) {
  .profile-nav a,
  .profile-nav li > span { padding: 0.45rem 0; }
}

.profile-nav a:hover,
.profile-nav a:focus-visible {
  color: var(--ink);
  border-bottom-color: var(--accent, var(--ink));
}

/* The site header is sticky, so without this the reader jumps to a heading
   that lands BEHIND it. Same value and same pattern as #what-you-get and the
   dashboard sections already use.

   Deliberately no scroll-behavior: smooth here. Every other anchor on this
   site jumps instantly, and making one page behave differently is worse than
   either choice on its own. Smooth scrolling is a site-wide decision, not a
   detail of this feature. */
.profile-main .profile-section { scroll-margin-top: var(--space-6); }

/* The footer's social icons and the country control share one row, so the
   switcher reads as placed beside them rather than dropped underneath.
   Wraps rather than squashing on a narrow phone. */
.footer-social-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  /* THE SPACE ABOVE BELONGS TO THE ROW, NOT TO ONE CHILD IN IT.
     .footer-social carries its own margin-top from when it stood alone, and
     inside a centred flex row that margin pushes the icons' box down while
     the country control has none, so the control sat visibly higher than the
     icons beside it. Rick spotted it straight away. The row takes the
     spacing, and the child's own margin is cleared below. */
  margin-top: var(--space-5);
}

/* Cleared here rather than at .footer-social itself, so the icons keep their
   original spacing on any brand or page that still renders them outside this
   row. */
.footer-social-row .footer-social { margin-top: 0; }

/* --- Back to top (1 Sep 2026): one small button, bottom right, on every
   page once the reader is a screen down. The site has genuinely long pages -
   the guides, a busy town page, a full member profile - and none of them had
   a way back up but the scrollbar.

   `hidden` IS THE NO-JAVASCRIPT STATE. A fixed button that nothing can
   dismiss or operate is worse than no button, which is the same contract
   .profile-sticky-cta carries two rules down. --- */
.back-to-top {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 40;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line-strong, var(--line));
  border-radius: 50%;
  background: var(--surface, #fff);
  color: var(--ink);
  cursor: pointer;
  box-shadow: var(--shadow-2, var(--shadow-1));
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 160ms ease, transform 160ms ease;
}

.back-to-top[hidden] { display: none; }
.back-to-top.is-shown { opacity: 1; transform: none; }

.back-to-top:hover,
.back-to-top:focus-visible { background: var(--tint, rgba(0, 0, 0, 0.05)); }

/* THE LIFT IS NOT IN CSS. Two different fixed bars can own the bottom of
   the screen - the profile's action bar, and the cookie bar on every page a
   first-time visitor opens - and either or both may be there. main.js
   measures whichever are actually visible and sets `bottom` directly, so
   this cannot go stale when a third one is added. */

@media (prefers-reduced-motion: reduce) {
  .back-to-top { transition: none; transform: none; }
}

/* .gallery-grid and .gallery-grid-shot were retired on 2 Sep 2026 with the
   in-page profile grid: the masthead cluster (.profile-head-gallery) and the
   pitch page's laptop specimen both draw .gallery-tile in a grid of their
   own. */

.gallery-tile {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  /* The box is 4:3 whatever the photograph is, and the image covers it. That
     is what turns a mixed bag of portrait and landscape phone photographs
     into one tidy grid instead of a ragged wall. */
  aspect-ratio: 4 / 3;
  background: var(--tint, rgba(0, 0, 0, 0.04));
}

.gallery-tile img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 180ms ease;
}

@media (hover: hover) {
  .gallery-tile:hover img { transform: scale(1.03); }
}

@media (prefers-reduced-motion: reduce) {
  .gallery-tile img { transition: none; }
  .gallery-tile:hover img { transform: none; }
}

.gallery-tile:focus-visible {
  outline: 2px solid var(--accent, var(--ink));
  outline-offset: 2px;
}

/* The "+N more" tile. A scrim over the last thumbnail rather than a separate
   empty box, so the grid stays a complete rectangle and the reader can still
   see there is a photograph underneath the number. */
.gallery-tile-more::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(15, 33, 55, 0.58);
}

.gallery-more-label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
  color: #fff;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}

/* --- The lightbox itself --- */

.gallery-dialog {
  /* Much wider than the plain .img-dialog, which is sized for a small
     example graphic. A room photograph needs the screen. */
  max-width: min(64rem, calc(100vw - 2 * var(--space-4)));
  width: 100%;
  padding: var(--space-3);
}

.gallery-dialog-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Cap the picture at most of the viewport height so a portrait photograph
     cannot push the caption and the counter off the bottom of the screen. */
  max-height: 72vh;
}

.gallery-dialog-img {
  max-width: 100%;
  max-height: 72vh;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--radius);
}

/* THE RESET AT THE TOP OF THIS FILE SETS img { display: block }, AND AN
   AUTHOR RULE BEATS THE USER AGENT'S [hidden] { display: none }. Without
   this line every photograph in the gallery renders at once, side by side,
   and the lightbox shows the whole set instead of one. Found by LOOKING at
   the page: the break tests read the markup, and the markup was correct.

   Same trap, same fix as .compare-tick[hidden], .join-panel[hidden],
   .field-error[hidden] and .cookie-bar[hidden] elsewhere in this file.

   It also restores the reason the images are safe to ship: display:none is
   what stops a browser fetching the five photographs nobody has paged to
   yet, so a twenty-photograph gallery costs a visitor one image, not
   twenty. */
.gallery-dialog-img[hidden] { display: none; }

.gallery-dialog-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  text-align: left;
  font-size: 1.2rem;
  /* THE CENTRED <p> GOTCHA, the same one .sample-flag p carries a note about.
     The base stylesheet caps every <p> at 70ch for readable prose, so this
     row was 70ch wide inside a dialog up to 64rem, and space-between put the
     counter in the middle of the picture instead of at its right edge. */
  max-width: none;
}

.gallery-dialog-caption {
  color: var(--ink);
  /* Take the room the counter does not need, so the counter is pushed to the
     far edge even when the caption is a couple of words. */
  flex: 1 1 auto;
}

.gallery-dialog-count {
  color: var(--ink-soft, var(--ink));
  white-space: nowrap;
  /* Right-aligned against the edge of the picture, not floating mid-frame. */
  text-align: right;
  flex: 0 0 auto;
}

/* Paging arrows, sitting over the picture at the vertical middle. 44px is
   the minimum reliable touch target, and these are the controls most likely
   to be used with a thumb. */
.gallery-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface, #fff);
  color: var(--ink);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-1);
}

.gallery-prev { left: var(--space-2); }
.gallery-next { right: var(--space-2); }

/* THE CLOSE BUTTON IS A CONTROL OVER A PHOTOGRAPH, so it gets the same
   treatment as the arrows either side of it. The plain .img-dialog-x is a
   bare glyph with no background, which is right on a small white example
   dialog and invisible over a picture of a sunlit room. Sharing the shape
   also fixes the hover: the arrows sat on a solid surface and the close
   button on nothing, so the same hover token read as two different colours.
   Scoped to .gallery-dialog, so the reviews-badge dialog is untouched. */
.gallery-dialog .img-dialog-x { top: var(--space-3); right: var(--space-3); }

.gallery-nav,
.gallery-dialog .img-dialog-x button {
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface, #fff);
  color: var(--ink);
  box-shadow: var(--shadow-1);
}

.gallery-nav:hover,
.gallery-nav:focus-visible,
.gallery-dialog .img-dialog-x button:hover,
.gallery-dialog .img-dialog-x button:focus-visible {
  background: var(--tint, rgba(0, 0, 0, 0.05));
  color: var(--ink);
}

/* --- The dashboard's own gallery editor --- */

.gallery-manage {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--space-3);
}

.gallery-manage-item {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-2);
  background: var(--surface, #fff);
}

.gallery-manage-item img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-sm, 6px);
}

.gallery-manage-item label {
  display: block;
  margin-top: var(--space-2);
  font-size: 0.85rem;
}

.gallery-manage-item input[type="text"],
.gallery-manage-item input[type="number"] { width: 100%; }

/* A photograph the member holds but her current allowance does not show.
   Dimmed rather than hidden, because she has to be able to see it to choose
   which ones DO show, and because a photograph that vanished with no
   explanation reads as data we lost. */
.gallery-manage-item.is-over-cap { opacity: 0.55; }
.gallery-manage-item.is-over-cap img { filter: grayscale(1); }
.gallery-over-cap-note {
  display: block;
  margin-top: var(--space-1);
  font-size: 0.8rem;
  color: var(--ink-soft, var(--ink));
}

/* Surgery-type sub-facet: a full-width band of its own directly under the
   bar row, visible whenever its parent condition is chosen - never inside
   the More filters panel, because it continues the bar's primary question
   ("Need help with?"... which surgery?) and a collapsed panel would hide it
   from exactly the patient it was built for. Its own row also means it can
   never tile the one-line bar, the fault facet_short exists to prevent
   (13 Aug 2026). */
.finder-bar > .finder-subfacet {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

/* Tick filters sit side by side and wrap; a forced row's note breaks below
   its own control without disturbing its neighbours. */
.filter-checks {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-7);
}

/* The three dropdowns share one line on desktop, each a readable width
   rather than a third of the page. */
.filter-selects {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}

@media (min-width: 720px) {
  .filter-selects { grid-template-columns: repeat(3, minmax(0, 18rem)); }
}

.filter-selects .finder-filter-field { margin: 0; }

.filter-body .filter-group { margin: 0; }

.filter-group-note {
  font-size: 0.9rem;
  color: var(--ink-mute);
  margin: 0 0 var(--space-3);
}

/* A group sub-heading that FOLLOWS a chip grid (the Training band's
   "Further training" after the schools row) needs air above it, or it sits
   on the rim of the row it does not belong to and the two groups read as
   one run of ticks. */
.filter-group .filter-check-grid + .filter-group-note {
  margin-top: var(--space-5);
}

/* One filter per row. SHORT LABEL FIRST, explanation only where it earns its
   place - that is the whole difference between this and the version Rick read
   as "a lot of information": a paragraph under every tick turned six controls
   into 851px. Safety-relevant notes stay visible; the rest sit behind the
   keyboard-reachable "?" icon. Never behind hover alone - .tip-bubble has
   pointer-events:none and no tap trigger, so a hover-only note does not exist
   on a phone. */
.filter-row { margin-bottom: var(--space-3); }
.filter-row:last-child { margin-bottom: 0; }

.filter-row-control {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.filter-row-note {
  display: block;
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--ink-mute);
  margin-top: var(--space-1);
  padding-left: 1.7rem; /* clears the chip's tick box */
}

/* The provenance mark. It replaces two headed cards and two paragraphs: at
   the moment of choosing a filter the question is "what do I want?", not "who
   told you that?". Built from the verified tokens so whatcounsellor's
   theme.css re-skins it for free. */
.filter-checked-pill {
  display: inline-block;
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--tone-verified-border);
  border-radius: var(--radius-stamp);
  background: var(--verified-wash);
  color: var(--tone-verified-ink);
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.4;
  white-space: nowrap;
}

.filter-provenance {
  margin: 0;
  max-width: none;
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--ink-mute);
}

.filter-body .finder-filter-field select { width: 100%; }
.filter-body .finder-filter-field label { display: flex; align-items: center; gap: 0.5rem; }

/* One line under a select, for a control that needs a word of reassurance
   rather than a "?" bubble. The school filter is the only one that does: its
   options are five surnames a patient has no way to rank, and the honest
   answer (you almost certainly do not need to choose) has to be visible
   rather than hidden behind an icon, or it does not do its job. */
.filter-field-note {
  margin: var(--space-2) 0 0;
  max-width: none;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--ink-mute);
}

/* The treatments band keeps its hairline so it reads as its own section of
   the panel - it is the one block Rick singled out as reading clearly, and
   its shape is unchanged. */
.finder-bar > .filter-body > .filter-group-wide {
  border-top: 1px solid var(--line);
  padding-top: var(--space-5);
}

/* Ticks in columns, not one tall stack: nine stacked checkboxes made the
   declared side four times the height of the verified side and pushed the
   price and gender controls off the bottom. Auto-fit means the count can
   grow without the layout being redesigned again. */
.filter-check-grid {
  display: grid;
  gap: var(--space-3) var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

/* The roomy variant: a wider column floor for lists carrying long names
   (the Training band's course entries), so a name stays on one line and
   the chips wrap as balanced rows instead of stranding one on its own. */
.filter-check-grid-roomy {
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

/* Wrapping labels stay hanging-indented past their tick box. */
.filter-check-grid .filter-chip {
  white-space: normal;
  align-items: flex-start;
}
.filter-check-grid .filter-chip::before { flex: none; margin-top: 0.1rem; }

/* Says out loud that the register narrowed the results itself. */
/* The Featured disclosure over search, town and topic results. A brand may
   give it its own notice colours (--results-notice-wash, --results-notice-rule):
   the WHAT themes do, because their verified pair is the family green and a
   paid-placement note must not wear the "checked" colour (visual review,
   30 Sep 2026). Without them it keeps the verified pair, as on MLD. */
.results-notice {
  background: var(--results-notice-wash, var(--verified-wash));
  border-left: 3px solid var(--results-notice-rule, var(--verified));
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-4);
  font-size: 0.95rem;
  max-width: none;
}

/* A forced filter is shown ticked but not changeable; the tick still reads as
   applied rather than greyed into looking inactive. */
.filter-chip-input:disabled + .filter-chip { cursor: default; }
.filter-chip-input:disabled + .filter-chip::before {
  color: var(--surface);
  background: var(--verified);
  border-color: var(--verified);
}


/* --- Applied filters: one removable chip each, so nothing narrows the
       results invisibly --- */
.active-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
}

.active-filters a {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem var(--space-3);
  border: 1px solid var(--filter-line);
  border-radius: var(--radius-stamp);
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--filter-ink);
  background: var(--surface);
}

.active-filters a:hover {
  border-color: var(--green);
  color: var(--green-deep);
}

.active-filters a span[aria-hidden] { font-size: 1.05rem; line-height: 1; }

.active-filters-clear a {
  border: 0;
  padding-inline: 0;
  text-decoration: underline;
  background: none;
}

/* The condition dropdown matches the checkbox toggles: same grey, and a
   custom chevron padded in from the right edge */
/* Width only. Type, colour and the chevron come from the one select rule. */
.finder-filters-row select { width: auto; }

.finder-filters-row .filter-reset { margin: 0; }

/* Toggle chips: visible, instant, one tap. The input stays real for
   no-JS submits and accessibility; the label wears the pill. */
.filter-chip-input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  cursor: pointer;
  font-size: 0.97rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--filter-ink);
  white-space: nowrap;
  transition: color 160ms var(--ease-out);
  /* Enlarge the hit area to >=24px (WCAG 2.5.8) without shifting layout. */
  padding-block: 3px;
  margin-block: -3px;
}

.filter-chip::before {
  content: '\2713';
  display: grid;
  place-items: center;
  width: 1.15rem;
  height: 1.15rem;
  font-size: 0.75rem;
  line-height: 1;
  color: transparent;
  background: var(--surface);
  border: 2px solid var(--filter-line);
  border-radius: var(--radius-stamp);
  transition: background-color 160ms var(--ease-out), border-color 160ms var(--ease-out);
}

.filter-chip:hover::before { border-color: var(--green); }

.filter-chip-input:checked + .filter-chip { color: var(--green-deep); }

.filter-chip-input:checked + .filter-chip::before {
  color: var(--surface);
  background: var(--green);
  border-color: var(--green);
}

.filter-chip-input:focus-visible + .filter-chip {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* --- Town pages --- */
.town-listing { margin-block: var(--space-6); }

.town-links { padding-block: var(--space-6) var(--space-4); max-width: 52rem; }

.town-nearby, .town-guides { max-width: none; }

.town-blocks p { color: var(--ink-soft); }

/* Pack-authored local editorial (brands/<key>/town_content/<slug>.php) */
.town-local .container { max-width: 52rem; }
.town-local p { color: var(--ink-soft); }
.town-local section + section { margin-block-start: var(--space-6); }

/* =========================================================================
   Package: profile-check
   Therapist profile pages, the enquiry flow and Check a Therapist.
   Token-driven additions only; merged into main.css by the orchestrator.
   ========================================================================= */

/* --- Profile masthead (header block, B3) --------------------------------- */
/* space-5, not space-6, since 2 Sep 2026: every pixel of masthead height is a
   pixel of the action card pushed under the fold on a 1366 x 768 laptop. */
.profile-masthead {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding-block: var(--space-5);
}

.profile-header {
  display: flex;
  gap: var(--space-6);
  align-items: center;
  flex-wrap: wrap;
}

.profile-photo {
  flex: none;
  width: 12.5rem;
  height: 12.5rem;
  border-radius: 50%;
  overflow: hidden;
  background: var(--green-wash);
  display: grid;
  place-items: center;
  color: var(--green);
  font-family: var(--font-serif);
  font-size: 2.4rem;
  /* The ring (Rick, 21 Sep 2026, after VerifiedPractitioner's portraits): a
     thin paper gap, a band in the ring colour and a faint halo, drawn as
     shadows so the circle and its overflow clip are untouched. The colours
     are tokens (--photo-ring, --photo-ring-halo): the brand's primary by
     default, MLD's own steel pick set in its theme. */
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 5px var(--photo-ring), 0 0 0 8px var(--photo-ring-halo), 0 8px 20px rgba(0, 0, 0, 0.12);
  margin: 8px;
}

.profile-photo img { width: 100%; height: 100%; object-fit: cover; }

.profile-head-main { flex: 1; min-width: min(100%, 20rem); }

/* ON A PHONE THE MASTHEAD IS CENTRED (Rick, 1 Sep 2026). Below 960px the
   layout stacks and the photograph is already centred, so a left-aligned
   name, subline, rating and chip rows under a centred portrait read as an
   alignment fault rather than a decision. Above 960px this is the left
   column of a two-column layout and stays left. */
/* IN THE MASTHEAD THE PROVENANCE LABELS SIT INLINE WITH THEIR CHIPS (Rick,
   2 Sep 2026): "Checked by us" then its stamps on one line, "Told to us by
   the therapist" then its stamps on the next. Stacked, the two captions cost
   the masthead two extra rows, read as bunched, and pushed the action card
   under the fold on a 1366 x 768 laptop. Result cards keep the stacked
   layout: their column is too narrow for a caption and chips to share a
   line. */
.profile-head-main .provenance { gap: var(--space-2); margin-bottom: 0; }
.profile-head-main .prov-row { flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.profile-head-main .prov-label { flex: none; }

@media (max-width: 719px) {
  /* A size down on a phone (Rick, 2 Sep 2026). The stamps and their captions
     are the proof, so they stay in view rather than folding behind a tap;
     they were simply taking a third of the first screen. */
  .profile-head-main .chip { font-size: 0.66rem; padding: 0.34rem 0.55rem; letter-spacing: 0.06em; }
  .profile-head-main .prov-label { font-size: 0.78rem; }
}

@media (max-width: 959px) {
  /* The portrait too (Rick, 2 Sep 2026): once the row wraps, the photograph
     sat on a row of its own at the LEFT edge under a centred name. */
  .profile-header { justify-content: center; }
  .profile-head-main { text-align: center; }
  .profile-head-main .prov-row { justify-content: center; }
  /* The pills row is a flex box, so text-align cannot centre it (Rick,
     21 Sep 2026: Founding member and Taking new clients sat left on a phone). */
  .profile-founding { justify-content: center; }
  /* The base stylesheet caps a <p> at 70ch for readable prose, and a capped
     block cannot centre itself - it strands at the left. Same gotcha the
     sample-flag rule carries a note about. */
  .profile-head-main p { max-width: none; margin-left: auto; margin-right: auto; }
  /* The chip rows are flex, so text-align does not reach them. */
  .profile-head-main .prov-chips,
  .profile-head-main .dash-chips,
  .profile-head-main .profile-rating { justify-content: center; }
  .profile-head-main .social-row { justify-content: center; }
}

/* Action buttons sit to the right, centred against the profile photo */
.profile-head-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-3);
  align-self: center;
  min-width: 13rem;
}

@media (max-width: 719px) {
  .profile-head-actions { width: 100%; flex-direction: row; flex-wrap: wrap; }
  .profile-head-actions .btn { flex: 1 1 12rem; }
}

/* Declared social addresses (app/lib/social.php): a row of icon links under
   the profile's action buttons. A LIST, so the count is announced; the
   bullets are removed rather than the semantics. Each hit area is 44px so a
   thumb can land on it, which is why the padding is on the link and not the
   svg. */
.social-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  list-style: none;
  margin: 0;
  padding: 0;
  justify-content: center;
}

.social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  color: var(--ink-mute);
  text-decoration: none;
}

/* An inline SVG sits on the text baseline, and two glyphs of different
   height then land at different heights inside the same circle (Rick,
   21 Sep 2026: the Facebook and Instagram icons did not line up). As a
   block in a centred flex box, both sit dead centre. */
.social-link svg { display: block; }

.social-link:hover,
.social-link:focus-visible {
  color: var(--green);
  background: var(--paper-2);
}


@media (min-width: 720px) {
  .profile-head-actions { margin-left: auto; flex: none; }
}

/* THE MASTHEAD PHOTO CLUSTER (2 Sep 2026): up to four of the member's own
   photographs where the action buttons used to be, each opening the
   gallery's lightbox. A fixed 2 x 2 box on desktop, so a therapist with one
   room photograph gets one wide tile and a therapist with twenty gets four
   and a "+16 more" - never a giant tile and never an orphan. On a phone it
   is a slim strip under the name that costs the screen about eighty pixels.
   The tiles reuse .gallery-tile, so the border, the 4:3 box and the hover
   are the gallery's own. */
.profile-head-gallery {
  display: grid;
  /* 8.5rem tiles (was 9.5rem): the 2 x 2 box then stands 212px tall, close to
     the 200px portrait beside it, instead of setting the masthead's height on
     its own. */
  grid-template-columns: repeat(2, 8.5rem);
  gap: var(--space-2);
  align-self: center;
  margin-left: auto;
  flex: none;
}
.profile-head-gallery .gallery-more-label { font-size: 0.95rem; }
@media (min-width: 960px) {
  .profile-head-gallery[data-count="1"] .gallery-tile,
  .profile-head-gallery[data-count="3"] .gallery-tile:first-child { grid-column: span 2; }
  /* Two photographs stand upright (Rick, 2 Sep 2026, from a side-by-side
     mock-up): a pair of 4:3 tiles made one thin row beside the portrait,
     and a 3:4 pair matches the portrait's height instead. */
  .profile-head-gallery[data-count="2"] .gallery-tile { aspect-ratio: 3 / 4; }
}
@media (max-width: 959px) {
  .profile-head-gallery {
    width: 100%;
    margin-left: 0;
    grid-template-columns: repeat(auto-fit, minmax(4.5rem, 1fr));
  }
}

.profile-head-main h1,
.profile-head-main .shot-title { margin-bottom: var(--space-2); } /* the site-wide h1 size (19 Oct 2026); phones keep 1.75rem beside the portrait */ /* space-2 again: since 21 Sep 2026 the subline sits directly under the name, so the room Rick asked for goes under the subline instead */

/* The founding mark, on its own line between the subline and the provenance
   rows (Rick, 21 Sep 2026: name, then "Verified MLD Therapist in
   Cheltenham", then the pills). Kept out of the provenance chip block below
   it, which is deliberately one uniform colourless style split into
   checked/declared rows. */
.profile-founding { margin-bottom: var(--space-3); display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
/* The provenance pills ("Checked by us" / "Told to us by ...") on the
   masthead are softly rounded rather than full pills (Rick, 21 Sep 2026:
   4px on those two rows only, after a first pass at 10px; Founding member
   and Taking new clients keep the 100px pill). */
.profile-head-main .prov-chips .chip { border-radius: 4px; }
/* The "i" inside the availability pill: the member's own note on hover or
   focus, in body type, anchored under the pill. */
.chip .chip-tip { margin-left: 0.15rem; }
/* The icon must not make its pill taller than the pill beside it (Rick,
   21 Sep 2026: "taking new clients pill is bigger than founding member"):
   16px, and the negative vertical margin keeps the chip's box at the text
   line while the circle overlaps the padding. */
.chip .chip-tip { display: inline-flex; align-items: center; }
.chip .chip-tip .tip-icon { width: 16px; height: 16px; min-width: 16px; min-height: 16px; font-size: 0.6rem; margin: -0.4rem 0; }
/* Opens DOWNWARDS (Rick, 21 Sep 2026: Rachel's longer note opened upwards and
   ran under the site header). Anchored to the icon's left edge on a desktop,
   to its right edge on a phone where the pills are centred near the edge. */
.chip .chip-tip .tip-bubble { top: calc(100% + 0.6rem); bottom: auto; left: 0; transform: none; text-transform: none; letter-spacing: normal; font-weight: 400; font-size: 0.85rem; line-height: 1.45; white-space: normal; width: 18rem; max-width: calc(100vw - 2rem); text-align: left; }
@media (max-width: 720px) {
  .chip .chip-tip .tip-bubble { left: auto; right: 0; }
}

.profile-subline {
  /* Rick, 21 Sep 2026: the subline is the profile's one-line summary and
     read too faintly at 0.97rem in mute ink. */
  color: var(--ink);
  font-weight: 600;
  font-size: 1.2rem;
  margin-bottom: var(--space-4);
  font-variant-numeric: tabular-nums;
}

.profile-header .btn-row { margin-top: var(--space-5); }

/* --- Profile layout: verification box first on mobile, right on desktop -- */
.profile-layout {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
  align-items: start;
}

@media (min-width: 960px) {
  .profile-layout { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--space-7); }
  .profile-layout .profile-main { order: 1; }
  .profile-layout .profile-aside { order: 2; position: sticky; top: calc(var(--header-offset) + var(--space-4)); }
}

.profile-section { margin-bottom: var(--space-7); }
.profile-section:last-child { margin-bottom: 0; }
/* The profile body band is space-7, not the site's space-8 (Rick, 2 Sep
   2026): with the contents menu directly above, 64px read as a hole before
   the first heading. An earlier padding on the About section itself stacked
   on top of this and doubled the gap; it is gone. */
.profile-body { padding-block: var(--space-7); }
.profile-section h2,
.profile-section .shot-title { margin-top: 0; }
/* Sub-headings inside About (help-with, treatments): clearly subordinate to
   the section title, clearly senior to body text. */
.profile-section h3,
.profile-section .shot-heading { font-size: 1.45rem; margin-top: var(--space-6); margin-bottom: var(--space-3); }

/* Hero rating line: stars link down to #reviews. */
.profile-rating { margin-bottom: var(--space-3); max-width: none; }
.profile-rating a { text-decoration: none; color: var(--ink); }
.profile-rating a:hover strong { text-decoration: underline; }

/* Member-declared facts folded into About when the standalone section went
   (qualified year, background) - quiet, one line. */
.profile-about-meta { color: var(--ink-mute); font-size: 0.95rem; }

/* The mobile enquiry bar. Shown by main.js between the masthead button leaving
   the screen and the enquiry section arriving; see the note in profile.php.

   It fades rather than slides. A fixed element translated below bottom:0 can
   add to the scrollable area in some browsers, and this file has already paid
   for one below-the-fold overflow bug; opacity changes nothing about layout.
   visibility rides with it so a keyboard or screen reader cannot reach two
   buttons that are not on screen.

   z-index 500 for the same reason the finder bar uses it: Leaflet's panes sit
   at 400+ and the profile carries a map. It stays under the sticky header
   (600), which it can never meet anyway. */
.profile-sticky-cta {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 500;
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  padding-bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
  background: var(--surface);
  border-top: 1px solid var(--line);
  box-shadow: 0 -6px 24px rgba(11, 45, 34, 0.12);
  opacity: 0;
  visibility: hidden;
  transition: opacity 180ms ease, visibility 0s linear 180ms;
}

.profile-sticky-cta[hidden] { display: none; }

.profile-sticky-cta.is-shown {
  opacity: 1;
  visibility: visible;
  transition: opacity 180ms ease, visibility 0s;
}

/* Equal halves, and no inherited button margin - the bar is one row or it is
   a mess on a 320px screen. */
.profile-sticky-cta .btn { flex: 1 1 0; min-width: 0; margin: 0; }

@media (min-width: 960px) {
  /* The rail's quick card takes over here, so the bar must not exist at all. */
  .profile-sticky-cta { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .profile-sticky-cta,
  .profile-sticky-cta.is-shown { transition: none; }
}

/* THE PROFILE'S ONE ACTION CARD (2 Sep 2026): price from, the action, the
   phone, the website, the social icons. Every width, because the masthead
   no longer carries any button. It renders in the rail when the masthead is
   showing photographs and in the masthead's right-hand column when there
   are none - partials/profile_quick.php. */
.profile-quick {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  padding: var(--space-5);
  margin-bottom: var(--space-5);
  text-align: center;
}

.profile-quick-fee { margin: 0 0 var(--space-4); max-width: none; color: var(--ink-soft); }
/* Book online and Send an enquiry on ONE row where the card is wide enough
   (Rick, 2 Sep 2026). Each button asks for 9rem, so in the rail they sit
   side by side and in a narrow card (the masthead column, a phone) they
   stack, which is the same rule the phone bar follows. */
.profile-quick-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* inline-flex so the label sits in the vertical middle when its neighbour
   wraps to two lines and stretches the row (Rick, 2 Sep 2026: "Book online"
   sat at the top of a tall button beside a two-line "Send an enquiry"). */
.profile-quick-cta { flex: 1 1 9rem; min-width: 0; margin: 0; display: inline-flex; align-items: center; justify-content: center; }
.profile-quick-phone { margin: var(--space-3) 0 0; max-width: none; font-size: 0.95rem; color: var(--ink-mute); }
/* One contact row (Rick, 21 Sep 2026): phone, website and social icons on
   a line under the buttons; wraps on a narrow card. The social list keeps
   its own centred flex row, so it sits inline with the text beside it. */
.profile-quick-contact { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--space-1) var(--space-4); margin-top: var(--space-3); }
.profile-quick-contact .profile-quick-phone { margin: 0; }
.profile-quick-contact .social-row { gap: 0; }
.profile-quick-contact .social-link { width: 40px; height: 40px; }
/* The member's own website and social addresses: one quiet row at the foot
   of the card under a hairline. Declared, unchecked, and in their contact
   card rather than anywhere near the Verification box. */
.profile-quick-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}
.profile-quick-site { font-size: 0.95rem; }
/* The pitch page's laptop specimen draws the same line as a <span>, because
   nothing inside a picture of a page may be a real link; it still has to
   LOOK like the link it is standing in for. */
.device-screen span.profile-quick-site { color: var(--green); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2.5px; }
/* The specimen's aside is narrower than a real rail at the laptop's scale, so
   the two buttons get tighter side padding and may not wrap their label:
   "Send an enquiry" on two lines inside a picture reads as a broken button. */
.device-screen .profile-quick-cta { padding-inline: var(--space-3); white-space: nowrap; }
/* In the masthead (a member with no photographs) the card IS the column. */
.profile-head-actions .profile-quick { width: 100%; min-width: 16rem; margin-bottom: 0; }

/* Reviews (collected through VerifiedPractitioner, synced nightly) */
.review-entry { border-top: 1px solid var(--line); padding-block: var(--space-4); }
.review-entry:last-of-type { border-bottom: 1px solid var(--line); }

.review-head { display: flex; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-2); }

.review-rating { color: var(--brass-deep); font-weight: 700; font-size: 0.85rem; }

/* Star glyphs (partial stars.php): brass fills over a hairline outline.
   Sized in ems so they scale with the line they sit in. */
.stars { display: inline-flex; align-items: center; gap: 0.1em; vertical-align: -0.12em; }
.stars svg { width: 1.05em; height: 1.05em; display: block; }
.stars-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Aggregate line at the top of the profile reviews section. */
.review-aggregate {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 1.15rem;
  margin-bottom: var(--space-4);
}
.review-aggregate .stars { font-size: 1.3rem; }

/* The member's public response under a review: ruled in, quieter voice. */
.review-reply {
  margin-top: var(--space-3);
  padding-left: var(--space-4);
  border-left: 2px solid var(--brass-soft);
  color: var(--ink-soft);
  font-size: 0.97rem;
}

/* Star rating line on result cards (data-gated: reviews present only). */
.result-rating {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: calc(-1 * var(--space-2)) 0 var(--space-3);
  font-size: 0.97rem;
}
.result-rating { flex-wrap: wrap; }
.result-rating .stars { font-size: 1.05rem; }
/* The Google signpost is review information, neither an operator check nor a
   member claim, so it sits under the rating rather than in the provenance rows
   - and on its OWN line, so it can never be read as the VP star figure. */
.result-google-note {
  color: var(--ink-mute);
  font-size: 0.9rem;
  margin: calc(-1 * var(--space-2)) 0 var(--space-3);
}

/* Two-source review CARDS (profile + the member's all-reviews page).

   Built on .verification-box - the same labelled-source card that holds the
   Verification panel on this page - so the Reviews section reads as part of
   the page rather than bolted on (Rick, 28 Aug 2026, after seeing the
   unstyled version live). Head = source mark + heading, body = the rating
   and the entries, footer = the muted attribution line. Two clearly
   labelled sources, never combined.

   STACKED, never side by side: this section sits in .profile-main, which is
   7fr of a 7fr/5fr grid from 960px, so a two-column split lands at roughly
   300px a card. Measured, not preferred. */
.review-card + .review-card { margin-top: var(--space-5); }

/* The Google mark sits at the head, at the seal's optical weight. */
.review-card-google .verification-box-head .icon-google { flex: none; }

/* The headline figure. Larger than a review's own stars so the card has one
   obvious reading order: rating, then evidence. */
.review-aggregate-lg {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  font-size: 1.35rem;
  margin: 0 0 var(--space-4);
}
.review-aggregate-lg .stars { font-size: 1.5rem; }
.review-aggregate-lg strong { font-variant-numeric: tabular-nums; }
.review-aggregate-count {
  font-size: 0.95rem;
  color: var(--ink-mute);
}

/* An empty Google line (JS not run, no key, Google unreachable) must not
   leave a gap above the link - the card still reads as complete. */
.review-aggregate-lg:empty { display: none; }

.review-card-link { font-size: 0.95rem; }

/* The entries sit between the rating and the footer, separated by hairlines
   rather than boxes - a card inside a card reads as noise. */
/* ONE hairline between entries, never doubled and never missing. The
   first-of-type reset MUST use the CHILD combinator: written as a descendant
   it also matched the first review inside the <details>, which stripped that
   review's rule AND its top padding so it collided with the one above the
   moment the expander opened (Rick spotted it, 28 Aug 2026). Entries revealed
   by the expander are not direct children of .review-list, so they keep the
   base rule and separate correctly. */
.review-card .review-entry { border-bottom: 0; }
/* The first entry KEEPS its rule (28 Aug 2026): with the heading block gone,
   this hairline is the only thing separating the rating summary from the
   reviews themselves. Every entry now carries a top border and nothing
   carries a bottom one, so the run is evenly ruled and never doubled -
   including the entries the expander reveals, which are not direct
   children of .review-list. */
.review-card .review-list { margin-bottom: var(--space-4); }

/* THE SOURCE LINE - one rule, both cards, so they cannot drift apart. Reads
   "[mark] ***** 4.6 from 18 reviews on <source>". The mark, the stars and
   (Rick, 28 Aug 2026 - a "Google reviews" heading above them read as clunky
   when the line already names its source). Ships hidden; main.js unhides it
   only once a real figure has landed, so a failed fetch never leaves a lone
   Google mark asserting nothing. */
.review-source-line {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  font-size: 1.35rem;
  margin: 0 0 var(--space-4);
}
.review-source-line .icon-google,
.review-source-line .wordmark-seal { flex: none; }
.review-source-line .stars { font-size: 1.5rem; }
.review-source-line strong { font-variant-numeric: tabular-nums; }
/* The source name wraps as ONE unit on a phone, never splitting
   "reviews on The MLD Register" across two lines mid-phrase. */
.review-source-line .review-aggregate-count { white-space: nowrap; }
/* MLD's 16px (features.text_min_16) makes this line wider than a 320px
   phone with the seal and stars beside it, so there it may wrap. */
.text-min-16 .review-source-line .review-aggregate-count { white-space: normal; }

/* The way back from the leave-a-review form. */
.review-form-back { margin-top: var(--space-5); font-size: 0.95rem; }
.review-card-more { margin: 0 0 var(--space-4); }

/* The leave-a-review invitation under the cards. */
.review-invite { font-size: 0.97rem; margin-top: var(--space-5); }

/* The all-reviews page's back link, above the heading. */
.reviews-all-back { font-size: 0.95rem; margin-bottom: var(--space-3); }
/* Enquiry form panel */
.enquiry-section {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-1);
  scroll-margin-top: var(--space-6);
}

/* Long review lists: five show, the rest sit behind a native expander so a
   member with a hundred reviews does not become a hundred-screen page. Inline
   rather than a link off to Google or VP: the visitor who is reading reviews
   is two scrolls from the enquiry form, and sending them to another tab is
   how a directory loses the enquiry. Google's own full list keeps its
   external link above. */
.reviews-more > summary,
.bio-more > summary {
  cursor: pointer;
  list-style: none;
  display: inline-block;
  margin-block: var(--space-4) 0;
  font-weight: 600;
  color: var(--green-deep);
  text-decoration: underline;
  text-decoration-color: var(--brass);
}
.reviews-more > summary::-webkit-details-marker,
.bio-more > summary::-webkit-details-marker { display: none; }
.reviews-more[open] > summary { display: none; }

/* Profile footer: report link + disclaimer line */
.profile-footer {
  margin-top: var(--space-7);
  border-top: 1px solid var(--line);
  padding-top: var(--space-5);
  font-size: 0.9rem;
  color: var(--ink-mute);
}

.profile-footer p { max-width: none; }

/* Enquiry confirmation screen */
.enquiry-success { padding-block: var(--space-7); }
.enquiry-success .enquiry-success-seal { color: var(--green); margin-bottom: var(--space-4); }

/* --- Check a Therapist (B8) ------------------------------------------- */
.page-check .container-narrow { max-width: 56rem; }
/* The single search input already carries the sage keyline; drop the panel
   chrome so /check is not a box drawn immediately inside another box. */
.page-check .search-box {
  max-width: none;
  background: transparent;
  border: 0;
  box-shadow: none;
  border-radius: 0;
  padding: 0;
}

.check-results { margin-top: var(--space-6); }

/* Check cards carry an avatar (left) like search results; inherit the
   flex row from .result-card. */
.check-card .result-main { max-width: none; }
.check-card .result-name, .check-card .result-meta { padding-right: 0; }
.check-card .result-name { margin-bottom: var(--space-2); }

/* Name block and "View full profile" on one row, the button centred on the
   name; leader rows sit below at full width. */
.check-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-bottom: var(--space-4);
}

.check-head-name { min-width: 0; }
.check-head-name .result-meta { margin-bottom: 0; }
.check-head .btn { flex: none; }

.check-checklist { grid-template-columns: 1fr; }

.check-footer-line { margin-top: var(--space-7); }
.check-footer-line p { max-width: none; }

/* =========================================================================
   pkg-badge - /verify verification card page (badge click-through)
   Token-driven additions only; merged into main.css by the orchestrator.
   ========================================================================= */

/* The card sits in a narrow measure, like a certificate on the desk. */
.verify-wrap { max-width: 34rem; }

/* Name and status chip stacked beside the seal in the box head. */
.verify-head-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
}

/* =========================================================================
   Package: join-stripe (join flow + Stripe hand-off)
   Staged CSS for merge into public/assets/css/main.css by the orchestrator.
   Token-driven only: existing custom properties, no new colours or fonts.
   ========================================================================= */

/* Join flow progress indicator: Choose tier -> Your details -> Payment ->
   Documents (A2). One stepper for the whole journey; main.js advances it
   live between the two /join panels. Ruled steps with serif index numbers,
   echoing the ledger index motif. */
.join-progress {
  list-style: none;
  display: flex;
  gap: var(--space-4);
  padding: 0;
  margin: var(--space-5) auto var(--space-6);
  max-width: var(--container-narrow);
}

.join-progress li {
  flex: 1;
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
  padding-top: var(--space-3);
  border-top: 2px solid var(--line);
  color: var(--ink-mute);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.join-progress li.is-current { border-top-color: var(--brass); color: var(--ink); }
.join-progress li.is-done { border-top-color: var(--green); color: var(--green-deep); }

.join-progress-num { font-family: var(--font-serif); font-size: 1.05rem; font-weight: 600; }
/* WHAT brands: a finished step shows a white tick in a green circle (Rick, 8 Oct 2026). */
/* WHAT brands: no step numbers, the stage names only (Rick, 14 Oct 2026); the tick stays on a finished stage. */
.join-progress-what .join-progress-num:empty { display: none; }
/* The current stage's rule in the brand's button colour: the decorative accent it used is the same as the plain rule on WhatHypno. */
.join-progress-what li.is-current { border-top-color: var(--green); }
.join-progress-what li.is-done .join-progress-num { display: inline-grid; place-items: center; width: 1.6rem; height: 1.6rem; margin-right: 0.4rem; border-radius: 50%; background: var(--tick-green) /* the joining ticks' own green, never the brand's --verified (navy on MLD; Rick, 18 Oct 2026) */; color: #fff; font-family: var(--font-sans); font-size: 0.85rem; font-weight: 700; line-height: 1; }

/* Narrow screens: four steps will not fit on one row. "Documents" alone has a
   min-content width wider than a quarter of a 320px viewport, and a flex item
   defaults to min-width:auto, so it refused to shrink and pushed the whole
   page sideways - 55px at 320 and 15px at 360, on the paid signup funnel.
   Two by two instead. minmax(0,1fr) caps the track, and min-width:0 is needed
   on BOTH boxes: on the li because it is a grid item, and again on the label
   because the li is itself a flex container, so the span carries its own
   min-width:auto. Without the second one a longer label, or the fallback font
   shown during font-display:swap, could still push the row out. */
@media (max-width: 540px) {
  .join-progress {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3) var(--space-4);
  }
  .join-progress li { min-width: 0; }
  .join-progress-label { min-width: 0; overflow-wrap: anywhere; }
}

/* JS-gated controls (join flow Next/Back): visible only once main.js has
   stamped html.js, so the no-JS render never shows a dead button. */
html:not(.js) .js-only { display: none !important; }

/* Join panels: the two /join screens (Choose your tier / Your details).
   Both render stacked without JS; main.js hides one at a time and animates
   the entry. Hidden inputs still submit - [hidden] never disables fields. */
.join-panel[hidden] { display: none; }

.join-panel-actions {
  /* The submit button stays first in the DOM (so Enter submits the form);
     row-reverse renders it on the RIGHT with the back link on the left. */
  display: flex;
  flex-direction: row-reverse;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-5);
  margin-top: var(--space-6);
}

/* Step 1 has ONE control and nothing to sit opposite it, so space-between
   pinned "Next: your details" hard against the right edge of a full-width
   panel with nothing beside it (Rick, 20 Aug 2026). Centre it, and give the
   panel room underneath so the button is not the last pixel on the page. */
.join-panel-actions-single {
  justify-content: center;
  padding-bottom: var(--space-7);
}

/* A button dressed as an inline link (e.g. "Back to tiers" on /join). */
.btn-link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 1rem;
  color: var(--green);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2.5px;
  cursor: pointer;
}

.btn-link::before { content: "\2190\00a0"; }

.btn-link:hover { text-decoration-thickness: 2px; }

@media (prefers-reduced-motion: no-preference) {
  .join-panel-enter { animation: join-panel-in 0.28s ease both; }
  @keyframes join-panel-in {
    from { opacity: 0; transform: translateY(0.5rem); }
    to { opacity: 1; transform: none; }
  }
}

/* Stripe Embedded Checkout container: the card form renders here inside a
   Stripe-hosted iframe. Reserve height so the page does not jump while the
   iframe loads; Stripe's own UI paints over the paper background. */
.stripe-embed {
  margin: var(--space-6) 0;
  min-height: 30rem;
  border-radius: var(--radius);
}

.stripe-embed-loading { padding: var(--space-6) 0; text-align: center; }

/* The Payment Link fallback block starts hidden and is revealed by JS only
   when the embed fails. .btn-row's display:flex would defeat the [hidden]
   attribute (equal specificity, later in the cascade), so pin it. */
[data-stripe-embed-fallback][hidden] { display: none; }

/* Concierge editable preview (/dashboard/preview): the member's finished profile
   as an editable form; the approve / save actions sit at the foot of the form. */
.preview-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin-top: var(--space-6);
}
.preview-actions .btn { min-width: 12rem; }
.preview-actions-note {
  margin: var(--space-3) 0 0;
  font-size: 0.9rem;
  color: var(--ink-mute);
}

/* The join content sits under the page header; give it room to breathe so
   the stepper is not cramped against the header. */
.page-join main > .container { padding-top: var(--space-7); }

/* Post-payment confirmation (/welcome): a single centred column with one clear
   next-step CTA. Deliberately NOT the /join/pending status leader-table - at
   the payment moment a status table only competes with the action we want. */
.welcome-confirm {
  max-width: 60rem;
  text-align: center;
  padding-bottom: var(--space-8);
}
.welcome-hero {
  max-width: 44rem;
  margin-inline: auto;
}
.welcome-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 4rem;
  height: 4rem;
  border-radius: 50%;
  background: var(--green-wash);
  color: var(--green);
  margin-bottom: var(--space-4);
}
.welcome-eyebrow {
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--green);
  max-width: none;
  margin-bottom: var(--space-3);
}
.welcome-hero h1 { margin-bottom: var(--space-4); }
.welcome-hero .lead {
  font-family: var(--font-serif);
  font-size: 1.2rem;
  color: var(--ink-soft);
  max-width: 40rem;
  margin-inline: auto;
  margin-bottom: var(--space-6);
}
/* The instruction paragraphs under the welcome lead: left-aligned inside the
   centred hero, because a run of centred paragraphs makes the eye hunt for the
   start of every line. */
.welcome-body {
  max-width: 40rem;
  margin: 0 auto var(--space-6);
  text-align: left;
  color: var(--ink-soft);
}
.welcome-body p { margin: 0 0 var(--space-4); }
.welcome-body p:last-child { margin-bottom: 0; }

.welcome-cta { margin-bottom: var(--space-4); }
.welcome-cta .btn { min-width: 15rem; }
.welcome-note {
  font-size: 0.95rem;
  color: var(--ink-mute);
  max-width: 34rem;
  margin-inline: auto;
  margin-bottom: 0;
}
.welcome-rule {
  margin-block: var(--space-8);
  border-top-color: var(--line);
}
.welcome-steps-title {
  margin-top: 0;
  margin-bottom: var(--space-6);
}
.welcome-steps {
  list-style: none;
  padding: 0;
  margin: 0 auto var(--space-8);
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
  text-align: left;
  max-width: 30rem;
}
@media (min-width: 760px) {
  .welcome-steps {
    grid-template-columns: repeat(3, 1fr);
    max-width: none;
    gap: var(--space-7);
  }
}
.welcome-steps > li { margin: 0; }
.welcome-step-num {
  display: block;
  font-family: var(--font-serif);
  font-size: 1.7rem;
  font-weight: 600;
  color: var(--brass);
  font-variant-numeric: tabular-nums;
  padding-bottom: var(--space-3);
  margin-bottom: var(--space-3);
  border-bottom: 1px solid var(--line);
}
.welcome-steps h3 { margin: 0 0 var(--space-2); font-size: 1.2rem; }
.welcome-steps p { margin: 0; color: var(--ink-soft); font-size: 1.05rem; }
.welcome-reassure {
  max-width: 44rem;
  margin-inline: auto;
  margin-bottom: var(--space-4);
  font-size: 0.95rem;
  color: var(--ink-mute);
}
.welcome-reassure:last-child { margin-bottom: 0; }

/* Concierge onboarding (/dashboard before a member is live): ONE focused,
   guided screen - the member's three things (answers, address, documents), or
   the waiting / approval state. Deliberately no section menu, no self-service
   panels, no competing CTAs. Engine-level (tokens only) so every concierge
   brand inherits it. */
.onboard-intro {
  font-size: 1.125rem; /* 18px, Rick 2 Sep 2026 */
  color: var(--ink-soft);
  margin: 0 auto var(--space-6);
  max-width: 44rem;
  text-align: center;
}
/* LEFT-ALIGNED once there is more than a sentence or two. Centring is right
   for a one-line reassurance and wrong for five paragraphs: every line starts
   in a different place, so the eye has to hunt for the next one. Rick has
   caught centred body copy before. The single-paragraph states above keep the
   centred treatment. */
.onboard-intro.onboard-intro-long { text-align: left; }
.onboard-intro p { margin: 0; }
.onboard-intro p + p { margin-top: var(--space-4); }
/* The "we don't start until you press Submit" line is the whole point of the
   screen, and .onboard-intro p { margin: 0 } was running it straight into the
   paragraph above as one block. */
.onboard-intro .onboard-intro-note { margin-top: var(--space-4); }
.onboard-intro strong { color: var(--ink); }

.onboard-progress { margin-bottom: var(--space-6); text-align: center; }

.onboard-step-head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}
.onboard-step-head h2 { margin: 0; }
.onboard-step-hint {
  margin: 20px 0px 40px 0px; /* Rick, 21 Aug 2026 */
  /* 1.125rem (18px), Rick 2 Sep 2026 (was 1.1rem, 21 Aug 2026): this is the
     sentence that explains the step, and it was set smaller than the field
     hints underneath it. */
  font-size: 1.125rem;
  color: var(--ink-mute);
}
.onboard-num {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: var(--brass-soft);
  color: var(--brass-deep);
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 1.15rem;
  font-variant-numeric: tabular-nums;
}
.onboard-step-status { margin-left: auto; flex: 0 0 auto; }
.onboard-step.is-done .onboard-num {
  background: var(--green-wash);
  color: var(--green);
}
.onboard-summary {
  margin: 0 0 var(--space-2);
  color: var(--ink-soft);
}
.onboard-form { margin-top: var(--space-2); }

/* ---------------------------------------------------------------------------
   The onboarding WIZARD (20 Aug 2026): one step per screen, with a stage bar.
   On a text step every stage is a <button type=submit name=goto>, so the three
   selectors below have to style a button, a link and a span identically -
   otherwise the bar visibly changes shape between step kinds. Hence the reset
   on .wizard-step rather than three separate rules.
   --------------------------------------------------------------------------- */
.wizard-bar { margin: 0 0 var(--space-6); }

.wizard-count {
  margin: 0 0 var(--space-3);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink-mute);
  letter-spacing: 0.02em;
}

.wizard-steps {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.wizard-step {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--surface);
  color: var(--ink-soft);
  font: inherit;
  font-size: 0.9rem;
  font-weight: 700;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

/* A <span> for the current step: no pointer, and it must not look pressable. */
.wizard-steps .is-current .wizard-step {
  cursor: default;
  border-color: var(--green);
  background: var(--green-wash);
  color: var(--ink);
}

.wizard-steps .is-done .wizard-step { border-color: var(--verified); }

.wizard-step:hover,
.wizard-step:focus-visible { border-color: var(--line-strong); }
.wizard-steps .is-current .wizard-step:hover { border-color: var(--green); }

.wizard-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--paper-2);
  color: var(--ink-mute);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}
.wizard-steps .is-done .wizard-num { background: var(--verified-wash); color: var(--verified); }
.wizard-steps .is-current .wizard-num { background: var(--green); color: var(--on-green); }
/* A completed step's tick is green on every directory (Rick, 28 Sep 2026):
   pale green behind a green tick, or solid green with a white tick on the
   step you are on. A step still to do keeps its number in the brand colour. */
.wizard-steps .wizard-num.is-tick { background: var(--tick-green-wash); color: var(--tick-green); }
.wizard-steps .is-current .wizard-num.is-tick { background: var(--tick-green); color: #fff; }

/* ALL SEVEN STEPS ON ONE ROW, SPREAD ACROSS THE COLUMN (Rick, 21 Aug 2026).
   They used to be tightened until they fit, which put all seven in the left
   third of a wide column and read as a bunched-up cluster rather than a trail
   across the page. Each stage now takes an EQUAL share of the row, so the bar
   spans its container at any width and the chips line up as a proper progress
   trail.

   `min-width` is what keeps it honest. Flex items with `flex: 1 1 0` shrink
   rather than wrap, so without a floor the labels would squash to nothing on a
   narrow desktop instead of moving to a second line. With it, the row WRAPS -
   which is the required behaviour: a stage a member cannot see is a stage they
   miss, and this bar must never scroll sideways. Same ruling as .dash-nav. */
@media (min-width: 900px) {
  .wizard-steps { gap: var(--space-1); }
  .wizard-step { gap: var(--space-1); padding: var(--space-2); }
  .wizard-num { width: 1.4rem; height: 1.4rem; font-size: 0.78rem; }
}

/* 1000px, NOT 900px, and the number is measured rather than chosen. The wizard
   column tops out at 880px, and seven chips wide enough for "About you" at
   0.9rem/700 need about 881px of it. At a 900px viewport the column is only
   813px, so equal shares there wrapped to two rows and left "Review" stretched
   across the whole second row on its own. The column reaches its 880px cap at
   about a 1000px viewport, which is where this can start. */
@media (min-width: 1000px) {
  .wizard-steps { gap: var(--space-2); }
  .wizard-steps > li { flex: 1 1 0; min-width: 7rem; }
  .wizard-step {
    width: 100%;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-2);
  }
}

/* Below 560px the labels stack the bar into a wall of chips. The NUMBERS stay,
   because "step 4 of 7" plus a numbered trail is still a position; the words
   are what will not fit. The count line above keeps the meaning for anyone
   reading the labels aloud. */
@media (max-width: 559px) {
  .wizard-steps .wizard-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .wizard-steps .is-current .wizard-label { position: static; width: auto; height: auto; overflow: visible; clip-path: none; }
  .wizard-step { padding: var(--space-2); }
}

.wizard-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
}
.wizard-nav .btn-primary { margin-left: auto; }

.wizard-form h2 { margin-top: 0; }

/* "Add another ..." - a <details> so a hidden row can never be unreachable,
   dressed as the quiet secondary control it is. */
.onboard-more { margin: 0 0 var(--space-5); }
.onboard-more > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  color: var(--ink-soft);
  font-size: 0.95rem;
  cursor: pointer;
  list-style: none;
}
.onboard-more > summary::-webkit-details-marker { display: none; }
.onboard-more > summary::before { content: '+'; font-weight: 700; color: var(--green); }
/* An open disclosure shows a minus, to pair with the plus above. The bytes
   here were U+0091 followed by '2' - a dash lost in a Windows-1252 paste -
   so opening "Add another address" drew a missing-glyph box and a 2 where
   the close affordance belongs (Rick, 21 Aug 2026). A plain ASCII hyphen on
   purpose: the file stays ASCII and a hyphen is the exact pair of the plus. */
.onboard-more[open] > summary::before { content: '-'; }
.onboard-more > summary:hover,
.onboard-more > summary:focus-visible { border-color: var(--green); color: var(--ink); }
.onboard-more-body { padding-top: var(--space-4); }

/* A heading for a group of fields that is NOT a <label>, because each field in
   the group carries its own. Matches .field label exactly so the certificate
   boxes read as one question with the rest of the form. */
.field-group-label {
  display: block;
  font-weight: 700;
  font-size: 1.125rem; /* 18px, Rick 2 Sep 2026 */
  margin: 0 0 var(--space-2);
  color: var(--ink);
}

/* One numbered box per training certificate. The old control was a single
   multi-file input: the only way to send three certificates at once was to
   hold Ctrl in the file dialog, and nothing on screen said so (Rick, 21 Aug
   2026). */
.doc-slots { margin: 0 0 var(--space-3); }
.doc-slot + .doc-slot { margin-top: var(--space-3); }
.doc-slot-label {
  display: block;
  margin: 0 0 var(--space-1);
  font-weight: 600;
  font-size: 1rem;
  color: var(--ink-soft);
}

/* One address inside the onboarding step's single form. Four sets of the
   same six fields in one column read as one enormous address, so each is a
   panel carrying its own name (Rick, 21 Aug 2026). */
.location-block {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  margin: 0 0 var(--space-5);
  background: var(--surface);
}
.location-block-title {
  margin: 0 0 var(--space-6);
  font-size: 1.6rem;
  font-weight: 600;
}
.location-block .location-remove { margin: var(--space-2) 0 0; }

/* The onboarding wizard runs its own rhythm: the page is a form, not a
   marketing band, so the section padding that suits a landing page leaves a
   gap above the first question (Rick, 21 Aug 2026). */
.page-onboarding .section { padding-block: var(--space-6); }

/* Air under the last button on the uploads step. */
.onboard-upload-submit { margin-bottom: var(--space-6); }

/* One price row: name, minutes, price. */
.fee-row,
.training-row {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: 1fr;
  margin-bottom: var(--space-4);
}
@media (min-width: 640px) {
  .fee-row { grid-template-columns: 2fr 0.7fr 0.9fr auto; }
  .training-row { grid-template-columns: 1.4fr 1fr 0.7fr; }
  /* One label wraps to two lines and the others do not, which left the three
     inputs on three different baselines. Aligning to the END of each cell puts
     the CONTROLS in a row, which is the thing being read as a row. */
  .fee-row, .training-row { align-items: end; }
}
.fee-row .field,
.training-row .field { margin-bottom: 0; }
.fee-remove { justify-self: start; min-height: 44px; }
[data-fee-status]:empty { margin: 0; }

/* NARROW SCREENS: three things each refuse to shrink, and together they pushed
   the training step 145px wider than a 320px phone (measured 21 Aug 2026).
   1. A grid item's min-width is auto, so a cell never goes below its content.
   2. A <select> sizes to its LONGEST option, and the school list contains
      "Aftercare Academy: Advanced MLD & Treatment Protocols".
   3. A <fieldset> has min-inline-size: min-content in every browser, so it
      then refuses to shrink around the row and takes the page with it.
   All three need answering; fixing any two leaves the page scrolling sideways.
   The fee rows carry the same shape and the same fix. */
.dash-fieldset { min-width: 0; }
.fee-row .field,
.training-row .field { min-width: 0; }
.fee-row select, .fee-row input,
.training-row select, .training-row input { max-width: 100%; }

/* One training and the certificate that evidences it, as a single block
   (Rick, 21 Aug 2026). The three claims stay on one row where there is width
   for them; the certificate goes UNDER them at every width rather than
   becoming a fourth column, because a file input is the widest control on the
   page and squeezing it into a quarter of the row hides the filename the
   browser prints beside it - which is the only confirmation the member gets
   that she chose the right file. */
.training-block {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* Tight side padding on a phone, where this card sits inside the fieldset's
     padding inside the container's: three sets of generous inline padding left
     the school picker 179px wide on a 320px screen. */
  padding: var(--space-4) var(--space-3);
  margin: 0 0 var(--space-4);
  background: var(--surface);
}
@media (min-width: 640px) {
  .training-block { padding: var(--space-4) var(--space-5); }
}
.training-block .training-row { margin-bottom: 0; }

/* The Course list for one school, and the "not enough yet" note under it.
   ONE GROUP PER SCHOOL is rendered and main.js hides the ones that do not
   match the chosen school; without JavaScript they all show, each under its
   own school heading, and the server still reads only the matching one. So
   this must look deliberate in both states, not like a form that failed to
   collapse. */
.training-courses { margin-top: var(--space-4); }
.training-course-group + .training-course-group {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px dashed var(--line);
}
.training-course-group fieldset.field { border: 0; padding: 0; margin: 0 0 var(--space-4); }
.training-course-group .checkbox-row { margin-bottom: var(--space-2); }
/* The whole row IS the label here, so the base .checkbox-row label rule (which
   targets a label INSIDE the row) never reaches it and the course names
   rendered bold, like field headings. */
.training-course-group label.checkbox-row { font-weight: 400; margin: 0 0 var(--space-2); }
.training-course-note {
  background: var(--brass-soft);
  border: 1px solid var(--brass);
  border-radius: var(--radius);
  color: var(--tone-warn-ink);
  padding: var(--space-3) var(--space-4);
  margin: var(--space-3) 0 0;
  font-size: 0.95rem;
}
.training-cert {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px dashed var(--line);
}
.training-cert input[type="file"] { max-width: 100%; }

/* "We have X on file." Says what we hold and nothing more. */
.onboard-received {
  margin: 0 0 var(--space-2);
  font-size: 0.95rem;
  color: var(--ink-soft);
}

/* Certificates on file that match no claimed training. Listed so nothing a
   member sent can look lost. */
.onboard-other-docs {
  margin: 0 0 var(--space-5);
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--line);
  background: var(--paper-2);
}
.onboard-doc-list {
  margin: 0 0 var(--space-2);
  padding-left: 1.2em;
  font-size: 0.95rem;
  color: var(--ink-soft);
}

/* A file the browser refused before the post: too big to send. Red, because
   unlike the certificate tally this one did NOT save. */
.field-error {
  margin: var(--space-2) 0 0;
  font-size: 0.95rem;
  color: var(--tone-danger-ink);
  font-weight: 600;
}
.field-error[hidden] { display: none; }

/* "Your photo" inside the About you step: a heading within a step, not a step
   heading. */
.onboard-subhead {
  font-size: 1.15rem;
  margin-bottom: var(--space-3);
}

/* A warning that is not an error: the certificate tally is a nudge, and it
   must not use the red that means "we did not save this". */
.form-warning {
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--brass);
  background: var(--paper-2);
  color: var(--ink-soft);
  font-size: 0.95rem;
}

/* The training/insurance claims. Set apart from the story questions above:
   these are facts we check, not words we publish, and the member should be able
   to see that at a glance. */
.onboard-claims {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5) var(--space-2);
  margin: 0 0 var(--space-5);
}
.onboard-claims > legend {
  float: left;              /* a fieldset legend ignores the fieldset's padding */
  width: 100%;
  font-weight: 700;
  font-size: 1.2rem; /* every dashboard legend, Rick 2 Sep 2026 */
  color: var(--ink);
  margin-bottom: var(--space-2);
}
.onboard-claims > legend + .field-hint { clear: both; }

/* The member's own photo step: current photo (or initials) beside the upload. */
.onboard-photo-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-5);
  flex-wrap: wrap;
}
/* min-width: 0 is the whole fix (21 Aug 2026). A flex item defaults to
   min-width: auto, so it refuses to shrink below its content's min-content
   width. The upload control ("Choose file" button + "No file chosen") is wider
   than a 360px phone once the 96px avatar and the gap are taken off, so the
   row pushed the whole page sideways and the member could scroll the preview
   left and right. The .field selector matches the approve-and-edit preview
   screen, which uses .field rather than .onboard-form. */
.onboard-photo-row .onboard-form,
.onboard-photo-row .field { margin-top: 0; flex: 1 1 16rem; min-width: 0; }
.onboard-photo-row input[type="file"] { max-width: 100%; }
.onboard-photo-current {
  flex: 0 0 auto;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--brass-soft);
  display: flex;
  align-items: center;
  justify-content: center;
}
.onboard-photo-current img { width: 100%; height: 100%; object-fit: cover; }
.onboard-photo-empty {
  font-family: var(--font-serif);
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--brass-deep);
}
.onboard-num svg { display: block; }

.onboard-edit { margin-top: var(--space-2); }
.onboard-edit > summary {
  cursor: pointer;
  color: var(--green);
  font-size: 0.95rem;
  font-weight: 600;
}
.onboard-edit-body { margin-top: var(--space-4); }

.onboard-confirm {
  text-align: center;
  max-width: 40rem;
  margin: 0 auto var(--space-6);
}
.onboard-confirm p { margin: 0 auto; max-width: 38rem; }
/* max-width: none on these centred <p>s: without it they inherit the base
   p{max-width:70ch}, which pins the box left so text-align:center lands the
   content left of the true page centre. */
.onboard-cta { text-align: center; margin-bottom: var(--space-6); max-width: none; }
.onboard-cta .btn { min-width: 15rem; }

/* The centred .onboard-received block that stood here was DEAD and was
   deleted on 21 Aug 2026. It styled a confirmation on the old "Photo and
   documents" step; that step is gone, no view in any brand referenced it any
   more, and it sat AFTER the live rule of the same name - so the receipt line
   beside a certificate box inherited a centred, 22rem-wide box and read as
   floating in the middle of a left-aligned field. The live rule is up beside
   .training-block. */

.onboard-change {
  border-top: 1px solid var(--line);
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  text-align: center;
}
.onboard-change > summary {
  cursor: pointer;
  color: var(--green);
  font-weight: 600;
}
.onboard-change-body { margin-top: var(--space-5); text-align: left; }
.onboard-change h2 { font-size: 1.05rem; margin-bottom: var(--space-3); }

/* The member's own "I have finished" panel. Centred and set apart from the
   numbered steps: it is the one thing on the page that ends the screen, so it
   must not read as a fifth step. */
.onboard-submit {
  text-align: center;
  border-color: var(--brass-soft);
}
.onboard-submit h2 { margin-top: 0; }
.onboard-submit p { margin: 0 auto var(--space-4); max-width: 38rem; }
.onboard-submit .onboard-form { margin-top: 0; }
.onboard-submit .btn { min-width: 15rem; }
.onboard-todo {
  list-style: none;
  padding: 0;
  margin: 0 auto var(--space-5);
  max-width: 34rem;
  text-align: left;
  display: inline-block;
}
.onboard-todo li { margin-bottom: var(--space-2); }

.onboard-reassure {
  font-size: 0.9rem;
  color: var(--ink-mute);
  margin: var(--space-6) auto 0;
  max-width: 40rem;
  text-align: center;
}
.onboard-signout {
  margin-top: var(--space-6);
  max-width: none;
  text-align: center;
  font-size: 0.9rem;
}
.onboard-signout a { color: var(--ink-mute); display: inline-flex; align-items: center; gap: 0.35rem; }

.join-fieldset {
  border: 0;
  padding: 0;
  margin: 0 0 var(--space-7);
  min-width: 0;
}

/* /join tier chooser: two boxes - Registered (with its billing options) and
   Featured - replacing the old four-card row. The four Stripe tier keys are
   unchanged; the billing radios inside a box submit the right one. */
.join-two-boxes {
  display: grid;
  gap: var(--space-5);
  align-items: start;
}

@media (min-width: 800px) {
  .join-two-boxes { grid-template-columns: 1fr 1fr; }
}

.tier-box {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  padding: clamp(var(--space-5), 4vw, var(--space-6));
  transition: border-color 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}

.tier-box:has(input[type="radio"]:checked) {
  border-color: var(--green);
  box-shadow: 0 0 0 1px var(--green), var(--shadow-2);
}

.tier-box-head { margin-bottom: var(--space-4); }
.tier-box-name { font-size: 1.5rem; margin: 0 0 var(--space-1); } /* card-heading size, 19 Oct 2026 */
.tier-box-price {
  font-family: var(--font-serif);
  font-size: 1.7rem;
  font-weight: 700;
  color: var(--green-deep);
  margin: 0 0 var(--space-2);
}
/* The VAT note sits inside the price line but reads as small print: body
   font, normal weight, muted - "£75/year including VAT". */
.tier-box-vat {
  font-family: var(--font-sans);
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--ink-mute);
  white-space: nowrap;
}
.tier-box-sub { color: var(--ink-soft); margin: 0; }
.tier-plus-lead { font-weight: 600; margin: 0 0 var(--space-3); }
.tier-box .tier-card-note { margin-top: var(--space-4); }
/* The join button sat flush against the rates boxes (Rick, 17 Aug 2026). */
.tier-box > .btn-block { margin-top: var(--space-5); }

.tier-billing-label {
  font-weight: 700;
  font-size: 0.95rem;
  margin: var(--space-5) 0 var(--space-3);
}

.tier-billing-group { display: flex; flex-direction: column; gap: var(--space-3); }

.tier-billing {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--paper);
  cursor: pointer;
  transition: border-color 140ms var(--ease-out), background 140ms var(--ease-out);
}

.tier-billing:hover { border-color: var(--line-strong); }
.tier-billing:has(input:checked) { border-color: var(--green); background: var(--green-wash); }
.tier-billing input { margin-top: 0.25rem; flex-shrink: 0; }
.tier-billing-text { display: flex; flex-direction: column; gap: 0.15rem; }
.tier-billing-price { font-weight: 700; font-size: 1.02rem; color: var(--ink); }
.tier-billing-note { font-size: 1rem; color: var(--ink-mute); line-height: 1.45; }

/* Small best-value marker for a billing option (used on /pricing). */
.tier-billing-flag {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tone-warn-ink);
  background: var(--brass-soft);
  border-radius: var(--radius-stamp);
  padding: 0.1rem 0.4rem;
  margin-left: 0.35rem;
  vertical-align: 0.08em;
}

/* On /pricing the billing rows are informational, not selectable: drop the
   pointer cursor and hover affordance so they do not read as clickable. */
.pricing-tiers .tier-billing { cursor: default; }
.pricing-tiers .tier-billing:hover { border-color: var(--line); }

/* SELECTABLE CARD (.choice-card; Rick, 14 Oct 2026, first used for the plans
   on the WHAT join page). One option of a radio group (or a checkbox) shown as
   a card. The REAL input sits inside the label, so the whole card is the
   target and it works without JavaScript; the input is hidden visually but
   stays focusable and announced. The round tick fills and the border thickens
   in the brand's button colour when chosen; a disabled choice stays visible,
   dashed and faded, with its reason under it.
   Markup: label.choice-card > input.choice-card-input + span.choice-card-tick
   + span.choice-card-body > span.choice-card-title + span.choice-card-note */
.choice-card {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  transition: border-color 140ms var(--ease-out), box-shadow 140ms var(--ease-out);
}
.choice-card:hover { border-color: var(--green); }
.choice-card-input { position: absolute; top: var(--space-4); left: var(--space-4); width: 1.5rem; height: 1.5rem; margin: 0; opacity: 0; pointer-events: none; }
.choice-card-tick {
  flex: none;
  position: relative;
  width: 1.5rem;
  height: 1.5rem;
  border: 2px solid var(--line-strong);
  border-radius: 50%;
  background: var(--surface);
  transition: background 140ms var(--ease-out), border-color 140ms var(--ease-out);
}
.choice-card-tick::after {
  content: "";
  position: absolute;
  inset: 0;
  background: #fff;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E") center / 100% no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E") center / 100% no-repeat;
  opacity: 0;
}
.choice-card-input:checked + .choice-card-tick { background: var(--green); border-color: var(--green); }
.choice-card-input:checked + .choice-card-tick::after { opacity: 1; }
.choice-card:has(.choice-card-input:checked) { border-color: var(--green); box-shadow: inset 0 0 0 1px var(--green); }
.choice-card-input:focus-visible + .choice-card-tick { outline: 3px solid var(--focus); outline-offset: 2px; }
@supports selector(:has(*)) {
  .choice-card-input:focus-visible + .choice-card-tick { outline: none; }
  .choice-card:has(.choice-card-input:focus-visible) { outline: 3px solid var(--focus); outline-offset: 3px; }
}
.choice-card:has(.choice-card-input:disabled) { cursor: not-allowed; background: transparent; border-style: dashed; border-color: var(--line-strong); box-shadow: none; }
.choice-card-input:disabled + .choice-card-tick,
.choice-card-input:disabled ~ .choice-card-body { opacity: 0.6; }
.choice-card-body { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.choice-card-title { font-weight: 700; font-size: 1.05rem; line-height: 1.35; color: var(--ink); }
.choice-card-note { font-size: 1rem; line-height: 1.45; color: var(--ink-mute); }
@media (prefers-reduced-motion: reduce) { .choice-card, .choice-card-tick { transition: none; } }

/* Offer cards: the engine's Featured card (partials/billing_featured.php)
   on every brand, and MLD's own membership card. Colours are brand tokens
   (--offer-free-ink, --offer-addon-ink, --offer-total-bg). MLD's large
   price figure and its compact phone layout stay in MLD's theme, because
   they belong to its own membership card. */
.offer-cards { align-items: stretch; }
.offer-card { display: flex; flex-direction: column; }
.offer-card .tier-box-head .offer-free { margin: 1rem 0 .35rem; color: var(--offer-free-ink); font: 600 1.12rem var(--font-sans); }
.offer-card.tier-box-addon .offer-free { color: var(--offer-addon-ink); }
.offer-card .offer-then, .offer-card .offer-frequency { font-size: 1rem; font-weight: 400; letter-spacing: 0; }
.offer-card .tier-box-vat { display: inline; margin: 0; font-size: .85rem; }
.offer-card .offer-frequency { white-space: nowrap; }
.offer-card .tier-plus-lead { font-size: 1rem; line-height: 1.55; }
.offer-card .tier-features { font-size: .97rem; line-height: 1.6; }
.offer-card .offer-terms { border-top: 1px solid var(--line); margin-top: 1rem; padding-top: 1rem; font-size: .9rem; line-height: 1.65; }
.offer-card .offer-terms p { margin-bottom: 1rem; }
.offer-card .offer-terms p:last-child { margin-bottom: 0; }
.offer-card .offer-total { padding: .9rem 1rem; background: var(--offer-total-bg); border-radius: var(--radius-stamp); }

/* The standard-comparison line sits tight under the tier cards */
.join-fieldset > .text-small { margin: var(--space-5) 0 0; }

.join-fieldset legend { padding: 0; }

.tier-pick {
  display: flex;
  flex-direction: column;
  cursor: pointer;
  font-weight: 400;
  transition: border-color 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}

.tier-pick .tier-radio-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.tier-pick input[type="radio"] {
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
  accent-color: var(--green);
}

.tier-pick .tier-name { margin: 0; }
.tier-pick .tier-price { display: block; }

.tier-price-strap {
  display: block;
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--green-deep);
  margin-bottom: var(--space-1);
}

.tier-pick .tier-price-note { display: block; }

.tier-card-note {
  display: block;
  font-size: 0.85rem;
  color: var(--ink-mute);
  border-top: 1px solid var(--line);
  padding-top: var(--space-3);
  margin-top: auto;
}

.tier-pick:hover { border-color: var(--line-strong); box-shadow: var(--shadow-2); }
.tier-pick:has(input[type="radio"]:checked) { border-color: var(--green); box-shadow: var(--shadow-2); }
.tier-pick:has(input[type="radio"]:focus-visible) { outline: 3px solid var(--focus); outline-offset: 2px; }

/* Application form fields */
.join-fields { max-width: var(--container-narrow); margin-inline: auto; margin-bottom: var(--space-8); }

.field-grid {
  display: grid;
  gap: 0 var(--space-5);
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .field-grid-2 { grid-template-columns: repeat(2, 1fr); }
  /* Label-grow fallback: inputs line up when one LABEL wraps. */
  .field-grid-2 > .field { display: flex; flex-direction: column; }
  .field-grid-2 > .field > label { flex-grow: 1; }
  /* Subgrid (all modern browsers): label, control and hint each share a row
     across the pair, so the inputs sit level whatever wraps - a two-line
     label OR a hint present on only one side. */
  @supports (grid-template-rows: subgrid) {
    .field-grid-2 { grid-template-rows: repeat(4, auto); }
    .field-grid-2 > .field { display: grid; grid-template-rows: subgrid; grid-row: span 4; align-content: start; }
    .field-grid-2 > .field > label { align-self: end; }
  }
}

/* "How did you hear of us?" (16 Oct 2026): the optional box under the
   choice, one wrapper so the pair's subgrid keeps its four rows. */
.join-heard-more .field { margin: var(--space-3) 0 0; }

/* Optional additional practice locations */
.join-extra-locations { margin-bottom: var(--space-5); }

.join-extra-locations summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--green);
  padding-block: var(--space-2);
}

.join-extra-locations summary:hover { color: var(--green-deep); }

/* Ruled ledger idiom, matching the dashboard's additional-locations block,
   rather than boxes-within-the-form. */
.location-row {
  border-top: 1px solid var(--line);
  padding: var(--space-4) 0 0;
  margin: var(--space-4) 0 0;
}

.location-row-title {
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin-bottom: var(--space-3);
}

/* =========================================================================
   pkg-dashboard - member auth pages (/login, /forgot-password,
   /reset-password), the member dashboard (/dashboard) and the printable
   membership certificate (/dashboard/certificate).
   Token-driven additions only; merged into main.css by the orchestrator.
   ========================================================================= */

/* --- Auth pages: a single calm panel, like a form on good paper --------- */
.auth-wrap { max-width: 26rem; margin-inline: auto; }

.auth-panel { padding: var(--space-6); }

.auth-seal {
  display: flex;
  justify-content: center;
  color: var(--green);
  margin-bottom: var(--space-5);
}

.auth-links { margin: var(--space-5) 0 0; font-size: 0.95rem; }

.auth-aside { text-align: center; }

/* --- Dashboard layout: sticky section nav beside the panels ------------- */
/* Member dashboard (16 Jul 2026): one narrow column, Overview open at the
   top, every other section an admin-section accordion. Anchor targets land
   clear of the viewport edge. */
.dash-section .panel,
.dash-section .admin-section { scroll-margin-top: var(--space-6); }

/* Dashboard header (Rick, 17 Jul 2026 v2 polish): title + welcome on the
   LEFT, "View your public profile" on the RIGHT (opens a new tab); wraps
   to stacked-left on small screens. Overrides the global centred rule. */
body .page-header.dash-header { text-align: left; }
body .page-header.dash-header .lead { margin-inline: 0; }
.dash-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4) var(--space-6);
  flex-wrap: wrap;
}
.dash-header-title h1 { margin-bottom: var(--space-2); }
.dash-header-action { max-width: none; margin: 0; }

/* ---- Dashboard v2 (Rick, 17 Jul 2026): top menu + sub-tabs + 75/25 grid.
   The menu band mirrors the admin-nav idiom; the sub-tabs are quiet pills;
   the right column holds the quick-action cards. */
.dash-menu { background: var(--surface); border-bottom: 1px solid var(--line); }
.dash-menu ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
  list-style: none;
  margin: 0;
  padding: var(--space-3) 0;
}
.dash-menu li { margin: 0; }
.dash-menu a {
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink-soft);
  padding: var(--space-2) 0;
  border-bottom: 2px solid transparent;
}
.dash-menu a:hover, .dash-menu a.is-active { color: var(--green-deep); border-bottom-color: var(--brass); }

.dash-subtabs { background: var(--paper-2); border-bottom: 1px solid var(--line); }
.dash-subtabs ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  list-style: none;
  margin: 0;
  padding: var(--space-2) 0;
}
.dash-subtabs li { margin: 0; }
.dash-subtabs a {
  text-decoration: none;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--ink-soft);
  padding: 0.3rem 0.8rem;
  border-radius: 999px;
}
.dash-subtabs a:hover { color: var(--green-deep); }
.dash-subtabs a[aria-current="page"] { background: var(--green-wash); color: var(--green-deep); }

/* THESE ROWS WRAP. They were briefly made to scroll sideways in one line to
   save height on a phone; Rick reversed it on 15 Aug 2026, and the reason is
   the one that matters more than the height: a member who cannot see an item
   does not know to look for it, so the menu items past the fold were simply
   never found. Every item is visible at every width, on as many lines as
   that takes. Do not reintroduce a horizontal scroll here. */

.dash-grid { display: grid; gap: var(--space-6); align-items: start; }
@media (min-width: 960px) {
  .dash-grid { grid-template-columns: 3fr 1fr; }
  .dash-grid-single { grid-template-columns: 1fr; }
}
.dash-main { min-width: 0; }
.dash-side .panel { padding: var(--space-4); }
.dash-side h2 { margin-bottom: var(--space-3); }
.dash-side .checklist { font-size: 0.92rem; }
.dash-quick-links { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }

/* Sidebar availability buttons breathe (Rick 17 Jul), and the small print
   underneath keeps its distance from the buttons (Rick 17 Aug). */
.dash-availability-form { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }

/* Referral link/message each carry their own Copy button (Rick 17 Jul). */
.dash-copy-row { display: flex; gap: var(--space-2); align-items: flex-start; }
.dash-copy-row textarea { flex: 1; min-width: 0; }
.dash-copy-btn { flex: none; display: inline-flex; align-items: center; gap: 0.4rem; }
.dash-quick-links a { font-weight: 600; }
.dash-copy-link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--green);
  text-decoration: underline;
  text-decoration-color: var(--link-underline);
  cursor: pointer;
}
.dash-copy-link:hover { color: var(--green-deep); }

/* For-therapists "proof" section: the live badge and the specimen
   certificate side by side (Rick, 17 Jul 2026). */
.proof-grid { display: grid; gap: var(--space-6); align-items: stretch; }
@media (min-width: 860px) { .proof-grid { grid-template-columns: 1fr 1fr; } }
.proof-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}
.proof-card h3 { margin: var(--space-5) 0 var(--space-3); }
.proof-visual { display: flex; justify-content: center; }
.proof-visual img {
  display: block;
  width: 100%;
  max-width: 340px;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.proof-visual-badge {
  align-items: center;
  background: var(--green-deep);
  border-radius: var(--radius);
  padding: var(--space-8) var(--space-5);
}
.proof-visual-badge svg { width: min(300px, 100%); height: auto; }

/* The Overview's calm status line: green = all fine, brass = a date is
   coming up, grey = received/awaiting us. */
.dash-status {
  border: 1px solid var(--line);
  border-left: 5px solid var(--green);
  background: var(--green-wash);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5);
}
.dash-status p { max-width: none; }
.dash-status-warn { border-left-color: var(--brass-deep); background: var(--brass-soft); }
.dash-status-info { border-left-color: var(--ink-mute); background: var(--paper-2); }

.dash-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin-bottom: var(--space-4);
}

/* Two form fields side by side where there is room. */
.dash-field-pair { display: grid; gap: 0 var(--space-4); }

@media (min-width: 720px) {
  .dash-field-pair { grid-template-columns: 1fr 1fr; }
  /* Label-grow fallback: inputs line up when one LABEL wraps (the pair cells
     are equal height, so growing the shorter label pushes its input down). */
  .dash-field-pair > .field { display: flex; flex-direction: column; }
  .dash-field-pair > .field > label { flex-grow: 1; }
  /* Subgrid (all modern browsers): label, control and hint each share a row
     across the pair, so the inputs sit level whatever wraps - a two-line
     label OR a hint present on only one side (the label-grow fallback alone
     pushed the hint-less field's input down by the hint height, which is
     exactly the "misaligned password fields" Rick saw on the New password /
     New password again pair). */
  @supports (grid-template-rows: subgrid) {
    .dash-field-pair { grid-template-rows: repeat(4, auto); }
    .dash-field-pair > .field { display: grid; grid-template-rows: subgrid; grid-row: span 4; align-content: start; }
    .dash-field-pair > .field > label { align-self: end; }
  }
}

/* Grouped checkboxes read as one ruled ledger block. */
.dash-fieldset {
  border: 2px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  margin: 0 0 var(--space-5);
}

.dash-fieldset legend {
  font-weight: 700;
  font-size: 1.2rem; /* Rick, 2 Sep 2026 */
  padding-inline: var(--space-2);
}

.dash-fieldset .checkbox-row:last-of-type { margin-bottom: var(--space-2); }

/* --- Onboarding checklist and completion meter (A2 step 8) -------------- */
.meter {
  height: 0.6rem;
  border-radius: 999px;
  background: var(--paper-2);
  border: 1px solid var(--line);
  overflow: hidden;
}

.meter-fill {
  height: 100%;
  background: var(--green);
  border-radius: 999px;
  transition: width 300ms var(--ease-out);
}

.meter-done-0 { width: 0; }
.meter-done-1 { width: 16.7%; }
.meter-done-2 { width: 33.3%; }
.meter-done-3 { width: 50%; }
.meter-done-4 { width: 66.7%; }
.meter-done-5 { width: 83.3%; }
.meter-done-6 { width: 100%; }

.meter-count { margin-top: var(--space-2); }

.checklist { list-style: none; margin: var(--space-4) 0 0; padding: 0; counter-reset: checklist; }

.checklist li {
  counter-increment: checklist;
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line);
  margin: 0;
}

.checklist li::before {
  content: counter(checklist, decimal-leading-zero);
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--brass);
  flex: none;
  min-width: 1.6rem;
}

.checklist .checklist-done { color: var(--ink-mute); }
.checklist .checklist-done span { text-decoration: line-through; text-decoration-color: var(--line-strong); }
.checklist .checklist-done::after {
  content: '\2713';
  margin-left: auto;
  color: var(--verified);
  font-weight: 700;
}

/* The referral milestone ladder (Refer panel, 8 Oct 2026): a reached rung is
   an achievement, not a finished chore, so it keeps its ink and gets the tick
   with no strike-through. */
.checklist .checklist-reached { font-weight: 600; }
.checklist .checklist-reached::after {
  content: '\2713';
  margin-left: auto;
  color: var(--verified);
  font-weight: 700;
}

/* --- Photo section ------------------------------------------------------ */
.dash-photo-row { display: flex; gap: var(--space-5); flex-wrap: wrap; align-items: flex-start; }

/* ROUND, matching the public profile and the result cards. It was a rounded
   square here only, so a member saw one shape while previewing and another
   the moment the photo went live. */
.dash-photo-current img,
.dash-photo-empty {
  width: 10rem;
  height: 10rem;
  border-radius: 50%;
  border: 1px solid var(--line);
  object-fit: cover;
}

.dash-photo-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--green-wash);
  color: var(--green);
  font-family: var(--font-serif);
  font-size: 2.4rem;
  font-weight: 600;
}

.dash-photo-choose { flex: 1; min-width: 16rem; }

/* THE HIDDEN-INPUT-AND-STYLED-LABEL PATTERN IS GONE (21 Aug 2026), and with it
   .photo-file-input, .photo-file-label, .field label.btn and .photo-submit.
   It only ever worked because choosing a file submitted the form on the spot,
   so nobody needed to see which file was chosen. The photo now waits for the
   profile form's own Save button, so the member has to be able to SEE what she
   picked and change her mind - which a plain file input does by itself, with
   JavaScript switched off as well. The wizard has always done it that way and
   this page now matches it. Do not restore a hidden input here. */

/* Mid-save the submit button says so and stops taking a second press. */
.btn.is-busy { opacity: 0.65; pointer-events: none; }

/* A file-size message names the file, and a filename is one unbreakable word.
   Without this it pushes its column - and the page - sideways on a phone. */
.field-error,
.field-hint { overflow-wrap: anywhere; }

/* --- Locations manager --------------------------------------------------- */
.location-entry {
  border-top: 1px solid var(--line);
  padding: var(--space-5) 0 var(--space-4);
  position: relative;
}

.location-grid { display: grid; gap: 0 var(--space-4); }

@media (min-width: 720px) {
  .location-grid { grid-template-columns: 1fr 1fr; }
}

.location-remove { margin-top: var(--space-3); }

.btn-danger-ghost {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--danger);
}

.btn-danger-ghost:hover { border-color: var(--danger); background: var(--danger-wash); color: var(--danger); }

.location-add { border-top: 1px solid var(--line); padding-top: var(--space-4); }

.location-add summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--green);
  margin-bottom: var(--space-4);
}

/* --- Badge embed --------------------------------------------------------- */
.dash-badge-preview {
  display: inline-block;
  padding: var(--space-4);
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* Badge size variations: each row shows the badge rendered at its real size
   on a preview panel, beside its dimensions and embed code. */
.badge-size {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  align-items: center;
  padding: var(--space-5) 0;
  border-top: 1px solid var(--line);
}

.badge-size:first-of-type { border-top: 0; padding-top: var(--space-2); }

.badge-size-preview {
  flex: none;
  display: grid;
  place-items: center;
  min-width: 17rem;
  min-height: 6.5rem;
  padding: var(--space-4);
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.badge-size-detail { flex: 1; min-width: 16rem; }

.badge-size-label {
  display: block;
  font-weight: 700;
  font-size: 0.95rem;
  margin-bottom: var(--space-2);
  font-variant-numeric: tabular-nums;
}

/* Tall enough to show the whole snippet without an inner scroll bar: the
   code is three lines that wrap to eight or nine on a phone, and a box that
   scrolls hides half of what the member is about to copy. main.js grows it
   to its exact content; this min-height is the no-JS floor. */
.badge-embed-code {
  font-size: 0.85rem;
  min-height: 10rem;
  color: var(--ink-soft);
  background: var(--paper-2);
  overflow: hidden;
}

/* --- Embed widget preview page (/embed/preview/*) ------------------------ */
/* The site CSP has no 'unsafe-inline' for styles, so the iframe is sized
   here rather than with a style attribute (which browsers would ignore). */
.embed-preview-frame { display: block; width: 100%; height: 520px; border: 0; }

/* The copyable snippet shows in full, soft-wrapped: copying still yields
   the single unbroken line. */
.embed-snippet {
  margin: 0 0 var(--space-5);
  padding: var(--space-4);
  font-size: 0.85rem;
  color: var(--ink-soft);
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --- Membership certificate ---------------------------------------------- */
.cert-actions { margin-bottom: var(--space-5); }

.certificate {
  max-width: 46rem;
  margin-inline: auto;
  background: var(--surface);
  border: 2px solid var(--green);
  border-radius: var(--radius);
  padding: var(--space-3);
}

.certificate-inner {
  border: 1px solid var(--brass);
  padding: clamp(var(--space-5), 6vw, var(--space-7));
  text-align: center;
}

.certificate-seal { display: flex; justify-content: center; color: var(--green); margin-bottom: var(--space-4); }

/* The short centred lines need max-width cleared, otherwise the base
   p{max-width:70ch} left-aligns their box inside the centred certificate. */
.certificate-register {
  font-family: var(--font-serif);
  font-size: 1.35rem;
  letter-spacing: 0.02em;
  color: var(--green-deep);
  margin-bottom: var(--space-2);
  max-width: none;
}

.certificate-kicker {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--brass-deep);
  margin-bottom: var(--space-5);
  max-width: none;
}

.certificate-name {
  font-size: clamp(2rem, 5vw, 2.8rem);
  margin: 0 auto var(--space-3);
  max-width: none;
}

.certificate-line { color: var(--ink-soft); margin-inline: auto; }

/* The founding mark, set in the certificate's own kicker vocabulary so the
   printed page and the PDF read as one design. Source stays sentence case;
   the capitals are typography, applied here. */
.certificate-founding {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--brass-deep);
  margin: var(--space-4) auto 0;
  max-width: none;
}

.certificate-details {
  max-width: 26rem;
  margin: var(--space-6) auto;
  text-align: left;
}

.certificate-footer-note {
  font-size: 0.85rem;
  color: var(--ink-mute);
  max-width: 36rem;
  margin: var(--space-6) auto var(--space-4);
}

.certificate-entity {
  font-family: var(--font-serif);
  font-size: 0.95rem;
  color: var(--green-deep);
  margin-bottom: 0;
  max-width: none;
}

/* Print: hide the site chrome, let the certificate own the page (A4). */
@media print {
  body.page-certificate .site-header,
  body.page-certificate .site-footer,
  body.page-certificate .skip-link,
  body.page-certificate .dash-menu,
  body.page-certificate .dash-subtabs,
  body.page-certificate .dash-noprint { display: none !important; }

  body.page-certificate { background: var(--surface); }

  body.page-certificate .section { padding-block: 0; }

  body.page-certificate .certificate {
    max-width: none;
    border-width: 2px;
    box-shadow: none;
    page-break-inside: avoid;
  }
}

/* =========================================================================
   pkg-admin-core - admin sign-in, TOTP enrolment, dashboard and settings
   Token-driven additions only; merged into main.css by the orchestrator.
   ========================================================================= */

/* The admin nav partial renders at page top level: keep its band full-bleed
   while its list lines up with .container content. */
.admin-nav ul {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 4vw, 2.5rem);
}

/* Admin screens breathe a little less than public editorial pages. */
.admin-main { padding-block: var(--space-6) var(--space-8); }

/* Sign-in: a narrow certificate on the desk. */
.admin-auth-panel {
  max-width: 28rem;
  margin-inline: auto;
  padding: var(--space-6);
}

.admin-auth-panel h1 { font-size: clamp(1.7rem, 3vw, 2.1rem); }

.admin-auth-seal { color: var(--green); }
.admin-auth-seal .seal-tick { color: var(--brass); }

/* Registration-index numerals on large seal lockups (seal.php $index):
   always brass, in any context. Dormant until a caller passes $index. */
.seal-index { color: var(--brass); }

/* TOTP enrolment. */
.admin-enrol-panel {
  max-width: 42rem;
  margin-inline: auto;
  padding: var(--space-6);
}

.admin-enrol-panel h1 { font-size: clamp(1.7rem, 3vw, 2.1rem); }

.admin-enrol-subhead {
  font-size: 1.05rem;
  margin-top: var(--space-5);
  margin-bottom: var(--space-2);
}

/* The base32 setup key: large, grouped, unmistakable. */
.totp-key {
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
  color: var(--green-deep);
  background: var(--green-wash);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  overflow-wrap: anywhere;
}

/* The QR code, drawn by main.js: always dark on white so any phone camera reads it. */
.totp-qr {
  display: block;
  width: fit-content;
  margin: var(--space-4) auto;
  padding: var(--space-4);
  background: #fff;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  line-height: 0;
}
.totp-qr[hidden] { display: none; }
.totp-qr img, .totp-qr canvas { max-width: 100%; height: auto; }

.totp-more { margin-top: var(--space-5); }
.totp-more summary { cursor: pointer; font-size: 1rem; }

/* The otpauth:// URI shown as plain text for apps that accept it. */
.totp-uri {
  font-size: 1rem;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  overflow-wrap: anywhere;
}

/* Dashboard stats that double as links into their queue or list. */
a.stat {
  display: block;
  text-decoration: none;
  transition: background-color 160ms var(--ease-out);
}

a.stat:hover { background: var(--verified-wash); }
a.stat:hover .stat-number { color: var(--green); }
a.stat .stat-label { display: block; }

.admin-quick-links {
  list-style: none;
  padding-left: 0;
  margin-bottom: 0;
}

.admin-quick-links li {
  margin: 0;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--line);
}

.admin-quick-links li:last-child { border-bottom: 0; padding-bottom: 0; }

.admin-quick-links a { font-weight: 600; }

.admin-quick-links .text-small { display: block; }

/* Settings form: readable measure, panels stacked. */
.admin-form { max-width: 46rem; }

.admin-founding-note { margin-bottom: var(--space-5); }

/* Inline field error (same rule as pkg-legal-contact; harmless duplicate). */
.field-error { color: var(--danger); }

/* --- Package: admin-ops (admin applications queue, member CRUD,
       enquiry log, email log) ---
   Token-driven only: existing custom properties, no new colours or fonts. */

/* Top gap comes from the hoisted .admin-nav band's margin (same as the admin
   dashboard); the container itself only pads the bottom. */
.admin-page { padding-block: 0 var(--space-8); }

/* ADMIN TEXT IS NOT PUBLIC PROSE.
   The global `p { max-width: 70ch }` is a READING MEASURE: about 70 characters
   a line is the comfortable span for someone reading an article, and it is
   right for every public page. It is wrong here. Admin panels sit inside the
   80rem shell, so 70ch left roughly a third of every panel empty while the
   text stacked up in a narrow column - Rick asked why, 16 Aug 2026, looking at
   the document pre-check panel. These screens are SCANNED, one member after
   another, not read.
   92ch, not `none`: an unbounded line across 1280px is genuinely hard to scan
   because the eye loses the start of the next line, so the cap is raised to
   use the panel rather than removed. Anything that sets its own max-width
   (.admin-steps, the centred blocks) still wins on specificity or later
   ordering. Only <p> is touched: list items and definition lists were never
   capped, so widening them was not the complaint and narrowing them would be a
   change with no reason behind it. */
.admin-page p { max-width: 92ch; }

.admin-page-head { margin-bottom: var(--space-5); }
.admin-page-head .admin-title { font-size: clamp(1.7rem, 3vw, 2.2rem); margin-bottom: var(--space-2); }
.admin-page-head p { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }

.admin-backlink { font-size: 0.92rem; margin-bottom: var(--space-4); }
.admin-backlink a { color: var(--ink-soft); text-decoration: none; }
.admin-backlink a:hover { color: var(--green-deep); text-decoration: underline; }

/* Queue and log filter tabs */
.admin-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
}

.admin-tabs li { margin: 0; }

.admin-tabs a {
  display: inline-block;
  padding: 0.35rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
}

.admin-tabs a:hover { border-color: var(--line-strong); color: var(--green-deep); }

.admin-tabs a[aria-current="page"] {
  background: var(--green-wash);
  border-color: var(--green);
  color: var(--green-deep);
}

/* Tables in the admin panels */
.admin-table { width: 100%; font-size: 0.95rem; }
.admin-table td { vertical-align: top; }
.admin-table .status-pill { white-space: nowrap; }
.admin-page-wide { max-width: none; }
/* Applications list: the applicant's photo in a circle beside the name, initials on a neutral disc when none. */
.admin-person { display: flex; align-items: center; gap: var(--space-3); }
/* 80px, name 1.1rem (Rick, 11 Oct 2026). */
.admin-avatar { flex: 0 0 auto; width: 80px; height: 80px; border-radius: 50%; object-fit: cover; }
.admin-person-name { font-size: 1.1rem; }
.admin-avatar-empty { display: inline-flex; align-items: center; justify-content: center; background: var(--paper-2); border: 1px solid var(--line); color: var(--ink-soft); font-size: 1.5rem; font-weight: 700; }
.admin-row-btn { white-space: nowrap; padding: 0.45rem 0.8rem; }
/* Verify panel: the Recommended action box. The admin's gold "your turn" tone
   (the same pair as .dash-status-warn), never grey (Rick, 11 Oct 2026). */
.recommend-box { margin-bottom: var(--space-5); padding: var(--space-4) var(--space-5); background: var(--brass-soft); border: 2px solid var(--brass); border-left: 8px solid var(--brass); border-radius: var(--radius); color: var(--ink); }
.recommend-kicker { margin: 0 0 var(--space-1); font-size: 0.78rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink); }
.recommend-title { margin: 0 0 var(--space-3); font-size: 1.2rem; }
.recommend-steps { margin: 0 0 var(--space-3); padding-left: 1.4rem; }
.recommend-steps li + li { margin-top: var(--space-2); }
/* Plain links in the box read in ink; a button keeps its own colours (22 Oct
   2026: this rule, at one class and one element, outweighed .btn-primary, so
   "Back to the queue" in the Next step box showed ink on the button colour). */
.recommend-box a:not(.btn) { color: var(--ink); }
/* The WHAT admission review page (21 Oct 2026, "review pages show only the
   steps"): the steps lead, the rest folds under Details, and nothing on the
   page is under 16px, the box's small print and its kicker included. */
.admission-review :is(.recommend-kicker, .text-small, .field-hint, code, small, summary, dt, label, .btn-sm) { font-size: 1rem; }
.admission-review .recommend-kicker { letter-spacing: 0; text-transform: none; }
.admission-review .recommend-steps code { overflow-wrap: anywhere; }
.admission-details { margin: var(--space-5) 0; padding: var(--space-3) var(--space-4); border: 1px solid var(--line); border-radius: var(--radius); }
.admission-details > summary { font-weight: 700; cursor: pointer; }
.admission-details[open] > summary { margin-bottom: var(--space-3); }
.admission-details dd { overflow-wrap: anywhere; }
/* The verify panel's folded reading (MLD, 21 Oct 2026): its summary reads as a control. */
.verify-reading > summary { font-weight: 700; cursor: pointer; margin-bottom: var(--space-2); }
/* Members list: a clear gap between the name and its chips (Rick, 21 Sep
   2026: the Featured and Founding chips sat hard against the name). */
.member-name-cell strong { margin-right: 0.55rem; }
.member-name-cell .chip + .chip { margin-left: 0.2rem; }
/* The pre-check verdict table: one heading row per document read (18 Sep 2026). */
.doc-check-table tr.doc-check-group th { text-align: left; font-weight: 700; padding-top: var(--space-4); border-bottom: 2px solid var(--line); }

/* Two-column working layout (applicant beside documents, and similar) */
.admin-split { display: grid; gap: var(--space-5); align-items: start; }

@media (min-width: 900px) {
  .admin-split { grid-template-columns: 1fr 1fr; }
}

/* Definition lists on detail pages */
.admin-dl { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-2) var(--space-5); margin: 0 0 var(--space-5); }
.admin-dl dt { color: var(--ink-mute); font-size: 0.9rem; padding-top: 0.1rem; }
.admin-dl dd { margin: 0; }

.admin-plain-list { list-style: none; margin: 0 0 var(--space-5); padding: 0; }
.admin-plain-list li { margin: 0 0 var(--space-3); padding-bottom: var(--space-3); border-bottom: 1px solid var(--line); }
.admin-plain-list li:last-child { border-bottom: 0; }

/* A multi-line alert needs air between its lines. Without it the warning reads
   as one block and the instruction at the end - the only part that tells the
   operator what to DO - is the part that gets skimmed past. Scoped to p + p,
   so every single-paragraph error message is untouched. */
.form-error p + p,
.form-success p + p { margin-top: var(--space-2); }
/* The dashboard flash sits in a centred card: centre its words too (Rick, 2 Sep 2026). */
.page-dashboard .dash-flash { text-align: center; }

/* The document pre-check summary. Short bullet points, plain disc markers, one
   fact each - the shape Rick asked for on 16 Aug 2026 in place of the
   paragraph that used to sit here. */
.doc-check-summary { margin: 0 0 var(--space-4); padding-left: 1.3rem; }
.doc-check-summary li { margin-bottom: var(--space-2); }
.doc-check-summary li:last-child { margin-bottom: 0; }

.admin-prewrap { white-space: pre-wrap; }

/* Side-by-side row actions (nominations queue: update form + delete form) */
.admin-inline-forms { display: flex; flex-wrap: wrap; gap: var(--space-5); align-items: end; }
.admin-inline-forms form:first-child { flex: 1 1 22rem; }

/* Inline document viewer */
.doc-figure { margin: 0 0 var(--space-5); }
.doc-figure figcaption { margin-bottom: var(--space-3); }
.doc-figure figcaption strong { display: block; }

.doc-figure img {
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
}

/* The A5 verification checklist (working aid, not stored) */
.check-list { list-style: none; margin: 0; padding: 0; max-width: 52rem; }
.check-list li { margin: 0; border-bottom: 1px solid var(--line); }
.check-list li:last-child { border-bottom: 0; }
.check-list label { display: flex; gap: var(--space-3); align-items: flex-start; padding: var(--space-3) 0; cursor: pointer; }
.check-list input[type="checkbox"] { flex: none; width: 1.15rem; height: 1.15rem; margin-top: 0.2rem; accent-color: var(--green); }

/* Form layouts inside panels */
.admin-form-grid { display: grid; gap: 0 var(--space-5); }
/* One rule between school rows on the trainings editor (Rick, 18 Sep 2026).
   The field above already carries its own bottom margin, so the rule only
   adds space below. */
.admin-training-rule { border-top-width: 2px; margin: 0 0 var(--space-5); }
/* An Other-courses row: Course, Detail and Certificate document on ONE line
   from a comfortable width (Rick, 18 Sep 2026); two columns below that. */
@media (min-width: 900px) {
  .admin-form-grid.admin-form-grid-3 { grid-template-columns: minmax(0, 2fr) minmax(0, 1.4fr) minmax(0, 2fr); }
}

@media (min-width: 700px) {
  .admin-form-grid { grid-template-columns: 1fr 1fr; }
}

/* A fee item's three fields (name / minutes / price) on ONE row from tablet up;
   name gets the most width, minutes and price stay narrow. minmax(0,..) stops a
   long name from blowing the grid out. Shared by the admin concierge builder,
   the member editable preview and the member dashboard fee editors. */
.fee-fields-row { display: grid; gap: 0 var(--space-4); }
@media (min-width: 640px) {
  .fee-fields-row { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); }
}
/* Detailed price rows (features.fee_rows_detailed, 1 Nov 2026): what the
   price includes takes the row's full width under the name and price; the
   link and the date share the line under it. Classes that only exist where
   the pack switches detailed rows on. */
.fee-row .fee-detail,
.fee-fields-row .fee-detail { grid-column: 1 / -1; }
@media (min-width: 640px) {
  .fee-row .fee-detail:not(.fee-detail-wide),
  .fee-fields-row .fee-detail:not(.fee-detail-wide) { grid-column: auto / span 1; }
  .fee-row .fee-detail-wide + .fee-detail,
  .fee-fields-row .fee-detail-wide + .fee-detail { grid-column: 1 / span 1; }
}
/* On the profile: what a detailed price includes, its date and its source,
   under the price; the clinic's team as name and role. */
.leader-row-detail { margin: -0.25rem 0 var(--space-3); color: var(--ink-soft); font-size: 1rem; line-height: 1.5; }
.leader-row-detail a { font-weight: 600; }
.profile-fee-confirm { margin: var(--space-3) 0 0; font-size: 1rem; color: var(--ink-soft); }
.profile-team { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
@media (min-width: 640px) { .profile-team { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.profile-team li { display: flex; flex-direction: column; padding: var(--space-3) var(--space-4); border-left: 3px solid var(--line-strong); background: var(--surface); }
.profile-team li span { color: var(--ink-soft); }

.admin-check-grid { display: grid; gap: var(--space-2); margin-bottom: var(--space-5); }

@media (min-width: 700px) {
  .admin-check-grid { grid-template-columns: 1fr 1fr; }
}

.check-label { display: flex; gap: var(--space-2); align-items: flex-start; font-size: 0.97rem; cursor: pointer; }
.check-label input[type="checkbox"] { flex: none; width: 1.05rem; height: 1.05rem; margin-top: 0.25rem; accent-color: var(--green); }

/* Status-change blocks (lapse / reinstate / remove) */
.admin-status-form { padding-bottom: var(--space-4); margin-bottom: var(--space-4); border-bottom: 1px solid var(--line); }
.admin-status-form h3 { font-size: 1.05rem; }
.admin-status-form .btn { margin-top: var(--space-3); }

/* Destructive areas keep the same tokens, flagged with the danger hue */
.danger-panel { border-color: var(--danger); }
.danger-panel > h2 { color: var(--danger); }

.admin-error-text { color: var(--danger); }

/* ---- Admin member page: stage banner + accordion sections ------------------
   The stage banner shows where a member is (a stepper) and the one next action;
   its tone (action/wait/done/warn) tints the accent. The record is then broken
   into collapsible <details> accordion sections. */
.admin-stage {
  --stage-accent: var(--ink-mute);
  border: 1px solid var(--line);
  border-left: 5px solid var(--stage-accent);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5);
  display: grid;
  gap: var(--space-4);
}
/* Outstanding side jobs. Sits under the stage banner and OUTSIDE every
   accordion, because the thing it exists to say was previously only visible to
   someone who already knew to open the right collapsed section. */
.admin-todo {
  border: 1px solid var(--danger);
  border-left: 5px solid var(--danger);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5);
}
.admin-todo-title { margin: 0 0 var(--space-3); font-size: 1.05rem; color: var(--danger); }
.admin-todo-list { list-style: none; padding: 0; margin: 0; }
.admin-todo-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line);
}
.admin-todo-list li:first-child { border-top: 0; padding-top: 0; }
.admin-todo-list li > span { flex: 1 1 22rem; }
.admin-todo-list .btn { flex: 0 0 auto; }

.admin-stage-action { --stage-accent: var(--brass-deep); }
.admin-stage-wait   { --stage-accent: var(--ink-mute); }
.admin-stage-done   { --stage-accent: var(--green); }
.admin-stage-warn   { --stage-accent: var(--danger); }

.admin-stage-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
}
.admin-stage-step {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 1rem; /* Rick, 2 Sep 2026 */
  color: var(--ink-mute);
}
.admin-stage-dot {
  flex: 0 0 auto;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  background: var(--paper-2);
  color: var(--ink-mute);
  border: 1px solid var(--line);
}
.admin-stage-step.is-done { color: var(--ink-soft); }
.admin-stage-step.is-done .admin-stage-dot { background: var(--green-wash); color: var(--green); border-color: var(--green-wash); }
.admin-stage-step.is-current { color: var(--ink); font-weight: 700; }
.admin-stage-step.is-current .admin-stage-dot { background: var(--stage-accent); color: var(--on-green); border-color: var(--stage-accent); }
.admin-stage-step-label { white-space: nowrap; }

.admin-stage-label { font-size: 1.125rem; } /* 18px, Rick 2 Sep 2026 */
.admin-stage-badge {
  display: inline-block;
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.12em 0.55em;
  border-radius: 999px;
  background: var(--stage-accent);
  color: var(--on-green);
  vertical-align: middle;
  margin-right: var(--space-2);
}
.admin-stage-next { color: var(--ink-soft); margin-top: var(--space-1); }
.admin-stage-now .btn { margin-top: var(--space-3); }
/* Guided review screen: a link and a form side by side under the draft. */
.admin-review-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-top: 1.25rem; } /* 20px clear of the draft box (Rick, 18 Sep 2026) */
/* Photos panel: profile photo + gallery tiles, each with its own small form. */
.admin-photos { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: var(--space-4); }
.admin-photo-card { border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--paper-2); padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); }
/* The thumbnail only: the full-size dialog inside the same card must keep its own size. */
.admin-photo-card > img, .admin-photo-zoom img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius); display: block; }
/* The profile photo thumbnail opens its full-size view (11 Oct 2026). */
.admin-photo-zoom { display: block; width: 100%; padding: 0; border: 0; background: none; border-radius: var(--radius); cursor: zoom-in; }
.admin-photo-zoom:focus-visible { outline: 3px solid var(--brass); outline-offset: 2px; }
.admin-photo-empty { aspect-ratio: 4 / 3; display: flex; align-items: center; justify-content: center; border: 1px dashed var(--line); border-radius: var(--radius); color: var(--ink-mute); font-size: 0.9rem; }
.admin-photo-label { margin: 0; font-weight: 700; font-size: 0.9rem; }
.admin-photo-card .field { margin: 0; }
.admin-photo-card input[type=file] { font-size: 0.85rem; max-width: 100%; }
/* The file control and its button sat touching: the form is ONE flex child
   of the card, so the card's gap never reached inside it (Rick, 18 Sep 2026).
   The actions row holds Replace beside Download. */
.admin-photo-card form { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-3); }
.admin-photo-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* Photo polish (21 Oct 2026): Original and New side by side at the same
   size, each in a square box; the original keeps its own shape inside it.
   The profile photo card spans two tiles so the pair is not postage stamps. */
.admin-photo-card-compare { grid-column: span 2; }
@media (max-width: 40rem) { .admin-photo-card-compare { grid-column: auto; } }
.photo-compare { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); max-width: 30rem; }
.photo-compare-one { grid-template-columns: minmax(0, 1fr); max-width: 15rem; }
.photo-compare-big { max-width: none; width: min(64rem, 100%); }
.photo-compare-big.photo-compare-one { width: min(32rem, 100%); }
.photo-compare-item { margin: 0; min-width: 0; }
.photo-compare-frame { aspect-ratio: 1 / 1; background: var(--paper-2, #f4f2ee); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; display: flex; align-items: center; justify-content: center; }
.photo-compare-frame img { width: 100%; height: 100%; object-fit: contain; display: block; }
.photo-compare-item figcaption { margin-top: var(--space-1); font-weight: 700; font-size: 1rem; }
.photo-compare-status { margin: var(--space-2) 0 0; font-size: 1rem; max-width: 40rem; }
.photo-compare-status.is-look { font-weight: 600; }
.photo-compare-action { margin: var(--space-2) 0 0; }
/* "See them full size": a quiet text button, so the one real action stays the only button. */
.admin-photo-full { align-self: flex-start; background: none; border: 0; padding: 0; color: var(--ink); font: inherit; font-size: 1rem; text-decoration: underline; text-underline-offset: 3px; cursor: zoom-in; }
/* A grid item sizes to its content unless told otherwise: without this the
   pair pushed the member record 13px past a 375px phone. */
.admin-photo-block { min-width: 0; }
/* The Higgsfield connection block, then (once connected) the pause setting
   below a rule with real room either side (Rick, 21 Oct 2026: "dont you know
   the meaning of creating spacing / gaps?"). */
.photo-polish-connection { margin: var(--space-4) 0 0; }
.photo-polish-action { margin: var(--space-4) 0 0; }
.photo-polish-connection.is-connected { padding-bottom: var(--space-6); margin-bottom: var(--space-6); border-bottom: 1px solid var(--line, rgba(0,0,0,.12)); }
/* Disconnect Higgsfield: a quiet text button (it posts its own small form). */
.photo-polish-disconnect { background: none; border: 0; padding: 0; color: var(--ink); font: inherit; font-size: 1rem; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.admin-photo-block .photo-compare-action + form, .admin-photo-block .photo-compare-status + form, .admin-photo-block .photo-compare + form { margin-top: var(--space-4); }
.gallery-dialog .photo-compare-big { margin: 0 auto; }
.gallery-dialog .photo-compare-big .photo-compare-frame { max-height: 70vh; }
/* The member's "finishing your photo" line (dashboard, onboarding, preview). */
.photo-polish-line { margin: var(--space-2) 0 0; font-size: 1.125rem; font-weight: 600; color: var(--ink); }
.photo-polish-line[hidden] { display: none; }
.btn-icon { display: inline-flex; align-items: center; gap: 0.4rem; }
.btn-icon svg { width: 1em; height: 1em; flex: none; }
.btn-icon-only { display: inline-flex; align-items: center; justify-content: center; padding: 0.55rem 0.7rem; }
.btn-icon-only svg { width: 1.15em; height: 1.15em; flex: none; }
/* Shown only when main.js has NOT run (the mirror of .js-only): a plain
   submit button behind a file input that otherwise uploads on choice. */
html.js .js-hide { display: none !important; }
/* The drafted bio, read before it is sent: body size, boxed, never the public pull-quote style. */
.admin-draft-text { border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--paper-2); padding: var(--space-4) var(--space-5); white-space: normal; }
.admin-draft-text p { margin: 0 0 var(--space-3); }

.admin-section {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  margin-bottom: var(--space-4);
}
.admin-section-head {
  list-style: none;
  cursor: pointer;
  padding: var(--space-4) var(--space-5);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  border-radius: var(--radius-lg);
}
.admin-section-head::-webkit-details-marker { display: none; }
.admin-section-head:hover { background: var(--paper-2); }
.admin-section-title { font-family: var(--font-serif); font-size: 1.2rem; font-weight: 600; }
.admin-section-head::after {
  content: "";
  margin-left: auto;
  width: 0.65rem;
  height: 0.65rem;
  border-right: 2px solid var(--ink-mute);
  border-bottom: 2px solid var(--ink-mute);
  transform: rotate(45deg);
  transition: transform 150ms var(--ease-out);
}
.admin-section[open] > .admin-section-head::after { transform: rotate(-135deg); }
.admin-section[open] > .admin-section-head {
  border-bottom: 1px solid var(--line);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.admin-section-body { padding: var(--space-5); }
.admin-section-body > :first-child { margin-top: 0; }

/* Numbered operator instructions. One step per line, using the full width of
   the panel: the global `p { max-width: 70ch }` is a reading measure for public
   prose and has no business narrowing an admin instruction. */
.admin-steps {
  margin: 0 0 var(--space-5);
  padding-left: 1.6rem;
  max-width: none;
  color: var(--ink-soft);
}
.admin-steps > li {
  max-width: none;
  margin-bottom: var(--space-3);
  padding-left: 0.3rem;
}
.admin-steps > li:last-child { margin-bottom: 0; }
.admin-steps > li::marker { font-weight: 700; color: var(--ink); }
.admin-steps strong { color: var(--ink); }

/* The live version: which step you are on, at a glance. */
.admin-steps-live > li { margin-bottom: var(--space-4); }
.admin-steps-live > li.is-done { color: var(--ink-mute); }
.admin-steps-live > li.is-done::marker { color: var(--green); }
.admin-steps-live > li.is-done > strong { color: var(--ink-mute); }
.admin-steps-live > li.is-current {
  background: var(--brass-soft);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  margin-left: -0.4rem;
}
.admin-steps-live > li.is-current::marker { color: var(--brass-deep); }
.admin-steps-live > li.is-todo { color: var(--ink-mute); }
/* An AUTOMATIC step is not the operator's turn and must never be highlighted
   as one. Muted like a todo, but it can never take the brass "do this next"
   treatment because the class is exclusive. */
.admin-steps-live > li.is-auto { color: var(--ink-mute); }
.admin-steps-live .status-pill { margin-left: var(--space-2); vertical-align: middle; }

/* VerifiedPractitioner setup block: the seven values to copy across. */
.admin-copyblock {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  margin: var(--space-5) 0;
  background: var(--paper);
}
.admin-copy-list { margin: 0; }
.admin-copy-list dt {
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--ink-soft);
  margin-top: var(--space-3);
}
.admin-copy-list dt:first-of-type { margin-top: 0; }
.admin-copy-list dd {
  margin: var(--space-1) 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3);
}
.admin-copy-value {
  flex: 1 1 18rem;
  word-break: break-word;
  font-family: var(--font-sans);
}
.admin-copy-empty { color: var(--ink-mute); font-style: italic; }
.admin-copy-btn { flex: 0 0 auto; }
.admin-copy-btn.is-copied { border-color: var(--green); color: var(--green); }
/* Clipboard refused: the text is selected instead, and the button says so. */
.admin-copy-btn.is-copy-failed { border-color: var(--brass-deep); color: var(--brass-deep); }
.admin-copy-value::selection { background: var(--brass-soft); }
.admin-section-danger { border-color: var(--danger); }
.admin-section-danger > .admin-section-head .admin-section-title { color: var(--danger); }

/* Filter bar on list pages */
.filter-bar { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-end; margin-bottom: var(--space-5); }
.filter-bar .field { margin-bottom: 0; }
.filter-bar input[type="search"] { min-width: 18rem; }

/* Inline row-level action forms */
.admin-inline-form { display: inline-block; margin: 0 var(--space-2) var(--space-2) 0; }
/* A course name is long ("LTA Fill and Flush: Lymphoedema Management of the Arm
   and Trunk"), and an operator cannot rename what they cannot read. The field
   shrinks with the column rather than clipping the name. */
.admin-course-rename { display: block; }
.admin-course-rename input[type="text"] { width: 100%; min-width: 0; margin-bottom: var(--space-2); }
.admin-courses-table td:first-child { min-width: 24rem; }
.admin-course-flags { margin: var(--space-2) 0 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }
.admin-course-flags:empty { display: none; }

/* Enquiry excerpts expand in place; content never leaves the page */
.admin-excerpt { max-width: 26rem; }
.admin-excerpt summary { cursor: pointer; color: var(--ink-soft); }
.admin-excerpt summary:hover { color: var(--green-deep); }
.admin-excerpt p { margin-top: var(--space-3); }

/* Pagination on the long logs */
.pagination { display: flex; gap: var(--space-4); align-items: center; margin-top: var(--space-5); }

/* ===========================================================================
   Compare page (/compare) and the profile's experience note
   =========================================================================== */

/* The member's own words about the one term this brand asks about. A quote
   block, because that is what it is: not our finding, theirs. Deliberately in
   About and never in the Verification card, so it can never borrow the
   authority of a fact somebody checked. */
.profile-experience-note {
  margin: var(--space-3) 0 0;
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--line-strong);
  background: var(--paper-2);
  color: var(--ink-soft);
  font-style: normal;
}

/* Wide content scrolls inside its own box. The page body must never scroll
   sideways, and three member columns plus the row labels will exceed a phone
   long before they exceed a desktop. */
.cmp-scroll {
  overflow-x: auto;
  margin-bottom: var(--space-5);
  /* The positioning context for the table's visually-hidden text: without it
     that text is placed against the page, outside this box's clip, and the
     whole document scrolled sideways at 375px (13 Oct 2026). */
  position: relative;
  min-width: 0;
}

.cmp-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 34rem;
}

.cmp-table th,
.cmp-table td {
  padding: var(--space-3) var(--space-4);
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line);
}

/* The row labels stay put while the member columns scroll under them:
   without this, scrolling right on a phone leaves a grid of bare values with
   nothing saying what any of them are. */
.cmp-table tbody th[scope="row"],
.cmp-table tfoot th[scope="row"] {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--paper);
  font-weight: 600;
  color: var(--ink-soft);
  min-width: 11rem;
}

.cmp-table thead th { border-bottom: 2px solid var(--line-strong); }

/* THE HONEST PART OF THIS TABLE. A grid implies every row was established the
   same way; these headings are what stop it saying that. Styled as loud as a
   section heading precisely because they are load-bearing, not decoration. */
.cmp-group th {
  position: sticky;
  left: 0;
  background: var(--green-wash);
  color: var(--green-deep);
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--line-strong);
}

/* The column heads are inside <th>, and the base th rule uppercases with
   letter-spacing - which is right for a row LABEL and wrong for a person's
   name and town. Reset it here rather than weakening the base rule. */
.cmp-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 10rem;
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink);
}

.cmp-head img {
  width: 4rem;
  height: 4rem;
  border-radius: 50%;
  object-fit: cover;
  margin-bottom: var(--space-1);
}

.cmp-name { font-weight: 600; }

.cmp-town {
  font-size: 0.85rem;
  color: var(--ink-mute);
}

/* Absence must read as absence, never as a fact. A blank cell in a comparison
   is ambiguous - did nobody ask, or did they say no? - so every empty value
   says which, quietly. */
.cmp-none { color: var(--ink-mute); }

.cmp-sub {
  display: block;
  margin-top: var(--space-1);
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--ink-mute);
}

.cmp-list {
  margin: 0;
  padding-left: 1.1rem;
  font-size: 0.9rem;
  line-height: 1.6;
}

.cmp-note { max-width: none; }

/* WHAT compare (conversion review SH-02, 10 Oct 2026). The scroll box is the
   positioning context for the table's visually-hidden text: without it that
   text is placed against the page, outside the box's clip, and widened the
   whole document at 375px. The box may shrink inside any flex or grid parent
   (min-width: 0) and carries a visible "Swipe to compare" hint on phones. */
.cmp-scroll-what {
  position: relative;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.cmp-table-what { min-width: 0; }
.cmp-table-what .cmp-head { min-width: 9rem; }
.cmp-table-what td p { margin: 0 0 var(--space-1); font-size: 0.9rem; }
.cmp-hint { display: none; margin: 0 0 var(--space-2); font-size: 0.85rem; font-weight: 600; color: var(--ink-soft); }
.cmp-hint::after { content: " \2192"; }
.cmp-missing { margin: 0 0 var(--space-3); padding: var(--space-3) var(--space-4); border-left: 3px solid var(--line-strong); background: var(--paper-2); }
@media (max-width: 40rem) {
  .cmp-hint { display: block; }
  .cmp-table-what { min-width: 30rem; }
  .cmp-table-what th,
  .cmp-table-what td { padding: var(--space-2) var(--space-3); }
  .cmp-table-what tbody th[scope="row"],
  .cmp-table-what tfoot th[scope="row"] { min-width: 6.5rem; max-width: 7.5rem; font-size: 0.85rem; }
  .cmp-table-what .cmp-head { min-width: 8rem; }
}

/* -------------------------------------------------------------------------
   Icon cards (For Therapists "What membership includes", About governance).
   One icon set, one layout: the icon holds a fixed column on the left so
   every heading in a row starts on the same line, and it drops above the
   text on a phone rather than squeezing the words into a narrow gutter.
   ------------------------------------------------------------------------- */
.card-iconed {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
}

.card-iconed-body { min-width: 0; }

.card-icon {
  flex: none;
  width: 3.25rem;
  height: 3.25rem;
  margin-top: 0.15rem;
}

@media (max-width: 479.98px) {
  .card-iconed { flex-direction: column; gap: var(--space-3); }
}

/* Reason cards (.reason-grid, .reason-card): short reasons to join, each an
   icon in the speech bubble over a heading and a sentence or two (the WHAT
   practitioners page's "Why counsellors choose WhatCounsellor", Rick 14 Oct
   2026: six of them, three in a row). Three in a row on desktop, two on a
   tablet, one on a phone. Soft filled panels in the page's own paper rather
   than bordered boxes ("fewer boxes and borders", 2 Jul 2026), so they sit
   on a white band; on a tinted band they turn white. */
.reason-grid {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 640px) {
  .reason-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 960px) {
  .reason-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.reason-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-6);
  background: var(--paper);
  border-radius: var(--radius-lg);
}

.reason-card h3 { margin: var(--space-2) 0 0; font-size: 1.25rem; }
.reason-card p { margin: 0; color: var(--ink-soft); }
.section-tint .reason-card { background: var(--surface); }

/* Icon boxes (.icon-box-grid, .icon-box): a list of short lines, each an
   icon over one sentence in the reason cards' soft panel (the pricing page's
   "What every membership includes", Rick 23 Oct 2026: "stylish icon boxes,
   4 in one row and 4 in the other"). Four in a row on desktop, two on a
   tablet; on a phone each box becomes a row, icon beside the words, so eight
   boxes stay short. A wrapping flex row rather than a grid, so a short last
   row (MLD's eleven, ten in the US) sits centred under the full ones. A WHAT
   brand puts the icon in the speech bubble; MLD, which never shows the
   bubble, in a round chip (.icon-chip). */
.icon-box-grid {
  --icon-box-gap: var(--space-5);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--icon-box-gap);
  margin-bottom: 0;
  padding: 0;
  list-style: none;
}

.icon-box {
  flex: 1 1 100%;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin: 0;
  padding: var(--space-4) var(--space-5);
  background: var(--paper);
  border-radius: var(--radius-lg);
  color: var(--ink);
  line-height: 1.5;
}

.section-tint .icon-box { background: var(--surface); }
.icon-box-text { min-width: 0; }

.icon-chip {
  --bubble-size: 4rem;
  display: inline-grid;
  place-items: center;
  flex: none;
  width: var(--bubble-size);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--green-wash);
}

@media (min-width: 640px) {
  .icon-box {
    flex: 0 0 calc((100% - var(--icon-box-gap)) / 2);
    flex-direction: column;
    justify-content: flex-start;
    text-align: center;
    padding: var(--space-6) var(--space-5);
  }
}

@media (min-width: 960px) {
  .icon-box { flex-basis: calc((100% - 3 * var(--icon-box-gap)) / 4); }
}

/* Watercolour cards (the WHAT master home's common reasons, every card a
   watercolour on paper, Rick 29 Sep 2026: "I love the watercolours").
   The painted paper is a touch warmer than any band; multiply lets it
   disappear into the ground instead of showing its rectangle. Moved here
   from WhatHypno's theme so every WHAT brand's watercolours sit the same
   way; MLD's templates do not use the class. */
.watercolour-cards .editorial-item img { mix-blend-mode: multiply; }
/* The card's own fade made it a separate layer while it ran, so the paper
   multiplied against nothing and showed white for a moment (Rick, 13 Oct
   2026). The card stays put and its image and words fade instead: an
   element's own opacity never cuts it off from the band behind it. */
.js.reveal-ready .watercolour-cards .editorial-item.reveal { opacity: 1; transform: none; transition: none; }
.js.reveal-ready .watercolour-cards .editorial-item.reveal > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out);
}
.js.reveal-ready .watercolour-cards .editorial-item.reveal.revealed > * { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js.reveal-ready .watercolour-cards .editorial-item.reveal > * { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* -------------------------------------------------------------------------
   Speech-bubble frame (.bubble-frame): the WHAT family signature, the open
   speech bubble of the Final square icons (Logos-for-web/Final/*-sq.svg,
   one outline shared by every brand), drawn around SMALL things only: step
   numbers, icons, small portraits and quote marks. Never a hero or a large
   photograph (Rick, 29 Sep 2026: at that size it reads as a block of
   colour, not an elegant frame). The outline is a mask,
   public/assets/img/shape/speech-bubble-frame.svg, painted in --bubble-line,
   so it takes each brand's colour from its tokens; whatever it holds sits
   centred in the bubble's body, above the tail (the padding is measured on
   the outline: the stroke is 8.5% of its width, the tail 29.5%). Size it with
   --bubble-size. Opt-in by class: only the WHAT master templates use it, so
   MLD's pages never show it.
   ------------------------------------------------------------------------- */
.bubble-frame {
  --bubble-size: 3.25rem;
  position: relative;
  box-sizing: border-box;
  display: inline-grid;
  place-items: center;
  flex: none;
  width: var(--bubble-size);
  min-width: 0;
  aspect-ratio: 54 / 56.606;
  /* Not percentages: a percentage padding is taken from the PARENT's width. */
  padding: calc(var(--bubble-size) * 0.085) calc(var(--bubble-size) * 0.085) calc(var(--bubble-size) * 0.295);
  line-height: 1;
  color: var(--bubble-ink, var(--green));
}
.bubble-frame::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--bubble-line, var(--brand-primary, var(--green)));
  -webkit-mask: url('../img/shape/speech-bubble-frame.svg') center / 100% 100% no-repeat;
  mask: url('../img/shape/speech-bubble-frame.svg') center / 100% 100% no-repeat;
  pointer-events: none;
}
.bubble-frame > img,
.bubble-frame > svg { position: relative; display: block; width: 78%; height: auto; margin: 0; }
/* On a dark band the outline takes the accent and the number the light ink. */
.section-green .bubble-frame { --bubble-line: var(--brass-on-dark); --bubble-ink: var(--on-green); }

/* A step number in the frame: the ledger numbers of the master pages. */
.index-num.bubble-frame {
  --bubble-size: 3rem;
  min-width: 0;
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 700;
  color: var(--bubble-ink, var(--green));
}
.index-list > li:has(> .bubble-frame) { align-items: flex-start; }
.index-list > li:has(> .bubble-frame) > p { padding-top: 0.45rem; }

/* An icon in the frame: the icon cards and the founding steps. The icon is
   already drawn in the brand colour, so the frame takes the soft accent and
   the drawing stays the thing the eye reads. */
.bubble-frame-icon { --bubble-size: 4rem; --bubble-line: var(--brass); }
.bubble-frame-icon > .card-icon { width: 94%; height: auto; margin: 0; }
/* A line icon (Lucide, drawn as a mask) sits at under half the bubble, so the
   outline never crowds it (Rick, 7 Oct 2026). */
.line-icon { display: block; width: calc(var(--bubble-size) * 0.46); aspect-ratio: 1; margin: 0; background: var(--bubble-ink, var(--green)); -webkit-mask-position: center; mask-position: center; -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; }
.bubble-frame > .line-icon { position: relative; }
/* One rule per Lucide icon: the page's CSP (style-src 'self') refuses inline style attributes, so each icon has a class, li-<name>. */
.li-badge-check { -webkit-mask-image: url(/assets/img/icons/lucide/badge-check.svg); mask-image: url(/assets/img/icons/lucide/badge-check.svg); }
.li-chart-column { -webkit-mask-image: url(/assets/img/icons/lucide/chart-column.svg); mask-image: url(/assets/img/icons/lucide/chart-column.svg); }
.li-circle-check { -webkit-mask-image: url(/assets/img/icons/lucide/circle-check.svg); mask-image: url(/assets/img/icons/lucide/circle-check.svg); }
.li-file-up { -webkit-mask-image: url(/assets/img/icons/lucide/file-up.svg); mask-image: url(/assets/img/icons/lucide/file-up.svg); }
.li-hand-coins { -webkit-mask-image: url(/assets/img/icons/lucide/hand-coins.svg); mask-image: url(/assets/img/icons/lucide/hand-coins.svg); }
.li-info { -webkit-mask-image: url(/assets/img/icons/lucide/info.svg); mask-image: url(/assets/img/icons/lucide/info.svg); }
.li-link { -webkit-mask-image: url(/assets/img/icons/lucide/link.svg); mask-image: url(/assets/img/icons/lucide/link.svg); }
.li-lock { -webkit-mask-image: url(/assets/img/icons/lucide/lock.svg); mask-image: url(/assets/img/icons/lucide/lock.svg); }
.li-mail { -webkit-mask-image: url(/assets/img/icons/lucide/mail.svg); mask-image: url(/assets/img/icons/lucide/mail.svg); }
.li-map-pin { -webkit-mask-image: url(/assets/img/icons/lucide/map-pin.svg); mask-image: url(/assets/img/icons/lucide/map-pin.svg); }
.li-message-square-text { -webkit-mask-image: url(/assets/img/icons/lucide/message-square-text.svg); mask-image: url(/assets/img/icons/lucide/message-square-text.svg); }
.li-pencil-line { -webkit-mask-image: url(/assets/img/icons/lucide/pencil-line.svg); mask-image: url(/assets/img/icons/lucide/pencil-line.svg); }
.li-scale { -webkit-mask-image: url(/assets/img/icons/lucide/scale.svg); mask-image: url(/assets/img/icons/lucide/scale.svg); }
.li-scroll-text { -webkit-mask-image: url(/assets/img/icons/lucide/scroll-text.svg); mask-image: url(/assets/img/icons/lucide/scroll-text.svg); }
.li-search-check { -webkit-mask-image: url(/assets/img/icons/lucide/search-check.svg); mask-image: url(/assets/img/icons/lucide/search-check.svg); }
.li-shield-check { -webkit-mask-image: url(/assets/img/icons/lucide/shield-check.svg); mask-image: url(/assets/img/icons/lucide/shield-check.svg); }
.li-user-round-check { -webkit-mask-image: url(/assets/img/icons/lucide/user-round-check.svg); mask-image: url(/assets/img/icons/lucide/user-round-check.svg); }
/* The profile's row and heading icons (the decision card fix round, 22 Oct 2026). */
.li-briefcase { -webkit-mask-image: url(/assets/img/icons/lucide/briefcase.svg); mask-image: url(/assets/img/icons/lucide/briefcase.svg); }
.li-calendar { -webkit-mask-image: url(/assets/img/icons/lucide/calendar.svg); mask-image: url(/assets/img/icons/lucide/calendar.svg); }
.li-calendar-clock { -webkit-mask-image: url(/assets/img/icons/lucide/calendar-clock.svg); mask-image: url(/assets/img/icons/lucide/calendar-clock.svg); }
.li-chevron-down { -webkit-mask-image: url(/assets/img/icons/lucide/chevron-down.svg); mask-image: url(/assets/img/icons/lucide/chevron-down.svg); }
.li-clock { -webkit-mask-image: url(/assets/img/icons/lucide/clock.svg); mask-image: url(/assets/img/icons/lucide/clock.svg); }
.li-map { -webkit-mask-image: url(/assets/img/icons/lucide/map.svg); mask-image: url(/assets/img/icons/lucide/map.svg); }
.li-phone { -webkit-mask-image: url(/assets/img/icons/lucide/phone.svg); mask-image: url(/assets/img/icons/lucide/phone.svg); }
.li-tag { -webkit-mask-image: url(/assets/img/icons/lucide/tag.svg); mask-image: url(/assets/img/icons/lucide/tag.svg); }
.li-user-round { -webkit-mask-image: url(/assets/img/icons/lucide/user-round.svg); mask-image: url(/assets/img/icons/lucide/user-round.svg); }
.li-camera { -webkit-mask-image: url(/assets/img/icons/lucide/camera.svg); mask-image: url(/assets/img/icons/lucide/camera.svg); }

.founding-invite .bubble-frame-icon { --bubble-size: 5rem; }
.founding-invite .bubble-frame-icon > .card-icon { width: 94%; height: auto; }

/* The About governance grid: the cards were far apart and tight inside.
   Rick, 18 Aug 2026. */
.page-about .verification-box { padding: var(--space-6); }

@media (min-width: 640px) {
  .page-about .grid-2 { gap: var(--space-5); }
}

/* The product specimen's label now sits UNDER the card as one line. */
.preview-frame-caption {
  margin: var(--space-3) 0 0;
  text-align: center;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--ink-mute);
}

/* Heading for the homepage trust strip, which had none at all. */
.trust-strip-title { margin: 0 0 var(--space-4); }

/* -------------------------------------------------------------------------
   Cookie consent bar (19 Aug 2026)

   Rendered only where analytics is configured, and starts hidden: JS reveals
   it for a visitor who has not answered yet. Fixed to the bottom rather than
   the top so it never fights the sticky header or the founding notice strip,
   both of which live at the top of the viewport.

   Colours and button treatment are the .cta-band pattern, not a new one:
   dark jade ground, Rick's gold for the affirmative action (black on gold,
   ~9:1) and a cream outline for the other. Reusing that pairing is what
   keeps the bar looking like part of the site rather than a plugin.
   ------------------------------------------------------------------------- */
.cookie-bar {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 60;
  background: #254338;
  color: var(--on-green);
  border-top: 1px solid var(--on-green-hairline);
  box-shadow: 0 -6px 24px rgb(0 0 0 / 0.18);
}

.cookie-bar[hidden] { display: none; }

.cookie-bar-inner {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding-block: var(--space-4);
  flex-wrap: wrap;
}

.cookie-bar-text {
  max-width: none; /* centred <p> gotcha: the base 70ch cap strands it left */
  margin: 0;
  flex: 1 1 22rem;
  font-size: 0.9375rem;
  line-height: 1.5;
}

.cookie-bar-text a { color: inherit; }

.cookie-bar-actions {
  display: flex;
  gap: var(--space-3);
  flex: 0 0 auto;
}

/* 44px minimum touch target: .btn-sm alone lands near 38px, which is fine
   for a link in a paragraph and too small for the only two controls on a
   bar a visitor must dismiss on a phone. */
.cookie-bar .btn {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.cookie-bar .btn-primary { background: #DBA239; color: #000; }
.cookie-bar .btn-primary:hover { background: color-mix(in oklab, #DBA239, #000 12%); color: #000; }
.cookie-bar .btn-secondary { color: var(--on-green); border-color: var(--cta-outline); }
.cookie-bar .btn-secondary:hover { background: var(--cta-outline-wash); color: var(--on-green); border-color: var(--on-green); }

/* On a phone the two buttons share the full width rather than stacking into
   a tall bar that covers the page behind it. */
@media (max-width: 560px) {
  .cookie-bar-inner { gap: var(--space-4); }
  .cookie-bar-actions { flex: 1 1 100%; }
  .cookie-bar-actions .btn { flex: 1 1 0; }
}

/* The bar is a live control, not part of the document. */
@media print {
  .cookie-bar { display: none !important; }
}

/* -------------------------------------------------------------------------
   Sample profile framing (19 Aug 2026)

   Only ever rendered on /sample-profile. The flag has to read as a label on
   the page rather than as part of the listing, so it takes the brass accent
   used for status elsewhere rather than the jade the profile itself uses -
   if it looked like the profile, it would be read as the profile.
   ------------------------------------------------------------------------- */
.sample-flag {
  background: var(--paper-2);
  border-bottom: 1px solid var(--brass-soft);
}

.sample-flag p {
  max-width: none; /* centred <p> gotcha: the base 70ch cap strands it left */
  margin: 0;
  padding-block: var(--space-3);
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* The therapist-facing close beneath the specimen. Jade band so it reads as
   the site talking, not as more of the fictional listing above it. */
.sample-cta {
  margin-top: var(--space-7);
  padding: var(--space-6);
  border-radius: var(--radius-lg);
  background: #254338;
  color: var(--on-green);
}

.sample-cta h2 { margin-top: 0; color: var(--on-green); }
/* WHAT brands: the invitation band uses the brand's own dark band colour, never MLD's green (Rick, 14 Oct 2026). */
.design-what .sample-cta { background: var(--green-deep); }
/* Admin launch forms: the tick, its button and the next form never touch (Rick, 14 Oct 2026). */
.admin-page form[action$="/admin/launch"] { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-3); margin-top: var(--space-4); }
.sample-cta p { max-width: 60ch; }
.sample-cta .btn-primary { background: #DBA239; color: #000; }
.sample-cta .btn-primary:hover { background: color-mix(in oklab, #DBA239, #000 12%); color: #000; }
.sample-cta .btn-secondary { color: var(--on-green); border-color: var(--cta-outline); }
.sample-cta .btn-secondary:hover { background: var(--cta-outline-wash); color: var(--on-green); border-color: var(--on-green); }

/* Leader rows on narrow phones (19 Aug 2026).

   .leader-label is flex:none, so a long label plus the dots' 1.5rem minimum
   plus the value cannot fit at 320px and the value is pushed off the right
   edge, taking the whole page's scroll width with it. Found on
   /sample-profile, where "Insurance document checked ... 19 June 2026"
   overflowed by 9px - but it is the SHARED verification card, so the first
   real member profile would have done exactly the same on a small phone.

   Under 420px the row becomes label-above-value and the dots go: a dotted
   leader only means anything when both ends sit on one line. Used by the
   profile, the dashboard, the certificate and both join pages, all of which
   gain the same behaviour and none of which relied on the overflow. */
@media (max-width: 420px) {
  .leader-row { flex-wrap: wrap; gap: 0.15rem; }
  .leader-row .leader-label { flex: 1 1 100%; }
  .leader-row .leader-dots { display: none; }
  .leader-row .leader-value { text-align: left; }
}

/* =========================================================================
   ADMIN, 25 Aug 2026 (Rick): a settings screen you can find things on, and
   a navigation bar that is not fourteen items wide.
   ========================================================================= */

/* The settings column was 46rem hard against the left edge of a wide
   container, so it read as a page with a hole in it. Centre it. */
.admin-form { margin-inline: auto; }

/* FOLDING PANELS. Native <details>, so the screen still opens and closes
   with JavaScript off; main.js only reports which folds were left open so
   the server can remember them. They all start closed - thirteen panels
   open at once is a scroll, not a screen. */
.panel-fold { padding: 0; }

.panel-fold > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-5);
  border-radius: var(--radius-lg);
  cursor: pointer;
  list-style: none;
}
.panel-fold > summary::-webkit-details-marker { display: none; }
.panel-fold > summary:hover { background: var(--paper); }

.panel-fold-title { margin: 0; font-size: 1.45rem; }

/* Chevron drawn in CSS rather than shipped as markup: one less thing that
   can fall out of step with the open state. */
.panel-fold > summary::after {
  content: "";
  flex: none;
  width: 0.55rem;
  height: 0.55rem;
  margin-right: 0.25rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  opacity: 0.5;
  transition: transform 160ms;
}
.panel-fold[open] > summary::after { transform: rotate(-135deg); }

/* The panel's padding moved onto the summary, so the body indents itself. */
.panel-fold > :not(summary) { margin-inline: var(--space-5); }
.panel-fold[open] > :last-child { margin-bottom: var(--space-5); }

/* Settings: separate country panels and a compact, persistent action bar. */
.settings-workspace { max-width: 72rem; }
.settings-toolbar {
  position: sticky; top: calc(var(--header-offset) + .5rem); z-index: 20;
  display: flex; align-items: end; gap: var(--space-3);
  padding: var(--space-4); margin-bottom: var(--space-5);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: 0 3px 14px rgb(0 0 0 / 8%);
}
.settings-jump { flex: 1; min-width: 0; }
.settings-jump label { display: block; font-weight: 600; margin-bottom: var(--space-2); }
.settings-jump select { width: 100%; }
.settings-workspace .panel-fold { scroll-margin-top: calc(var(--header-offset) + 8rem); }
.settings-fields { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 var(--space-5); }
.settings-fields .field { min-width: 0; }
.settings-fields .settings-textarea { min-height: 8rem; }
.settings-subheading {
  grid-column: 1 / -1; margin: var(--space-4) 0;
  padding-bottom: var(--space-2); border-bottom: 1px solid var(--line);
  font-size: 1rem; color: var(--ink-soft);
}
@media (min-width: 760px) {
  .settings-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .settings-field-wide { grid-column: 1 / -1; }
}
@media (max-width: 600px) {
  .settings-toolbar { flex-wrap: wrap; }
  .settings-jump { flex-basis: 100%; }
  .settings-toolbar .btn { flex: 1; }
  .settings-workspace .panel-fold { scroll-margin-top: calc(var(--header-offset) + 12rem); }
}

/* GROUPED ADMIN NAV. Reuses the public header's dropdown component - the same
   .has-children / .nav-sub-toggle / .nav-sub markup and the same main.js
   handler - so the codebase has ONE dropdown, not two. Only the colours
   change, because the header band is dark and this one is light. */
.admin-nav .has-children { position: relative; }

.admin-nav .nav-sub-toggle {
  font-size: 0.95rem;
  color: var(--ink-soft);
  padding: var(--space-2) 0;
}
.admin-nav .nav-sub-toggle:hover,
.admin-nav .has-children.is-active > .nav-sub-toggle {
  color: var(--ink);
  border-bottom-color: var(--brass);
}

.admin-nav .nav-sub {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  transform: none;
  min-width: 14rem;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow-2);
  z-index: 20;
}
.js .admin-nav .has-children.open > .nav-sub { display: block; }
html:not(.js) .admin-nav .has-children:hover > .nav-sub,
html:not(.js) .admin-nav .has-children:focus-within > .nav-sub { display: block; top: 100%; }

.admin-nav .nav-sub li { margin: 0; }
.admin-nav .nav-sub a {
  display: block;
  padding: 0.45rem 0.7rem;
  border-radius: 7px;
  border-bottom: 0;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--ink-soft);
}
.admin-nav .nav-sub a:hover,
.admin-nav .nav-sub a[aria-current="page"] { background: var(--paper); color: var(--ink); }

/* -------------------------------------------------------------------------
   Procedure ticker (.ticker-strip) - added 6 Sep 2026 for the MLD homepage
   (Rick's ask): a thin dark strip under the hero that slides a list of
   procedures across the screen. Engine-level so any brand can use it; the
   words live in the page that prints them. HOW THE LOOP WORKS: the page
   prints the list twice inside .ticker-track, the track is as wide as its
   content, and the keyframe slides it left by exactly half its own width,
   so the second copy arrives where the first started and the loop has no
   visible seam. Each item carries its own leading champagne diamond, so the
   spacing is identical across the seam. The strip pauses on hover so a
   reader can hold a word still, and prefers-reduced-motion stops the slide:
   the row stands still and scrolls sideways, the duplicate is hidden.
   Colours are tokens only (--green-deep is the dark band ground in every
   brand, --brass-on-dark the accent cut made for it), so the strip follows
   each brand's theme.css without a rule here changing. The two edge fades
   are pseudo-elements in the band's own colour, so the words melt into the
   band at each side rather than being cut off flat. --ticker-h is the
   strip's fixed height; the hero reads the same token to reserve the room.
   ------------------------------------------------------------------------- */
.ticker-strip,
.hero-bleed:has(.ticker-strip) { --ticker-h: 2.75rem; }

.ticker-strip {
  position: relative;
  overflow: hidden;
  background: var(--green-deep);
  color: var(--paper);
  height: var(--ticker-h);
  display: flex;
  align-items: center;
}

.ticker-strip::before,
.ticker-strip::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 4rem;
  z-index: 1;
  pointer-events: none;
}

.ticker-strip::before {
  left: 0;
  background: linear-gradient(90deg, var(--green-deep), color-mix(in oklab, var(--green-deep) 0%, transparent));
}

.ticker-strip::after {
  right: 0;
  background: linear-gradient(270deg, var(--green-deep), color-mix(in oklab, var(--green-deep) 0%, transparent));
}

.ticker-track {
  display: flex;
  flex: none;
  width: max-content;
  animation: ticker-scroll 36s linear infinite;
  will-change: transform;
}

.ticker-strip:hover .ticker-track { animation-play-state: paused; }

.ticker-list {
  display: flex;
  flex: none;
  gap: var(--space-6);
  margin: 0;
  padding: 0 var(--space-6) 0 0;
  list-style: none;
}

.ticker-list li {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.ticker-list li::before {
  content: "";
  width: 0.4rem;
  height: 0.4rem;
  flex: none;
  transform: rotate(45deg);
  background: var(--brass-on-dark);
}

@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .ticker-strip { overflow-x: auto; scrollbar-width: thin; }
  .ticker-track { animation: none; }
  .ticker-list[aria-hidden="true"] { display: none; }
  .ticker-strip::before,
  .ticker-strip::after { content: none; }
}

/* Ticker INSIDE the hero copy (Rick, 6 Sep 2026, third placement): on a
   phone the strip sits between the subhead sentence and the search card;
   on desktop it stays below the copy and the photograph as the hero's
   bottom edge, where it has been since it was the hero's sibling. The
   markup therefore lives in .hero-copy after .hero-subhead, and on desktop
   it is lifted out of the flow and pinned to the hero's bottom edge: the
   hero reserves the strip's height in its bottom padding and its
   min-height, so the copy keeps its centre and the visible photograph its
   crop (the media block stops above the strip). The container loses its
   position so the strip anchors to the hero rather than to it, and the
   photograph moves to z-index -1 inside the hero's own stacking context
   (isolation: isolate) so the in-flow copy still paints above it. Scoped
   with :has() so a hero without a ticker, on any brand or page, does not
   move. */
.hero-bleed:has(.ticker-strip) {
  padding-bottom: calc(var(--space-7) + var(--ticker-h));
  min-height: calc(34rem + var(--ticker-h));
}

.hero-bleed:has(.ticker-strip) > .container { position: static; }
.hero-bleed:has(.ticker-strip) > .hero-bleed-media { z-index: -1; bottom: var(--ticker-h); }

.hero-bleed:has(.ticker-strip) .ticker-strip {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
}

@media (min-width: 960px) {
  .hero-bleed:has(.ticker-strip) {
    padding-bottom: calc(var(--space-8) + var(--ticker-h));
    min-height: calc(40rem + var(--ticker-h));
  }
}

/* Private admin email history; keep long addresses and message URLs contained. */
.email-history-table { min-width: 960px; }
.email-history-table td { overflow-wrap: anywhere; }
/* Email log columns (Rick, 18 Sep 2026): the two pill columns take only what
   their pill needs, the date, names and address never break mid-word (the
   .table-scroll wrapper scrolls sideways instead when a screen is narrow),
   and the address and subject get the room. First name fits ten characters. */
.email-history-table .email-date { white-space: nowrap; }
.email-history-table td:nth-child(2), .email-history-table td:nth-child(3) { white-space: nowrap; min-width: 6rem; }
.email-history-table td:nth-child(4) { min-width: 16rem; white-space: nowrap; }
.email-history-table td:nth-child(5) { min-width: 12rem; }
.email-history-table th:nth-child(6), .email-history-table td:nth-child(6) { width: 1%; white-space: nowrap; }
/* Delivery sizes itself: pill-wide until a bounce reason appears, then up to 18rem for the reason to read on two or three lines. */
.email-history-table td:nth-child(7) .admin-error-text { display: inline-block; max-width: 18rem; }
.email-view-link { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border: 1px solid var(--border, #ddd9cf); border-radius: 8px; }
.email-view-link:hover, .email-view-link:focus-visible { background: var(--paper, #f5f4f0); outline: 2px solid currentColor; outline-offset: 2px; }
.email-message-meta { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 24px; }
.email-message-meta dt { font-weight: 600; }
.email-message-meta dd { margin: 0; overflow-wrap: anywhere; }
.email-message-body { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.75; border-top: 1px solid var(--border, #ddd9cf); margin-top: 24px; padding-top: 24px; }
.email-history-table .email-date { white-space: nowrap; }
.email-webhook-url code { display: inline-block; padding: 0.5rem 0.75rem; overflow-wrap: anywhere; background: var(--paper-2); border-radius: var(--radius-sm, 6px); }
/* The Therapists / Admin / All switch on the email log (18 Sep 2026). */
.email-audience { display: inline-flex; border: 1px solid var(--line); border-radius: var(--radius-sm, 6px); overflow: hidden; }
.email-audience a { display: inline-block; padding: 0.55rem 0.95rem; min-height: 44px; text-decoration: none; color: var(--ink); background: var(--paper); font-weight: 600; line-height: 1.6; }
.email-audience a + a { border-left: 1px solid var(--line); }
.email-audience a:hover, .email-audience a:focus-visible { background: var(--paper-2); }
.email-audience a[aria-current="true"] { background: var(--ink); color: var(--paper); }
.filter-bar .field .label { display: block; margin-bottom: 0.35rem; font-weight: 600; }
/* The message dialog: the email as sent, inside a sandboxed frame sized to its content. */
.email-dialog { position: relative; width: min(56rem, calc(100vw - 2 * var(--space-5))); max-height: calc(100vh - 2 * var(--space-5)); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-2, var(--shadow-1)); padding: 0; overflow: auto; }
.email-dialog::backdrop { background: rgba(26, 34, 30, 0.55); }
.email-dialog-head { padding: var(--space-4) var(--space-5); padding-right: 4rem; border-bottom: 1px solid var(--line); }
.email-dialog-head h2 { margin: 0; font-size: 1.5rem; overflow-wrap: anywhere; }
.email-dialog-meta { margin: var(--space-2) 0 0; font-size: 0.9rem; color: var(--ink-soft); overflow-wrap: anywhere; }
.email-dialog-body { padding: var(--space-4) var(--space-5); }
.email-dialog-body .notice { margin-bottom: var(--space-4); }
.email-dialog-body .email-message-body { border-top: 0; margin-top: 0; padding-top: 0; }
.email-frame { display: block; width: 100%; border: 0; min-height: 10rem; background: #fff; }

/* PHONE: back in the flow of the copy, between the subhead and the search
   card, and bled to both screen edges with the margin trick: the copy box
   is the viewport minus the container's two gutters, so half its width
   minus half the viewport is exactly one gutter, negative. */
@media (max-width: 719px) {
  .hero-bleed:has(.ticker-strip) { padding-bottom: 0; min-height: 0; }
  .hero-bleed:has(.ticker-strip) > .hero-bleed-media { z-index: auto; bottom: auto; }
  .hero-bleed:has(.ticker-strip) .ticker-strip {
    position: relative;
    margin-block: var(--space-6);
    margin-inline: calc(50% - 50vw);
  }
}

/* -------------------------------------------------------------------------
   Profile page tightening (19 Sep 2026): the bio behind "Read more", the
   declared lists in two columns under their own Services heading, the
   practice facts in leader rows beside the map, the rail sticking by its
   bottom edge when it is taller than the window, and on phones the
   Verification card moving below About so a reader meets the person before
   the paperwork. Rick's brief of 19 Sep 2026, after his and ChatGPT's
   reviews of Rachel Fincham's preview.
   ------------------------------------------------------------------------- */

/* "Read more about Claire" sits straight after the last visible paragraph
   (no top margin) and, once open, reads "Show less" above the rest. The
   shared summary style is on .reviews-more > summary further up. */
.bio-more > summary { margin-block: 0; }
.bio-more[open] > summary { margin-bottom: var(--space-3); }
.bio-more:not([open]) .bio-more-close,
.bio-more[open] .bio-more-open { display: none; }

/* The "?" beside each Services sub-heading carries that list's own caveat,
   so the provenance is one sentence under the section heading rather than a
   paragraph over every list. The bubble anchors left, in body type. */
.profile-section h3 .tip { margin-left: var(--space-2); vertical-align: middle; }
.profile-section h3 .tip-bubble {
  left: 0;
  transform: none;
  width: 18rem;
  max-width: 80vw;
}
/* On a phone the "?" sits at the END of the heading, so a bubble growing
   rightwards from it left the page. Anchor it to the icon's right edge and
   let it grow leftwards instead (21 Sep 2026). */
@media (max-width: 720px) {
  .profile-section h3 .tip-bubble { left: auto; right: 0; }
}
.profile-section h3 .tip-bubble {
  white-space: normal;
  font-family: var(--font-sans);
  font-size: 0.85rem;
  font-weight: 400;
  line-height: 1.45;
  text-align: left;
}

/* Location & fees: facts in leader rows across the whole column. The map
   that used to sit beside them went on 21 Sep 2026 (Rick): Get directions
   does its job, and the address now has room to sit on one line. */
.profile-practice { margin-bottom: var(--space-5); }
.profile-practice .leader-row { font-size: 1rem; }
.profile-practice .leader-label { flex: 0 1 auto; min-width: 0; }
.profile-practice .leader-value-sub a { font-weight: 600; }

/* A rail taller than the window cannot be shown whole, and pinned by its top
   its bottom is unreachable. That is the normal case on a small or zoomed-in
   screen (Rick, 19 Sep 2026: older patients zoom in) and for a member with
   several checked trainings. main.js measures and marks it is-tall: the rail
   then flows with the page and ONLY the action card stays pinned, so Book
   online and Enquire are always on screen while the Verification card reads
   at the top and scrolls away like ordinary content, sliding under the card.
   The rail stretches to the column's height so the card can travel the whole
   way down to the enquiry form. Without the script nothing changes. */
@media (min-width: 960px) {
  .profile-layout .profile-aside.is-tall { position: static; align-self: stretch; }
  .profile-layout .profile-aside.is-tall .profile-quick { position: sticky; top: calc(var(--header-offset) + var(--space-4)); z-index: 2; }
  /* The action card itself taller than the room under the header (the
     decision card fix round, 22 Oct 2026; a laptop at 125% zoom): main.js
     marks the rail is-tall-card and sets --quick-pin-top so the card pins
     by its bottom, 16px above the window's foot. The price and facts scroll
     up under the header with the page; Send enquiry stays whole on screen. */
  .profile-layout .profile-aside.is-tall-card .profile-quick { top: var(--quick-pin-top, calc(var(--header-offset) + var(--space-4))); }
}

/* A location as a small stack, not a leader row (Rick, 19 Sep 2026: the name
   wrapping against a wrapping address read as a mess): the name on its own
   line, the address beneath with Get directions at the right, dropping under
   the address where the line is short. */
.profile-place { margin-bottom: var(--space-4); }
.profile-place-name { margin: 0 0 0.15rem; max-width: none; font-weight: 600; }
.profile-place-address { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.25rem var(--space-4); margin: 0; max-width: none; }
.profile-place-address > span { min-width: 0; }
.profile-place-directions { white-space: nowrap; font-weight: 600; }
.profile-place-note { margin: 0.25rem 0 0; max-width: none; font-size: 0.92rem; color: var(--ink-mute); }

/* "Who I work with" and "Typical working hours" on the profile, both the
   member's own declarations. On for every directory since 29 Sep 2026 (Rick's
   decision 6), so their styles live here, built on tokens, instead of only in
   profile-details.css, which loads only with the member_profile_extensions
   config switch. Each section renders only for a member who filled it in. */
.profile-client-types,
.profile-training,
.profile-hours { margin-block: var(--space-6); }
.profile-client-types dl > div { margin-block: var(--space-3); }
.profile-client-types dt { font-weight: 600; }
.profile-client-types dd { margin: var(--space-1) 0 0; }
.public-hours-grid {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-size: 0.82rem;
  margin-block: var(--space-4);
}
.public-hours-grid :is(td, th) {
  padding: 0.6rem 0.3rem;
  text-align: center;
  border-bottom: 1px solid var(--line);
  overflow-wrap: anywhere;
}
.public-hours-grid th:first-child { text-align: left; width: 7rem; }
.public-hours-grid abbr { text-decoration: none; }
.public-hours-grid td { color: inherit; }
/* An empty period: a muted middle dot, read out as "Not working". */
.public-hours-none { color: var(--ink-mute); }
.public-hours-days { display: none; }
@media (max-width: 650px) {
  .public-hours-grid { display: none; }
  .public-hours-days { display: block; }
  .public-hours-days > div { margin-block: var(--space-3); }
  .public-hours-days dt { font-weight: 600; }
  .public-hours-days dd { margin: var(--space-1) 0 0; }
  .profile-hours h3 { line-height: 1.4; }
}

/* Phones and tablets: the aside and the main column dissolve into the one
   grid (display: contents) so their children can be ordered as a reader
   wants them - the action card, then About, then the Verification card,
   then everything else. Before this the whole rail came first and a reader
   met the paperwork before a word about the person. Nothing folds: the card
   is the proof and is still complete, only lower. */
@media (max-width: 959.98px) {
  .profile-layout { gap: var(--space-7); }
  .profile-layout .profile-aside,
  .profile-layout .profile-main { display: contents; }
  .profile-layout .profile-quick { order: 1; margin-bottom: 0; }
  .profile-layout .profile-main > .profile-section { order: 4; margin-bottom: 0; }
  .profile-layout #about { order: 2; }
  .profile-layout .verification-box { order: 3; }
}

/* =========================================================================
   Shared page components promoted from brands/mld/theme.css (23 Sep 2026,
   for WhatHypno). The pill label above a heading and the founding stat
   chips were styled for MLD alone; every brand pack can now use them.
   brands/mld/theme.css keeps its own identical rules plus its #ac7826 pill
   tone, and loads after this file, so MLD renders exactly as before. The
   colour here is the token, so each brand's theme.css decides it.
   ========================================================================= */
.brass-pill,
.founding-invite-eyebrow { color: var(--brass-deep); }
.brass-pill {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  max-width: none;
  margin-bottom: var(--space-3);
}
/* A pill inside a dark band (the WHAT master home's "Our approach", 29 Sep
   2026) reads in the accent made for dark grounds; the light-ground tone
   would all but vanish on the deep band. No MLD page puts a pill in a dark
   band, so MLD renders exactly as before. */
.section-green .brass-pill { color: var(--brass-on-dark); }
/* The highlighted word in a hero heading (the profession word on the WHAT
   master home). The brand's exact primary where its theme names one, else
   the primary token. MLD's theme keeps its own colour for it, loaded after
   this file, so MLD is unchanged. */
.hero-accent-word { color: var(--brand-primary, var(--green)); }
.founding-invite .text-center { margin-left: auto; margin-right: auto; }
.founding-invite-eyebrow {
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: var(--space-2);
}
.founding-invite-facts {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-4);
  list-style: none;
  padding: 0;
  margin: var(--space-5) auto var(--space-2);
  max-width: 60rem;
}
.founding-invite-facts li {
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 2px solid var(--brass);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
  padding: 0.75rem 1.2rem;
  font-size: 0.95rem;
  color: var(--ink-mute);
  text-align: center;
  flex: 1 1 12rem;
}
.founding-invite-facts li strong {
  display: block;
  font-family: var(--font-serif);
  font-size: 1.3rem;
  color: var(--ink);
}
/* Two by two (the WHAT master home, visual review 30 Sep 2026): the card-list
   ruling puts three in a row and any other count two by two. Four in one row
   also squeezed two of the four headings onto two lines, so the row read
   ragged; at half the width each heading holds one line and the grid keeps
   the cards in a row the same height. Opt-in, so MLD's facts are unchanged. */
.founding-invite-facts-pairs {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  max-width: 46rem;
}
/* The grid's gap is the only space between the facts, so the rows sit as
   far apart as the columns (polish pass, 30 Sep 2026: the list items'
   bottom margin had made the row gap 8px wider). */
.founding-invite-facts-pairs > li { margin: 0; }
@media (min-width: 640px) {
  .founding-invite-facts-pairs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.founding-invite .card { text-align: left; }
/* The founding steps (.founding-invite-steps, the WHAT master home): where
   the cards sit in a row, each card shares the row's three tracks (icon,
   heading, text) through subgrid, so every card's text starts at the same
   height even when one heading wraps onto a second line (polish pass,
   30 Sep 2026). The card's own gap replaces the row's between its tracks. */
@media (min-width: 960px) {
  .founding-invite-steps > .card {
    display: grid;
    grid-row: span 3;
    grid-template-rows: subgrid;
    row-gap: 0;
    align-content: start;
  }
  .founding-invite-steps > .card > * { align-self: start; }
}
.founding-invite .card h3 { margin-top: var(--space-3); }
.founding-invite .card-icon { width: 4.75rem; height: 4.75rem; }

/* The fold-out on the WHAT join boxes ("More about payment", "More about
   Featured"): the full terms stay one click away, the box stays short
   (Rick, 7 Oct 2026). */
.offer-fold { margin: var(--space-3) 0 0; }
.offer-fold summary { cursor: pointer; color: var(--green); font-weight: 600; font-size: 0.95rem; }
.offer-fold summary:hover { text-decoration: underline; }
.offer-fold p { margin: var(--space-2) 0 0; font-size: 0.92rem; color: var(--ink-soft); }

/* "Check founding places in your area" on the WHAT join pages. */
.places-check { max-width: 36rem; margin: 0 auto var(--space-6); padding: var(--space-4) var(--space-5); background: var(--green-wash); border: 1px solid var(--line); border-radius: var(--radius, 8px); }
.places-check label { display: block; margin-bottom: var(--space-2); font-size: 0.95rem; }
.places-check .search-box-row input { min-width: 0; }
.places-check-result { margin: var(--space-3) 0 0; font-weight: 600; color: var(--ink); }
.places-check-open { color: var(--tone-verified-ink, var(--green)); }
.places-check-open, .places-check-full { display: flex; align-items: center; gap: 0.55rem; }
.places-check-open::before, .places-check-full::before { content: ""; flex: none; width: 1.35em; height: 1.35em; background: currentColor; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: contain; mask-size: contain; }
.places-check-open::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E"); }
.places-check-full { color: var(--tone-warn-ink, #8C5328); }
.places-check-full::before { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM6.4 7.8L7.8 6.4 10 8.6l2.2-2.2 1.4 1.4L11.4 10l2.2 2.2-1.4 1.4L10 11.4l-2.2 2.2-1.4-1.4L8.6 10z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM6.4 7.8L7.8 6.4 10 8.6l2.2-2.2 1.4 1.4L11.4 10l2.2 2.2-1.4 1.4L10 11.4l-2.2 2.2-1.4-1.4L8.6 10z'/%3E%3C/svg%3E"); }

/* The WHAT join page in three steps (Rick, 8 Oct 2026): a short summary,
   Step 1 the places check, Step 2 the plan cards and the one Featured line.
   The plan cards are .choice-card (since 14 Oct 2026); a plan the engine would not give is
   disabled, never hidden, with its reason under it. */
.join-summary { max-width: 46rem; margin: 0 auto var(--space-5); text-align: center; }
.join-step-label { font-size: 1.15rem; margin: 0 0 var(--space-3); }
.join-plan-group { display: grid; grid-template-columns: 1fr; gap: var(--space-3); margin: 0 0 var(--space-4); }
@media (min-width: 640px) { .join-plan-group { grid-template-columns: 1fr 1fr; } }
.tier-billing:has(input:disabled) { opacity: 0.6; cursor: not-allowed; background: var(--paper-2); }
/* The label and its (i) are ONE flex item that takes the rest of the row, so
   the (i) follows the words inline and, on a phone, wraps with the last word
   instead of dropping to a line of its own (Rick, 14 Oct 2026): a word joiner
   (U+2060) between the label and the (i) AND nowrap on the item with normal
   wrapping inside the label: Chrome needs both (measured at 375, 14 Oct 2026). The bubble is
   placed against the whole row (the .tip is not positioned here), so it opens
   inside the screen wherever the (i) lands. */
.join-featured-row { position: relative; margin: 0 0 var(--space-2); }
.join-featured-row input[type="checkbox"] { flex: none; }
.join-featured-label { flex: 1 1 0; min-width: 0; white-space: nowrap; }
.join-featured-label label { display: inline; font-weight: 600; white-space: normal; }
.join-featured-label .tip { position: static; vertical-align: middle; margin-left: 0.4rem; }
.join-featured-row .tip-bubble { left: 0; right: auto; transform: none; max-width: 100%; }
.join-small { font-size: 0.92rem; color: var(--ink-mute); margin: var(--space-2) 0 0; }

/* The shorter WHAT start (conversion review SH-05, 10 Oct 2026; one line since
   14 Oct 2026): a helper under the Featured box and a small order summary above
   the Next button. */
.places-check .field-hint { margin: var(--space-2) 0 0; }
.join-featured-row { flex-wrap: wrap; }
.join-featured-row .join-featured-note { flex: 1 1 100%; margin: calc(var(--space-1) * -1) 0 0 2.2rem; }
/* Always two rows, with or without Featured (Rick's decision 3, 15 Oct 2026): "Your plan: ..." then the price sentence. */
.join-selection-summary-what { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1); margin: var(--space-5) 0 var(--space-4); padding: var(--space-3) var(--space-4); background: var(--paper-2); border-radius: var(--radius); font-size: 0.98rem; max-width: none; }
.join-selection-summary-what > span { color: var(--ink-soft); font-weight: 600; }
.join-selection-summary-what > strong { color: var(--ink); }

/* Registration and insurance facts (profile, check, verify, compare): a small
   ledger, label over value with a hairline between rows, and the dated check
   marked with the verified tick, in place of the indented definition list
   (Rick, 7 Oct 2026). The profile decision card's facts (.profile-facts, 22 Oct
   2026) are the same component. */
:is(.admission-facts, .profile-facts) { display: grid; gap: 0; margin: var(--space-3) 0 var(--space-4); padding: 0; }
:is(.admission-facts, .profile-facts) .fact { padding: 0.7rem 0; border-top: 1px solid var(--line); }
:is(.admission-facts, .profile-facts) .fact:first-child { border-top: 0; padding-top: 0.2rem; }
:is(.admission-facts, .profile-facts) dt { margin: 0 0 0.15rem; font-size: 0.74rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-mute); }
:is(.admission-facts, .profile-facts) dd { margin: 0; font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
.admission-facts .fact-ok dd::before {
  content: ""; display: inline-block; width: 1.05em; height: 1.05em; margin-right: 0.45em; vertical-align: -0.17em;
  background: var(--verified, var(--green));
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Accepted-register cards on the verification standard: the body's logo above
   its label, every logo on the same 3:1 canvas. */
.route-card { display: flex; flex-direction: column; align-items: center; justify-content: space-between; gap: var(--space-4); text-align: center; }
.route-logo { display: block; width: 100%; max-width: 15rem; height: auto; aspect-ratio: 3 / 1; object-fit: contain; object-position: center; }

[data-join-step1-only][hidden] { display: none !important; }
/* ONE centred column for the WHAT join step (Rick, 14 Oct 2026): the places
   panel, its sentence and the whole plan panel (cards side by side, Featured,
   payment, VAT, Your plan, Next) share one width and one centre line. Phones
   are narrower than it, so they are unchanged. MLD's panel has no plan group. */
.places-check,
.join-summary,
.join-note,
.join-panel:has(.join-plan-group) { max-width: 48rem; margin-left: auto; margin-right: auto; }
.join-step-title { display: block; margin: var(--space-7, 3rem) 0 var(--space-4); text-align: center; font-size: clamp(1.6rem, 3.2vw, 2.3rem); line-height: 1.25; } /* the section h2 size (19 Oct 2026) */
.join-fieldset > legend { float: none; width: 100%; padding: 0; }

/* WHAT home on a phone (conversion review SH-06, 10 Oct 2026): the photograph
   under the search is a mood, not the next thing the visitor came for, so it
   is limited in height and the first section after it arrives sooner. MLD's
   home (with its ticker) keeps its own hero. */
@media (max-width: 719px) {
  .hero-bleed:not(:has(.ticker-strip)) .hero-bleed-media { height: clamp(13rem, 58vw, 17rem); }
}

/* WHAT local pages (towns and services; conversion review SH-07, 10 Oct
   2026): the cards come first and the map supports them. Beside the cards on
   a wide screen, after them on a phone, and shorter than the banner either
   way, so the count and the first cards are on the first screen. MLD's local
   pages keep their banner. */
@media (min-width: 960px) {
  .search-layout.search-layout-local {
    grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
    align-items: start;
  }
  .search-layout.search-layout-local .map-sticky {
    order: 0;
    position: sticky;
    top: calc(var(--header-offset) + var(--space-4));
  }
  .search-layout.search-layout-local .map-frame { height: min(34rem, calc(100vh - var(--header-offset) - 4rem)); }
}
@media (max-width: 959.98px) {
  .search-layout.search-layout-local .map-sticky { order: 1; }
  .search-layout.search-layout-local .map-frame { height: 18rem; }
}

/* WHAT profiles on a phone (conversion review SH-07, 10 Oct 2026): room
   between a practical-details label and its value (the shared 420px rule
   was beaten by .profile-practice's own label rule, so the two ran
   together). The smaller phone portrait is in the compact WHAT profile
   block below since 14 Oct 2026. MLD's profile is untouched. */
@media (max-width: 420px) {
  :is(.design-what, .profile-what).page-profile .profile-practice .leader-row { row-gap: 0.1rem; margin-bottom: var(--space-4); }
  :is(.design-what, .profile-what).page-profile .profile-practice .leader-label { flex: 1 1 100%; }
}

/* =========================================================================
   THE COMPACT WHAT PROFILE (Rick, 14 Oct 2026, from the 13 Oct UX review,
   "AGREE ALL FOUR"; what-brands/DESIGN-STANDARDS.md, 14 Oct 2026 row).
   Every rule hangs on :is(.design-what, .profile-what).page-profile (a live WHAT profile and the
   WHAT /sample-profile), so MLD's profile is untouched. Brand differences
   come only from the theme tokens.
   ========================================================================= */

/* The shell: about 72rem and centred, so the masthead, the section menu and
   the body share one edge and the reading column keeps a sensible measure. */
:is(.design-what, .profile-what).page-profile :is(.sample-flag, .profile-masthead, .profile-nav, .profile-body) > .container { max-width: 72rem; }

/* The masthead: the portrait at its own desktop size (12.5rem, Rick: "keep
   the size of our profile image on the desktop"), the identity beside it,
   left-aligned at every width. The room photographs left the masthead on
   14 Oct 2026 (the profile header, below): "Where you'll meet" in Location
   and fees. */
:is(.design-what, .profile-what).page-profile .profile-header {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  justify-content: stretch;
  column-gap: var(--space-6);
  row-gap: var(--space-4);
}
:is(.design-what, .profile-what).page-profile .profile-head-main { min-width: 0; text-align: left; }
:is(.design-what, .profile-what).page-profile .profile-head-main h1 { overflow-wrap: break-word; }
:is(.design-what, .profile-what).page-profile .profile-head-main p { max-width: none; margin-left: 0; margin-right: 0; }
:is(.design-what, .profile-what).page-profile .profile-head-main > :is(h1, .profile-status, .profile-subline, .profile-checked-line, .profile-rating) { margin: 0; }
/* Founding member and the member number (the slim header, 14 Oct 2026): our
   own quiet record, on the title line in the muted ink, not a badge. */
:is(.design-what, .profile-what).page-profile .profile-meta { font-weight: 400; color: var(--ink-mute); white-space: nowrap; }
/* The record is kept whole and never leaves a dot hanging (fix round, 22
   Oct 2026: a founder with two towns read "...and online · Founding member
   ·" with "No. WC-0042" alone below). Each dot sits centred in the gap
   before its part, outside the part's box, so a dot at the start of a line
   falls outside the row and is clipped. From 720px the title row is a
   wrapping flex row: the record follows the town where it fits and
   otherwise takes its own line, whole. Under 720px it always has its own
   line with no leading dot (below), and its two parts take two lines only
   where they cannot share one (an MLD founder on a 320px phone). */
:is(.design-what, .profile-what).page-profile .profile-meta { display: inline-flex; column-gap: 0.8em; position: relative; }
:is(.design-what, .profile-what).page-profile .profile-meta-part { position: relative; }
:is(.design-what, .profile-what).page-profile .profile-meta-sep { position: absolute; top: 0; right: 100%; width: 0.8em; text-align: center; }
@media (min-width: 720px) {
  :is(.design-what, .profile-what).page-profile .profile-subline { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 0.8em; row-gap: 0; overflow: hidden; }
}
/* Availability (the profile header, 14 Oct 2026): a soft pill in the
   brand's own colour family (its wash, its keyline, its deep ink), never
   green, which stays for checks; the member's note behind its "i". Since
   the slim header it is smaller, at the right of the name's row, with an
   "i" about 0.9em across (its hit area stays 24px). The note opens under
   the pill, held to the pill's right edge so it never leaves the page. */
:is(.design-what, .profile-what).page-profile .profile-status { display: flex; align-items: center; }
:is(.design-what, .profile-what).page-profile .profile-availability { position: relative; display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.15rem 0.65rem; border: 1px solid var(--tone-neutral-border); border-radius: 999px; background: var(--green-wash); color: var(--green-deep); font-size: 0.85rem; font-weight: 600; line-height: 1.3; white-space: nowrap; }
:is(.design-what, .profile-what).page-profile .profile-availability .tip { position: static; }
:is(.design-what, .profile-what).page-profile .profile-availability .tip-icon { position: relative; width: 1.32em; height: 1.32em; min-width: 0; min-height: 0; font-size: 0.68em; border-color: currentColor; color: inherit; }
:is(.design-what, .profile-what).page-profile .profile-availability .tip-icon::after { content: ""; position: absolute; inset: -6px; }
:is(.design-what, .profile-what).page-profile .profile-availability .tip-bubble { top: calc(100% + 0.5rem); bottom: auto; right: 0; left: auto; transform: none; width: 18rem; max-width: calc(100vw - 2rem); text-align: left; }
/* The checked membership line keeps the verified tick and its link to what
   we check; green is for checked evidence only. The tick stays level with
   the first line when a long register name wraps. */
:is(.design-what, .profile-what).page-profile .profile-checked { display: inline-flex; align-items: flex-start; gap: 0.4em; font-weight: 600; color: var(--verified, var(--green)); text-decoration: none; }
:is(.design-what, .profile-what).page-profile .profile-checked::before {
  content: ""; flex: none; width: 1.05em; height: 1.05em;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E") center / contain no-repeat;
  margin-top: 0.15em;
}
:is(.design-what, .profile-what).page-profile .profile-checked:hover,
:is(.design-what, .profile-what).page-profile .profile-checked:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
/* A phone (the slim header, 14 Oct 2026): the portrait at about 6rem BESIDE
   the left-aligned name with the availability pill under it, then the title
   line (wrapping as it needs), the checked membership line, the rating where
   there is one, the hairline and the contact buttons, each the full width.
   display: contents lets the name and the pill sit beside the portrait
   while the rows under it span the full width. With no pill the name is
   centred beside the portrait on its own. */
@media (max-width: 719px) {
  :is(.design-what, .profile-what).page-profile .profile-header { column-gap: var(--space-4); row-gap: 0; }
  :is(.design-what, .profile-what).page-profile .profile-photo { grid-column: 1; grid-row: 1 / span 2; width: 5.75rem; height: 5.75rem; margin: 6px; font-size: 1.5rem; }
  :is(.design-what, .profile-what).page-profile .profile-head-main { display: contents; }
  :is(.design-what, .profile-what).page-profile .profile-head-main > :is(h1, .profile-status) { grid-column: 2; }
  :is(.design-what, .profile-what).page-profile .profile-head-main > h1 { align-self: end; font-size: 1.75rem; line-height: 1.15; }
  /* Room under the name before the pill (Rick, 14 Oct 2026), the same
     step as between the lines below it. */
  :is(.design-what, .profile-what).page-profile .profile-head-main > h1:has(+ .profile-status) { margin-bottom: var(--space-3); }
  :is(.design-what, .profile-what).page-profile .profile-head-main > h1:not(:has(+ .profile-status)) { grid-row: 1 / span 2; align-self: center; margin-bottom: 0; }
  :is(.design-what, .profile-what).page-profile .profile-head-main > .profile-status { align-self: start; }
  :is(.design-what, .profile-what).page-profile .profile-head-main > :is(.profile-subline, .profile-checked-line, .profile-rating, .profile-contact) { grid-column: 1 / -1; }
  :is(.design-what, .profile-what).page-profile .profile-head-main > .profile-subline { margin-top: var(--space-3); font-size: 1.05rem; }
  /* The title and town on one line, the quiet "Founding member · No. ..."
     on the next, never a dot left hanging at a line's end. */
  :is(.design-what, .profile-what).page-profile .profile-meta { display: flex; flex-wrap: wrap; overflow: hidden; margin-top: 0.15rem; font-size: 0.98rem; }
  :is(.design-what, .profile-what).page-profile .profile-meta > .profile-meta-sep { display: none; }
  :is(.design-what, .profile-what).page-profile .profile-head-main > :is(.profile-checked-line, .profile-rating) { margin-top: var(--space-3); }
  /* The note under the pill starts at the content's left edge (the pill
     begins one portrait, 5.75rem and its 6px margins, one column gap and
     its own 1px keyline in) and never runs past the right one (the
     container's gutter). */
  :is(.design-what, .profile-what).page-profile .profile-availability .tip-bubble { right: auto; left: calc(-1 * (5.75rem + 12px + var(--space-4) + 1px)); width: min(18rem, calc(100vw - 2 * clamp(1.25rem, 4vw, 2.5rem))); }
}

/* The body: the reading column and a fixed 21rem side panel, one
   --profile-gap apart (the profile round 2, 22 Oct 2026: 32px, was 4rem),
   the same gap as between the cards. The is-tall rule above still applies:
   a rail taller than the window flows with the page and pins only the
   action card. */
:is(.design-what, .profile-what).page-profile .profile-body { --profile-gap: var(--space-6); }
@media (max-width: 959.98px) {
  :is(.design-what, .profile-what).page-profile .profile-body { --profile-gap: var(--space-5); }
}
@media (min-width: 960px) {
  :is(.design-what, .profile-what).page-profile .profile-layout { grid-template-columns: minmax(0, 1fr) 21rem; gap: var(--profile-gap); }
}

/* Registration and insurance: all six facts at every size, in quieter
   sentence-case labels (the words are the template's own; only the capitals
   were CSS), tighter rows and the one explanation under them. */
:is(.design-what, .profile-what).page-profile .verification-box-head { padding-bottom: var(--space-3); margin-bottom: var(--space-2); }
:is(.design-what, .profile-what).page-profile .admission-facts { margin: 0 0 var(--space-3); }
:is(.design-what, .profile-what).page-profile .profile-facts .fact,
:is(.design-what, .profile-what).page-profile .admission-facts .fact { padding: 0.5rem 0; }
:is(.design-what, .profile-what).page-profile .profile-facts dt,
:is(.design-what, .profile-what).page-profile .admission-facts dt { margin-bottom: 0.1rem; font-size: 0.85rem; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--ink-mute); }
:is(.design-what, .profile-what).page-profile .profile-facts dd,
:is(.design-what, .profile-what).page-profile .admission-facts dd { font-size: 0.98rem; }
:is(.design-what, .profile-what).page-profile .verification-box > p { margin-bottom: 0; font-size: 0.9rem; line-height: 1.55; color: var(--ink-mute); }

/* Services: since 22 Oct 2026 each list is quiet wrapping tags across the
   full width (.profile-tags, below in THE PROFILE AS A DECISION PAGE), one
   group under another, never folded; the side-by-side columns are gone. A
   member's own bulleted list (Training and experience) wears a neutral
   bullet; the green tick stays for the one checked line (.service-checked). */
:is(.design-what, .profile-what).page-profile .profile-service-group .tier-features { margin-bottom: 0; }
:is(.design-what, .profile-what).page-profile .profile-training-list li::before,
:is(.design-what, .profile-what).page-profile .profile-service-group .tier-features li:not(.service-checked)::before {
  top: 0.6em;
  left: 0.3rem;
  width: 0.4rem;
  height: 0.4rem;
  border: 0;
  border-radius: 50%;
  background: var(--ink-mute);
  transform: none;
}
:is(.design-what, .profile-what).page-profile .profile-services-note { margin: var(--space-5) 0 0; }

/* The fee notes stay with the prices: a modest left rule in the brand's warm
   second colour (WhatHypno --accent-warm; WhatCounsellor's apricot is its
   --brass), never a coloured card. */
:is(.design-what, .profile-what).page-profile .profile-fee-notes { margin: var(--space-4) 0; padding: var(--space-3) var(--space-4); border-left: 3px solid var(--accent-warm, var(--brass)); background: var(--paper); border-radius: 0 var(--radius) var(--radius) 0; }
:is(.design-what, .profile-what).page-profile .profile-fee-notes > .leader-row:last-child { margin-bottom: 0; }
:is(.design-what, .profile-what).page-profile .profile-fee-note { margin: var(--space-2) 0 0; max-width: none; }
:is(.design-what, .profile-what).page-profile .profile-fee-notes > .profile-fee-note:first-child { margin-top: 0; }

/* Typical working hours stay open as a short day-by-day list at every width
   (no grid on the WHAT brands): the day, then its stated periods. */
:is(.design-what, .profile-what).page-profile .public-hours-days { display: block; margin: var(--space-3) 0; border-top: 1px solid var(--line); }
:is(.design-what, .profile-what).page-profile .public-hours-days > div { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: var(--space-3); margin: 0; padding: var(--space-2) 0; border-bottom: 1px solid var(--line); }
:is(.design-what, .profile-what).page-profile .public-hours-days dt { font-weight: 600; }
:is(.design-what, .profile-what).page-profile .public-hours-days dd { margin: 0; }
@media (max-width: 400px) {
  :is(.design-what, .profile-what).page-profile .public-hours-days > div { grid-template-columns: 6.5rem minmax(0, 1fr); gap: var(--space-2); }
}

/* -------------------------------------------------------------------------
   THE WHAT PROFILE HEADER (Rick's GO, 14 Oct 2026; DESIGN-STANDARDS.md, the
   14 Oct "profile header" row, which replaces the 2 Sep "masthead
   photographs, never buttons" rule on the WHAT brands only). Who the person
   is, what we checked, whether they are taking clients and how to reach
   them, first: partials/profile_contact.php in the masthead, the room
   photographs as "Where you'll meet" in Location and fees, and the rail's
   own buttons only once the masthead row has gone (main.js, data-follow).
   ------------------------------------------------------------------------- */

/* THE SLIM HEADER (Rick, 14 Oct 2026: "slick and sleek, not deep"). Four
   rows beside the portrait, nothing dead on the right: the name with the
   availability pill at the right of its row; the title and town with the
   quiet founding mark and member number; the checked membership line (the
   rating at its right where there is one); and, under a hairline, the
   contact row with the phone number at the right. The name is set in Source
   Serif 4, the self-hosted serif whose @font-face (section 2, font-display:
   swap) is in this file for every brand; the WHAT themes keep Figtree for
   everything else. */
:is(.design-what, .profile-what).page-profile .profile-masthead { padding-block: var(--space-6); }
:is(.design-what, .profile-what).page-profile .profile-head-main h1 { font-family: 'Source Serif 4', Georgia, 'Times New Roman', serif; font-weight: 600; }
:is(.design-what, .profile-what).page-profile .profile-checked-line { font-size: 1.02rem; }
:is(.design-what, .profile-what).page-profile .profile-checked-date { font-weight: 400; }
@media (min-width: 720px) {
  :is(.design-what, .profile-what).page-profile .profile-head-main { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: var(--space-5); row-gap: var(--space-2); }
  :is(.design-what, .profile-what).page-profile .profile-head-main > * { grid-column: 1 / -1; }
  :is(.design-what, .profile-what).page-profile .profile-head-main > h1 { grid-column: 1; }
  :is(.design-what, .profile-what).page-profile .profile-head-main > .profile-status { grid-column: 2; grid-row: 1; justify-self: end; }
  /* Centring in the row puts the pill on the middle of the name's capitals;
     the eye reads a name by its lower-case letters, whose middle is about
     a tenth of the name's size lower in Source Serif 4 (the size is the
     name's own clamp, below). */
  :is(.design-what, .profile-what).page-profile .profile-head-main > .profile-status { position: relative; top: calc(0.1 * clamp(2rem, 4vw, 2.9rem)); }
  :is(.design-what, .profile-what).page-profile .profile-head-main > .profile-checked-line:has(+ .profile-rating) { grid-column: 1; }
  :is(.design-what, .profile-what).page-profile .profile-head-main > .profile-rating { grid-column: 2; justify-self: end; }
}
/* MLD (the WHAT layout through its pack, 16 Oct 2026): the star rating
   sits on the checked line, never a row of its own. Wide screens: at the
   right end of that line, where the WHAT rating sits. A phone: it follows
   the checked words in the same paragraph, wrapping like text, with the
   wrapped words held clear of the tick. Only MLD's markup carries
   .profile-rating-inline, so the WHAT brands are untouched. */
:is(.design-what, .profile-what).page-profile .profile-rating-inline { margin: 0; text-indent: 0; white-space: nowrap; }
@media (min-width: 720px) {
  :is(.design-what, .profile-what).page-profile .profile-checked-line:has(.profile-rating-inline) { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; column-gap: var(--space-5); row-gap: var(--space-2); }
}
@media (max-width: 719px) {
  :is(.design-what, .profile-what).page-profile .profile-checked-line:has(.profile-rating-inline) { padding-left: 1.45em; text-indent: -1.45em; }
  :is(.design-what, .profile-what).page-profile .profile-checked-line:has(.profile-rating-inline) .profile-checked { display: inline; }
  :is(.design-what, .profile-what).page-profile .profile-checked-line:has(.profile-rating-inline) .profile-checked::before { display: inline-block; width: 1.05em; margin: 0 0.4em 0 0; vertical-align: -0.15em; }
  :is(.design-what, .profile-what).page-profile .profile-rating-inline { display: inline-block; margin-left: 0.4em; }
}

/* The contact row: Send enquiry first, Book online and Visit website where
   the member has them, the Save icon, and the number large at the right.
   Wraps on a narrow column, never scrolls sideways. */
:is(.design-what, .profile-what).page-profile .profile-contact { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin-top: var(--space-3); padding-top: var(--space-4); border-top: 1px solid var(--line); }
:is(.design-what, .profile-what).page-profile .profile-contact > .btn { display: inline-flex; align-items: center; justify-content: center; margin: 0; }
:is(.design-what, .profile-what).page-profile .profile-contact-call { gap: 0.45em; }
:is(.design-what, .profile-what).page-profile .profile-contact-call-icon {
  flex: none; width: 1.05em; height: 1.05em; background: currentColor;
  -webkit-mask: url(/assets/img/icons/lucide/phone.svg) center / contain no-repeat;
          mask: url(/assets/img/icons/lucide/phone.svg) center / contain no-repeat;
}
:is(.design-what, .profile-what).page-profile .profile-contact > .profile-contact-call { display: none; }
:is(.design-what, .profile-what).page-profile .profile-contact-phone { display: inline-flex; align-items: center; gap: var(--space-2); margin-left: auto; min-height: 2.75rem; font-size: 1.125rem; font-weight: 600; line-height: 1.2; color: var(--ink-mute); text-decoration: none; font-variant-numeric: tabular-nums; white-space: nowrap; }
:is(.design-what, .profile-what).page-profile .profile-contact-phone:hover,
:is(.design-what, .profile-what).page-profile .profile-contact-phone:focus-visible { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 4px; }
:is(.design-what, .profile-what).page-profile .profile-contact-phone-icon {
  flex: none; width: 1.1rem; height: 1.1rem; background: var(--green);
  -webkit-mask: url(/assets/img/icons/lucide/phone.svg) center / contain no-repeat;
          mask: url(/assets/img/icons/lucide/phone.svg) center / contain no-repeat;
}
/* Save: the compare shortlist's own list (main.js), as a borderless icon
   button (the slim header, 14 Oct 2026) with a 44px tap target, its words in
   its aria-label and title, and a wash on hover and focus; saved, it shows
   the ticked bookmark. Shown only by the script. */
:is(.design-what, .profile-what).page-profile .profile-save {
  display: inline-grid; place-items: center; flex: none;
  width: 2.75rem; height: 2.75rem; padding: 0;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--green); cursor: pointer;
  transition: background-color 180ms var(--ease-out);
}
:is(.design-what, .profile-what).page-profile .profile-save[hidden] { display: none; }
:is(.design-what, .profile-what).page-profile .profile-save:hover,
:is(.design-what, .profile-what).page-profile .profile-save:focus-visible { background: var(--green-wash); }
:is(.design-what, .profile-what).page-profile .profile-save-icon {
  width: 1.4rem; height: 1.4rem; background: currentColor;
  -webkit-mask: url(/assets/img/icons/lucide/bookmark.svg) center / contain no-repeat;
          mask: url(/assets/img/icons/lucide/bookmark.svg) center / contain no-repeat;
}
:is(.design-what, .profile-what).page-profile .profile-save[aria-pressed="true"] .profile-save-icon { -webkit-mask-image: url(/assets/img/icons/lucide/bookmark-check.svg); mask-image: url(/assets/img/icons/lucide/bookmark-check.svg); }
@media (prefers-reduced-motion: reduce) {
  :is(.design-what, .profile-what).page-profile .profile-save { transition: none; }
}
/* A phone (the slim header's design review, 14 Oct 2026): the buttons two
   by two, Call and Send enquiry, then Book online and Visit website; a
   button alone in its row (no phone, or only one of the two links) spans
   it. Call says "Call" with the phone icon, the number in its accessible
   name. Save sits in the top-right corner of the identity block, beside the
   name, and the name keeps clear of it. */
@media (max-width: 719px) {
  :is(.design-what, .profile-what).page-profile .profile-header { position: relative; }
  :is(.design-what, .profile-what).page-profile .profile-contact { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); margin-top: var(--space-4); }
  :is(.design-what, .profile-what).page-profile .profile-contact > .btn { width: 100%; min-width: 0; padding-inline: var(--space-3); white-space: nowrap; }
  :is(.design-what, .profile-what).page-profile .profile-contact > .profile-contact-call { display: inline-flex; }
  :is(.design-what, .profile-what).page-profile .profile-contact > .btn-primary:first-child,
  :is(.design-what, .profile-what).page-profile .profile-contact > .btn-primary + .profile-contact-cta:not(:has(+ .btn)) { grid-column: 1 / -1; }
  :is(.design-what, .profile-what).page-profile .profile-save { position: absolute; top: -0.3rem; right: -0.6875rem; }
  :is(.design-what, .profile-what).page-profile .profile-header:has(.profile-save:not([hidden])) .profile-head-main > h1 { padding-right: 2.25rem; }
  :is(.design-what, .profile-what).page-profile .profile-contact > .profile-contact-phone { display: none; }
}

/* Where you'll meet: the room photographs beside the address, the same 4:3
   tiles and "+N more" as before, in one row of up to four (two by two on a
   small phone). */
:is(.design-what, .profile-what).page-profile .profile-meet { margin: var(--space-5) 0 var(--space-6); }
:is(.design-what, .profile-what).page-profile .profile-meet-title { margin: 0 0 var(--space-2); max-width: none; font-weight: 600; color: var(--ink); }
:is(.design-what, .profile-what).page-profile .profile-meet-gallery { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-2); max-width: 40rem; }
:is(.design-what, .profile-what).page-profile .profile-meet-gallery[data-count="1"] { grid-template-columns: minmax(0, 1fr); max-width: 15rem; }
:is(.design-what, .profile-what).page-profile .profile-meet-gallery[data-count="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 25rem; }
:is(.design-what, .profile-what).page-profile .profile-meet-gallery[data-count="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: 32rem; }
:is(.design-what, .profile-what).page-profile .profile-meet-gallery .gallery-more-label { font-size: 0.95rem; }
@media (max-width: 479px) {
  :is(.design-what, .profile-what).page-profile .profile-meet-gallery[data-count="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* The example's note that its Book online and Visit website stay on this
   page: where both land, clear of the sticky header. */
:is(.design-what, .profile-what).page-profile .sample-links-note { scroll-margin-top: calc(var(--header-offset) + var(--space-6)); }

/* The section menu: About, Services, Fees, Contact on one line at 320px;
   it still wraps, never scrolls, when a member has more sections. */
:is(.design-what, .profile-what).page-profile .profile-nav ul { column-gap: var(--space-5); }
@media (max-width: 399px) {
  :is(.design-what, .profile-what).page-profile .profile-nav ul { column-gap: var(--space-4); }
}

/* The rail: "Sessions from" and the social icons stay; the card's own
   buttons, phone and website follow the masthead row (main.js sets
   data-follow="hidden" on the rail while that row is on screen; without the
   script they simply show). Below 960px the phone bar does that job, so the
   card is the decision card's facts alone, still a card (22 Oct 2026: on a
   phone it sits straight under the header and answers price, free call,
   formats and availability before About; see THE PROFILE AS A DECISION
   PAGE below). */
:is(.design-what, .profile-what).page-profile .profile-quick { display: flex; flex-direction: column; gap: var(--space-4); }
:is(.design-what, .profile-what).page-profile .profile-quick > * { margin: 0; }
:is(.design-what, .profile-what).page-profile .profile-quick-follow > .profile-quick-contact { margin-top: var(--space-3); }
@media (min-width: 960px) {
  :is(.design-what, .profile-what).page-profile .profile-aside[data-follow="hidden"] :is(.profile-quick-follow, .profile-quick-followonly) { display: none; }
}
@media (max-width: 959.98px) {
  :is(.design-what, .profile-what).page-profile :is(.profile-quick-follow, .profile-quick-followonly) { display: none; }
  :is(.design-what, .profile-what).page-profile .profile-quick { gap: var(--space-3); }
  :is(.design-what, .profile-what).page-profile .profile-quick-social { justify-content: flex-start; }
}

/* -------------------------------------------------------------------------
   THE PROFILE AS A DECISION PAGE (Rick's GO, 22 Oct 2026; what-brands/output/
   profile-review-2026-10-22/VERDICT.md items 1 to 7, DESIGN-STANDARDS.md 22
   Oct row). A therapist profile, not a CV: the decision card at the top of
   the side panel, and About, Services, Location and fees, Reviews and the
   enquiry on the same white card the side panel uses (--surface, --line,
   --radius-lg, --shadow-1), one gap between cards, section headings at
   1.8rem so they never compete with the name (Rick), sub-headings a clear
   step under them and never under 16px. The portrait and the name are
   untouched. Every brand through its own tokens, MLD (.profile-what) too.
   ------------------------------------------------------------------------- */

/* The decision card: left-aligned, the price line as its lead, the facts
   under a hairline in the dated-facts list the Registration card uses. */
:is(.design-what, .profile-what).page-profile .profile-quick { text-align: left; }
:is(.design-what, .profile-what).page-profile .profile-quick-fee { font-size: 1.2rem; line-height: 1.35; color: var(--ink); }
:is(.design-what, .profile-what).page-profile .profile-quick-fee-length { white-space: nowrap; }
:is(.design-what, .profile-what).page-profile .profile-quick .profile-facts { margin: 0; }
:is(.design-what, .profile-what).page-profile .profile-quick-fee + .profile-facts { padding-top: var(--space-1); border-top: 1px solid var(--line); }
:is(.design-what, .profile-what).page-profile .profile-quick-fee + .profile-facts .fact:first-child { padding-top: 0.5rem; }
:is(.design-what, .profile-what).page-profile .profile-quick .profile-facts dd { font-weight: 500; overflow-wrap: break-word; }

/* The main column's sections as cards, one gap apart. */
:is(.design-what, .profile-what).page-profile .profile-main > .profile-section {
  margin: 0 0 var(--profile-gap);
  padding: var(--space-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}
:is(.design-what, .profile-what).page-profile .profile-main > .profile-section:last-child { margin-bottom: 0; }
/* The card's own padding is its last gap: whatever ends a card (a list, the
   fee notes, the hours note) adds no margin under it. */
:is(.design-what, .profile-what).page-profile .profile-main > .profile-section > :last-child,
:is(.design-what, .profile-what).page-profile .profile-main > .profile-section > :last-child > :last-child,
:is(.design-what, .profile-what).page-profile .profile-main .profile-practice-facts > :last-child { margin-bottom: 0; }
/* The heading scale: section 1.8rem (Rick, 22 Oct 2026), sub-headings
   1.25rem; on a phone, where the name is 1.75rem, 1.5rem and 1.2rem so a
   section heading never outsizes the name. */
:is(.design-what, .profile-what).page-profile .profile-main .profile-section > h2 { margin: 0 0 var(--space-4); font-size: 1.8rem; line-height: 1.2; }
:is(.design-what, .profile-what).page-profile .profile-main .profile-section h3 { margin: var(--space-6) 0 var(--space-3); font-size: 1.25rem; line-height: 1.3; }
:is(.design-what, .profile-what).page-profile .profile-main .profile-section > :is(h2, p) + .profile-service-group > h3 { margin-top: var(--space-5); }

/* Services: quiet tags across the full width, groups one under another. */
:is(.design-what, .profile-what).page-profile .profile-service-group .profile-tags { margin-bottom: 0; }
:is(.design-what, .profile-what).page-profile .profile-service-checked { margin: var(--space-4) 0 0; }

/* Training and experience: the member's list under its lead-in. */
:is(.design-what, .profile-what).page-profile .profile-training-list { margin: 0 0 var(--space-4); }
:is(.design-what, .profile-what).page-profile .profile-training > :last-child { margin-bottom: 0; }

/* Phones and tablets: the cards one gap apart in the single column. */
@media (max-width: 959.98px) {
  :is(.design-what, .profile-what).page-profile .profile-layout { gap: var(--profile-gap); }
  :is(.design-what, .profile-what).page-profile .profile-main > .profile-section { margin-bottom: 0; }
}
@media (max-width: 719px) {
  :is(.design-what, .profile-what).page-profile :is(.profile-quick, .verification-box, .profile-main > .profile-section) { padding: var(--space-5) var(--space-4); }
  :is(.design-what, .profile-what).page-profile .profile-main .profile-section > h2 { font-size: 1.5rem; }
  :is(.design-what, .profile-what).page-profile .profile-main .profile-section h3 { margin-top: var(--space-5); font-size: 1.2rem; }
}

/* -------------------------------------------------------------------------
   ICONS AND COLOUR ON THE PROFILE (Rick, 22 Oct 2026, after the decision
   card screenshots: "the page looks really text heavy and lacks icons and
   colours to differentiate aspects"). Each style once, on each brand's own
   tokens, MLD (.profile-what) too:
   - a small line icon (the Lucide set through what_icon(), 1.25rem, in the
     brand ink --green) before each main-column section heading, and hung in
     the left gutter of each decision card row, Registration row and
     location, level with the row's first line; always aria-hidden, the words
     carry the meaning;
   - the decision card on the brand's pale wash with the availability pill's
     keyline, so it reads as the place to decide, apart from the white
     content cards;
   - Areas tags on the brand wash in the brand ink, Approaches tags on the
     accent tint (--profile-tag-alt-bg: apricot on WhatCounsellor, gold on
     MLD, warm ivory with an apricot keyline on WhatHypno, whose own soft
     accent is the same sea glass as its wash), so the lists are told apart;
   - the checked rows of the Registration card (the check date, the
     insurance end date, a checked training) in the green tick and green
     words of the header's checked line;
   - "Read more about {name}" as the secondary button with a chevron.
   ------------------------------------------------------------------------- */
:is(.design-what, .profile-what).page-profile .line-icon.line-icon-inline { display: inline-block; flex: none; width: 1.25rem; height: 1.25rem; margin: 0; background: var(--green); }
/* Hung in the gutter: the row's words keep one edge, 2rem in. */
:is(.design-what, .profile-what).page-profile .icon-row { position: relative; padding-left: 2rem; }
:is(.design-what, .profile-what).page-profile .icon-row > .line-icon-inline { position: absolute; left: 0; top: calc((1lh - 1.25rem) / 2); }
:is(.design-what, .profile-what).page-profile .facts-iconed .fact { padding-left: 2rem; }
:is(.design-what, .profile-what).page-profile .facts-iconed dt { position: relative; }
:is(.design-what, .profile-what).page-profile .facts-iconed dt > .line-icon-inline,
:is(.design-what, .profile-what).page-profile .facts-iconed .fact-ok > dt::before { position: absolute; left: -2rem; top: calc((1lh - 1.25rem) / 2); }
/* Before a section heading, on its first line. */
:is(.design-what, .profile-what).page-profile .profile-section > h2 > .line-icon-inline { margin-right: 0.6rem; vertical-align: -0.05em; }
/* The checked rows: the header's checked-line tick and its green words. */
:is(.design-what, .profile-what).page-profile .facts-iconed .fact-ok > dt::before {
  content: ""; width: 1.25rem; height: 1.25rem;
  background: var(--verified, var(--green));
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill-rule='evenodd' d='M10 0a10 10 0 100 20 10 10 0 000-20zM5.2 10.1l1.3-1.4 2.2 2.3 4.7-5 1.4 1.4-6.1 6.4z'/%3E%3C/svg%3E") center / contain no-repeat;
}
:is(.design-what, .profile-what).page-profile .facts-iconed .fact-ok dd { color: var(--verified, var(--green)); font-weight: 600; }
:is(.design-what, .profile-what).page-profile .facts-iconed .fact-ok dd::before { content: none; }
/* The decision card on the brand wash, keyline as the availability pill. */
:is(.design-what, .profile-what).page-profile .profile-quick { background: var(--green-wash); border-color: var(--tone-neutral-border); }
/* A card taller than the room under the header (main.js marks the rail
   is-tall-card and pins the card by its foot): until that foot reaches the
   window's foot, the card's buttons ride at the window's foot on the same
   wash, so Send enquiry is on screen from the moment the header's contact
   row scrolls away. The two shadows are the wash above and below them, so
   no half line of the facts shows around the buttons. */
@media (min-width: 960px) {
  :is(.design-what, .profile-what).page-profile .profile-aside.is-tall-card .profile-quick-follow { position: sticky; bottom: var(--space-4); z-index: 1; background: var(--green-wash); box-shadow: 0 calc(-1 * var(--space-3)) 0 var(--green-wash), 0 var(--space-4) 0 var(--green-wash); }
}
/* The two kinds of tag, each with a 1px keyline a shade darker than its own
   tint (the profile round 2, 22 Oct 2026), mixed from the brand's tokens so
   the shape reads; a brand that sets --profile-tag-alt-border keeps it. The
   plain --line first, for a browser without color-mix(). */
:is(.design-what, .profile-what).page-profile .profile-tags > .chip-quiet { background: var(--green-wash); border-color: var(--line); border-color: color-mix(in oklab, var(--green-wash), var(--green) 22%); color: var(--green); }
:is(.design-what, .profile-what).page-profile .profile-tags-alt > .chip-quiet { background: var(--profile-tag-alt-bg, var(--brass-soft)); border-color: var(--line); border-color: var(--profile-tag-alt-border, color-mix(in oklab, var(--profile-tag-alt-bg, var(--brass-soft)), var(--ink) 14%)); color: var(--ink); }
/* A detail in brackets inside an accent tag stays in the ink: the muted ink
   falls under 4.5:1 on WhatCounsellor's apricot. */
:is(.design-what, .profile-what).page-profile .profile-tags-alt > .chip-quiet .text-muted { color: var(--ink); }
/* Read more: a plain text link in the brand colour, body size, with a small
   chevron that turns when open (the profile round 2, 22 Oct 2026; it was the
   secondary button). No box or border; its padding makes the tap target
   44px tall; the site's focus ring. */
:is(.design-what, .profile-what).page-profile .bio-more > summary.bio-more-link { display: inline-flex; align-items: center; gap: 0.35rem; min-height: 44px; margin: 0; padding-block: 0.625rem; font-size: 1rem; font-weight: 600; line-height: 1.5; color: var(--green); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2.5px; text-decoration-color: var(--link-underline); }
:is(.design-what, .profile-what).page-profile .bio-more > summary.bio-more-link:hover { color: var(--green-deep); text-decoration-color: currentColor; }
:is(.design-what, .profile-what).page-profile .bio-more > summary.bio-more-link:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 2px; }
:is(.design-what, .profile-what).page-profile .bio-more > summary.bio-more-link > .line-icon-inline { width: 1rem; height: 1rem; background: currentColor; transition: transform 180ms var(--ease-out); }
:is(.design-what, .profile-what).page-profile .bio-more[open] > summary.bio-more-link { margin-bottom: var(--space-2); }
:is(.design-what, .profile-what).page-profile .bio-more[open] > summary.bio-more-link > .line-icon-inline { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  :is(.design-what, .profile-what).page-profile .bio-more > summary.bio-more-link > .line-icon-inline { transition: none; }
}

/* -------------------------------------------------------------------------
   THE PROFILE, ROUND 2 (Rick's GO, 22 Oct 2026). Every brand through its
   own tokens, MLD (.profile-what) too:
   - the checks card (Registration and insurance; MLD's Verification) is a
     card in the main column straight after About, #checks, the target of
     the checked line under the name; its rows in two columns from 720px so
     it stays short, one column on a phone; never folded. The side panel
     holds only the decision card.
   - anchor jumps land each card's top edge 24px under the header's real
     foot (--header-real from main.js plus --space-4 on html, plus 8px here);
   - the side panel never anchors scrolling: its buttons appear and go as
     the reader scrolls, and the browser's scroll anchoring then moved the
     page under a reader who had just jumped to About.
   ------------------------------------------------------------------------- */
:is(.design-what, .profile-what).page-profile .profile-main > :is(.profile-section, .verification-box) { scroll-margin-top: var(--space-2); }
:is(.design-what, .profile-what).page-profile .profile-layout .profile-aside { overflow-anchor: none; }
:is(.design-what, .profile-what).page-profile .profile-main > .verification-box { margin: 0 0 var(--profile-gap); border-color: var(--line); }
:is(.design-what, .profile-what).page-profile .profile-main > .verification-box:last-child { margin-bottom: 0; }
:is(.design-what, .profile-what).page-profile .profile-main > .verification-box > .verification-box-head { margin: 0 0 var(--space-4); padding-bottom: 0; border-bottom: 0; }
:is(.design-what, .profile-what).page-profile .profile-main > .verification-box > .verification-box-head h2 { min-height: 0; font-size: 1.8rem; line-height: 1.2; }
:is(.design-what, .profile-what).page-profile .profile-main > .verification-box > .verification-box-head h2 > .line-icon-inline { margin-right: 0.6rem; }
@media (min-width: 720px) {
  :is(.design-what, .profile-what).page-profile .profile-main > .verification-box { padding: var(--space-6); }
  :is(.design-what, .profile-what).page-profile .profile-main > .verification-box .admission-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-6); }
  :is(.design-what, .profile-what).page-profile .profile-main > .verification-box .admission-facts > .fact:nth-child(-n+2) { border-top: 0; padding-top: 0; }
}
@media (max-width: 719px) {
  :is(.design-what, .profile-what).page-profile .profile-main > .verification-box > .verification-box-head h2 { font-size: 1.5rem; }
}
/* Phones and tablets: the single column's grid gap is the only space
   between cards, so the checks card drops its own bottom margin there, as
   the sections do (the fix round, 22 Oct 2026: it made 48px before
   Services where every other gap is 24px). */
@media (max-width: 959.98px) {
  :is(.design-what, .profile-what).page-profile .profile-main > .verification-box { margin-bottom: 0; }
}
/* MLD's Verification card in the main column (rows, not a list): from
   720px the training on the left and the dated rows on the right, so the
   card stays short; the heading and "What does Verified mean?" across the
   top and foot. Words and rows unchanged. Without :has() it stays one
   column. */
@media (min-width: 720px) {
  :is(.design-what, .profile-what).page-profile .profile-main > .verification-box:has(> .leader-row-training) { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-6); align-items: start; }
  :is(.design-what, .profile-what).page-profile .profile-main > .verification-box:has(> .leader-row-training) > :not(.leader-row) { grid-column: 1 / -1; }
  :is(.design-what, .profile-what).page-profile .profile-main > .verification-box:has(> .leader-row-training) > .leader-row-training { grid-column: 1; grid-row: 2 / span 6; }
  :is(.design-what, .profile-what).page-profile .profile-main > .verification-box:has(> .leader-row-training) > .leader-row:not(.leader-row-training) { grid-column: 2; }
}

/* The WHAT legal pages' short contents list (conversion review SH-09, 10 Oct
   2026): links to the clauses and headings already on the page. */
.legal-contents { margin: var(--space-5) 0; padding: var(--space-4) var(--space-5); background: var(--paper-2); border-radius: var(--radius); }
.legal-contents-title { margin: 0 0 var(--space-2); }
.legal-contents ul { margin: 0; padding: 0; list-style: none; font-size: 0.95rem; line-height: 1.7; }
@media (min-width: 720px) { .legal-contents ul { columns: 2; column-gap: var(--space-6); } }
.legal-contents li { break-inside: avoid; }
.cmp-table-what .cmp-initials { display: grid; place-items: center; width: 4rem; height: 4rem; margin-bottom: var(--space-1); border-radius: 50%; background: var(--green-wash); color: var(--green); font-family: var(--font-serif); font-size: 1.2rem; }

/* -------------------------------------------------------------------------
   Photo band (.photo-band): one photograph edge to edge across the screen
   in its own band, between two sections (Rick, 13 Oct 2026, the WHAT
   practitioners page: "make the image full width, no bleed and parallax").
   .photo-band-parallax lets main.js move the photograph a little slower
   than the page; the photograph is made taller than the band only while
   that script runs, so without it the picture sits centred and still.
   ------------------------------------------------------------------------- */
.photo-band {
  position: relative;
  overflow: hidden;
  height: clamp(16rem, 38vw, 34rem);
  margin: 0;
}
.photo-band img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.photo-band-js .photo-band-parallax img {
  position: absolute;
  left: 0;
  top: -15%;
  height: 130%;
  will-change: transform;
}

/* WHAT plan boxes (offer_box partial and the pricing page's Featured card):
   the plan's name is the largest thing in the box and the free months sit
   under it (Rick, 13 Oct 2026: "The packages titles should be the largest
   items", not "Six months free"). */
.tier-box-what .tier-box-name { font-size: 1.5rem; line-height: 1.15; margin-bottom: var(--space-2); }
.tier-box-what .tier-box-price { font-size: 1.2rem; line-height: 1.35; }
.tier-box-what .tier-box-flag { font-size: 0.8rem; }
.tier-box-what .tier-plus-lead { font-weight: 400; }
.btn-row-center { justify-content: center; }
.text-balance { text-wrap: balance; }
.page-pricing .page-header .lead { max-width: 50rem; }
/* "Learn more" on the Featured card: the rest of its words, folded. */
.tier-more { margin-top: var(--space-4); }
.tier-more > summary { cursor: pointer; font-weight: 600; color: var(--green); width: fit-content; }
.tier-more > summary:hover { text-decoration: underline; }
.tier-more[open] > summary { margin-bottom: var(--space-3); }

/* A photograph beside text, cut to the text's height (Rick, 13 Oct 2026,
   WhatHypno's About photo "too tall, crop it from the top so it matches the
   height of the text"). The photo keeps its bottom and loses its top. In the
   single phone column it shows whole. */
@media (min-width: 640px) {
  .ledger-photo-fit { min-height: 18rem; }
  .ledger-photo-fit img { position: absolute; inset: 0; height: 100%; object-fit: cover; object-position: center bottom; }
}

/* About, "Why we built it": a wider gap between the words and the photo
   (Rick, 13 Oct 2026). */
@media (min-width: 640px) {
  .about-story .grid-2 { column-gap: clamp(3rem, 7vw, 7rem); }
}

/* join-form-ux (15 Oct 2026): the WHAT join page, offer page and application
   form (what-brands/briefs/ENGINE-join-form-ux.md). Every rule hangs off
   markup only the WHAT brands print, or a class MLD never carries, so MLD
   looks as before. The reusable classes (also listed in ENGINE.md):
   .step-line       one line "Step N of M: Stage", shown on phones in place
                    of a step bar (the join's and the application form's)
   .step-number     the "Step 1: " of an inner heading, hidden where
                    .step-line shows, so a screen never has two numberings
   .form-section    a group of fields under its own heading; with
                    .dash-fieldset it is a CARD on the WHAT sign-up and member
                    screens (body .design-what) and every brand's admin (body
                    .page-admin), and a hairline sub-group inside a card
                    (round 3, "CARD SECTIONS" below)
   .radio-row       radios side by side where there is room
   .onboard-more-quiet  an .onboard-more disclosure as a "+ Add ..." text link
   .link-action     a quiet text button (Edit, Remove, Cancel, Keep editing)
   .hairline-list   a plain list, its items set apart by hairlines
   .help-offer      decision 13's one-line help offer, muted, no box
   .onboard-review, .review-missing, .review-lines  the WHAT Review and
                    submit card: what is missing, the button, then one short
                    line per step with an Edit link
   .location-place and .location-suggestions: the postcode suggestion list,
                    the same rules as MLD's theme.css, so every brand has it
   Text links are 44px tall on phones (padding, not a bigger look). */

/* The step indicator: the bar on desktop, one line on a phone. */
.step-line { display: none; }
@media (max-width: 559px) {
  .step-line { display: block; margin: var(--space-4) 0 var(--space-5); text-align: center; font-size: 0.95rem; font-weight: 700; color: var(--ink); max-width: none; }
  .wizard-bar .step-line { margin: 0; text-align: left; }
  .join-progress-what, .wizard-steps-what, .step-line ~ .wizard-count, .step-number { display: none; }
}
/* The application form's bar (decision 7): a tick is a saved step, the filled
   number the step you are on, an outlined number still to do. */
.wizard-steps-what .wizard-num { background: transparent; box-shadow: inset 0 0 0 1.5px var(--line-strong); color: var(--ink-mute); }
.wizard-steps-what .is-done .wizard-num,
.wizard-steps-what .wizard-num.is-tick { background: var(--tick-green-wash); box-shadow: none; color: var(--tick-green); }
.wizard-steps-what .is-current .wizard-num { background: var(--green); box-shadow: none; color: var(--on-green); }
.wizard-steps-what .is-done .wizard-step { border-color: var(--line); }

/* Postcode suggestions and the town under the field. */
.location-place { color: var(--ink); font-weight: 600; }
.location-place:empty { display: none; }
.location-suggestions { position: absolute; inset: calc(100% + .25rem) 0 auto; z-index: 12; list-style: none; margin: 0; padding: .25rem; max-height: 17rem; overflow-y: auto; overscroll-behavior: contain; background: var(--surface); border: 1px solid var(--line); border-radius: .4rem; box-shadow: 0 .5rem 1.5rem #0f21371a; }
.location-suggestions[hidden] { display: none; }
.location-suggestions [role="option"] { min-height: 44px; padding: .55rem .75rem; margin: 0; cursor: pointer; border-radius: .25rem; line-height: 1.4; overflow-wrap: anywhere; }
.location-suggestion-name, .location-suggestion-area { display: block; }
.location-suggestion-name { font-weight: 600; color: var(--ink); }
.location-suggestion-area { font-size: .85rem; color: var(--ink-soft); }
.location-suggestions [role="option"]:hover, .location-suggestions [aria-selected="true"] { background: var(--ink); }
.location-suggestions [role="option"]:hover span, .location-suggestions [aria-selected="true"] span { color: #fff; }
.location-status:empty { margin: 0; }
@media (max-width: 650px) { .location-suggestions { max-height: min(17rem, 40svh); } }

/* A plain list set apart by hairlines: the offer's terms, the saved courses. */
.hairline-list { list-style: none; margin: 0 0 var(--space-3); padding: 0; }
.hairline-list > li { margin: 0; padding: var(--space-3) 0; border-top: 1px solid var(--line); }
.hairline-list > li:first-child { border-top: 0; padding-top: 0; }
.card-setup .hairline-list { margin: var(--space-3) 0 0; }
.card-setup .hairline-list > li { padding: .6rem 0; font-size: .94rem; line-height: 1.5; color: var(--ink-soft); }
.card-setup .hairline-list > li:first-child { padding-top: 0; }
.card-setup .hairline-list strong { color: var(--ink); }
/* The offer page: room between "Membership details" and the box she ticks. */
.card-setup-details + .card-setup-form { margin-top: var(--space-5); }
.hairline-list .course-editor { margin-top: var(--space-3); }
.hairline-list .course-editor:first-child { margin-top: 0; }
.hairline-list .course-actions { margin-top: var(--space-1); }
.hairline-list .course-status { display: inline; margin: 0; }

/* CARD SECTIONS (decision 20, round 3). One rule set for every bordered
   section whose heading used to sit in or break its top border: .dash-fieldset,
   .form-section and an admin fieldset.field. Scope: the WHAT brands' sign-up
   and member screens (body .design-what, which layout.php sets on design
   'what' only) and every brand's admin (body .page-admin). MLD's public and
   member screens carry neither hook, so they draw exactly as before.
   A section is a card: heading inside and aligned with its fields, a 1px
   --line border, --surface, the card radius of .panel, one padding. The WHAT
   location row is a card of its own. Inside a card (.panel, .admin-section,
   another section) a section is never a second card: it is a sub-group under
   a hairline, its heading one size down. */
:is(.design-what, .page-admin, .signup-what) :is(.dash-fieldset, .form-section),
.page-admin fieldset.field,
:is(.design-what, .signup-what) .onboard-what [data-location-row] { min-width: 0; margin: 0 0 var(--space-5); padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); }
:is(.design-what, .page-admin, .signup-what) :is(.dash-fieldset, .form-section) > legend,
.page-admin fieldset.field > legend { float: left; width: 100%; margin: 0 0 var(--space-4); padding: 0; font-family: var(--font-serif); font-size: 1.375rem; font-weight: 600; line-height: 1.25; letter-spacing: -0.01em; color: var(--ink); }
:is(.design-what, .page-admin, .signup-what) :is(.dash-fieldset, .form-section) > :not(legend),
.page-admin fieldset.field > :not(legend) { clear: both; }
:is(.design-what, .page-admin, .signup-what) :is(.dash-fieldset, .form-section, [data-location-row]) > :last-child,
.page-admin fieldset.field > :last-child { margin-bottom: 0; }
/* A section inside a card: a hairline sub-group, no second box. */
:is(.design-what, .page-admin, .signup-what) :is(.panel, .admin-section, .dash-fieldset, .form-section, fieldset.field, [data-location-row]) :is(.dash-fieldset, .form-section, fieldset.field:has(> legend):not(.training-course-group fieldset)) { margin: var(--space-5) 0 var(--space-4); padding: var(--space-4) 0 0; border: 0; border-top: 1px solid var(--line); border-radius: 0; background: none; }
:is(.design-what, .page-admin, .signup-what) :is(.panel, .admin-section, .dash-fieldset, .form-section, fieldset.field, [data-location-row]) :is(.dash-fieldset, .form-section, fieldset.field) > legend { float: left; width: 100%; margin: 0 0 var(--space-3); padding: 0; font-family: inherit; font-size: 1.125rem; font-weight: 600; letter-spacing: 0; }
:is(.design-what, .page-admin, .signup-what) :is(.panel, .admin-section, .dash-fieldset, .form-section, fieldset.field, [data-location-row]) :is(.dash-fieldset, .form-section, fieldset.field) > :not(legend) { clear: both; }
/* The first thing in a card needs no hairline above it. */
:is(.design-what, .signup-what) .onboard-what [data-location-row] > input[type="hidden"]:first-child + .form-section,
:is(.design-what, .page-admin, .signup-what) :is(.panel, .admin-section, .dash-fieldset, .form-section) > :is(.dash-fieldset, .form-section):first-child { margin-top: 0; padding-top: 0; border-top: 0; }
/* A card has a little less room than the page: its grid cells may shrink
   below their content and a file control never runs past the border. */
:is(.design-what, .page-admin, .signup-what) :is(.dash-fieldset, .form-section, [data-location-row]) :is(.dash-field-pair, .location-grid) > * { min-width: 0; }
:is(.design-what, .page-admin, .signup-what) :is(.dash-fieldset, .form-section) input[type="file"] { max-width: 100%; }
/* The prices note under "Add another price", inside the Price list card. */
:is(.design-what, .signup-what) .onboard-what [data-fee-status] + .field { margin-top: var(--space-5); }
@media (max-width: 559px) {
  :is(.design-what, .page-admin, .signup-what) :is(.dash-fieldset, .form-section),
  .page-admin fieldset.field,
  :is(.design-what, .signup-what) .onboard-what [data-location-row] { padding: var(--space-4); }
  :is(.design-what, .page-admin, .signup-what) :is(.dash-fieldset, .form-section) > legend,
  .page-admin fieldset.field > legend { font-size: 1.25rem; }
}
.onboard-what .radio-row { display: flex; flex-wrap: wrap; gap: 0 var(--space-6); }
.onboard-what .radio-row .checkbox-row { margin-bottom: var(--space-3); }
.onboard-what .checkbox-row input[type="radio"] { width: 1.2rem; height: 1.2rem; margin-top: 0.2rem; flex: none; accent-color: var(--green); }
.onboard-what .field { margin-bottom: var(--space-4); }
/* Fix round (15 Oct 2026): a price row's fields keep no space under them, so
   Remove lines up with the inputs; beside them it is as tall as they are. */
.onboard-what .fee-row .field { margin-bottom: 0; }
@media (min-width: 640px) {
  .onboard-what .fee-row .fee-remove { min-height: 3.5rem; }
}
.onboard-what .field-hint { margin-top: var(--space-1); }
.onboard-what .field > .field-hint:last-child { margin-bottom: 0; }
.onboard-what .onboard-more-quiet { margin: 0 0 var(--space-4); }
.onboard-what .onboard-more-quiet > summary { padding: var(--space-1) 0; border: 0; color: var(--green-deep, var(--green)); font-weight: 600; text-decoration: underline; text-underline-offset: 0.2em; text-decoration-thickness: 1px; }
.onboard-what .onboard-more-quiet > summary:hover,
.onboard-what .onboard-more-quiet > summary:focus-visible { color: var(--ink); text-decoration-thickness: 2px; }
.onboard-what .onboard-more-quiet > .onboard-more-body { padding-top: var(--space-3); }
.onboard-what [hidden] { display: none !important; }
/* A quiet saved line inside a section ("Course saved."), with room below it. */
.onboard-what .form-section > .field-chosen { margin: 0 0 var(--space-3); }
.onboard-what textarea[rows="2"] { min-height: 4.5rem; }
:is(.design-what, .signup-what) .dash-side-card .onboard-what .form-section { border-top: 0; margin-top: var(--space-3); padding-top: 0; }
.dash-side-card .onboard-what .radio-row { flex-direction: column; }

/* A quiet text button, underlined like a link, the green of the "+ Add" links. */
.link-action { display: inline-flex; align-items: center; background: none; border: 0; padding: var(--space-1) 0; margin: 0 var(--space-4) 0 0; font: inherit; font-weight: 600; color: var(--green-deep, var(--green)); text-decoration: underline; text-underline-offset: 0.2em; text-decoration-thickness: 1px; cursor: pointer; }
.link-action:hover, .link-action:focus-visible { color: var(--ink); text-decoration-thickness: 2px; }
@media (max-width: 640px) {
  .link-action,
  .onboard-what .onboard-more-quiet > summary { min-height: 44px; padding-top: 0; padding-bottom: 0; }
}

/* Join and offer pages on a phone (round 3): buttons run the full width with
   a little less side padding, so the long labels ("Continue with standard
   membership") sit on one line at the same text size. */
@media (max-width: 559px) {
  :is(.design-what, .signup-what).page-join main .btn-lg,
  :is(.design-what, .signup-what).page-join .search-box-row .btn { width: 100%; padding-left: var(--space-4); padding-right: var(--space-4); }
}

/* Review and submit (round 3, Rick: "predominantly for them to click the
   button"): one card, the button first and largest, one line on what happens
   next, then a short "Check your answers" list under a hairline. */
.onboard-review > h3 { margin: 0 0 var(--space-3); font-size: 1.375rem; }
.onboard-review > p { margin: 0 0 var(--space-2); }
.onboard-review .btn-lg { min-width: 18rem; }
.onboard-review > .onboard-review-note { margin: var(--space-3) 0 0; font-size: 0.92rem; color: var(--ink-mute); }
.review-missing { margin: 0 0 var(--space-4); padding-left: 1.25rem; list-style: disc; }
.review-missing li { margin: 0 0 var(--space-1); padding-left: var(--space-1); line-height: 1.5; }
/* Lift the card a little so the button is above the fold at 1280 x 800. */
.wizard-bar:has(~ .onboard-review) { margin-bottom: var(--space-5); }
h2:has(+ .onboard-review) { margin-top: var(--space-5); margin-bottom: var(--space-3); }
.review-lines { margin: var(--space-5) 0 0; padding: var(--space-4) 0 0; border-top: 1px solid var(--line); font-size: 0.92rem; line-height: 1.45; }
.review-lines > div { display: grid; grid-template-columns: 8.5rem minmax(0, 1fr) auto; gap: 0 var(--space-4); align-items: baseline; padding: 0.3rem 0; }
.review-lines dt { font-weight: 600; color: var(--ink); }
.review-lines dd { margin: 0; min-width: 0; color: var(--ink-soft); overflow-wrap: anywhere; }
.review-lines dd.is-missing { color: var(--ink-mute); font-style: italic; }
.review-lines .review-edit a { font-weight: 600; }
@media (max-width: 559px) {
  .onboard-review .btn-lg { width: 100%; min-width: 0; }
  .review-lines > div { display: block; position: relative; padding-right: 3.25rem; }
  .review-lines dt, .review-lines dd { display: inline; }
  .review-lines dt::after { content: ": "; }
  .review-lines .review-edit { position: absolute; top: 0.3rem; right: 0; }
  /* Fix round (15 Oct 2026): on a phone the Submit button sits above the fold.
     Only the space above it tightens (header, step line, page heading, card);
     the card's own heading is hidden from sight but kept for screen readers,
     since the page heading already says "Review and submit". Text sizes stay. */
  .page-onboarding:has([data-review-step]) .page-header { padding-block: var(--space-5) var(--space-4); }
  .page-onboarding .section:has([data-review-step]) { padding-top: var(--space-4); }
  .wizard-bar:has(~ .onboard-review) { margin-bottom: var(--space-2); }
  h2:has(+ .onboard-review) { margin-top: var(--space-2); margin-bottom: var(--space-2); }
  .panel.onboard-review { padding-top: var(--space-4); }
  .onboard-review > h3 { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .review-missing { margin-bottom: var(--space-3); }
}

.help-offer { margin: var(--space-6) auto 0; max-width: none; text-align: center; font-size: 0.92rem; color: var(--ink-mute); }
.help-offer a { color: inherit; }
/* mld-parity (17 Oct 2026): on MLD's WHAT sign-up (body .signup-what) a training row inside a card
   section is a hairline sub-group, never a card in a card (DESIGN-STANDARDS 15 Oct "card sections"). */
.signup-what .form-section .training-block { border: 0; border-radius: 0; padding: 0; background: transparent; }
.signup-what .form-section .training-block + .training-block,
.signup-what .form-section .onboard-more-body > .training-block { border-top: 1px solid var(--line); padding-top: var(--space-4); }

/* end join-form-ux (15 Oct 2026) */

/* what-public-pages (15 Oct 2026) */
/* Builder B (items 6 to 11). The WHAT example profile's actions: placeholder
   links (no href, data-example-only) keep the button's place and shape at the
   disabled weight .btn[disabled] uses, ignore the pointer so no hover suggests
   a working link, and one "Example only" note follows the contact row. */
:is(.design-what, .profile-what).page-profile a[data-example-only] { opacity: 0.55; cursor: not-allowed; pointer-events: none; }
:is(.design-what, .profile-what).page-profile .profile-save[disabled] { opacity: 0.55; cursor: not-allowed; }
:is(.design-what, .profile-what).page-profile .profile-example-note { grid-column: 1 / -1; margin: var(--space-3) 0 0; font-size: 1rem; line-height: 1.45; color: var(--ink-mute); }
/* The one provenance note under "About {name}" (or "Services"). */
:is(.design-what, .profile-what).page-profile .profile-provided-note { margin-top: calc(-1 * var(--space-2)); }
/* A short second line under a page header's lead (the Check page before the
   launch): centred with the lead from 640px, quieter than it. */
.page-header .page-header-note { max-width: 46rem; margin: var(--space-3) auto 0; color: var(--ink-mute); }
@media (max-width: 639px) { .page-header .page-header-note { margin-inline: 0; } }
/* end what-public-pages builder B */

/* what-public-pages (15 Oct 2026), builder A (item 5): the directory preview
   (app/views/what/partials/search_preview.php). WHAT-only markup and the
   .page-search-preview body class, so MLD looks as before. Reusable classes
   (also listed in ENGINE.md):
   .chip-example              the "Example" pill on a card that describes
                              nobody (calm, dashed, never the checks' green
                              or Featured's brass)
   .result-example-flag       its line above the card's name
   .search-preview-banner     the one banner over the preview's results
   .search-preview-count      the quiet "4 example profiles" opposite the heading
   .search-preview-filters-note  one line under a bar whose filters are off
   .result-example-only       the quiet "Example only" where an example card
                              that opens nothing would have its button */
.chip-example {
  background: var(--surface);
  border: 1px dashed var(--ink-mute);
  color: var(--ink-soft);
}
.result-example-flag { margin: 0 0 var(--space-2); line-height: 1; }
.search-preview-banner p { margin: 0; max-width: none; }
.search-preview-banner p + p { margin-top: var(--space-2); }
.search-preview-banner a { font-weight: 600; }
.results-head h2.results-count { margin: 0; font-size: 1.5rem; } /* card-heading size, 19 Oct 2026 */
.search-preview-count { margin: 0; color: var(--ink-mute); font-size: 1rem; }
.search-preview-filters-note { margin: var(--space-3) 0 0; font-size: 1rem; color: var(--ink-mute); }
.result-example-only { display: inline-block; padding: 0.4rem 0; font-size: 1rem; font-weight: 600; color: var(--ink-mute); white-space: nowrap; }
.page-search-preview .filter-chip-input:disabled + .filter-chip,
.page-search-preview .finder-filter-field select:disabled { opacity: 0.55; cursor: not-allowed; }
/* A switched-off filter is not an applied one: no tick unless it was chosen
   (the forced-filter rule above ticks every disabled chip). */
.page-search-preview .filter-chip-input:disabled:not(:checked) + .filter-chip::before {
  color: transparent;
  background: var(--surface);
  border-color: var(--filter-line);
}
/* The launch sign-up stands where a live search's map would. */
.search-preview-aside .prelaunch-notice { margin: 0; padding: var(--space-5); text-align: left; }
.search-preview-aside .prelaunch-notice h2 { font-size: 1.5rem; } /* one card-heading size, 19 Oct 2026 */
.search-preview-aside .prelaunch-fields { grid-template-columns: 1fr; }
.preview-frame-caption-second { display: block; margin-top: var(--space-2); }
/* At phone width the card's longest dated chip is wider than the text column
   the card's 2rem padding leaves, so the card ran 2px past the screen at
   375. A 1rem inset keeps it inside. */
@media (max-width: 420px) {
  .page-search-preview .result-card { padding: var(--space-4); }
}
/* end what-public-pages builder A */

/* what-public-pages (15 Oct 2026), item 12: MINIMUM TEXT 16px on every WHAT
   public and member page (Rick: "Minimum text should be 16px otherwise it is
   not legible"; what-brands/DESIGN-STANDARDS.md, 15 Oct row). One block of
   overrides: each rule repeats a shared rule's selector under .design-what
   (one class more, so it wins without touching MLD), sets 1rem, and where a
   label was letter-spaced capitals it becomes plain case with no tracking,
   which is what keeps it narrow enough at 1rem. Secondary text stays
   secondary through colour and weight, never through size. Only a glyph
   inside an icon (a tick or number in a circle, the "i" of a tip, a filter
   tick, a map cluster count) stays smaller. The member area (member_layout.php,
   which carries no .design-what) is the group headed MEMBER AREA below, scoped
   to every member-area theme except MLD's. Checked by a sweep of every visible
   text node at 375, 768 and 1280 (what-brands/output/what-public-pages/16px/).
   WHAT admin too since 22 Oct 2026 (review-page-guides: "nothing under 16px
   on every WHAT admin screen"): the rules no longer skip .what-admin, and the
   admin's own small parts are in the block headed WHAT ADMIN at the end of
   this file. MLD's admin carries neither class, so it is unchanged. */

/* Labels that were small letter-spaced capitals: 1rem, plain case. */
:is(.design-what, .text-min-16) .chip,
:is(.design-what, .text-min-16) .hero-eyebrow,
:is(.design-what, .text-min-16) .brass-pill,
:is(.design-what, .text-min-16) .founding-invite-eyebrow,
:is(.design-what, .text-min-16) .welcome-eyebrow,
:is(.design-what, .text-min-16) .recommend-kicker,
:is(.design-what, .text-min-16) .footer-heading,
:is(.design-what, .text-min-16) .site-footer-light .footer-heading,
:is(.design-what, .text-min-16) .status-pill,
:is(.design-what, .text-min-16) .tier-flag,
:is(.design-what, .text-min-16) .tier-box-what .tier-box-flag,
:is(.design-what, .text-min-16) .tier-billing-flag,
:is(.design-what, .text-min-16) .filter-checked-pill,
:is(.design-what, .text-min-16) .location-row-title,
:is(.design-what, .text-min-16) .admission-facts dt,
:is(.design-what, .text-min-16).page-profile .admission-facts dt, /* admin profile preview too (fix round, 21 Oct 2026) */
:is(.design-what, .text-min-16).page-profile .profile-facts dt,
:is(.design-what, .text-min-16) .cmp-group th,
:is(.design-what, .text-min-16) .ticker-list li,
:is(.design-what, .text-min-16) .compare-table td[data-label]::before,
:is(.design-what, .text-min-16) .billing-ui .billing-eyebrow,
:is(.design-what, .text-min-16) .membership-status,
:is(.design-what, .text-min-16) .membership-facts dt {
  font-size: 1rem;
  letter-spacing: 0;
  text-transform: none;
}
/* A chip at 1rem: a little more line height, and it may wrap inside a
   narrow card instead of pushing the card wider than a phone (a live result
   card ran 2px past the screen at 375 with "Registration checked Oct 2026"). */
:is(.design-what, .text-min-16) .chip { font-weight: 600; line-height: 1.25; padding: 0.3rem 0.75rem; max-width: 100%; white-space: normal; }
:is(.design-what, .text-min-16) .chip .chip-tip .tip-icon { font-size: 0.75rem; }
:is(.design-what, .text-min-16) .prov-chips { flex-wrap: wrap; min-width: 0; }
:is(.design-what, .text-min-16) .status-pill { padding: 0.2rem 0.65rem; }
:is(.design-what, .text-min-16) .footer-heading { font-weight: 700; }

/* Everything else that was under 1rem. */
:is(.design-what, .text-min-16) :where(th),
:is(.design-what, .text-min-16) .nav-item > a,
:is(.design-what, .text-min-16) .nav-sub-toggle,
:is(.design-what, .text-min-16) .nav-sub a,
:is(.design-what, .text-min-16) .header-login,
:is(.design-what, .text-min-16) .header-cta,
:is(.design-what, .text-min-16) .notice-bar p,
:is(.design-what, .text-min-16) .country-switch > summary,
:is(.design-what, .text-min-16) .country-switch-list a,
:is(.design-what, .text-min-16) .country-banner p,
:is(.design-what, .text-min-16) .site-footer,
:is(.design-what, .text-min-16) .footer-legal,
:is(.design-what, .text-min-16) .footer-phone-secondary,
:is(.design-what, .text-min-16) .btn-sm,
:is(.design-what, .text-min-16) .cta-band .btn,
:is(.design-what, .text-min-16) .field-error,
:is(.design-what, .text-min-16) input[type="file"]::file-selector-button,
:is(.design-what, .text-min-16) .field-key,
:is(.design-what, .text-min-16) .ledger-caption,
:is(.design-what, .text-min-16) .leader-row,
:is(.design-what, .text-min-16) .leader-value-sub,
:is(.design-what, .text-min-16) .search-microcopy,
:is(.design-what, .text-min-16) .preview-frame-head,
:is(.design-what, .text-min-16) .preview-frame-note,
:is(.design-what, .text-min-16) .preview-frame-caption,
:is(.design-what, .text-min-16) .device-caption,
:is(.design-what, .text-min-16) .disclaimer-box,
:is(.design-what, .text-min-16) .verification-box-footer,
:is(.design-what, .text-min-16) .verification-more > summary,
:is(.design-what, .text-min-16) .breadcrumbs,
:is(.design-what, .text-min-16) .result-meta,
:is(.design-what, .text-min-16) .result-fee,
:is(.design-what, .text-min-16) .prov-label,
:is(.design-what, .text-min-16) .profile-head-main .prov-label,
:is(.design-what, .text-min-16) .profile-head-main .chip,
:is(.design-what, .text-min-16) .tier-price-note,
:is(.design-what, .text-min-16) .tier-card .tier-features,
:is(.design-what, .text-min-16) .prose-meta,
:is(.design-what, .text-min-16) .stat-label,
:is(.design-what, .text-min-16) .error-detail,
:is(.design-what, .text-min-16) .featured-meta,
:is(.design-what, .text-min-16) .under-hero,
:is(.design-what, .text-min-16) .offer-table,
:is(.design-what, .text-min-16) .tier-note,
:is(.design-what, .text-min-16) .pricing-foot li,
:is(.design-what, .text-min-16) .founder-sig-role,
:is(.design-what, .text-min-16) .finder-field label,
:is(.design-what, .text-min-16) .check-strip-text,
:is(.design-what, .text-min-16) .check-strip-link,
:is(.design-what, .text-min-16) .filter-group .checkbox-row label,
:is(.design-what, .text-min-16) .tip-bubble,
:is(.design-what, .text-min-16) .chip .chip-tip .tip-bubble,
:is(.design-what, .text-min-16) .profile-section h3 .tip-bubble,
:is(.design-what, .text-min-16) .results-sort-control label,
:is(.design-what, .text-min-16) .result-matches,
:is(.design-what, .text-min-16) .compare-tick,
:is(.design-what, .text-min-16) .compare-tray-count,
:is(.design-what, .text-min-16) .compare-tray-clear,
:is(.design-what, .text-min-16) .finder-filter-field label,
:is(.design-what, .text-min-16) .finder-more > summary,
:is(.design-what, .text-min-16) .profile-nav a,
:is(.design-what, .text-min-16) .profile-nav li > span,
:is(.design-what, .text-min-16) .gallery-manage-item label,
:is(.design-what, .text-min-16) .gallery-over-cap-note,
:is(.design-what, .text-min-16) .filter-group-note,
:is(.design-what, .text-min-16) .filter-row-note,
:is(.design-what, .text-min-16) .filter-provenance,
:is(.design-what, .text-min-16) .filter-field-note,
:is(.design-what, .text-min-16) .results-notice,
:is(.design-what, .text-min-16) .active-filters a,
:is(.design-what, .text-min-16) .filter-chip,
:is(.design-what, .text-min-16) .profile-head-gallery .gallery-more-label,
:is(.design-what, .text-min-16).page-profile .profile-meet-gallery .gallery-more-label,
:is(.design-what, .text-min-16) .profile-about-meta,
:is(.design-what, .text-min-16) .profile-quick-phone,
:is(.design-what, .text-min-16) .profile-quick-site,
:is(.design-what, .text-min-16) .review-rating,
:is(.design-what, .text-min-16) .review-reply,
:is(.design-what, .text-min-16) .result-rating,
:is(.design-what, .text-min-16) .result-google-note,
:is(.design-what, .text-min-16) .review-aggregate-count,
:is(.design-what, .text-min-16) .review-card-link,
:is(.design-what, .text-min-16) .review-form-back,
:is(.design-what, .text-min-16) .review-invite,
:is(.design-what, .text-min-16) .reviews-all-back,
:is(.design-what, .text-min-16) .profile-footer,
:is(.design-what, .text-min-16) .preview-actions-note,
:is(.design-what, .text-min-16) .welcome-note,
:is(.design-what, .text-min-16) .welcome-reassure,
:is(.design-what, .text-min-16) .wizard-count,
:is(.design-what, .text-min-16) .wizard-step,
:is(.design-what, .text-min-16) .onboard-more > summary,
:is(.design-what, .text-min-16) .training-course-note,
:is(.design-what, .text-min-16) .onboard-received,
:is(.design-what, .text-min-16) .onboard-doc-list,
:is(.design-what, .text-min-16) .form-warning,
:is(.design-what, .text-min-16) .onboard-edit > summary,
:is(.design-what, .text-min-16) .onboard-reassure,
:is(.design-what, .text-min-16) .onboard-signout,
:is(.design-what, .text-min-16) .tier-box-vat,
:is(.design-what, .text-min-16) .offer-card .tier-box-vat,
:is(.design-what, .text-min-16) .tier-billing-label,
:is(.design-what, .text-min-16) .offer-card .tier-features,
:is(.design-what, .text-min-16) .offer-card .offer-terms,
:is(.design-what, .text-min-16) .tier-price-strap,
:is(.design-what, .text-min-16) .tier-card-note,
:is(.design-what, .text-min-16) .auth-links,
:is(.design-what, .text-min-16) .dash-menu a,
:is(.design-what, .text-min-16) .dash-subtabs a,
:is(.design-what, .text-min-16) .dash-side .checklist,
:is(.design-what, .text-min-16) .checklist li::before,
:is(.design-what, .text-min-16) .badge-size-label,
:is(.design-what, .text-min-16) .badge-embed-code,
:is(.design-what, .text-min-16) .embed-snippet,
:is(.design-what, .text-min-16) .totp-uri,
:is(.design-what, .text-min-16) .check-label,
:is(.design-what, .text-min-16) .cmp-town,
:is(.design-what, .text-min-16) .cmp-sub,
:is(.design-what, .text-min-16) .cmp-list,
:is(.design-what, .text-min-16) .cmp-table-what td p,
:is(.design-what, .text-min-16) .cmp-hint,
:is(.design-what, .text-min-16) .cmp-table-what tfoot th[scope="row"],
:is(.design-what, .text-min-16) .cookie-bar-text,
:is(.design-what, .text-min-16) .sample-flag p,
:is(.design-what, .text-min-16) .email-dialog-meta,
:is(.design-what, .text-min-16) .profile-place-note,
:is(.design-what, .text-min-16) .public-hours-grid,
:is(.design-what, .text-min-16) .founding-invite-facts li,
:is(.design-what, .text-min-16) .offer-fold summary,
:is(.design-what, .text-min-16) .offer-fold p,
:is(.design-what, .text-min-16) .places-check label,
:is(.design-what, .text-min-16) .join-small,
:is(.design-what, .text-min-16) .join-selection-summary-what,
:is(.design-what, .text-min-16).page-profile .profile-availability,
:is(.design-what, .text-min-16).page-profile .profile-meta,
:is(.design-what, .text-min-16).page-profile .admission-facts dd, /* admin profile preview too */
:is(.design-what, .text-min-16).page-profile .profile-facts dd,
:is(.design-what, .text-min-16).page-profile .verification-box > p,
:is(.design-what, .text-min-16) .legal-contents ul,
:is(.design-what, .text-min-16) .location-suggestion-area,
:is(.design-what, .text-min-16) .card-setup .hairline-list > li,
:is(.design-what, .text-min-16) .onboard-review > .onboard-review-note,
:is(.design-what, .text-min-16) .review-lines,
:is(.design-what, .text-min-16) .help-offer,
:is(.design-what, .text-min-16) .leaflet-container .leaflet-control-attribution,
/* billing.css (the offer page and Membership) */
:is(.design-what, .text-min-16) .card-setup-label,
:is(.design-what, .text-min-16) .card-setup-breakdown,
:is(.design-what, .text-min-16) .card-setup-consent,
:is(.design-what, .text-min-16) .card-setup-reminders,
:is(.design-what, .text-min-16) .card-setup-footer,
:is(.design-what, .text-min-16) .card-setup-details,
:is(.design-what, .text-min-16) .card-setup-notice,
:is(.design-what, .text-min-16) .billing-back,
:is(.design-what, .text-min-16) .membership-price span,
:is(.design-what, .text-min-16) .billing-ui .membership-subline,
:is(.design-what, .text-min-16) .billing-ui .membership-protection,
:is(.design-what, .text-min-16) .membership-facts small,
:is(.design-what, .text-min-16) .membership-next p:not(.billing-eyebrow),
:is(.design-what, .text-min-16) .billing-section > p,
:is(.design-what, .text-min-16) .billing-disclosure summary,
:is(.design-what, .text-min-16) .billing-disclosure > p,
:is(.design-what, .text-min-16) .billing-check,
:is(.design-what, .text-min-16) .billing-alert,
:is(.design-what, .text-min-16) .billing-invoices li,
:is(.design-what, .text-min-16) .billing-terms-link,
:is(.design-what, .text-min-16) .billing-page-footer {
  font-size: 1rem;
}
/* The small print keeps its quieter colour and a normal weight, so it still
   reads as small print at full size. */
:is(.design-what, .text-min-16) .footer-legal,
:is(.design-what, .text-min-16) .profile-footer,
:is(.design-what, .text-min-16) .billing-page-footer { line-height: 1.6; }
:is(.design-what, .text-min-16) .result-meta,
:is(.design-what, .text-min-16) .prose-meta,
:is(.design-what, .text-min-16) .preview-frame-caption { font-weight: 400; }
:is(.design-what, .text-min-16) .preview-frame-caption { letter-spacing: 0; }
:is(.design-what, .text-min-16) .tip-bubble { line-height: 1.45; }
:is(.design-what, .text-min-16) .leaflet-container .leaflet-control-attribution { line-height: 1.4; }
:is(.design-what, .text-min-16) .billing-ui .billing-button,
:is(.design-what, .text-min-16) .billing-form select { font-size: 1rem; }
/* A form control no rule sizes falls back to the browser's 13.33px: 1rem
   instead, at no specificity, so every sized control keeps its own size. */
:where(:is(.design-what, .text-min-16)) :where(input, select, textarea, button) { font-size: 1rem; }
/* Two fields side by side: the larger labels and hints made a pair's
   min-content wider than the column at 768 (the course editor ran 17px past
   the screen), so the two tracks may shrink. */
@media (min-width: 720px) {
  :is(.design-what, .text-min-16) .dash-field-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  :is(.design-what, .text-min-16) .dash-field-pair > .field { min-width: 0; grid-template-columns: minmax(0, 1fr); }
}
/* A count in the "More filters" button is a number in a circle: it keeps its
   own size, the rule's one exception. */

/* The join stage bar and the application step bar (Rick, 15 Oct 2026): plain
   case at 1rem, no letter spacing; each bar shows only from the width where
   every label fits on one line, and below that the one line "Step N of 4:
   Stage" / "Step N of 7: Step" stands in its place (one indicator a screen).
   The widths are measured, not chosen: see ENGINE.md (what-public-pages). */
:is(.design-what, .text-min-16) .join-progress-what li { font-size: 1rem; font-weight: 600; letter-spacing: 0; text-transform: none; }
:is(.design-what, .text-min-16) .join-progress-what .join-progress-label { white-space: nowrap; }
:is(.design-what, .text-min-16) .join-progress-what { gap: var(--space-3); }
:is(.design-what, .text-min-16) .join-progress-what li.is-done .join-progress-num { width: 1.35rem; height: 1.35rem; margin-right: 0.15rem; }
:is(.design-what, .text-min-16) .step-line { font-size: 1rem; }
/* Seven steps share the row by their own width rather than equal shares: at
   1rem, equal shares wide enough for "About you" no longer fit the 880px
   column, while sized to their words all seven do. */
@media (min-width: 1000px) {
  :is(.design-what, .text-min-16) .wizard-steps-what > li { flex: 1 1 auto; min-width: 0; }
}
:is(.design-what, .text-min-16) .wizard-steps-what .wizard-label { white-space: nowrap; }
/* Where the bars switch (measured 15 Oct 2026 in headless Chrome, both WHAT
   brands, every 8px from 560 to 1400). The join bar's tightest home is the
   offer page's card column: all four stages fit on one line each from 560px,
   with room to spare from 600px, so it shows from 600. The application bar's
   seven steps fit on one row from 904px, so it shows from 920. */
/* The join stage bar as four segments (Rick, 4 Nov 2026: "4 segments and
   when they are completed that part of the bar can go green. It should still
   indicate what step they are on and what step that is"). A finished stage is
   a full green segment with its tick, the current stage half green with its
   name in bold, a stage still to come a grey track. Phones keep the four
   segments without the names, and the line under them says "Step N of 4:
   Stage" (main.js keeps both in step as the visitor moves between panels). */
:is(.design-what, .text-min-16) .join-progress-what { max-width: 48rem; } /* the join column's width, so the bar lines up with the panels under it */
:is(.design-what, .text-min-16) .join-progress-what li { position: relative; border-top: 0; padding-top: calc(10px + var(--space-3)); color: var(--ink-mute); }
:is(.design-what, .text-min-16) .join-progress-what li::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 10px; border-radius: 999px; background: var(--line-strong); }
:is(.design-what, .text-min-16) .join-progress-what li.is-done::before { background: var(--tick-green); }
:is(.design-what, .text-min-16) .join-progress-what li.is-current::before { background: linear-gradient(to right, var(--tick-green) 50%, var(--line-strong) 50%); }
:is(.design-what, .text-min-16) .join-progress-what li.is-current { color: var(--ink); font-weight: 700; }
:is(.design-what, .text-min-16) .join-progress-what li.is-done { color: var(--ink); }
@media (max-width: 599px) {
  :is(.design-what, .text-min-16) [data-join-progress-line] { display: block; margin: var(--space-3) 0 var(--space-5); text-align: center; font-weight: 700; color: var(--ink); max-width: none; }
  :is(.design-what, .text-min-16) .join-progress-what { display: flex; gap: var(--space-2); margin: var(--space-5) auto 0; }
  :is(.design-what, .text-min-16) .join-progress-what li { padding-top: 10px; }
  :is(.design-what, .text-min-16) .join-progress-what .join-progress-num,
  :is(.design-what, .text-min-16) .join-progress-what .join-progress-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
@media (max-width: 919px) {
  :is(.design-what, .text-min-16) .wizard-bar .step-line { display: block; margin: 0; text-align: left; font-weight: 700; color: var(--ink); max-width: none; }
  :is(.design-what, .text-min-16) .wizard-steps-what,
  :is(.design-what, .text-min-16) .wizard-bar .step-line ~ .wizard-count { display: none; }
}

/* Review and submit (Rick, 15 Oct 2026): the summary under the hairline has
   its own small heading; each row starts with its status (the step bar's
   tick for a finished step, an amber "!" for a required step that holds
   Submit back, a short muted line for an optional step left empty), the
   whole row tints on hover and keyboard focus and opens its step (the Edit
   link stretched over the row), and on a phone Edit sits under the value.
   Classes: .review-lines-heading, .review-line (+ -done / -needs /
   -optional), .review-status. Markup: what/partials/onboard_review_step.php. */
:is(.design-what, .text-min-16) .review-lines-heading { margin: var(--space-5) 0 0; padding-top: var(--space-4); border-top: 1px solid var(--line); font-family: var(--font-sans); font-size: 1rem; font-weight: 700; line-height: 1.4; color: var(--ink); }
:is(.design-what, .text-min-16) .review-lines-heading + .review-lines { margin-top: var(--space-2); padding-top: 0; border-top: 0; }
:is(.design-what, .text-min-16) .review-lines > .review-line { position: relative; grid-template-columns: 10.5rem minmax(0, 1fr) auto; align-items: center; margin: 0 calc(-1 * var(--space-2)); padding: 0.45rem var(--space-2); border-radius: var(--radius); }
:is(.design-what, .text-min-16) .review-line:hover,
:is(.design-what, .text-min-16) .review-line:focus-within { background: var(--tint, rgba(0, 0, 0, 0.04)); }
:is(.design-what, .text-min-16) .review-line:has(a:focus-visible) { outline: 2px solid var(--focus); outline-offset: 1px; }
:is(.design-what, .text-min-16) .review-line .review-edit a:focus-visible { outline: none; }
:is(.design-what, .text-min-16) .review-line .review-edit a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
:is(.design-what, .text-min-16) .review-line dt { display: flex; align-items: center; gap: var(--space-2); }
:is(.design-what, .text-min-16) .review-status { display: inline-grid; place-items: center; flex: none; width: 1.4rem; height: 1.4rem; border-radius: 50%; font-size: 0.8rem; font-weight: 700; line-height: 1; }
:is(.design-what, .text-min-16) .review-line-done .review-status { background: var(--tick-green-wash); color: var(--tick-green); }
:is(.design-what, .text-min-16) .review-line-needs .review-status { background: var(--brass-soft); color: var(--tone-warn-ink); }
:is(.design-what, .text-min-16) .review-line-optional .review-status::before { content: ""; width: 0.6rem; border-top: 2px solid var(--line-strong); }
:is(.design-what, .text-min-16) .review-lines dd.is-missing { color: var(--tone-warn-ink); font-style: normal; }
@media (max-width: 559px) {
  :is(.design-what, .text-min-16) .review-lines > .review-line { display: grid; grid-template-columns: minmax(0, 1fr); padding-right: var(--space-2); }
  :is(.design-what, .text-min-16) .review-lines .review-line dt { display: flex; }
  :is(.design-what, .text-min-16) .review-lines .review-line dt::after { content: none; }
  :is(.design-what, .text-min-16) .review-lines .review-line dd { display: block; padding-left: calc(1.4rem + var(--space-2)); }
  :is(.design-what, .text-min-16) .review-lines .review-line .review-edit { position: static; }
}

/* MEMBER AREA (member_layout.php: body.member-admin, html[data-brand] = the
   pack's member_admin.theme). member-admin.css sets its text in pixels from
   11px up; on every WHAT theme (anything but MLD's "mld") each of those rules
   is 16px. The initials in the round avatar and the count in a nav badge are
   glyphs inside an icon and keep their size. */
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin nav.open .nav-sub,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .reviewbar,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .review-inner select,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .review-reset,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .workspace-label,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .account-button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin nav a,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .eyebrow,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .text-button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .panel-head p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .smalltext,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .status,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .badge,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .inline-note,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .next-action p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .metric-label,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .metric-note,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin table,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin th,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin td .smalltext,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .list-foot,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .profile-meta,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .availability-label,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .confirm-note,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .membership-mini .price span,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .step-row p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .section-nav a,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .editor-description,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .field label,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .field .hint,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .input-affix span,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .check,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .savebar>span,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .field-error,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .filterbar label,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .empty p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .plan-banner p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .plan-price span,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .detail-list>div,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .footnote,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .chart text,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .faq details p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .footer,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .footer button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .toast,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin #dialog-body p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .message,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .demo-options,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .page-heading .button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .mobile-menu,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .page-heading p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .page-heading .eyebrow,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .panel-head .text-button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .table-action .text-button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin td,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .save-actions .text-button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .timeline h3,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .timeline p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .mobile-profile-toggle,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin #nav>a,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin #nav summary,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin #nav .dropdown-links a,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .rail-identity>p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .availability-summary,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .rail-links>h3,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .rail-links nav a,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .rail-profile-link button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .card-period,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .primary-stat>span,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .secondary-stat>span,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .enquiry-summary>span,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .enquiry-attention,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .enquiry-clear,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .latest-enquiry,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .latest-enquiry>span:first-child,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .latest-enquiry>span:last-child,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .membership-summary p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .membership-summary>.button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin input,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin select,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin textarea,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .savebar .text-button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .context-help,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .account-name,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin #nav.open .dropdown-links a,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .savebar .button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .mobile-member .availability-summary,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .mobile-member>.text-button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .availability-tone,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .rail-profile-link a,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .checkbox-row label,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .field-hint,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .hint,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .btn,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .enquiry-row>span,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .mobile-member>a,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .hours-periods,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .work-day legend,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .work-cell {
  font-size: 1rem;
}

/* The Membership page inside the member area (billing.css), and a warning
   line the member area shares with the public pages. */
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-ui .billing-eyebrow,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .membership-status,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .membership-facts dt,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .card-setup-label,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .card-setup-breakdown,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .card-setup-consent,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .card-setup-reminders,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .card-setup-footer,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .card-setup-details,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .card-setup-notice,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-back,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .membership-price span,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-ui .membership-subline,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-ui .membership-protection,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .membership-facts small,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .membership-next p:not(.billing-eyebrow),
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-section > p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-disclosure summary,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-disclosure > p,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-check,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-alert,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-invoices li,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-terms-link,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-page-footer,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-ui .billing-button,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .billing-form select,
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin .form-warning {
  font-size: 1rem;
}
:is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin :is(.billing-ui .billing-eyebrow, .membership-status, .membership-facts dt) { letter-spacing: 0; text-transform: none; }

/* search-modes (16 Oct 2026): the In person / Online or phone switch above
   the WHAT home and search page search (app/views/what/partials/
   search_mode_switch.php) and the Online or phone results
   (app/views/what/partials/search_online.php). Classes appear only where a
   pack switches features.search_modes on, so MLD looks as before. Two real
   radios in a fieldset: arrow keys move between them and the focus ring sits
   on the label.
   REFINED 16 Oct 2026 (Rick; what-brands/briefs/ENGINE-home-search-refine.md):
   the switch is visually secondary, a quiet segmented control. A very light
   neutral grey track (mixed from the brand's own ink); the chosen option is a
   white raised segment with a hairline edge and the brand's light shadow, in
   bolder type, so it never relies on colour alone; dark text on both, and no
   solid brand colour on either, so the search button is the card's only
   solid colour. Each label's bold width is reserved (::after, data-text), so
   choosing never nudges the control. */
.search-mode {
  --mode-track: color-mix(in srgb, var(--ink) 6%, var(--surface));
  --mode-edge: color-mix(in srgb, var(--ink) 14%, var(--surface));
  border: 0; margin: 0 0 var(--space-4); padding: 0; min-inline-size: 0;
}
.search-mode-options {
  display: inline-grid;
  grid-template-columns: 1fr 1fr;
  max-width: 100%;
  padding: 3px;
  background: var(--mode-track);
  border: 1px solid var(--mode-edge);
  border-radius: 999px;
}
.search-mode-option { position: relative; display: flex; min-width: 0; }
.search-mode-option input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.search-mode-option label {
  flex: 1 1 auto;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  margin: 0;
  padding: 0.4rem var(--space-4);
  border-radius: 999px;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.2;
  text-align: center;
  color: var(--ink-soft);
  background: transparent;
  cursor: pointer;
  transition: background-color 160ms var(--ease-out), box-shadow 160ms var(--ease-out), color 160ms var(--ease-out);
}
.search-mode-option label::after {
  content: attr(data-text);
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: 700;
  pointer-events: none;
}
.search-mode-option input:hover:not(:checked) + label { color: var(--ink); background: rgb(255 255 255 / 0.6); }
.search-mode-option input:checked + label {
  color: var(--ink);
  font-weight: 700;
  background: var(--surface);
  box-shadow: 0 0 0 1px var(--mode-edge), var(--shadow-1);
}
.search-mode-option input:focus-visible + label { outline: 3px solid var(--focus); outline-offset: 2px; }
/* The home hero box labels its fields at 1.25rem; the switch keeps 1rem. */
.page-home .search-box .search-mode label { font-size: 1rem; margin-bottom: 0; }
.search-box .search-mode-option label { margin-bottom: 0; }
/* On a small phone each option takes the width its words need, so "Online
   or phone" stays on one line at 320px. */
@media (max-width: 379.98px) {
  .search-mode-options { display: grid; width: 100%; grid-template-columns: auto auto; }
  .search-mode-option label { padding-inline: var(--space-2); }
}
/* The home card (16 Oct 2026): its heading names the card and follows the
   mode (home.php); headline, supporting text, the form, then the one
   primary action. */
.search-box-heading {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-size: 1.5rem; /* card-heading size, 19 Oct 2026 */
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--ink);
}
.search-box [data-mode-in-person-only][hidden],
.finder-field[data-mode-in-person-only][hidden] { display: none; }
/* Search fields on the WHAT home card and search bar (16 Oct 2026): a 1px
   neutral edge at rest, mixed from the brand's ink to 3.5:1 on white (WCAG
   1.4.11), and the brand's focus colour on focus (the shared input:focus
   rule). One height for the area field, the reason dropdown and the search
   button on the home card, so all three line up. MLD keeps its keyline. */
.design-what {
  --field-edge: color-mix(in srgb, var(--ink) 55%, var(--surface));
}
.design-what .search-box-row input[type="search"],
.design-what .search-box-row .search-box-reason,
.design-what .finder-bar input[type="search"],
.design-what .finder-bar select {
  border: 1px solid var(--field-edge);
}
.design-what .search-box-row input[type="search"]:hover,
.design-what .search-box-row .search-box-reason:hover,
.design-what .finder-bar input[type="search"]:hover,
.design-what .finder-bar select:hover { border-color: var(--ink-soft); }
.design-what .search-box-row input[type="search"]:focus,
.design-what .search-box-row .search-box-reason:focus,
.design-what .finder-bar input[type="search"]:focus,
.design-what .finder-bar select:focus { border-color: var(--focus); }
.design-what .search-box-row input[type="search"],
.design-what .search-box-row .search-box-reason {
  height: 3.125rem;
  padding-top: 0.6rem;
  padding-bottom: 0.6rem;
}
/* Chromium's in-page select lays its text out as a flex row: centre it like the input's. */
.design-what .search-box-row .search-box-reason { align-items: center; }
.design-what .search-box .search-microcopy a { color: var(--ink-soft); }
/* On a phone the fields fill the card, so the button does too. */
@media (max-width: 559.98px) {
  .design-what .search-box .search-box-submit { width: 100%; }
}
/* Found on the same walk (WHAT search bar, phones): the "Help with" select
   kept its widest option's width (.finder-filters-row select sets width:
   auto) and ran past the bar at 320px, and Sort by past the page edge. Both
   now fit their line. */
@media (max-width: 559.98px) {
  .design-what .finder-field-condition { min-width: 0; }
  .design-what .finder-field-condition select { width: 100%; }
  /* The same for the Sort by select beside the result count. */
  .design-what .results-sort-control { min-width: 0; max-width: 100%; }
  .design-what .results-sort-control select { min-width: 0; flex: 1 1 auto; }
}
.finder-bar .search-mode { margin-bottom: var(--space-3); }
.finder-field-radius[hidden] { display: none; }
/* The Online or phone results have no map column: the list spans the bar's
   width, so the two line up. */
.result-format { margin: var(--space-1) 0 0; font-size: 1rem; color: var(--ink-soft); }
.search-online-fallback a, .search-try-online a { font-weight: 600; }
/* Pages of the Online or phone results (the shared .pagination, with buttons). */
.search-online-pages { justify-content: center; flex-wrap: wrap; gap: var(--space-3) var(--space-4); }
.search-online-page-of { font-size: 1rem; color: var(--ink-soft); }
/* end search-modes (16 Oct 2026) */

/* mld-what-improvements (16 Oct 2026): MINIMUM TEXT 16px on MLD (Rick's GO,
   15 Oct 2026; features.text_min_16, text_min_16_enabled()). layout.php puts
   text-min-16 on every MLD public page (never /admin) and member_layout.php
   on the member area, so the WHAT brands' 16px rules above, written on
   :is(.design-what, .text-min-16) and on
   :is(:root:not([data-brand="mld"]) body, body.text-min-16).member-admin,
   reach MLD too. These rules cover what only MLD prints. Measured with a sweep
   of every visible text node at 375 and 1280; only a glyph inside an icon
   (a tip's "i", a step number or tick in its circle, a compare mark) stays
   smaller. The WHAT brands never carry text-min-16. */
/* The pricing and join cards' flags: plain case at 1rem, as the WHAT flags. */
.text-min-16 .tier-box-flag { font-size: 1rem; letter-spacing: 0; text-transform: none; }
/* MLD's join cards and plan line (17 Oct 2026, the places check walk): the price words, leads, notes and totals at 1rem, on the join page only. */
.text-min-16.page-join .offer-cards :is(.offer-then, .offer-frequency, .tier-plus-lead, .offer-essential, .offer-total, .offer-disclosure > summary, .tier-billing-note),
.text-min-16.page-join .join-selection-summary { font-size: 1rem; }
/* The join stage bar: plain case at 1rem; below 600px the one line "Step N
   of 4: Stage" (partials/join_progress.php, [data-join-progress-line]) stands
   in its place, as on the WHAT brands. */
.text-min-16 .join-progress li { font-size: 1rem; letter-spacing: 0; text-transform: none; }
@media (max-width: 599px) {
  .text-min-16 .join-progress:not(.join-progress-what) { display: none; }
}
/* Leader rows in a narrow rail card (the Verification card): at 1rem a label
   and date side by side wrapped to three lines, so each row stacks the label
   over its value, as the WHAT brands' Registration and insurance card does. */
.text-min-16 :is(.profile-aside, .profile-main > .verification-box) .leader-row:not(.leader-row-training) { flex-wrap: wrap; row-gap: 0.15rem; }
.text-min-16 :is(.profile-aside, .profile-main > .verification-box) .leader-row:not(.leader-row-training) .leader-dots { display: none; }
.text-min-16 :is(.profile-aside, .profile-main > .verification-box) .leader-row:not(.leader-row-training) .leader-value { flex: 1 1 100%; text-align: left; }
/* end mld-what-improvements 16px */

/* WHAT ADMIN (review-page-guides, 22 Oct 2026). Rick: "make damn sure its easy
   as possible to review and approve a member". Every /admin page of a WHAT
   brand carries .what-admin (layout.php); MLD's admin never does.
   1. ONE PILL: every status pill and chip on the operator's screens is the
      same rounded pill in sentence case at 1rem, coloured by meaning only
      (DESIGN-STANDARDS, 4 Oct 2026 row): gold = your turn, grey = waiting or
      information, violet = with them to approve, green = done or live, red =
      needs a look. Chips are information, so grey.
   2. 16px: the admin's own parts that were under 1rem. */
.what-admin .admin-stage-dot { width: 2rem; height: 2rem; font-size: 1rem; } /* 16px on the WHAT admin (22 Oct 2026 fix round) */
.what-admin .status-pill,
.what-admin .chip,
.what-admin .admin-stage-badge {
  display: inline-block;
  border-radius: 100px;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  line-height: 1.25;
  padding: 0.2rem 0.7rem;
  max-width: 100%;
  white-space: normal;
  vertical-align: baseline;
}
.what-admin .chip,
.what-admin .chip-featured,
.what-admin .chip-founding { background: var(--paper-2); border: 0; color: var(--ink-soft); }
.what-admin .admin-backlink a,
.what-admin .admin-tabs a,
.what-admin .btn-sm,
.what-admin .admin-photo-label,
.what-admin .admin-photo-empty,
.what-admin .text-small,
.what-admin .field-hint,
.what-admin .hint,
.what-admin small,
.what-admin :where(td, th, input, select, textarea, button, label, summary),
.what-admin .admin-nav a,
.what-admin .admin-nav-logout a,
.what-admin .admin-dl dt,
.what-admin .secret-badge,
.what-admin input[type=file],
.what-admin .field input[type=file] { font-size: 1rem; }
/* A table that scrolls inside its panel keeps everything in it, the hidden
   "Open" heading included (an absolute child escaped and made the whole
   queue and members list scroll sideways at 375). */
.what-admin .table-scroll { position: relative; }
/* The application page's two columns may shrink to the phone, and a long
   file name breaks rather than pushing the page sideways at 375. */
.what-admin .admin-split > * { min-width: 0; }
.what-admin .doc-figure figcaption { overflow-wrap: anywhere; }
.what-admin .admin-dl { grid-template-columns: max-content minmax(0, 1fr); }
.what-admin .admin-dl dd { min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 600px) {
  .what-admin .admin-dl { grid-template-columns: minmax(0, 1fr); row-gap: 0; }
  .what-admin .admin-dl dd { margin-bottom: var(--space-3); }
}


/* View as this member (22 Oct 2026, app/lib/view_as.php). The bar an admin
   sees across the top of every page while viewing as a member: the brand's
   accent (--accent in the member area, --brass on public pages) with dark ink
   text (4.5:1 or more on every brand's accent) and Exit in the brand's dark
   colour, so it never blends into a dark header. The note a refused
   save shows sits at the foot of the screen. 16px throughout. Never sticky:
   both headers already are. */
.view-as-bar { background: var(--accent, var(--brass)); color: var(--ink); font-size: 1rem; line-height: 1.4; }
.view-as-inner { max-width: var(--container, 80rem); margin: 0 auto; padding: 0.625rem 1rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.view-as-bar .view-as-text { flex: 1 1 auto; min-width: 0; margin: 0; color: var(--ink); font-size: 1rem; }
.view-as-bar .view-as-exit { flex: none; display: inline-block; padding: 0.4rem 1.25rem; border-radius: 999px; background: var(--strong, var(--ink)); color: #fff; font-size: 1rem; font-weight: 600; text-decoration: none; }
.view-as-bar .view-as-exit:hover { text-decoration: underline; }
.view-as-bar .view-as-exit:focus-visible { outline: 3px solid var(--strong, var(--ink)); outline-offset: 2px; }
.view-as-bar .view-as-refused { position: fixed; left: 1rem; right: 1rem; bottom: 1rem; z-index: 1000; max-width: 34rem; margin: 0 auto; padding: 0.875rem 1.125rem; border-radius: 12px; background: #1d2421; color: #fff; font-size: 1rem; box-shadow: 0 8px 24px rgb(0 0 0 / 0.25); }
.view-as-bar .view-as-refused[hidden] { display: none; }
.view-as-start { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; margin: 0.75rem 0 0; }
.view-as-start .text-muted { font-size: 1rem; }

/* UPLOAD RECEIPTS (uploads-and-review, 22 Oct 2026): every brand, MLD too.
   .upload-on-file is the line under a document box once we hold the file:
   a green tick, "Uploaded 22 October 2026" and her file's name.
   .upload-notice is the ticked line per kind in the green box on the page
   after a save. 1rem everywhere, and a long phone file name wraps rather
   than pushing the page sideways at 375px. */
.upload-on-file { margin: 0 0 var(--space-2); font-size: 1rem; line-height: 1.5; color: var(--ink); overflow-wrap: anywhere; }
.upload-on-file-tick, .upload-notice-tick { color: var(--tick-green); font-weight: 700; }
.upload-on-file-name { color: var(--ink-soft); }
.upload-notices { font-size: 1rem; overflow-wrap: anywhere; }
.upload-notice-tick { color: inherit; }

/* EVIDENCE REVIEW STEPS (uploads-and-review, 22 Oct 2026): each step a button
   that opens what Rick checks in a new tab, with its sentence under it, the
   same at every width. Long register names wrap inside the button. */
.admission-step { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); }
.admission-step .admission-open { white-space: normal; text-align: left; max-width: 100%; }
.admission-step-note { min-width: 0; }
.admission-review .recommend-steps li + li { margin-top: var(--space-3); }
.admission-other h3 { font-size: 1.25rem; margin: var(--space-4) 0 var(--space-2); }

/* =========================================================================
   WHAT POLISH (31 Oct 2026, Rick). Every rule is scoped to .design-what or
   to a state MLD never reaches, so MLD renders as before.
   - Dark bands (.cta-band, .section-green, the sample profile's .sample-cta):
     the primary (left) button is the brand's filled-button colour (--green)
     with white text (Rick: "make the primary left cta button the brand
     colour with white text"). White on --green: WhatChiro 5.9:1,
     WhatCounsellor 7.3:1, WhatHypno 6.0:1, WhatLifecoach 5.6:1, WhatOsteo
     9.8:1, WhatPhysio 6.1:1. Hover goes darker, never to the band colour.
     The secondary (outline) button keeps each theme's own colours.
   - Home search suggestions: the field's wrap carries the In person only
     switch, and .search-box-row's display rule would beat [hidden].
   - The "Stuck? Email ..." help line sat flush on the footer: room below it
     (48px; MLD too since 31 Oct 2026, the one rule here that is not scoped).
   ========================================================================= */
.design-what :is(.cta-band, .section-green, .sample-cta) .btn-primary { background: var(--green); border-color: var(--green); color: #fff; }
.design-what :is(.cta-band, .section-green, .sample-cta) .btn-primary:hover { background: color-mix(in oklab, var(--green), #000 14%); border-color: color-mix(in oklab, var(--green), #000 14%); color: #fff; }
.search-box-row .location-input-wrap[hidden] { display: none; }
.help-offer { padding-bottom: var(--space-7); } /* every brand: MLD's /join and onboarding too (31 Oct 2026) */
/* A register card without a logo (its body's guidance forbids showing one)
   centres its name, so a row that mixes the two still reads as one set. */
.design-what .route-card:not(:has(.route-logo)) { justify-content: center; }
