
/* ==========================================================================
   Liquid Breathwork facilitator directory
   Deep Surrender tokens only. Token definitions live in /css/variables.css.
   ========================================================================== */

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

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

body {
  font-family: var(--font-body);
  font-weight: var(--fw-regular);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--cream);
  /* The site's body is a FIXED 135deg gradient, not flat navy. Without it the
     directory's navy reads deader than every other page on the site.
     The colour under the image is declared separately and deliberately: a fixed
     image only paints the viewport, so anything that renders the page taller
     than one screen (a full-page screenshot, a print) shows the colour instead
     of the browser's white canvas. */
  background-color: var(--abyss);
  background-image: linear-gradient(135deg, var(--abyss) 0%, var(--deep-water) 50%, var(--abyss) 100%);
  background-attachment: fixed;
  min-height: 100vh;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* The default panel surface. .section--alt swaps it; nothing else does. */
  --panel: var(--undertow-60);
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  margin-bottom: var(--space-md);
}

h1 { font-size: var(--fs-h1); color: var(--cream);     margin-bottom: var(--space-lg); }
h2 { font-size: var(--fs-h2); color: var(--warm-sand); margin-bottom: var(--space-xl); }
h3 { font-size: var(--fs-h3); color: var(--warm-sand); margin-bottom: var(--space-lg); }
h4 { font-size: var(--fs-h4); color: var(--gold);      margin-bottom: var(--space-md); }

p {
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  margin-bottom: var(--space-lg);
  color: var(--cream);
}

a { color: var(--gold); text-decoration: none; transition: color var(--ease); }
a:hover { color: var(--warm-sand); }
/* The site distinguishes links by colour alone. Keyboard focus gets an underline
   as well, so the focused link is identifiable without relying on hue. */
a:focus-visible { text-decoration: underline; }

strong { font-weight: var(--fw-semibold); }
em { font-style: italic; }

ul, ol { list-style: none; }

img { max-width: 100%; height: auto; display: block; }

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   Skip link. Real link, real focus, no JavaScript.
   -------------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  padding: var(--space-sm) var(--space-md);
  background: var(--gold);
  color: var(--abyss);
  z-index: 300;
}
.skip-link:focus { left: var(--space-md); top: var(--space-md); }

/* --------------------------------------------------------------------------
   Sections. Navy and sand, alternating. There is no third background.

   Vertical padding only: the horizontal 5% belongs to .wrap, exactly as it
   belongs to the site's .container, so a full-bleed sand band reaches both
   edges of the viewport while its content stays on the grid.
   -------------------------------------------------------------------------- */
.section {
  position: relative;
  padding: var(--space-section) 0;
  /* The body's gradient, repeated and pinned to the viewport so every navy
     section samples the same one and the page reads as a single surface. It is
     declared here rather than left transparent so a navy section still has an
     explicit background of its own, which is what makes "navy or sand, never a
     third" an invariant a test can check. Where an engine downgrades a fixed
     attachment to scroll (iOS), each section paints the same gradient, starting and ending on
     --abyss, so the seams stay invisible. */
  background-color: var(--abyss);
  background-image: linear-gradient(135deg, var(--abyss) 0%, var(--deep-water) 50%, var(--abyss) 100%);
  background-attachment: fixed;
  /* The hairline under every section. Part of why the site reads as one system. */
  border-bottom: 1px solid var(--gold-10);
}

.section--alt {
  background: var(--warm-sand);
  color: var(--abyss);
  border-top: 1px solid var(--gold-20);
  border-bottom: 1px solid var(--gold-20);
  /* Glass over sand is mud. Panels on this section go solid navy instead. */
  --panel: var(--deep-water);
}

.section--alt h1, .section--alt h2 { color: var(--abyss); }
.section--alt h3 { color: var(--deep-water); }
.section--alt h4 { color: var(--undertow); }
.section--alt p  { color: var(--deep-water); }
.section--alt .eyebrow { color: var(--undertow); }

/* Gold on sand is banned as body text. Links on sand get the deep navy and an
   underline so they are still obviously links without the contrast failure.

   :where(), NOT a chain of :not(). This rule has to LOSE to the dark-panel rules
   below it, and every :not() argument adds a class's worth of specificity: the
   site's own a:not(.btn-primary):not(.nav-cta) scores higher than
   .section--alt .card__name a, which is precisely how every card title in the
   grid came out gold and underlined. :where() contributes nothing, so this stays
   at one class and the panel rules win on merit. */
.section--alt a:where(:not(.btn, .btn-primary, .btn--ghost, .btn-ghost, .nav-cta)) {
  color: var(--undertow);
  text-decoration: underline;
}
.section--alt a:where(:not(.btn, .btn-primary, .btn--ghost, .btn-ghost, .nav-cta)):hover { color: var(--abyss); }

/* --------------------------------------------------------------------------
   ...EXCEPT inside a dark panel sitting on that light section.

   THE PANEL'S BACKGROUND DECIDES THE TEXT COLOUR, NOT THE SECTION'S. The rules
   above target elements directly, so they beat the cream a panel passes down by
   inheritance, and the result is navy on navy: the "No facilitators match that
   yet" heading was very nearly invisible on the live directory, and Ryan caught
   it in a screenshot. This block is the general fix, listing every dark panel
   once instead of patching them one bug at a time.
   -------------------------------------------------------------------------- */
.section--alt :is(.card, .filters, .panel-list > li, .empty, .notice, .relay-form, .data-table, .pagination__page, .pagination__step),
.section--alt :is(.card, .filters, .panel-list > li, .empty, .notice, .relay-form, .data-table) :is(h1, h2, h3, h4, p, li, dt, dd, summary, caption) {
  color: var(--cream);
}
/* A form label already reads --warm-sand on any dark surface, and that sand is
   the site's own label colour. Left out of the rule above on purpose: cream
   labels would be a directory-only invention. */
.section--alt :is(.card, .filters, .panel-list > li, .empty, .notice, .relay-form) :is(.eyebrow, .skills__label) { color: var(--gold); }
.section--alt .data-table th { color: var(--gold); }

/* ...and a link inside a dark panel gets the dark-surface treatment, whatever
   colour the section behind the panel is. That is the bug Ryan saw: facilitator
   names in the grid rendering as underlined links that "read like raw HTML". */
.section--alt .card a,
.section--alt .panel-list a,
.section--alt .empty a,
.section--alt .notice a,
.section--alt .pagination a {
  color: var(--gold);
  text-decoration: none;
}

.section--alt .card a:hover,
.section--alt .card a:focus-visible,
.section--alt .panel-list a:hover,
.section--alt .panel-list a:focus-visible,
.section--alt .empty a:hover,
.section--alt .empty a:focus-visible,
.section--alt .pagination a:hover,
.section--alt .pagination a:focus-visible { text-decoration: underline; }

/* The card title is the card's primary action, so it reads as a heading in the
   card's own text colour and turns gold on hover. It is still distinguishable
   without colour: it is the only heading-sized text in the card, and it gains an
   underline on hover and on keyboard focus. */
.card__name a,
.section--alt .card__name a {
  color: var(--cream);
  text-decoration: none;
  /* Padding, not a bigger font: the title is the card's primary action and a
     24px line box is under the tap-target floor. */
  display: inline-block;
  padding: 0.25rem 0;
}
.card__name a:hover,
.card__name a:focus-visible,
.section--alt .card__name a:hover,
.section--alt .card__name a:focus-visible {
  color: var(--gold);
  text-decoration: underline;
}

/* --------------------------------------------------------------------------
   Containers and section rhythm
   -------------------------------------------------------------------------- */
.wrap {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 5%;
}

/* Reading measure. Body copy never spans the full container on wide screens. */
.narrow {
  max-width: var(--max-width-text);
  margin-left: auto;
  margin-right: auto;
}

/* The site's signature section intro: eyebrow, centred h2, 48px gold rule. */
.section-header {
  text-align: center;
  margin-bottom: var(--space-2xl);
}
.section-header h2 { margin-bottom: var(--space-xs); }
.section-header p { margin-left: auto; margin-right: auto; max-width: var(--max-width-text); }

.gold-line {
  width: 48px;
  height: 2px;
  background: var(--gold);
  margin-bottom: var(--space-lg);
  /* Decorative rule, not a divider anything can click through. */
  pointer-events: none;
}
.section-header .gold-line,
.gold-line--center { margin-left: auto; margin-right: auto; }

.eyebrow {
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: var(--fw-semibold);
  color: var(--gold);
  margin-bottom: var(--space-sm);
  display: block;
}

.lede { font-size: 1.15rem; }

/* Spacing utilities. These exist so no template ever needs a style attribute:
   the CSP sets style-src 'self' with no 'unsafe-inline', which blocks inline
   style attributes outright. A missing utility class is a visual bug; adding
   'unsafe-inline' to get one would be a security regression. */
.mt-sm  { margin-top: var(--space-sm); }
.mt-lg  { margin-top: var(--space-lg); }
.mt-xl  { margin-top: var(--space-xl); }
.mt-2xl { margin-top: var(--space-2xl); }

/* Visible to a screen reader, not to the eye. Deliberately NOT display:none,
   which would hide it from assistive tech too. Takes no clicks, so it cannot
   sit invisibly on top of selectable copy. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Hero. The wash is decorative, so it is behind the text and takes no clicks.
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  color: var(--cream);
  padding: var(--space-4xl) 0 var(--space-3xl);
  border-bottom: 1px solid var(--gold-10);
  overflow: hidden;
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 20% 0%, var(--undertow-60), transparent 65%);
  /* LOCKED: decorative layers never intercept a click. Removing either of these
     two lines makes every word in the hero unselectable. */
  pointer-events: none;
  z-index: 0;
}

.hero > * {
  position: relative;
  z-index: 1;
}

/* A listing hero is a statement, so it centres, exactly like every other hero
   on the site. The PROFILE hero is a portrait beside a headline and uses a bare
   .wrap, so this rule deliberately does not reach it. */
.hero .wrap.narrow { text-align: center; }
.hero .wrap.narrow .gold-line { margin-left: auto; margin-right: auto; }

/* The rule sits tight under an h2 in a section header, which is the site's
   look. Under a 3.5rem h1 it needs air, or it reads as an underline on the
   first two words rather than as a rule. */
.hero .gold-line { margin-top: var(--space-md); }

/* --------------------------------------------------------------------------
   Filter bar. A plain GET form: works with JavaScript disabled, works for a
   crawler, and every filtered view has a real URL an answer engine can cite.

   GRID, NOT FLEX WRAP. Flex with a 12rem basis gives each field its own row
   the moment the viewport is narrower than about 26rem, which on a phone is a
   six-row tower the visitor has to scroll past to reach a single facilitator.
   A grid can pair City with State and Specialty with the second axis, which is
   what the mobile block below does, and auto-fit spreads the same fields across
   one row on a desktop with no second set of rules.
   -------------------------------------------------------------------------- */
.filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-md) var(--space-lg);
  align-items: end;
  background: var(--panel);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--gold-20);
  border-radius: var(--radius-md);
  padding: var(--space-xl);
  color: var(--cream);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  /* Grid items default to min-content, and a <select> holding "Conscious
     Connected Breathwork" has a very wide min-content. Without this the track
     refuses to shrink and the whole page scrolls sideways on a phone. */
  min-width: 0;
}

/* The site's label: sand, small, medium weight, sentence case. The gold
   uppercase micro-caps this used to carry are the single cheapest thing that
   made the filter bar look like it came from somewhere else. */
.field label {
  display: block;
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: var(--warm-sand);
  margin-bottom: var(--space-xs);
}

.field input,
.field select,
.field textarea {
  font-family: var(--font-body);
  /* 1rem minimum. Anything smaller and iOS Safari zooms the page on focus, which
     is the classic "the whole layout jumped" mobile bug. */
  font-size: var(--fs-body);
  color: var(--cream);
  background: var(--undertow-60);
  border: 1px solid var(--gold-20);
  border-radius: var(--radius-md);
  padding: var(--space-sm) var(--space-md);
  width: 100%;
  min-width: 0;
  /* Comfortable touch target on a phone without making desktop fields chunky. */
  min-height: 2.75rem;
  transition: border-color var(--ease);
}

.field input:focus,
.field select:focus,
.field textarea:focus { outline: none; border-color: var(--gold); }

/* The submit button sits on the baseline of the last row of inputs. */
.field--submit .btn { width: 100%; }

.field textarea { min-height: 9rem; resize: vertical; }

.field input::placeholder,
.field textarea::placeholder { color: var(--cream-40); }

/* --------------------------------------------------------------------------
   Buttons. The site's, exactly: 4px radius, not a 20px pill. This was the
   loudest visual mismatch after the navigation.
   -------------------------------------------------------------------------- */
.btn,
.btn-primary {
  display: inline-block;
  background: var(--gold);
  color: var(--abyss);
  font-family: var(--font-body);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-btn);
  padding: var(--space-sm) 1.75rem;
  border-radius: var(--radius-sm);
  border: none;
  cursor: pointer;
  text-decoration: none;
  text-align: center;
  transition: all var(--ease);
}
.btn:hover,
.btn-primary:hover {
  background: var(--warm-sand);
  color: var(--abyss);
  transform: translateY(-2px);
  box-shadow: var(--shadow-hover);
  text-decoration: none;
}

.btn--ghost,
.btn-ghost {
  display: inline-block;
  background: transparent;
  color: var(--gold);
  font-family: var(--font-body);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-btn);
  padding: var(--space-sm) 1.75rem;
  border-radius: var(--radius-sm);
  border: 2px solid var(--gold);
  cursor: pointer;
  text-decoration: none;
  transition: all var(--ease);
}
.btn--ghost:hover,
.btn-ghost:hover {
  background: var(--gold);
  color: var(--abyss);
  transform: none;
  text-decoration: none;
}

/* A ghost button on the sand section takes the sand treatment, but one inside a
   dark panel on that section keeps the gold. */
.section--alt .btn--ghost,
.section--alt .btn-ghost { color: var(--abyss); border-color: var(--abyss); }
.section--alt .btn--ghost:hover,
.section--alt .btn-ghost:hover { background: var(--abyss); color: var(--warm-sand); }
.section--alt :is(.card, .empty, .notice, .relay-form, .filters) .btn--ghost {
  color: var(--gold);
  border-color: var(--gold);
}

.btn-group { display: flex; gap: var(--space-lg); flex-wrap: wrap; }
.btn-group--center { justify-content: center; }

/* ==========================================================================
   Global site header. Identical structure to liquidbreathwork.com.
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--abyss);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--gold-10);
}

.site-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* Wider than the page container, exactly as the site's nav is. */
  max-width: var(--max-width-nav);
  margin: 0 auto;
  padding: 1.25rem 5%;
  width: 100%;
  gap: var(--space-md);
}

.site-logo {
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: 1.3rem;
  color: var(--warm-sand);
  letter-spacing: 1px;
  text-decoration: none;
  white-space: nowrap;
}
.site-logo:hover { color: var(--gold); text-decoration: none; }

.nav-links {
  display: flex;
  gap: 0;
  list-style: none;
  align-items: center;
  margin: 0;
  padding: 0;
}

.nav-links > li { position: relative; }

.nav-links > li > a,
.nav-links > li > .nav-dropdown-trigger {
  display: block;
  font-family: var(--font-body);
  font-weight: var(--fw-regular);
  font-size: var(--fs-nav);
  color: var(--cream);
  text-decoration: none;
  transition: color var(--ease);
  padding: 0.5rem 1rem;
  cursor: pointer;
  background: none;
  border: none;
  white-space: nowrap;
  /* The site's trigger is a <button>, which takes the UA's line-height: normal.
     Ours is a <label> (the CSS-only drawer needs one), and a label inherits the
     body's 1.8. That single inherited value made every mobile drawer row about
     8px taller than the live site's and the desktop header 1.4px taller. Same
     element, same class names, different default. */
  line-height: normal;
}

.nav-links > li > a:hover,
.nav-links > li > .nav-dropdown-trigger:hover { color: var(--gold); text-decoration: none; }

/* The section the visitor is in. Every page this Worker serves is under Free
   Tools, so that trigger carries the marker and the directory entry inside it
   carries aria-current. Colour is not the only signal: the dropdown item is
   also the one with the gold rule beside it. */
.nav-links > li.is-current-section > .nav-dropdown-trigger { color: var(--gold); }

.nav-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 240px;
  background: var(--abyss);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--gold-10);
  border-radius: var(--radius-md);
  padding: var(--space-xs) 0;
  margin: 0;
  list-style: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: all var(--ease);
  z-index: 200;
}

/* Hover is the site's rule verbatim. :focus-within is additive: it is what lets
   a keyboard reach the menu with no script, and the live site lacks it. */
.nav-links > li:hover > .nav-dropdown,
.nav-links > li:focus-within > .nav-dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.nav-dropdown a {
  display: block;
  padding: 0.6rem 1.25rem;
  color: var(--cream);
  font-size: var(--fs-small);
  text-decoration: none;
  transition: all var(--ease);
}
.nav-dropdown a:hover {
  color: var(--gold);
  background: var(--undertow-60);
  text-decoration: none;
}

.nav-dropdown a.is-current {
  color: var(--gold);
  box-shadow: inset 3px 0 0 var(--gold);
}

/* The gold CTA pill. The site wins this with !important over its own nav-link
   rules; the same is needed here for the same reason. */
.nav-links > li > a.nav-cta,
a.nav-cta {
  background: var(--gold) !important;
  color: var(--abyss) !important;
  padding: 0.5rem 1.25rem !important;
  font-size: var(--fs-small) !important;
  font-weight: var(--fw-semibold) !important;
  border-radius: var(--radius-sm);
  letter-spacing: 0.02em;
  transition: opacity var(--ease), transform var(--ease);
}
.nav-links > li > a.nav-cta:hover,
a.nav-cta:hover {
  opacity: 0.9;
  color: var(--abyss) !important;
  transform: translateY(-1px);
  text-decoration: none;
}

/* --------------------------------------------------------------------------
   The hamburger, and the checkbox that drives it.

   CLIPPED, NOT display:none. A display:none input is not focusable, which would
   leave a keyboard user with no way to open the drawer on a phone. Clipped, it
   is still in the focus order: Tab reaches it, Space opens the menu.
   -------------------------------------------------------------------------- */
.nav-state {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  /* It is 1px and invisible, but the locked rule is that nothing invisible ever
     intercepts a pointer. The label is what a pointer uses. */
  pointer-events: none;
}

.nav-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
  /* A 3-bar icon is 34px tall inside 8px of padding: already past the 44px
     touch floor once the padding is counted. */
}
.nav-toggle span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--cream);
  margin: 5px 0;
  transition: all var(--ease);
}

/* Keyboard focus lands on the clipped input, so the visible affordance has to
   show it. Same for the dropdown triggers. */
.nav-state:focus-visible + .nav-toggle span { background: var(--gold); }
.nav-state:focus-visible + .nav-dropdown-trigger {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
  color: var(--gold);
}

/* ==========================================================================
   Global site footer.
   ========================================================================== */

.site-footer {
  background: var(--abyss);
  border-top: 1px solid var(--gold-10);
  padding: var(--space-2xl) 5%;
}

.footer-grid {
  max-width: var(--max-width);
  margin: 0 auto var(--space-lg);
  display: grid;
  grid-template-columns: 1.4fr repeat(5, 1fr);
  gap: var(--space-lg);
}

.footer-brand .site-logo { display: block; margin-bottom: var(--space-md); }
.footer-brand p {
  color: var(--cream-50);
  font-size: var(--fs-nav);
  line-height: 1.7;
}

.site-footer h4 {
  color: var(--warm-sand);
  font-family: var(--font-body);
  font-weight: var(--fw-semibold);
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: var(--space-md);
}

.site-footer a {
  color: var(--cream-50);
  font-size: var(--fs-nav);
  display: block;
  margin-bottom: var(--space-xs);
  transition: color var(--ease);
  text-decoration: none;
}
.site-footer a:hover { color: var(--gold); text-decoration: none; }

.social-links {
  display: flex;
  gap: var(--space-lg);
  margin-top: var(--space-md);
}
.social-links a {
  width: 40px;
  height: 40px;
  margin-bottom: 0;
  border: 1px solid var(--gold);
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all var(--ease);
  font-size: var(--fs-small);
}
.social-links a:hover { background: var(--gold); color: var(--abyss); }

/* The site ships these two rules in an inline <style> inside the footer.
   style-src 'self' has no 'unsafe-inline', so an inline block would be
   dropped: they live in the stylesheet instead. */
.footer-quicklinks-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.3rem 0.9rem;
}
.footer-quicklinks-grid a {
  font-size: 0.72rem;
  line-height: 1.3;
  white-space: normal;
  margin-bottom: 0;
}

.footer-bottom {
  border-top: 1px solid var(--gold-10);
  padding-top: var(--space-xl);
  text-align: center;
}
.footer-bottom p {
  color: var(--warm-sand);
  font-size: var(--fs-small);
  opacity: 0.6;
  margin-bottom: 0;
}
.footer-legal { margin-top: var(--space-xs); }
.footer-legal a {
  display: inline;
  margin-bottom: 0;
  color: var(--warm-sand);
  font-size: inherit;
}
.footer-legal a:hover { color: var(--gold); }

/* ==========================================================================
   Chrome responsive. The site's breakpoints, not the directory's.
   ========================================================================== */

@media (max-width: 1024px) {
  /* The site has NO rule between 481px and 1024px, so its six-column footer
     squeezes on a tablet. Reproducing that bug is not parity, it is a bug, so
     the grid drops to three columns here and one below 480px. Flagged in
     SITE-PARITY.md section 4g. */
  .footer-grid { grid-template-columns: repeat(3, 1fr); }
  .footer-quicklinks-col { grid-column: span 2; }
}

@media (max-width: 768px) {
  .nav-toggle { display: block; }

  .nav-links {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--abyss);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    flex-direction: column;
    padding: var(--space-xl) 5%;
    gap: 0;
    border-top: 1px solid var(--gold-10);
    /* The drawer is taller than a phone screen once a sub-menu is open, and it
       is absolutely positioned, so it has to scroll inside itself rather than
       running off the bottom of the viewport with no way to reach the end. */
    max-height: 80vh;
    overflow-y: auto;
  }

  /* The whole mobile navigation, with no JavaScript: the label checks the box,
     the box opens the drawer. The site does this with a class main.js adds. */
  .nav-state--drawer:checked ~ .nav-links { display: flex; }

  .nav-links > li { width: 100%; text-align: center; }

  .nav-links > li > a,
  .nav-links > li > .nav-dropdown-trigger { padding: 0.75rem 0; width: 100%; }

  .nav-dropdown {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    background: none;
    border: none;
    padding: 0 0 0 var(--space-md);
    display: none;
    min-width: 0;
  }
  /* Same trick one level down, for each sub-menu inside the drawer. */
  .nav-links > li > .nav-state:checked ~ .nav-dropdown { display: block; }
  /* Sub-items read LEFT-aligned inside a centred 240px box on the live drawer.
     The text-align: center on li above cascades into the sub-menu and made ours
     centred and full width, which is the one geometry difference a person would
     actually notice with a drawer section open.
     (No backticks in this file: it is one big template literal.) */
  .nav-dropdown {
    text-align: start;
    width: 240px;
    margin-inline: auto;
  }
  .nav-dropdown a { padding: 0.5rem 0; font-size: var(--fs-small); }
  .nav-dropdown a.is-current { box-shadow: none; }

  .site-nav { padding: var(--space-md) 5%; }

  .footer-grid { grid-template-columns: repeat(2, 1fr); }
  .footer-quicklinks-col { grid-column: span 2; }
  .footer-quicklinks-grid a { font-size: var(--fs-small); }
}

@media (max-width: 480px) {
  .footer-grid { grid-template-columns: 1fr; gap: var(--space-lg); }
  .footer-quicklinks-col { grid-column: auto; }
  .footer-quicklinks-grid { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   Cards. The site's glass card: --panel, 1px gold-20 hairline, 8px radius,
   2rem of padding, and a 4px lift on hover.
   -------------------------------------------------------------------------- */
.card-grid {
  display: grid;
  /* 17rem, not 19rem: three columns on a 1280px screen instead of two, which is
     a third fewer rows to scroll through at any directory size. auto-FILL, not
     auto-fit, so the tracks stay put and a short row is not stretched. */
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  /* Each card is its own height. Stretching them to the tallest in the row
     leaves a card with a short bio carrying 200px of empty navy, which reads as
     a rendering fault rather than as whitespace. */
  align-items: start;
  gap: var(--space-xl);
  margin-top: var(--space-2xl);
  padding: 0;
  list-style: none;
}

/* A city with one facilitator, or two, is a real and common state, and the
   auto-fill grid leaves that card marooned in the left third of a 1200px sand
   band. One or two results get a centred layout at a card's natural width
   instead: the same component, laid out deliberately rather than by accident. */
.card-grid:has(> li:first-child:last-child) {
  grid-template-columns: minmax(0, 24rem);
  justify-content: center;
}
.card-grid:has(> li:first-child + li:last-child) {
  grid-template-columns: repeat(2, minmax(0, 24rem));
  justify-content: center;
}

.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  background: var(--panel);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--cream);
  border: 1px solid var(--gold-20);
  border-radius: var(--radius-md);
  padding: var(--space-xl);
  box-shadow: var(--shadow-card);
  transition: all var(--ease);
}
.card:hover {
  border-color: var(--gold-40);
  transform: translateY(-4px);
  box-shadow: var(--shadow-hover);
}

/* Portrait beside the name and location, rather than above them: it halves the
   vertical space the identity block costs, which is the whole card budget at a
   hundred facilitators. */
.card__head {
  display: flex;
  gap: var(--space-md);
  /* Top-aligned, not centred: the identity block is taller than the 72px
     portrait, and centring it floats the name above the top of the circle. */
  align-items: flex-start;
}

.card__id { min-width: 0; }

.card__nameline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
}

.card__name {
  margin: 0;
  font-size: var(--fs-h4);
  color: var(--cream);
}

.card__meta {
  font-size: var(--fs-small);
  color: var(--cream-80);
  margin: var(--space-xs) 0 0;
}

.card__excerpt {
  font-size: var(--fs-small);
  line-height: 1.7;
  color: var(--cream-80);
  margin: 0;
}

/* --------------------------------------------------------------------------
   Portrait, with a monogram underneath.

   The site already ships this pattern as .facilitator-photo: a circle with a
   3px gold border that scales on hover. This is that treatment, on a frame that
   also has to survive a missing photo and a dead one.

   THE FRAME OWNS THE SIZE, THE IMAGE ONLY FILLS IT. A facilitator with a photo,
   one without, and one whose photo 404s all occupy the same pixels, so nothing
   in the grid moves when an image loads or fails.

   THE MONOGRAM IS ALWAYS PAINTED, BEHIND. There is no CSS selector for a broken
   image and this Worker ships no JavaScript, so the only fallback that can
   survive a 404 is one that was already there.

   A BROKEN PHOTO PAINTS THE MONOGRAM, NOT A GLYPH. Chrome draws its
   broken-image icon inside any sized <img> that fails, even with alt="". A
   broken image is no longer a REPLACED element, though, which is the one moment
   CSS gets to generate a box inside it, so ::before repaints the monogram over
   the icon. A loaded image generates no pseudo-element and is untouched. This is
   not a theoretical edge case: a replacement photo deletes the live object
   before the replacement is approved, so a dead photo_key is a routine state.
   -------------------------------------------------------------------------- */
.portrait {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: var(--undertow);
  border: 2px solid var(--gold);
  transition: transform 0.4s ease, border-color 0.4s ease;
}

.portrait--card { width: 4.5rem; height: 4.5rem; }
.portrait--hero { width: 11rem; height: 11rem; border-width: 3px; }

.portrait--hero:hover { transform: scale(1.05); border-color: var(--warm-sand); }

.portrait__monogram {
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  letter-spacing: 0.04em;
  line-height: 1;
  color: var(--gold);
  /* Decorative: aria-hidden in the markup, since the name is the adjacent
     heading. Takes no clicks so it can never sit on top of selectable copy, and
     selection is never disabled here: that declaration is banned outright. */
  pointer-events: none;
}

.portrait--card .portrait__monogram { font-size: 1.5rem; }
.portrait--hero .portrait__monogram { font-size: 3.5rem; }

.portrait__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 0%;
}

/* Generated ONLY when the image failed to load. Decorative, so it takes no
   clicks, exactly like every other overlay in this file. */
.portrait__img::before {
  content: attr(data-initials);
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--undertow);
  color: var(--gold);
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  letter-spacing: 0.04em;
  line-height: 1;
  pointer-events: none;
}

.portrait--card .portrait__img::before { font-size: 1.5rem; }
.portrait--hero .portrait__img::before { font-size: 3.5rem; }

/* --------------------------------------------------------------------------
   Chips: specialties, verification.
   -------------------------------------------------------------------------- */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* A chip row that is a browse control rather than a card's metadata: it sits
   under a centred section header, so it centres too. */
.chips--center { justify-content: center; margin-top: var(--space-lg); }

.chip {
  display: inline-block;
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--gold-40);
  background: var(--gold-10);
  color: var(--cream);
  transition: all var(--ease);
}

/* A chip that is a link gives its padding to the anchor, so the whole pill is
   the tap target instead of just the glyphs inside it. Without this the target
   is the ~19px text box, well under the 32px floor for a secondary control. */
.chip:has(> a) { padding: 0; }
.chip > a {
  display: block;
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-pill);
  color: var(--cream);
  text-decoration: none;
}
.chip:hover { border-color: var(--gold); }

/* A chip inside a dark PANEL keeps the dark-surface treatment. The sand rule
   below repaints a chip deep-water, which on a deep-water card is an invisible
   pill: the specialty labels read as bare text with a stray indent. */
.section--alt .card .chip,
.section--alt .empty .chip,
.section--alt .notice .chip {
  background: var(--gold-10);
  border-color: var(--gold-40);
  color: var(--cream);
}

/* Locked contrast rule: a component sitting on the sand section must contrast
   with it. The navy version of a chip is cream text on a faint gold wash, which
   on sand is cream on sand and unreadable. On sand a chip becomes what every
   other component becomes: a solid deep-water panel with cream text. */
.section--alt .chip {
  background: var(--deep-water);
  border-color: var(--deep-water);
  color: var(--cream);
}
.section--alt .chip a {
  color: var(--cream);
  text-decoration: underline;
}

/* "+3 more" on a card. Quieter than a real specialty: it is a count, not a claim. */
.chip--count {
  border-style: dashed;
  background: transparent;
  color: var(--cream-80);
}

.badge {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: var(--fw-semibold);
  padding: 0.3rem 0.8rem;
  border-radius: var(--radius-sm);
  background: var(--gold);
  color: var(--abyss);
}

/* --------------------------------------------------------------------------
   Lists that breathe. Each item is its own card, not a cramped bullet.
   -------------------------------------------------------------------------- */
.panel-list {
  list-style: none;
  margin: var(--space-xl) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  gap: var(--space-lg);
}

.panel-list > li {
  background: var(--panel);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--cream);
  border: 1px solid var(--gold-20);
  border-radius: var(--radius-md);
  padding: var(--space-lg) var(--space-xl);
  transition: all var(--ease);
}
.panel-list > li:hover {
  border-color: var(--gold-40);
  transform: translateY(-4px);
}

.panel-list h3 {
  margin: 0 0 var(--space-xs);
  font-size: var(--fs-h4);
  color: var(--warm-sand);
}
.panel-list h3 a { display: inline-block; padding: 0.25rem 0; }
.panel-list p { margin: 0; color: var(--cream-80); font-size: var(--fs-small); }
.panel-list a { color: var(--gold); }

/* --------------------------------------------------------------------------
   Profile page
   -------------------------------------------------------------------------- */
.profile-head {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xl);
  align-items: flex-start;
}

.profile-headline { flex: 1 1 20rem; min-width: 15rem; }
.profile-headline h1 { margin-bottom: var(--space-xs); }

.profile-location {
  font-size: 1.1rem;
  color: var(--warm-sand);
  margin: 0 0 var(--space-xs);
}

/* --------------------------------------------------------------------------
   The two skill axes in the profile hero.

   Two labelled groups, not one long chip row: "Specialties" is what they do in
   a Breathwork room, "Also trained in" is everything else they hold, and a
   visitor should never have to work out which a chip belongs to.

   The overflow disclosure is a native <details>. No JavaScript exists on these
   pages, and its contents are in the DOM at parse time, so every chip is
   readable by a crawler whether or not a human expands it.
   -------------------------------------------------------------------------- */
.skills {
  display: grid;
  gap: var(--space-lg);
  margin-top: var(--space-lg);
}

.skills__label {
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: var(--fw-semibold);
  color: var(--gold);
  margin: 0 0 var(--space-xs);
}

.skills__more { margin-top: var(--space-xs); }

.skills__more summary {
  display: inline-block;
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-pill);
  border: 1px dashed var(--gold-40);
  color: var(--gold);
  cursor: pointer;
  list-style: none;
}
.skills__more summary::-webkit-details-marker { display: none; }
.skills__more[open] summary { border-style: solid; }

/* Required beside the second axis, every time it renders: the Verified badge a
   few lines above covers a Breathwork certification and nothing else. */
.skills__note {
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--cream-60);
  margin: var(--space-sm) 0 0;
  max-width: var(--max-width-text);
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin-top: var(--space-xl);
}

/* --------------------------------------------------------------------------
   Pagination. Real anchors: a crawler walks the whole directory through them
   and a visitor with scripting off gets the identical experience.
   -------------------------------------------------------------------------- */
.pagination { margin-top: var(--space-2xl); }

.pagination__status {
  font-size: var(--fs-small);
  margin: 0 0 var(--space-md);
}

.pagination__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  list-style: none;
  margin: 0;
  padding: 0;
}

.pagination__page,
.pagination__step {
  display: inline-block;
  /* 2.75rem square: a comfortable thumb target, not a 12px numeral. */
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding: 0.7rem var(--space-md);
  text-align: center;
  border-radius: var(--radius-sm);
  border: 1px solid var(--gold-20);
  background: var(--panel);
  color: var(--cream);
  font-size: var(--fs-small);
  transition: all var(--ease);
}
.pagination__page:hover,
.pagination__step:hover { border-color: var(--gold); }

.pagination__page--current {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--abyss);
  font-weight: var(--fw-semibold);
}

.pagination__gap {
  display: inline-block;
  padding: 0 var(--space-xs);
  color: var(--cream-60);
}

.section--alt .pagination__gap { color: var(--undertow); }
.section--alt .pagination__status { color: var(--deep-water); }

/* The bio. Sanitized at publish, re-serialized at render, escaped by default. */
.bio { max-width: var(--max-width-text); }
.bio p { margin: 0 0 var(--space-lg); }
.bio ul,
.bio ol { margin: 0 0 var(--space-lg); padding-left: var(--space-lg); list-style: disc; }
.bio li { margin-bottom: var(--space-xs); }

/* --------------------------------------------------------------------------
   Designed table. Never a bare <table> on an LBW page.
   -------------------------------------------------------------------------- */
.data-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--cream);
  border: 1px solid var(--gold-20);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-top: var(--space-xl);
}

.data-table th,
.data-table td {
  text-align: left;
  padding: 1.15rem var(--space-lg);
  border-bottom: 1px solid var(--gold-20);
  vertical-align: top;
}

.data-table th {
  font-size: var(--fs-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  font-weight: var(--fw-semibold);
}

.data-table tr:last-child td { border-bottom: none; }

.table-scroll { overflow-x: auto; }

/* --------------------------------------------------------------------------
   Contact relay. There is no published address anywhere on this site, by design.
   -------------------------------------------------------------------------- */
.relay-form {
  display: grid;
  gap: var(--space-lg);
  background: var(--panel);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--cream);
  border: 1px solid var(--gold-20);
  border-radius: var(--radius-md);
  padding: var(--space-xl);
  max-width: var(--max-width-text);
  margin: 0 auto;
}

/* Honeypot. Off-screen rather than display:none, because some bots skip
   display:none fields. Not a text node a human can reach, and it takes no
   clicks, so it cannot interfere with selecting real copy. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Callouts. These keep the gold accent bar: an empty state and a form result
   are interruptions, and they should not read as one more card in the grid.
   -------------------------------------------------------------------------- */
.notice,
.empty {
  background: var(--panel);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--cream);
  border: 1px solid var(--gold-20);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius-md);
  padding: var(--space-xl);
  max-width: var(--max-width-text);
  margin-left: auto;
  margin-right: auto;
}

.notice { margin-top: var(--space-lg); margin-bottom: var(--space-lg); }
.empty { margin-top: var(--space-2xl); }
.empty h2 { font-size: var(--fs-h3); margin-bottom: var(--space-md); }
.empty p:last-child,
.notice p:last-child { margin-bottom: 0; }

.form-hint { font-size: var(--fs-small); color: var(--cream-60); margin: 0; }

/* Code blocks (the embed snippet). Horizontally scrollable inside their own
   container so a long URL never makes the page body scroll sideways. */
pre {
  margin: 0;
  overflow-x: auto;
  font-size: var(--fs-small);
  line-height: 1.6;
}
code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

/* --------------------------------------------------------------------------
   Embeddable events widget. Its own compact shell, same tokens.
   -------------------------------------------------------------------------- */
.widget-body {
  background: var(--abyss);
  color: var(--cream);
  padding: var(--space-lg);
}

.widget-head {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  align-items: baseline;
  justify-content: space-between;
  border-bottom: 1px solid var(--gold-20);
  padding-bottom: var(--space-sm);
  margin-bottom: var(--space-md);
}

.widget-head h1 { font-size: var(--fs-h4); margin: 0; }

.widget-list { display: grid; gap: var(--space-md); list-style: none; margin: 0; padding: 0; }

.widget-list > li {
  background: var(--undertow-60);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius-md);
  padding: var(--space-md) var(--space-lg);
}

.widget-list h2 { font-size: 1.05rem; margin: 0 0 0.25rem; color: var(--warm-sand); }
.widget-list p { margin: 0; font-size: var(--fs-small); color: var(--cream-80); }

.widget-foot {
  margin-top: var(--space-lg);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--gold-20);
  font-size: var(--fs-xs);
  color: var(--cream-60);
}

/* --------------------------------------------------------------------------
   Cross-links out to the Near Me apps and the certification training.
   -------------------------------------------------------------------------- */
.linkout {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-md);
  list-style: none;
  margin: var(--space-lg) 0 0;
  padding: 0;
}

.linkout > li {
  background: var(--panel);
  border: 1px solid var(--gold-20);
  border-radius: var(--radius-sm);
  padding: 0.5rem var(--space-lg);
}
.linkout a { color: var(--gold); }

/* --------------------------------------------------------------------------
   Responsive. The site drops section padding at 768px and again at 480px; the
   directory's own two-column filter grid lands at 640px, between them.
   -------------------------------------------------------------------------- */
@media (max-width: 768px) {
  .section { padding: var(--space-2xl) 0; }
  .hero { padding: var(--space-2xl) 0; }
  .section-header { margin-bottom: var(--space-xl); }
  .portrait--hero { width: 8.75rem; height: 8.75rem; }
  .portrait--hero .portrait__monogram,
  .portrait--hero .portrait__img::before { font-size: 2.75rem; }
  .panel-list { grid-template-columns: 1fr; }
  .btn,
  .btn-primary,
  .btn--ghost,
  .btn-ghost { max-width: 22rem; }
}

@media (max-width: 640px) {
  .filters,
  .relay-form,
  .card,
  .empty,
  .notice,
  .panel-list > li { padding: var(--space-lg); }

  .card-grid { grid-template-columns: 1fr; gap: var(--space-lg); margin-top: var(--space-xl); }

  /* Two even columns instead of six stacked rows. City sits beside State and
     Specialty beside the second axis, so the filter bar is four rows on a phone
     rather than a tower the visitor scrolls past to reach a facilitator. */
  .filters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .field--q,
  .field--submit { grid-column: 1 / -1; }

  .profile-head { gap: var(--space-lg); }
  .portrait--hero { width: 7.5rem; height: 7.5rem; }
  .portrait--hero .portrait__monogram,
  .portrait--hero .portrait__img::before { font-size: 2.5rem; }

  .data-table th,
  .data-table td { padding: var(--space-md); }

  .actions .btn,
  .actions .btn--ghost { width: 100%; text-align: center; }

  /* Numbers keep their tap target; the words shrink to fit the row. */
  .pagination__step { padding: 0.7rem var(--space-sm); }
}

@media (max-width: 480px) {
  .section { padding: var(--space-xl) 0; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  .card:hover,
  .panel-list > li:hover,
  .portrait--hero:hover { transform: none; }
}
