/* ═══════════════════════════════════════════════════════════════
   BeeBhakti · styles.css
   Single stylesheet for the whole site.

   Colour values with an 8-digit hex (e.g. #D4A14145) are the brand
   colours with an alpha suffix, matching the previous inline styles.
   Dynamic, data-driven colours are passed from the components as the
   CSS variable --c (e.g. an event's accent colour).

   Contents:
     1. Fonts & design tokens
     2. Global styles
     3. Animations
     4. Typography
     5. Layout
     6. Header & navigation
     7. Buttons
     8. Cards & sections
     9. Forms
    10. Footer
    11. Utilities
    12. Responsive styles
   ═══════════════════════════════════════════════════════════════ */

/* ── 1. Fonts & design tokens ─────────────────────────────────── */
/* The Google Fonts request no longer lives here as an @import. An
   @import inside a stylesheet is only discovered once the stylesheet
   itself has arrived, so the faces used to start downloading a full
   round trip after everything else. build.py now writes the request
   as a <link> in every page's <head>, beside the preconnects, and
   404.html carries its own copy. Montserrat is asked for as ONE
   variable file per script (wght@300..700) rather than five static
   weights — the same typeface, fewer files (7 Sep 2026). */

:root{
  /* The site is a committed light design: warm cream, painted
     explicitly. Saying so lets a browser in dark mode keep native
     form controls and scrollbars light against the cream instead of
     rendering them dark. A dark theme of BeeBhakti's own is a
     founder decision, recorded in docs/build-log.md, 7 Sep 2026. */
  color-scheme: light;
  --honey:      #D4A141;   /* Golden Honey */
  --gold:       #E8B84B;   /* lighter honey for gradients */
  --saffron:    #E8C060;   /* warm highlight */
  --cream:      #F5EFE6;   /* Warm Cream */
  --petal:      #FAF3EC;   /* slightly warmer cream */
  --warm-white: #FBF6EE;   /* near white with warmth */
  --deep-earth: #5B3E1F;   /* Earthy Brown */
  --sage:       #6E9DB8;   /* Sky Blue (online/calm tags) */
  --rose:       #F7C8C0;   /* Lotus Pink */
  --dusk:       #7A5535;   /* warm dusk */
  --dark-bg:    #231204;   /* deep warm dark */
  --mid-bg:     #33200C;   /* warm mid dark */
  --text-dark:  #3A200A;   /* deep earthy text */
  --text-mid:   #5B3E1F;   /* Earthy Brown for text */
  --text-light: #7A5535;   /* lighter warm text — was #87683C */
  --error:      #B3261E;

  /* A category colour written as TEXT, as opposed to filling a pill
     or an accent bar (F69, 8 Sep 2026). At 11px on its own tinted
     badge, every one of the eleven type colours read between 2.4 and
     4.0:1 on cream, all below the 4.5 the guidance asks for. Written
     as text they take 58% of themselves and 42% of --text-dark,
     which is the least darkening that carries the worst of them
     past 4.6:1; the pill's tint, its border and every accent bar
     keep the founder's colour untouched. The night theme tunes these
     hues on its own ground, so there it is 100% and this does
     nothing. */
  --type-ink: 58%;
  /* The same idea for a colour that arrives from the DATA rather than
     from a gathering type — a resource kind, a calendar kind, a
     speciality, a book's accent. Those cannot be themed, so one share
     serves both appearances: --text-dark is the deep brown by day and
     the ivory by night, and 52% carries the worst of them past 4.6:1
     either way. */
  --ink-data: 52%;

  /* ── Roles, not hues (7 Sep 2026) ───────────────────────────
     The founder's night theme (F64, D366) swaps colours by ROLE, so
     the rules below name the role a colour plays. Every value here
     is exactly the literal the rule carried before, which is what
     keeps the light site pixel-identical; the night block at the end
     of this file gives each role its dark value. */
  --page:        #FBF6EE;   /* the page itself (= --warm-white) */
  --page-soft:   #FAF3EC;   /* alternating sections (= --petal) */
  --page-cream:  #F5EFE6;   /* the hero's top and a few strips (= --cream) */
  --surface:     #FFFFFF;   /* cards, panels, menus: what was "white" */
  --panel:       #FBF6EE;   /* sheets and modals that were warm-white */
  --field:       #FBF6EE;   /* inputs */
  --hover:       #FAF3EC;   /* a row or option under the pointer */
  --selected:    #FDF6E7;   /* a chosen state's fill */
  --photo-ph:    #F5EADC;   /* behind a portrait while it loads */
  --skeleton:    #EFE6D8;   /* loading placeholders */
  --on-accent:   #FFFFFF;   /* text on a honey fill */
  --on-accent-strong: #3A200A; /* the primary buttons' darker text */
  --on-dark:     #FFFFFF;   /* text on a dark band */
  --ink-deep:    #2E1A06;   /* the deep brown mixed into type colours */
  --honey-deep:  #B0873A;   /* a darker honey for two small lines */
  --ember:       #B5544A;   /* the warm red of Follow and Presale */
  --icon-muted:  #87683C;   /* the quiet stroke of search, fly, chevron */
  --earth:       #8B6230;   /* mid earth: the speciality tags */

  /* The whole site is set in Montserrat (Aug 2026). This token still
     carries the name --font-serif because 52 rules reference it and the
     distinction is worth keeping: it marks the DISPLAY text (headings,
     titles, verses, wordmarks) as opposed to --font-sans for labels and
     body. Both resolve to the same family today, so restoring a display
     face means changing this one line back to
       'Playfair Display', Georgia, serif
     and adding Playfair+Display back to the @import above. */
  --font-serif: 'Montserrat', system-ui, sans-serif;
  --font-sans:  'Montserrat', system-ui, sans-serif;
  --font-mono:  'DM Mono', 'SF Mono', monospace;
  /* The header's page links only (14 Sep 2026, founder: match
     timacamara.com) — small, uppercase and widely spaced. */
  --font-nav:   'DM Sans', sans-serif;

  --grad-honey:  linear-gradient(135deg, var(--honey), var(--gold));
  --grad-earth:  linear-gradient(160deg, var(--deep-earth), var(--mid-bg));

  /* ── The fluid layout spine ──────────────────────────────────
     One gutter, one shell, one rhythm. Everything below is a
     continuous function of the viewport rather than a set of
     breakpoints, so the page keeps redistributing space as the
     window grows instead of jumping at four fixed sizes.

     --page-edge is the site's single gutter: the header, every page
     title and every section share it, so content always begins on
     the same line as the BeeBhakti logo. It grows with the viewport
     (a 20px margin on a phone is generous; on a 27" display it would
     look like a mistake) and stops at 72px so ultrawide screens get
     their air from the shell instead. */
  --page-edge:   clamp(20px, 4vw, 72px);
  --page-pad-x:  var(--page-edge);

  /* Content shells. Three tiers, each fluid between a floor (never
     narrower than the design was before) and a ceiling (so a 4K
     display never stretches a line of text past readability):
       wide   — card and map grids, the widest compositions
       mid    — three-across card rows, calendars, feature blocks
       read   — running prose; capped near 80 characters
       narrow — single-field forms and short invitations
     Below the floor each one simply follows its parent (min(100%,…)),
     which is what keeps phones and tablets working. */
  --w-wide:   clamp(1100px, 84vw, 1660px);
  --w-mid:    clamp(960px,  72vw, 1360px);
  --w-read:   clamp(780px,  52vw,  880px);
  --w-narrow: clamp(520px,  44vw,  660px);

  /* Vertical rhythm and gaps scale on the same curve as the gutter,
     so the space between things stays in proportion to the space
     around them at every resolution. */
  --section-pad-y: clamp(48px, 5.2vw, 108px);
  --gap-sm: clamp(10px, 0.9vw, 16px);
  --gap-md: clamp(16px, 1.5vw, 28px);
  --gap-lg: clamp(22px, 2.2vw, 40px);
  --gap-xl: clamp(30px, 3.2vw, 60px);
  /* Card grids get a gap of their own, deliberately tighter than
     --gap-md. A gap that grows as fast as the page does eats the room
     the next column needed, so a wider window can end up with FEWER,
     fatter cards — the opposite of the point. */
  --gap-grid: clamp(16px, 1.2vw, 24px);

  /* Event-type colours — one muted, palette-friendly colour per
     category, used everywhere a type appears (card badges, filter
     pills, map legend). */
  --type-festival:   #9A6794;   /* soft plum */
  --type-retreat:    #5E8CAD;   /* muted sky blue */
  --type-workshop:   #C2762F;   /* warm orange */
  --type-kirtan:     #C08A28;   /* golden honey */
  --type-course:     #4E938A;   /* soft teal */
  --type-temple:     #6F9060;   /* sage green (temple programmes) */
  --type-satsang:    #7E8A50;   /* muted olive */
  --type-pilgrimage: #B0684C;   /* warm terracotta */
  --type-online:     #C0708A;   /* dusty lotus pink */
  /* The two types added 24 Aug 2026. Neither is a new colour: each
     points at a token this palette already carries, which is what
     rule 2 asks for. The nine hues above are spoken for, so these two
     take the brand's own rather than inventing a tenth and eleventh.
     --sage is documented above as the calm token, which is the one
     that fits meditation; --text-light is deliberately the quietest
     thing here, for a badge whose real words are the organiser's. */
  --type-yoga:       var(--sage);
  --type-other:      var(--text-light);
}

/* Type classes: set the shared accent variable --c, which the .tag,
   .card-accent, and .type-pill rules already consume — and --ink,
   the share of that colour used when it is written as TEXT rather
   than painted as a fill (see --type-ink above). A tag with no type
   sets neither, so it keeps its own colour at full strength. */
.t-festival { --c: var(--type-festival); --ink: var(--type-ink, 100%); }
.t-retreat { --c: var(--type-retreat); --ink: var(--type-ink, 100%); }
.t-workshop { --c: var(--type-workshop); --ink: var(--type-ink, 100%); }
.t-kirtan { --c: var(--type-kirtan); --ink: var(--type-ink, 100%); }
.t-course { --c: var(--type-course); --ink: var(--type-ink, 100%); }
.t-temple { --c: var(--type-temple); --ink: var(--type-ink, 100%); }
.t-satsang { --c: var(--type-satsang); --ink: var(--type-ink, 100%); }
.t-pilgrimage { --c: var(--type-pilgrimage); --ink: var(--type-ink, 100%); }
.t-online { --c: var(--type-online); --ink: var(--type-ink, 100%); }
.t-yoga { --c: var(--type-yoga); --ink: var(--type-ink, 100%); }
.t-other { --c: var(--type-other); --ink: var(--type-ink, 100%); }
/* A tag coloured from the data rather than from a gathering type —
   a resource kind, a calendar kind, a facilitator's speciality. Those
   colours arrive as literals from app.jsx, so they cannot be themed,
   and raw they read between 2.1 and 4.3:1 in daylight and between
   2.2 and 4.3:1 at night. Half of the colour and half of --text-dark
   carries the worst of them past 4.6:1 in BOTH appearances, because
   that token is the deep brown by day and the ivory by night — one
   share, no theming needed (F69, 8 Sep 2026). */
.tag--ink { --ink: var(--ink-data); }

/* ── 2. Global styles ─────────────────────────────────────────── */
* { box-sizing: border-box; margin: 0; padding: 0; font-family: var(--font-sans); }
/* The site uses no italics anywhere: the tags browsers slant by
   default are reset so new copy can never introduce one. */
em, i, cite, var, dfn, address, blockquote, q { font-style: normal; }
html, body { margin: 0; padding: 0; }
#root { min-height: 100svh; }

.app {
  font-family: var(--font-sans);
  background: var(--page);
  min-height: 100svh;
  color: var(--text-dark);
  /* clip (not hidden) so position: sticky keeps working inside */
  overflow-x: clip;
}

::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: var(--page-soft); }
::-webkit-scrollbar-thumb { background: #E8C06055; border-radius: 3px; }

/* ── 3. Animations ────────────────────────────────────────────── */
@keyframes petalFall{ 0%{opacity:0;transform:rotate(45deg) translateY(0);} 10%{opacity:.6;} 90%{opacity:.2;} 100%{opacity:0;transform:rotate(220deg) translateY(640px) translateX(60px);} }
@keyframes beeFloat{ 0%,100%{transform:translateY(0) rotate(-3deg);} 40%{transform:translateY(-4px) rotate(3deg);} 70%{transform:translateY(-1px) rotate(0deg);} }
@keyframes fadeUp{ from{opacity:0;transform:translateY(20px);} to{opacity:1;transform:translateY(0);} }
@keyframes fadeIn{ from{opacity:0;} to{opacity:1;} }
@keyframes shimmer{ 0%{background-position:-200% center;} 100%{background-position:200% center;} }
@keyframes lotusBloom{ 0%,100%{transform:scale(1);opacity:.5;} 50%{transform:scale(1.35);opacity:1;} }
@keyframes softGlow{ 0%,100%{opacity:.25;} 50%{opacity:.6;} }
@keyframes pulse{ 0%,100%{opacity:1;} 50%{opacity:.5;} }

.fade-in { animation: fadeIn .9s ease; }

/* Motion respects the visitor's preference, everywhere at once.
   Four scattered blocks used to still four animations while the
   hero's shimmer, the globe's blooms and glow, the fade-ups and the
   button lifts carried on — and the app's own comment claimed
   "prefers-reduced-motion stills every animation in CSS". Now it
   does: every animation and transition collapses to an instant, so
   each element lands straight on its final state (the hero stack
   still appears; the skeletons still fade, only at once) and nothing
   drifts, breathes or shimmers. Scrolling stops being smooth for the
   same reader; app.jsx picks the same answer for its own scrollTo
   calls (SCROLL_BEHAVIOR). The per-rule blocks below stay: harmless,
   and each carries the story of why it was written. (7 Sep 2026) */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── 4. Typography ────────────────────────────────────────────── */
/* ── Alignment system ─────────────────────────────────────────
   Headings, overlines, short leads, quotes, empty states and CTAs are
   centred; body copy, cards, lists, filters and forms are left-aligned
   for readability and fast scanning. Cards set their own alignment so
   they are never affected by a centred ancestor. */

/* Keyboard focus: one clear honey ring everywhere, only for
   keyboard navigation (mouse clicks stay clean) */
:where(a, button, [role="button"], input, select, textarea):focus-visible {
  /* The ring is --honey-text, not --honey: raw honey on cream reads
     2:1, under the 3:1 a focus indicator needs against what surrounds
     it. At night the token is the bright honey and reads 9:1. */
  outline: 2px solid var(--honey-text); outline-offset: 2px;
}

/* Small uppercase overline above headings */
.overline { font-size: 12px; font-weight: 700; letter-spacing: .2em; color: var(--honey); margin-bottom: 8px; white-space: nowrap; text-align: center; }
.overline--wide { letter-spacing: .22em; margin-bottom: 14px; opacity: .85; }
.overline--verse { letter-spacing: .22em; margin-bottom: 28px; opacity: .7; }

/* Serif section headings — shared base + per-section sizes */
.h2 { font-family: var(--font-serif); font-weight: 400; color: var(--deep-earth); font-style: normal; text-align: center; }
/* The vw term is gentler than it was (4vw hit its cap by ~1100px and
   then stopped responding); the caps are higher, so headings keep
   growing with the shell instead of freezing at laptop size. */
.h2--featured { font-size: clamp(26px, 2.8vw, 52px); line-height: 1.1; }
.h2--philosophy { font-size: clamp(28px, 2.9vw, 54px); line-height: 1.2; margin-top: 20px; }
.h2--bhakti { font-size: clamp(28px, 3vw, 56px); font-weight: 300; line-height: 1.15; margin-bottom: clamp(18px, 1.8vw, 32px); }
.h2--listing { font-size: clamp(24px, 2.3vw, 42px); margin-top: 20px; margin-bottom: 12px; }
.h2--support { font-size: clamp(24px, 2.4vw, 44px); margin-top: 20px; }
/* Over a quiet list of questions rather than a grid of cards, so a
   step down from the full section-heading size. Shallow slope: the
   shared .h2--support curve sits flat at 24px up to 1000px and then
   climbs hard to 44px, which is what made it feel oversized on a
   large screen and undersized on a laptop. Roughly 23 → 26 → 31 →
   36px from 375 to 1920. */
.h2--faq { font-size: clamp(23px, 1.1vw + 15px, 36px); }
.h2--about { font-size: clamp(22px, 1.9vw, 34px); margin: 22px 0 16px; text-align: center; }
/* A full sentence rather than a title, so it sits a step below the
   welcome headline. It reads as one line from about 560px upward —
   the sentence needs ~25× its font size, and the section always has
   more than that — so the old 30ch measure (which broke it over two
   lines at every size) is gone. On a small phone it still wraps, and
   balance keeps the two lines even rather than leaving one word
   stranded. */
.h2--features { font-size: clamp(20px, 1.8vw, 33px); line-height: 1.35; margin-inline: auto; text-wrap: balance; }

/* Page titles live in the "Plain page title" block below (.page-head) */

/* Body copy — the one shared paragraph style, used on every page.
   Always spans the full width of its parent container; spacing
   overrides come from the margin utilities, never from max-width.
   The size drifts up gently on larger screens (17 → 18.5px) so a
   wider reading column keeps the same comfortable line length
   instead of simply fitting more words on a line. */
.prose { width: 100%; font-size: clamp(17px, 0.13vw + 16.4px, 18.5px); color: var(--text-mid); line-height: 1.85; margin: 0 0 clamp(14px, 1vw, 20px); text-align: left; }
.prose--sm { font-size: clamp(16px, 0.11vw + 15.5px, 17.5px); }

/* Decorative quote marks */
.quote-mark { font-size: 46px; color: var(--honey); opacity: .3; font-family: Georgia; line-height: .6; margin-bottom: 22px; }
.quote-mark--md { font-size: 36px; opacity: .35; margin-bottom: 18px; }

/* Inline SVG icon helpers */
.ic { flex-shrink: 0; vertical-align: -2px; }
.ic-b { flex-shrink: 0; }

/* ── 5. Layout ────────────────────────────────────────────────── */
/* svh, not vh: on phones the dynamic browser chrome makes 100vh
   taller than the visible page, which pushes content under the URL
   bar on first paint. */
.page { padding-top: 66px; min-height: 100svh; background: var(--page); }
/* Page bodies that open flush with the header: the same left edge as
   the logo and the rail pages, so nothing shifts sideways as you
   move between pages.

   The shell is centred, not left-anchored. Up to the point where it
   reaches its cap this is the same thing — the gutter IS the margin,
   so the title still starts under the logo — but past the cap the
   whole page keeps its balance instead of hugging the left edge and
   leaving a growing void on the right. The header uses the identical
   shell (.nav-inner), so the logo and the content edge stay on one
   line at every width. */
.page-edge {
  width: min(100% - var(--page-edge) * 2, var(--w-wide));
  margin-inline: auto;
  padding-left: 0; padding-right: 0;
}
.container { width: 100%; margin-inline: auto; }
/* The width utilities are now fluid tiers rather than fixed pixels:
   each grows with the viewport and stops at a ceiling chosen for what
   it holds. min(100%, …) keeps them inside their parent on phones,
   where the section padding is what sets the width. */
.mw-560 { max-width: min(100%, var(--w-narrow)); }
.mw-780 { max-width: min(100%, var(--w-read)); }
.mw-840 { max-width: min(100%, clamp(840px, 56vw, 940px)); }
.mw-960 { max-width: min(100%, var(--w-mid)); }
.mw-1060 { max-width: min(100%, var(--w-mid)); }
.mw-1100 { max-width: min(100%, var(--w-wide)); }

/* Long-form pages (Privacy) keep a reading measure inside the shell.
   The gutter is subtracted from the width rather than added as
   padding, so the column centres on exactly the same axis as every
   other centred block on the page. Declared after .container, whose
   width: 100% would otherwise win on equal specificity. */
.about-body {
  width: min(100% - var(--page-edge) * 2, var(--w-read));
  padding-block: clamp(44px, 5vw, 88px);
}

.z1 { position: relative; z-index: 1; }

/* Decorative layers */
.hex-bg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

/* Section shells. Every section is full-bleed and pads itself with
   the shared gutter; the container inside it carries the measure, so
   backgrounds run edge to edge while content stays balanced. */
.section-featured { padding: var(--section-pad-y) var(--page-pad-x); background: var(--page); }
.section-philosophy { padding: var(--section-pad-y) var(--page-pad-x); position: relative; overflow: hidden; }
/* No background of its own any more. Its only home is the About page,
   whose sections alternate petal and warm white; carrying petal with it
   put two petal bands side by side and they read as one long block. */
.section-bhakti { padding: var(--section-pad-y) var(--page-pad-x); background: var(--page); position: relative; overflow: hidden; }
.section-verse { padding: var(--section-pad-y) var(--page-pad-x); background: linear-gradient(135deg, var(--deep-earth) 0%, var(--mid-bg) 100%); text-align: center; position: relative; overflow: hidden; }
.section-support { padding: var(--section-pad-y) var(--page-pad-x); background: var(--page-soft); position: relative; overflow: hidden; }

/* One shared heading block for every section: centred overline,
   heading and short lead. Long body copy lives outside it and stays
   left-aligned. The gap below the heading grows with the section's
   own padding so the rhythm holds at every resolution. */
.section-head { text-align: center; margin-bottom: clamp(26px, 2.6vw, 52px); }
.section-head .prose { text-align: center; margin-left: auto; margin-right: auto; max-width: 68ch; }
.section-sub { font-size: clamp(14.5px, 0.16vw + 14px, 17px); color: var(--text-mid); line-height: 1.7; margin-top: 8px; text-align: center; }

/* Dark page heroes */

.heart-divider { display: flex; align-items: center; gap: 12px; margin: 14px 0 12px; }
.heart-divider-line { width: 56px; height: 1px; background: #E8C06050; }

/* ── 6. Header & navigation ───────────────────────────────────── */
/* The bar itself is full-bleed (the blur and the hairline run the
   whole width); its contents sit in the same shell as every page, so
   the logo lands exactly on the content edge — including past the
   point where the shell stops growing and starts centring. */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 200;
  background: #F5EFE6F8; backdrop-filter: blur(16px);
  border-bottom: 1px solid #D4A14130;
  padding: 0 var(--page-edge); height: 64px;
  display: flex; align-items: center;
}
.nav-inner {
  width: min(100%, var(--w-wide));
  margin-inline: auto;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-md);
}
.nav-brand { display: flex; align-items: center; cursor: pointer; margin-right: clamp(20px, 2.4vw, 56px); }
.nav-brand-row { display: inline-flex; align-items: center; gap: 8px; flex-wrap: nowrap; }
.nav-logo { height: 38px; width: auto; mix-blend-mode: multiply; display: block; flex-shrink: 0; }
.nav-wordmark { font-family: var(--font-serif); font-size: 13px; font-weight: 700; color: var(--deep-earth); letter-spacing: .12em; line-height: 1; white-space: nowrap; }
.nav-wordmark-accent { color: var(--honey-text); }
/* The link row breathes as the header widens rather than staying a
   fixed cluster pinned to the right edge. The uppercase, widely
   spaced labels (14 Sep 2026) need ~50px more than the old ones, so
   below 1680px the gap closes faster, down to 10px at 1200px where
   the burger takes over; wider than that it is 1.5vw as before. */
.nav-links { display: flex; align-items: center; gap: clamp(10px, min(4vw - 42px, 1.5vw), 34px); }

/* Nav text links */
.nl { color: var(--text-mid); text-decoration: none; font-family: var(--font-nav); font-size: 11.5px; font-weight: 500; font-style: normal; text-transform: uppercase; letter-spacing: .22em; line-height: 1.75; white-space: nowrap; transition: color .2s; cursor: pointer; background: none; border: none; padding: 0; }
.nl:hover, .nl.on { color: var(--honey); }
.nl.on { border-bottom: 1.5px solid var(--honey); padding-bottom: 2px; }

/* "Share an Event" pill in the nav */
.nav-cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 20px; border-radius: 50px;
  background: var(--grad-honey);
  border: none; cursor: pointer;
  box-shadow: 0 3px 14px #D4A14140;
  transition: all .3s;
  font-family: var(--font-sans);
  font-size: 13px; font-weight: 500; letter-spacing: .04em; color: var(--on-accent);
}
.nav-cta:hover { transform: translateY(-1px); box-shadow: 0 6px 20px #D4A14155; }

/* Mobile hamburger */
.nav-burger { background: none; border: none; cursor: pointer; padding: 8px; display: flex; flex-direction: row; align-items: center; gap: 10px; min-height: 44px; box-sizing: border-box; }
/* "Menu" beside the bars: the label style of timacamara.com's menu
   and language switcher (F124) — a step heavier and a little tighter
   than the links it opens onto. */
.nav-burger-label {
  font-family: var(--font-nav); font-size: 11px; font-weight: 600; font-style: normal;
  text-transform: uppercase; letter-spacing: .16em; line-height: 1;
  color: var(--deep-earth);
}
.nav-burger-bars { display: flex; flex-direction: column; gap: 5px; }
.nav-burger-bar { display: block; width: 24px; height: 2px; background: var(--deep-earth); border-radius: 2px; transition: all .3s; }
.nav-burger.is-open .nav-burger-bar:nth-child(1) { transform: rotate(45deg) translateY(5px); }
.nav-burger.is-open .nav-burger-bar:nth-child(2) { opacity: 0; }
.nav-burger.is-open .nav-burger-bar:nth-child(3) { transform: rotate(-45deg) translateY(-5px); }

/* Data status banner */
.data-banner {
  position: fixed; top: 64px; left: 0; right: 0; z-index: 250;
  background: var(--error); color: var(--on-dark);
  padding: 10px 20px; text-align: center;
  font-family: var(--font-sans); font-size: 13px; line-height: 1.5;
}

/* Mobile menu overlay. justify-content: center is safe only while the
   list is shorter than the screen — on a phone held sideways, or a
   short window, it would centre a list taller than the overlay and
   cut off both ends unreachably. safe centring plus a scroll keeps
   every item available at any height, and the type steps down when
   there is genuinely no room. */
/* Mobile menu: a drawer from the right, under the header, over a
   dimmed page. It stays in the DOM and slides both ways on the
   .is-open class (a transform, so the page is never re-laid-out),
   and the visibility switch is delayed on the way out so the drawer
   finishes leaving before it stops being rendered. No new colours:
   the scrim is the site's brown at low alpha, the panel the footer's
   and verse section's earth gradient (the founder chose the dark one
   over the cream, 2 Sep 2026), the text cream, and the current page
   the same gold the honey gradient already carries. */
.mobile-menu-scrim {
  position: fixed; top: 64px; left: 0; right: 0; bottom: 0; z-index: 185;
  background: #5B3E1F66;
  opacity: 0; visibility: hidden;
  transition: opacity .3s ease, visibility 0s linear .3s;
}
.mobile-menu-scrim.is-open { opacity: 1; visibility: visible; transition: opacity .5s ease, visibility 0s; }
.mobile-menu {
  position: fixed; top: 64px; right: 0; bottom: 0; z-index: 190;
  width: min(86vw, 360px);
  background: var(--grad-earth); color: var(--cream);
  border-left: 1px solid #D4A14140;
  box-shadow: -18px 0 48px #23120455;
  display: flex; flex-direction: column; align-items: stretch;
  padding: 14px 0 max(20px, env(safe-area-inset-bottom));
  overflow-y: auto; overscroll-behavior: contain;
  transform: translateX(100%); visibility: hidden;
  /* Two paces (2 Sep 2026, the founder found the first "too quick"):
     it arrives in half a second on a long, soft ease-out, and leaves
     in .3s — an opening is something to watch, a closing is something
     to be done with. The transition a state change uses is the one
     declared on the state it is going TO, so the opening pace sits on
     .is-open and the closing pace here. */
  transition: transform .3s cubic-bezier(.4, 0, .6, 1), visibility 0s linear .3s;
}
.mobile-menu.is-open { transform: none; visibility: visible; transition: transform .5s cubic-bezier(.22, .8, .26, 1), visibility 0s; }
/* The honeycomb behind the top of the drawer: the same HexBg the hero
   uses, at 7%, masked away between a third and two thirds of the way
   down so the CTA and the account foot sit on plain earth. The rows
   are lifted above it. */
.mobile-menu > .hex-bg {
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 30%, transparent 62%);
  mask-image: linear-gradient(180deg, #000 0%, #000 30%, transparent 62%);
}
.mobile-menu > :not(.hex-bg) { position: relative; z-index: 1; }
/* Each row settles in a beat after the one above it, using the
   fadeUp the rest of the site already has; --i is set on the row. */
.mobile-menu.is-open > :not(.hex-bg) {
  animation: fadeUp .6s cubic-bezier(.2, .7, .2, 1) both;
  animation-delay: calc(100ms + var(--i, 0) * 50ms);
}
.mobile-menu-link {
  display: flex; align-items: center; width: 100%; min-height: 52px; box-sizing: border-box;
  background: none; border: none; border-left: 3px solid transparent; cursor: pointer;
  text-align: left; color: var(--cream); padding: 12px 24px 12px 25px;
  /* The desktop row's type on the phone too (founder, 14 Sep 2026 —
     F124): small, uppercase, widely spaced. The row keeps its 52px
     height, so the tap target does not shrink with the letters. */
  font-family: var(--font-nav); font-size: 11.5px; font-weight: 500; font-style: normal;
  text-transform: uppercase; letter-spacing: .22em; line-height: 1.75;
  transition: background .15s ease, color .15s ease;
}
.mobile-menu-link:active { background: #FBF6EE1A; }
.mobile-menu-link.on { color: var(--gold); border-left-color: var(--gold); background: #FBF6EE12; }
/* Account group at the foot of the drawer: avatar + name, then the
   account actions — one place, like any profile menu */
.mobile-menu-account {
  margin-top: auto; padding-top: 12px; border-top: 1px solid #FBF6EE22;
  display: flex; flex-direction: column; align-items: stretch; gap: 0;
}
.mobile-menu-account-head {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-sans); font-size: 13px; letter-spacing: .04em;
  color: #F5EFE699; padding: 8px 24px 6px 28px;
}
.mobile-menu-link--account { min-height: 48px; padding: 10px 24px 10px 25px; color: #F5EFE6CC; }
.mobile-menu-link--signout {
  color: #F5EFE699; min-height: 48px; padding: 10px 24px 10px 25px;
}
.mobile-menu-cta {
  margin: 18px 24px 10px;
  background: var(--grad-honey);
  color: var(--on-accent); border: none; cursor: pointer;
  font-family: var(--font-sans);
  font-size: 15px; font-weight: 600; letter-spacing: .04em;
  min-height: 48px; padding: 13px 24px; border-radius: 50px;
  box-shadow: 0 4px 18px #D4A14145;
  display: flex; align-items: center; justify-content: center; gap: 10px;
}
@media (prefers-reduced-motion: reduce) {
  .mobile-menu, .mobile-menu-scrim { transition: none; }
  .mobile-menu.is-open > :not(.hex-bg) { animation: none; }
}

/* Brand lockup (logo + BeeBhakti title on dark sections) */
.brand { display: inline-block; }
.brand-row { display: inline-flex; align-items: center; flex-wrap: nowrap; }
.brand-logo { width: auto; mix-blend-mode: screen; opacity: 0.9; display: block; }
.brand-title { font-family: var(--font-serif); font-weight: 700; letter-spacing: .1em; line-height: 1; }
.brand-title-accent { color: var(--saffron); }

/* First-visit verse overlay */

/* ── Home hero ────────────────────────────────────────────────── */
.hero {
  min-height: 100svh;
  background: linear-gradient(180deg, var(--page-cream) 0%, var(--page-soft) 45%, var(--warm-white) 100%);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  position: relative; overflow: hidden;
  /* The arrival breathes in proportion to the screen it lands on */
  padding-top: clamp(76px, 7vh, 120px); padding-bottom: clamp(44px, 5vh, 90px);
}
.hero-stack {
  position: relative; z-index: 2;
  display: flex; flex-direction: column;
  align-items: center; text-align: center;
  padding: 0 var(--page-edge); width: 100%;
  /* Grows past its old 960px cap on large screens so the headline,
     stats and journey cards spread instead of sitting in a column
     with half the display empty on either side */
  max-width: calc(min(100%, max(960px, 68vw)) + var(--page-edge) * 2);
  opacity: 0; transform: translateY(22px);
  transition: all 1.2s cubic-bezier(.16, 1, .3, 1);
}
.hero-stack.is-in { opacity: 1; transform: translateY(0); }
/* Headline sits on a single line from 1000px up (it wraps below that —
   see the phone block at the end of this file). The size is solved
   backwards from the line: the limit is the column the headline sits
   in, not the viewport, so the column is spelled out here exactly as
   .hero-stack computes it and the font size is simply that width
   divided by the string's own width in ems. Montserrat sets "Find
   Bhakti gatherings around the world" at 20.2× the font size; 21
   leaves room for the rounding, the scrollbar 100vw does not know
   about, and a fallback face a little wider than Montserrat.
   Rises to a 62px ceiling as the column grows. */
.hero-title {
  font-family: var(--font-serif); font-weight: 400; color: var(--deep-earth);
  line-height: 1.12; letter-spacing: -.01em; margin-bottom: 10px;
  font-size: min(62px, calc(min(100vw - 2 * clamp(20px, 4vw, 72px), max(960px, 68vw)) / 21));
  max-width: 100%; white-space: nowrap;
}
.hero-title-accent {
  background: linear-gradient(135deg, var(--saffron), var(--gold), var(--honey));
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
  background-size: 200% 100%; animation: shimmer 4.5s linear infinite;
}
.hero-subline { font-family: var(--font-serif); font-size: clamp(16px, 1.4vw, 24px); color: var(--text-light); line-height: 1.6; margin: 0 0 clamp(16px, 1.8vw, 30px); }
.hero-alt-link { background: none; border: none; cursor: pointer; font-family: var(--font-sans); font-size: 13px; color: var(--text-mid); border-bottom: 1px solid #D4A14150; padding-bottom: 2px; margin-bottom: 6px; transition: color .2s; }
.hero-alt-link:hover { color: var(--honey); }
.hero-proof { font-size: clamp(13px, 0.35vw + 12.3px, 16.5px); color: var(--text-light); line-height: 1.75; max-width: min(100%, clamp(600px, 44vw, 780px)); margin: clamp(14px, 1.6vw, 26px) auto 0; font-family: var(--font-sans); }
/* Social proof under the stats (F32): one centred line, quieter and
   smaller than the counters above it — existing tokens only, no box.
   The padding keeps its wrap clean at 360px.

   Honey, not grey (founder, 25 Aug 2026): between the counters and
   the welcome sentence the line read as one more strip of body text.
   It now wears the digits' own colour family — --honey-text, the
   dark honey minted for text this small, because the counters' raw
   --honey fails contrast below headline sizes — and the 600 weight
   the other small honey lines carry. */
.hero-social-proof {
  margin: clamp(12px, 1.4vw, 20px) auto 0; padding: 0 12px;
  text-align: center; font-family: var(--font-sans);
  font-size: clamp(12px, 0.3vw + 11.3px, 14px);
  color: var(--honey-text, var(--honey)); font-weight: 600;
  letter-spacing: .03em; line-height: 1.5;
}
/* On a phone the hero stacks tight and the line sat crunched between
   the stats and the welcome (founder, same day): more air above and
   a little below, so it reads as its own quiet beat. */
@media (max-width: 768px) {
  .hero-social-proof { margin: 22px auto 6px; }
}

/* Hero search bar */

/* Hero globe. Sized by whichever axis is scarcer: it grows on a wide
   display, and shrinks on a short one (a laptop in a 1440×720 window)
   rather than pushing the stats and journey cards below the fold. */
.hero-globe { position: relative; width: clamp(190px, min(24vw, 30vh), 340px); margin: clamp(4px, 1vh, 14px) 0 2px; display: flex; align-items: center; justify-content: center; }
.hero-glow {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 140%; height: 140%; border-radius: 50%;
  pointer-events: none; z-index: 0;
  background: radial-gradient(circle, #E8C06014 0%, transparent 62%);
  animation: softGlow 6s ease-in-out infinite;
}
.hero-globe-img { position: relative; z-index: 1; width: 100%; height: auto; mix-blend-mode: multiply; user-select: none; pointer-events: none; display: block; }
.globe-bloom {
  position: absolute;
  width: 10px; height: 10px; border-radius: 50%;
  background: radial-gradient(circle, var(--rose) 20%, #D4A14170 60%, transparent 100%);
  box-shadow: 0 0 12px 4px #F7C8C060;
  animation: lotusBloom 8.4s ease-in-out infinite;
  pointer-events: none; z-index: 2;
}

/* Hero stats */
.hero-stats { display: flex; gap: clamp(28px, 4.5vw, 90px); justify-content: center; flex-wrap: wrap; margin-top: clamp(4px, 1vh, 14px); }
.stat { text-align: center; }
.stat-num { font-family: var(--font-mono); font-size: clamp(24px, 1.9vw, 38px); font-weight: 500; color: var(--honey-text); line-height: 1; letter-spacing: -.02em; }
.stat-label { font-size: clamp(11px, 0.08vw + 10.6px, 12.5px); color: var(--text-light); letter-spacing: .14em; margin-top: 5px; white-space: nowrap; font-family: var(--font-sans); }


/* ── 7. Buttons ───────────────────────────────────────────────── */
.bg { display: inline-flex; align-items: center; justify-content: center; border-radius: 50px; font-family: var(--font-sans); font-size: 13px; font-weight: 600; letter-spacing: .04em; cursor: pointer; transition: all .3s; border: none; text-decoration: none; }
.bg-g { background: var(--grad-honey); color: var(--on-accent); padding: 12px 28px; box-shadow: 0 4px 18px #D4A14145; }
.bg-g:hover { transform: translateY(-2px); box-shadow: 0 8px 28px #D4A14160; }
/* The press. Hover lifts a button, but a thumb never hovers: on a
   phone the only feedback was the page changing. A touch now settles
   the button a hair while it is held, the same on every .bg, so the
   tap is acknowledged before the answer arrives. (7 Sep 2026) */
.bg:active { transform: translateY(0) scale(.98); transition-duration: .08s; }
.bg-o { background: transparent; color: var(--honey); border: 1.5px solid var(--honey); padding: 11px 26px; }
.bg-o:hover { background: var(--honey); color: var(--on-accent-strong); }
.bg-gh { background: transparent; color: var(--cream); border: 1.5px solid #F5EFE640; padding: 11px 26px; }
.bg-gh:hover { border-color: #F5EFE680; background: #F5EFE610; }
/* Ghost button for LIGHT backgrounds — the cream .bg-gh above is
   invisible on petal/cream sections */
.bg-gh--light { color: var(--text-mid); border-color: #8B623040; }
.bg-gh--light:hover { color: var(--deep-earth); border-color: #8B623080; background: #8B623008; }
.bg--sm { padding: 7px 18px; font-size: 14px; }
.bg--block { padding: 12px 18px; text-decoration: none; }

/* Filter pill button */

.btn-row { display: flex; gap: 12px; flex-wrap: wrap; }
/* The count inside "Show more gatherings" — quieter than the label it
   follows, since it is the detail and not the action. */
.btn-count {
  margin-left: 10px; padding-left: 10px;
  border-left: 1px solid currentColor;
  opacity: .7; font-weight: 400; font-variant-numeric: tabular-nums;
}

/* ── 8. Cards & sections ──────────────────────────────────────── */
/* Coloured tag chip — accent colour arrives as --c */
.tag {
  display: inline-block; padding: 3px 11px; border-radius: 20px;
  background: color-mix(in srgb, var(--c, var(--honey)) 9.4%, transparent);
  /* Text falls back to --honey-text, not --honey: at 11px raw honey
     on cream reads at 2:1 ("1 upcoming" on the facilitator cards).
     The tint and border above keep the founder's colour; only the
     LETTERS darken, and only for a tag that carries a type — --ink
     is unset otherwise, so the share is 100% and nothing moves.
     (7 Sep 2026, F69) */
  color: color-mix(in srgb, var(--c, var(--honey-text)) var(--ink, 100%), var(--text-dark));
  font-size: 11px;
  font-family: var(--font-sans); font-weight: 600;
  letter-spacing: .05em;
  border: 1px solid color-mix(in srgb, var(--c, var(--honey)) 20.8%, transparent);
}


/* Event card (featured grid). Each card is its own container: what
   happens inside it is decided by how wide THE CARD ended up, not by
   how wide the window is — the same card sits in a 3-across homepage
   row, a 5-across events grid and a single mobile column, and it
   should read correctly in all three. */
.ec { container-type: inline-size; background: var(--surface); border: 1px solid #E8C06022; border-radius: 16px; padding: clamp(20px, 1.6vw, 32px); cursor: pointer; transition: all .3s; position: relative; overflow: hidden; font-family: var(--font-sans); display: flex; flex-direction: column; text-align: left; }
.ec .card-foot { margin-top: auto; }
.ec:hover { transform: translateY(-4px); box-shadow: 0 12px 40px #D4A14118; border-color: #D4A14155; }

/* Shared card internals (featured + map event cards) */
.card-accent { position: absolute; top: 0; left: 0; right: 0; height: 3px; border-radius: 16px 16px 0 0; background: linear-gradient(90deg, var(--c, var(--honey)), transparent); }
.card-top { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 14px; }
/* min-width: 0 lets the tag cluster give way first when the top row
   is tight — it wraps onto another line, which is what it is built
   to do — instead of squeezing the place beside it (F75). */
.card-tags { display: flex; gap: 7px; align-items: center; flex-wrap: wrap; min-width: 0; }
/* The place sits at the right of the card's top row, opposite the
   type tags. Since it names the CITY (F75) it can be long — one
   gathering's city field holds three of them — and the row is a
   nowrap flex, so before this a long one ran 135px past the edge of
   its own card. The words now truncate; the flag never does, because
   it is the flag that carries the country. */
.card-loc {
  font-size: 12px; color: var(--text-light); font-style: normal;
  display: inline-flex; align-items: baseline; min-width: 0;
  /* It keeps its natural width up to seven tenths of the row. Every
     real city fits inside that; the one field holding three of them
     is truncated rather than allowed off the card. */
  max-width: 70%;
}
.card-place { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* The flag beside the place, and the globe where there is no place to
   name (F74, 8 Sep 2026). The founder asked for warmth and quick
   context "without making the cards feel busy", so it is a shade
   smaller than the words it follows, a little desaturated and a
   little transparent — present at a glance, quiet on a second look.
   line-height is pinned because an emoji is a tall glyph and would
   otherwise push the row it sits in. No font is named: the browser
   reaches for the system emoji face on its own, and naming one would
   be a typeface this palette has not got. */
.card-flag {
  /* .95em first, then a little bigger at the founder's ask (8 Sep
     2026). 1.15em is still under the size a badge would be, and the
     pinned line-height keeps a taller glyph from pushing its row. */
  margin-left: .35em; font-size: 1.15em; line-height: 1; flex: none;
  opacity: .85; filter: saturate(.85);
}
.card-title { font-family: var(--font-serif); font-size: 20px; font-weight: 600; color: var(--deep-earth); margin-bottom: 8px; line-height: 1.2; }
.card-desc { font-size: 14px; color: var(--text-mid); line-height: 1.55; margin-bottom: 16px; }
.card-foot { display: flex; justify-content: space-between; align-items: center; }
/* A row, so the date can hold the left and the suitability badge can
   be pushed to the right edge — the same edge the country sits on in
   .card-top above (that row is space-between, and both share the
   card's padding, so the two right edges line up exactly). The
   row-gap is what gives the badge air on a narrow card, where the
   date is too long to leave room and the badge takes its own line. */
.card-date {
  font-size: 13px; color: var(--honey); font-weight: 600;
  display: flex; flex-wrap: wrap; align-items: center; gap: 7px 10px;
}
.card-open { margin-top: auto; padding-top: 12px; font-size: 12px; color: var(--honey); font-weight: 600; }

.clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.clamp-resp { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

/* The event cards' own container queries live just after .map-card's
   rules further down, where they can win on source order. */

/* ── Card grids ───────────────────────────────────────────────
   Every grid tracks the viewport twice over: the gap grows with the
   shared rhythm, and the minimum column itself is fluid, so a grid
   adds a column when there is genuinely room for one instead of
   stretching three cards to twice their comfortable width. The
   min(100%, …) wrapper is what keeps a 320px phone from forcing a
   track wider than the screen. */
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, clamp(260px, 15vw, 300px)), 1fr)); gap: var(--gap-grid); }
.res-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, clamp(256px, 14.5vw, 300px)), 1fr)); gap: var(--gap-grid); }
.text-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, clamp(250px, 14vw, 290px)), 1fr)); gap: var(--gap-grid); }
.pod-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, clamp(288px, 16.5vw, 340px)), 1fr)); gap: var(--gap-grid); }
.philosophy-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); gap: var(--gap-lg); }
.listing-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); gap: var(--gap-md); }
/* auto-FILL, not auto-fit: empty tracks are kept, so three buttons in
   a wide panel stay button-sized instead of stretching to fill it */
/* Four small icon tiles: capped so they stay tiles rather than
   stretching to a quarter of a very wide page each */
.support-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, clamp(180px, 13vw, 240px)), 1fr)); gap: var(--gap-md); max-width: min(100%, 1120px); margin-inline: auto; }

/* Philosophy value cards */
.value-card { container-type: inline-size; background: var(--surface); border-radius: 20px; padding: clamp(26px, 2.5vw, 46px) clamp(22px, 2vw, 38px); border: 1px solid color-mix(in srgb, var(--c, var(--honey)) 12.5%, transparent); text-align: center; }
/* The three cards' tints are literals in app.jsx — the fly's dusk,
   the bee's honey, the bhakta's ember — so each one fails in one
   appearance or the other: dusk reads 6.6:1 by day and 2.2:1 at
   night. They take --ink-data like every other colour that comes
   from the data (F69, 8 Sep 2026). */
.value-title { font-family: var(--font-serif); font-size: 22px; font-weight: 600; color: color-mix(in srgb, var(--c, var(--honey)) var(--ink-data), var(--text-dark)); margin-bottom: 12px; }
.value-desc { font-size: 15px; color: var(--text-mid); line-height: 1.65; margin-bottom: 12px; }
.value-note { font-size: 13px; color: var(--text-light); font-style: normal; }
/* Scaled by the card's own width, so the three cards read the same
   whether they sit one-up on a phone or three-up on a large display */
.value-title { font-size: clamp(22px, 5.6cqi, 27px); }
.value-desc { font-size: clamp(15px, 4.1cqi, 17px); }
.value-note { font-size: clamp(13px, 3.6cqi, 14.5px); }

/* Rotating verse section */
.verse-text { font-family: var(--font-serif); font-size: clamp(18px, 1.7vw, 32px); font-weight: 300; font-style: normal; color: var(--cream); line-height: 1.75; margin-bottom: 18px; }
.verse-ref { font-size: 13px; color: var(--saffron); letter-spacing: .14em; margin-bottom: 6px; }
.verse-note { font-size: 13px; color: #F5EFE672; font-style: normal; }
.verse-dots { display: flex; gap: 8px; justify-content: center; margin-top: 28px; }
.verse-dot { width: 8px; height: 8px; border-radius: 4px; background: #D4A14135; border: none; cursor: pointer; transition: all .3s; }
/* background-COLOR, not the `background` shorthand. The shorthand
   resets every background-* longhand it does not mention, and one of
   those is background-clip — which the phone block sets to
   content-box so the 8px dot keeps its size while 18px of padding
   around it takes the tap (rule 8).

   So on a phone the ACTIVE dot, and only the active dot, painted its
   honey across the whole 44x44 padding box: a gold square the size of
   a button under the verse, with four small marks beside it. Reported
   by the founder on 8 Sep 2026 from their own phone. Desktop was
   fine, because without that padding the border box and the content
   box are the same 8 by 8. */
.verse-dot.on { width: 26px; background-color: var(--honey); }

/* ── Our Roots ────────────────────────────────────────────────
   The homepage's one quiet breath about where this bhakti comes
   from: a heading, two sentences and a single door. Deliberately
   lighter than the sections either side of it — no cards, no grid,
   no artwork of its own — so the roots become visible without
   becoming the loudest thing on the page. Beeswax cream, the same
   warm ground the newsletter and philosophy bands already use.

   The portrait is optional (PRABHUPADA_PORTRAIT in app.jsx). With
   no photograph the copy simply centres itself and the section is
   complete; with one, the two sit side by side and the copy aligns
   left beside it. Nothing here needs changing when a portrait
   arrives, and nothing reserves space for one that never does. */
/* A grid rather than a wrapping flex row: flex would have decided
   for itself, at a width that moves with the copy, when the portrait
   drops above the text — and it dropped it centred over a paragraph
   that was still aligned left. The switch is made here instead, once,
   at a width the whole layout agrees on. */
.roots-card {
  position: relative; z-index: 1;
  display: grid; gap: clamp(20px, 2.6vw, 48px);
  justify-items: center; text-align: center;
}
@media (min-width: 760px) {
  .roots-card:has(> .roots-portrait) {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center; justify-items: start; text-align: left;
  }
}
.roots-portrait {
  width: clamp(132px, 13vw, 200px); aspect-ratio: 1; height: auto;
  border-radius: 50%; object-fit: cover;
  border: 3px solid #E8C06055; box-shadow: 0 10px 34px #5B3E1F14;
}
/* A readable measure whichever way it lands: never wider than the
   prose it holds, never so narrow that two sentences become six
   lines on a large display. */
.roots-text { max-width: 62ch; text-align: inherit; }
.roots-prose { margin-bottom: clamp(20px, 2vw, 32px); text-align: inherit; }
.roots-cta { text-decoration: none; }

/* Seva / support section */
.seva { padding: 80px var(--page-pad-x); background: linear-gradient(160deg, var(--page-soft), var(--page)); position: relative; overflow: hidden; }
/* Warm dusk band: darker than the light sections around it, but
   clearly lighter than the footer — the footer stays the single
   darkest element on every page, so nothing else reads as "the end" */
.seva--dark { background: linear-gradient(160deg, var(--dusk), var(--deep-earth)); }
.seva-inner { max-width: min(100%, clamp(840px, 58vw, 1040px)); margin: 0 auto; position: relative; z-index: 1; text-align: center; }
.seva-title { font-family: var(--font-serif); font-size: clamp(26px, 2.9vw, 50px); font-weight: 300; color: var(--deep-earth); line-height: 1.2; margin-bottom: clamp(14px, 1.4vw, 26px); font-style: normal; }
.seva--dark .seva-title { color: var(--cream); }
.seva-lead { font-size: clamp(16.5px, 0.16vw + 16px, 19px); color: var(--text-mid); line-height: 1.8; margin: 0 auto 12px; max-width: 68ch; }
.seva--dark .seva-lead { color: #F5EFE665; }
.seva-sub { font-size: clamp(15px, 0.14vw + 14.5px, 17.5px); color: var(--text-light); line-height: 1.75; margin: 0 auto clamp(30px, 3.4vw, 60px); font-style: normal; max-width: 70ch; }
.seva--dark .seva-sub { color: #F5EFE645; }
.seva-note { font-size: 13px; color: var(--text-light); margin-top: 20px; font-style: normal; }
/* "write to us first" (F115): the one link in the band, in the site's
   link colour, so somebody who is not listed can reach the address and
   the list of what to send without hunting for it. */
.seva-write {
  color: var(--honey-text, var(--honey)); font-weight: 600;
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
}
.seva--dark .seva-note { color: #F5EFE635; }

/* Donation tiers */
.tier-row { display: flex; gap: var(--gap-md); justify-content: center; flex-wrap: wrap; margin-bottom: clamp(28px, 3vw, 52px); }
.tier { flex: 1 1 170px; max-width: clamp(200px, 15vw, 280px); background: var(--surface); border: 1.5px solid #E8C06035; border-radius: 16px; padding: clamp(20px, 1.8vw, 32px) clamp(14px, 1.3vw, 24px); cursor: pointer; transition: all .3s; text-align: center; }
.seva--dark .tier { background: #D4A14112; border-color: #D4A14125; }
.tier:not(.tier--highlight):hover { transform: translateY(-3px); }
.tier--highlight { background: var(--grad-honey); border: none; box-shadow: 0 8px 28px #D4A14145; }
.seva--dark .tier--highlight { background: var(--grad-honey); }
.tier-amount { font-family: var(--font-mono); font-size: 34px; font-weight: 500; color: var(--honey); line-height: 1; margin-bottom: 8px; letter-spacing: -.02em; }
.tier--highlight .tier-amount { color: var(--on-dark); }
.tier-label { font-size: 14px; font-weight: 600; color: var(--deep-earth); margin-bottom: 4px; font-family: var(--font-sans); }
.seva--dark .tier-label { color: var(--cream); }
.tier--highlight .tier-label { color: var(--on-dark); }
.tier-sub { font-size: 12px; color: var(--text-light); }
.seva--dark .tier-sub { color: #F5EFE645; }
.tier--highlight .tier-sub { color: color-mix(in srgb, var(--surface) 70.00%, transparent); }

/* Seva CTA + thank-you state */
.seva-cta {
  background: var(--grad-honey);
  color: var(--on-accent); border: none; padding: 14px 36px;
  border-radius: 50px; font-family: var(--font-sans);
  font-size: 15px; font-weight: 600; letter-spacing: .03em;
  cursor: pointer; transition: all .3s;
  box-shadow: 0 6px 24px #D4A14145;
}
.seva-cta:hover { transform: translateY(-2px); box-shadow: 0 10px 32px #D4A14160; }
.seva-thanks {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 32px; border-radius: 50px;
  background: var(--page-soft);
  border: 1.5px solid #D4A14150;
  font-family: var(--font-sans);
  font-size: 15px; color: var(--honey); font-style: normal;
}
.seva--dark .seva-thanks { background: #D4A14120; }

/* Listing tiers */
/* ── The listing section's layout system ──────────────────────
   Two edges, and only two. Card rows span the container; every
   piece of running text — the intro, the add-on intro, the
   end-of-period notice and the closing line — shares one centred
   measure. Before this the section had five different left edges
   (the container at 151, prose at 563, the add-on grid and the
   notice at 458) with alignment flipping between centred and left
   from block to block. */
.listing {
  --listing-measure: min(100%, clamp(560px, 48vw, 800px));
  --listing-step: clamp(34px, 3.2vw, 64px);
  padding: var(--section-pad-y) var(--page-pad-x);
  background: var(--page-soft); position: relative; overflow: hidden;
}
.listing .section-head .prose, .listing .listing-note {
  max-width: var(--listing-measure);
  margin-inline: auto; text-align: center;
}
/* Desktop has far more room than the measure was using: the intro
   was wrapping to four short lines inside an 1100 container. The
   measure widens from 1000px up, so the whole section (intro, the
   end-of-listing notice, the closing note) keeps reading down one
   spine — only wider. Below 1000 nothing changes. */
@media (min-width: 1000px) {
  .listing { --listing-measure: min(100%, clamp(680px, 66vw, 980px)); }
  /* The closing seva note is one sentence and is meant to read as one
     line, so it takes the whole container rather than the section
     measure — the only place the spine widens, and only on desktop. */
  .listing .listing-note { max-width: 100%; }
}
/* Both heading blocks clear their cards by the same amount, so the
   pricing row and the add-on row sit on one rhythm */
.listing .section-head { margin-bottom: clamp(24px, 2.2vw, 42px); }

/* ── Every listing includes ───────────────────────────────────
   The shared features, once, between the intro and the grid: a
   quiet label over one horizontal row. It wraps to a column on a
   phone rather than being squeezed. */
.listing-includes {
  margin: 0 auto clamp(22px, 2.2vw, 40px);
  padding-top: clamp(4px, 0.6vw, 12px);
  text-align: center;
}
.listing-includes-label {
  display: block;
  font-family: var(--font-sans); font-size: 12px; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--honey-text, var(--honey));
  margin-bottom: clamp(10px, 1vw, 16px);
}
.listing-includes-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(10px, 1.4vw, 34px);
}
.listing-includes-item {
  display: inline-flex; align-items: baseline; gap: 8px;
  font-family: var(--font-sans);
  font-size: clamp(13.5px, 0.12vw + 13px, 15px);
  line-height: 1.5; color: var(--text-mid);
}

.plan {
  container-type: inline-size;
  /* One token for the padding and the badge, so the badge sits on
     the same line as the content it labels. Tighter than it was:
     with the shared features lifted out, each card holds four short
     lines and does not need a deep frame around them. */
  --plan-pad-x: clamp(20px, 1.6vw, 30px);
  --plan-pad-y: clamp(22px, 1.8vw, 32px);
  background: var(--surface); border: 1.5px solid #E8C06030; border-radius: 20px;
  padding: var(--plan-pad-y) var(--plan-pad-x);
  position: relative; overflow: hidden; text-align: left;
}
/* Transparent border rather than none: the featured card keeps its
   dark ground and shadow, but its box metrics now match the other
   three exactly — with border:none its content sat 1.5px out of
   line with its neighbours and the card measured 3px wider. */
/* Distinct by ground and badge, not by weight: the shadow is lighter
   than it was so the featured card sits in the row rather than
   looming out of it. Same box metrics as the other three. */
.plan-tier { font-size: 12px; letter-spacing: .18em; color: var(--honey); margin-bottom: 10px; }
.plan-price { font-family: var(--font-mono); font-size: 40px; font-weight: 500; color: var(--deep-earth); line-height: 1; margin-bottom: 4px; letter-spacing: -.02em; }
.plan-price-note { font-size: 12px; white-space: nowrap; color: var(--text-light); margin-bottom: 6px; }
/* Last line in the card now that the features live above the grid,
   so no trailing margin — the card's own padding closes it */
.plan-for { font-size: 14px; color: var(--text-mid); font-style: normal; margin-bottom: 0; }
/* The two-line reserve that used to sit here existed to keep the
   four feature lists starting on one line. Those now live above the
   grid, and the description is the last thing in the card, so its
   top already aligns across all four and the grid equalises the
   heights — the reserve would only add a blank line to every card. */
.plan-star { color: var(--honey); font-size: 14px; line-height: 1.5; }
.listing-note { text-align: center; font-size: 14px; color: var(--text-light); margin-top: clamp(24px, 2.2vw, 44px); font-style: normal; line-height: 1.75; }

/* Resource cards (books, music, podcasts) — accent colour via --c.
   Its own container, so the body below adapts to the card rather
   than to the window (see the @container rules after .res-links). */
.res-card { container-type: inline-size; background: var(--surface); border: 1px solid #E8C06022; border-radius: 18px; overflow: hidden; transition: all .3s; display: flex; flex-direction: column; text-align: left; }
.res-card:hover { transform: translateY(-4px); box-shadow: 0 12px 40px #D4A14118; border-color: var(--hc, #D4A14155); }
.res-card-accent { height: 3px; background: linear-gradient(90deg, var(--c, var(--honey)), transparent); }
.res-card-body { padding: 22px 22px 20px; flex: 1; display: flex; flex-direction: column; }
.res-card-top { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 14px; gap: 8px; }
.res-year { font-size: 12px; color: var(--text-light); flex-shrink: 0; }
.res-title { font-family: var(--font-serif); font-size: 21px; font-weight: 600; color: var(--deep-earth); line-height: 1.2; margin-bottom: 8px; }
.res-title--tight { margin-bottom: 4px; }
.res-title--pod { margin: 14px 0 4px; }
.res-subtitle { font-size: 13px; color: var(--text-light); font-style: normal; margin-bottom: 8px; line-height: 1.4; }
.res-author { font-size: 14px; color: var(--c, var(--honey)); font-weight: 600; margin-bottom: 14px; letter-spacing: .02em; }
.res-host { font-size: 14px; color: var(--c, var(--honey)); font-weight: 600; margin-bottom: 14px; }
.res-desc { font-size: 14px; color: var(--text-mid); line-height: 1.65; margin-bottom: 16px; flex: 1; }
.res-desc--pod { margin-bottom: 20px; }
.res-forwho { background: var(--page-soft); border-radius: 10px; padding: 9px 12px; font-size: 13px; color: var(--text-light); font-style: normal; line-height: 1.5; margin-bottom: 18px; }
.pod-platforms { display: flex; gap: 8px; flex-wrap: wrap; }

/* Resource image — the same 16:9 frame on every resource card
   (books, albums, sacred texts, podcasts, films & videos), so the
   grids stay even whatever the artwork's own proportions are. */
.res-img-wrap { position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; flex-shrink: 0; background: var(--page-soft); padding: 10px; }
/* Portrait artwork (book covers, posters, square podcast art) gets a
   squarer frame, so a tall cover fills it instead of floating in a
   wide letterbox that read as broken. */
.res-img-wrap--tall { aspect-ratio: 5 / 4; }
/* The artwork is never cropped or zoomed: shown whole and centred
   inside the fixed 16:9 frame, on a uniform white ground */
.res-img { width: 100%; height: 100%; object-fit: contain; object-position: center; display: block; }
/* On sacred-text cards the frame sits inside the card padding */
.text-card .res-img-wrap { border-radius: 10px; margin-bottom: 16px; }

/* Outlined pill link that fills with its accent colour on hover */
.pill-link {
  display: block; text-align: center; padding: 11px 0;
  border-radius: 50px; border: 1.5px solid var(--c, var(--honey));
  color: var(--c, var(--honey)); text-decoration: none;
  font-family: var(--font-sans); font-size: 14px; font-weight: 500;
  letter-spacing: .03em; transition: all .25s;
}
.pill-link:hover { background: var(--c, var(--honey)); color: var(--on-accent); }
.pill-link--sm { display: inline-flex; align-items: center; gap: 5px; padding: 8px 16px; font-size: 13px; letter-spacing: normal; }
/* Album cards carry one pill per streaming service, side by side in the
   same style; they stack if the card gets too narrow for both. */

/* ── Inside a resource card ───────────────────────────────────
   Same idea as the event cards: padding and type are a percentage of
   the card's own width (cqi), clamped so they start where they are
   today and grow as the card does. A book card in a 4-across grid on
   a large display and the same card alone on a phone then look like
   deliberate versions of one another. */
.res-card-body {
  padding: clamp(22px, 6.4cqi, 32px) clamp(22px, 6.4cqi, 32px) clamp(20px, 5.8cqi, 28px);
}
.res-title { font-size: clamp(21px, 5.5cqi, 25px); }
.res-desc { font-size: clamp(14px, 3.9cqi, 16px); }

/* Resources page */
/* ── Rail layout (Resources + Events) ─────────────────────────
   Desktop: a sticky rail on the left — the page's own sections on
   Resources, every filter on Events — with a plain title and the
   content in the column beside it. The rail spans both rows so it
   starts level with the title. No coloured hero band: the title is
   a simple serif line over a hairline rule, so the real content
   begins near the top of the page.
   Narrow screens: title first, then the rail, then the content. */
.rail-layout {
  display: grid;
  /* The rail is a proportion of the page, not a fixed slab: it widens
     with the shell so the filters/index never wrap more than they
     need, and the content column keeps the majority of the growth. */
  --rail-w: clamp(224px, 15vw, 300px);
  --rail-bleed: clamp(16px, 1.4vw, 30px);
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  grid-template-areas: "rail head" "rail content";
  column-gap: clamp(28px, 2.4vw, 56px); row-gap: clamp(22px, 2vw, 38px);
  align-items: start;
  /* The gutter is taken out of the width instead of added as margin,
     so the shell centres once it reaches its cap — the rail still
     starts under the logo (the header uses the same shell), and an
     ultrawide display no longer leaves a void down the right side. */
  width: min(100% - var(--page-edge) * 2, var(--w-wide));
  margin-inline: auto;
  padding: clamp(28px, 2.6vw, 52px) 0 clamp(56px, 6vw, 110px);
  position: relative;
}

/* ── The beeswax panel behind the rail ────────────────────────
   A warm wax surface running down the page's left edge, made of
   the same honeycomb geometry as the site's HexBg so it reads as
   brand rather than ornament. Three near-invisible layers: a comb
   texture, a soft sheen where light would catch poured wax, and a
   warm tint. It bleeds past the page edge to the viewport, and the
   mask melts it away toward the bottom so it never ends on a hard
   line. Kept faint enough that the honey-tinted active pill still
   reads as the brightest thing in the column. */
/* z-index 0, never -1: a negative pseudo-element paints before the
   backgrounds of block descendants, so .page's opaque warm-white
   would cover the wax entirely. Instead the panel sits at 0 and the
   grid's own children are lifted above it below. */
/* The bleed is measured from the shell to the viewport rather than
   from a fixed gutter, so the wax still reaches the left edge of the
   screen after the shell starts centring on wide displays. */
.rail-layout::before {
  content: ""; position: absolute; z-index: 0;
  top: 0; bottom: 0;
  left: calc((100% - 100vw) / 2);
  width: calc((100vw - 100%) / 2 + var(--rail-w) + var(--rail-bleed));
  border-radius: 0 20px 20px 0;
  /* Everything here is translucent so the page reads through the
     wax: a light warm wash, a comb impression at a fraction of its
     old weight, and a white sheen down the middle where the labels
     sit, which lifts them clear of the texture. */
  background-color: #E8D5AE1F;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='34.64' viewBox='0 0 30 34.64'%3E%3Cg fill='none' stroke='%23A87C2E' stroke-width='0.85' opacity='0.055'%3E%3Cpolygon points='15,2 28,9.5 28,25 15,32 2,25 2,9.5'/%3E%3Cpolygon points='30,19 43,26.5 43,42 30,49.5 17,42 17,26.5'/%3E%3C/g%3E%3C/svg%3E"),
    linear-gradient(100deg, #EFE0C608 0%, color-mix(in srgb, var(--surface) 45.10%, transparent) 46%, #EBD9B80F 100%);
  background-size: 46px 53.1px, auto;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 100%);
}
/* The wax edge: a hairline that fades out with the panel itself */
.rail-layout::after {
  content: ""; position: absolute; z-index: 0;
  top: 0; left: calc(var(--rail-w) + var(--rail-bleed)); width: 1px; height: 62%;
  background: linear-gradient(180deg, #D4A14100, #D4A14126 18%, #D4A14100);
}
@media (prefers-reduced-transparency: reduce) {
  .rail-layout::before { background-image: none; }
}
/* Events carries five filter groups, so its rail is a little wider */
.rail-layout--wide { --rail-w: clamp(248px, 16vw, 300px); }
/* No page title (Resources): drop the header row so the content
   starts level with the rail instead of below an empty cell */
.rail-layout--flush { grid-template-areas: "rail content"; }
/* Event Facilitators gives the search its own row: on the desktop it
   sits exactly where it always has, over the results and beside the
   rail; stacked on a phone it can then come FIRST, above the A–Z row
   (see the narrow-screen block below). Searching by name is the
   primary action here — the letters are the fallback. */
.rail-layout--guides { grid-template-areas: "rail head" "rail search" "rail content"; }
.guide-search-area { grid-area: search; min-width: 0; position: relative; z-index: 1; }
/* The search box kept the bottom margin it needed as the first thing
   inside the results column. In its own grid row that margin ADDS to
   the layout's row-gap instead of being the gap (grid items do not
   collapse margins), which pushed the field to 56px clear of the list
   at 1280 and 82px at 1920 — far enough that it read as belonging to
   the paragraph above rather than to the results it filters. The row
   gap is the spacing now. */
.guide-search-area .search-wrap { margin-bottom: 0; }
/* The three grid children ride above the wax panel. The rail outranks
   the content column so the guide-search dropdown still opens over
   the map rather than behind it. */
.rail { grid-area: rail; align-self: start; position: sticky; top: 88px; z-index: 2; }
/* On a short window (a laptop at 1440×720, a browser sharing the
   screen with something else) a sticky rail taller than the viewport
   leaves its last rows permanently out of reach — so it scrolls
   within itself instead. Only here: at normal heights these rails fit,
   and letting them overflow keeps any dropdown free to open past the
   rail's bottom edge.
   The Gatherings rail is excluded because it runs its own scroll box
   at every height (see "The Filters bar"): its Filters bar has to stay
   put while the filters travel under it, which it cannot do if the
   whole rail is what scrolls. */
@media (min-width: 1000px) and (max-height: 780px) {
  .rail:not(.rail--filters) {
    max-height: calc(100svh - 104px);
    overflow-y: auto; overscroll-behavior: contain;
    scrollbar-width: thin; padding-bottom: 12px;
  }
}
.rail-layout > .page-head { position: relative; z-index: 1; }
/* The nav rail's rows carry their own padding so the hover/active
   pill has room. Pulling the rail out by exactly that inset puts the
   labels and icons back on the page's left edge — the same line as
   the logo in the header — while the pill still bleeds past it. */
.rail--nav {
  display: flex; flex-direction: column; gap: 2px;
  --rail-inset: 14px; margin-left: calc(var(--rail-inset) * -1);
}
.rail-label {
  font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--text-light); opacity: .8;
  padding: 0 var(--rail-inset, 14px) 10px;
}
/* These rails' own rows start flush, so their labels do too */
.filter-panel .rail-label, .rail--alpha .rail-label { padding-left: 0; }

/* ── A–Z index (Event Facilitators) ───────────────────────────
   A compact grid, not a 26-row column: every letter stays visible
   without scrolling. Deliberately quiet — 26 bordered white tiles
   read as the loudest thing in the column, competing with the
   search bar that is the page's primary action. The letters keep
   their footprint but drop their boxes: type on the wax, with only
   the chosen one wearing honey. */
.rail--alpha { display: flex; flex-direction: column; gap: 10px; }
.alpha-all {
  display: flex; align-items: center; gap: 6px;
  /* Pulled out by its own padding so the label sits on the page's
     left edge while the active pill bleeds past it */
  margin-left: -14px; width: calc(100% + 14px);
  padding: 9px 14px; border-radius: 10px;
  background: none; border: none; cursor: pointer; text-align: left;
  font-family: var(--font-sans); font-size: 14px; font-weight: 500;
  color: var(--text-mid); transition: background .2s ease, color .2s ease;
}
.alpha-all:hover { background: color-mix(in srgb, var(--surface) 47.84%, transparent); color: var(--deep-earth); }
.alpha-all.on { color: var(--honey-text, var(--honey)); font-weight: 600; }
/* The count reads as part of the label — "All (41)" — rather than a
   badge pinned to the far edge, which is what made this row look
   like a heavier control than it is. */
.alpha-count { font-size: 13px; font-weight: 500; color: var(--text-light); }
.alpha-all.on .alpha-count { color: var(--honey-text, var(--honey)); }
.alpha-grid {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 5px;
}
/* A touch screen wider than the phone breakpoint — an iPad in portrait
   is 1024px and gets this desktop grid — still has a thumb on it. The
   44px rule below 1000px does nothing for those, so give the cells a
   real height wherever the pointer is coarse. */
@media (pointer: coarse) {
  .alpha-btn { aspect-ratio: auto; min-height: 44px; }
}
.alpha-btn {
  aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center;
  background: none; border: 1px solid transparent; border-radius: 8px;
  font-family: var(--font-sans); font-size: 13px; font-weight: 500;
  color: var(--text-mid); cursor: pointer;
  transition: background .18s ease, color .18s ease;
}
.alpha-btn:hover:not(:disabled) { background: color-mix(in srgb, var(--surface) 76.86%, transparent); color: var(--deep-earth); }
.alpha-btn.on {
  background: var(--honey); color: var(--on-accent-strong); font-weight: 600;
  box-shadow: 0 1px 4px #5B3E1F1F;
}
/* A letter with nobody under it stays in place, greyed — the index
   keeps one stable shape instead of reshuffling as you search */
.alpha-btn:disabled {
  background: none; color: var(--text-light); opacity: .32; cursor: default;
}
/* Reset beside the result count */
.result-reset {
  background: none; border: none; cursor: pointer; padding: 0 0 0 10px;
  font-family: var(--font-sans); font-size: 13px; color: var(--honey-text, var(--honey));
  text-decoration: underline; text-underline-offset: 2px;
}
.rail-item {
  display: flex; align-items: center; gap: 12px; width: 100%;
  background: none; border: none; cursor: pointer; text-align: left;
  font-family: var(--font-sans); font-size: 14px; font-weight: 500;
  letter-spacing: .02em; color: var(--text-mid);
  padding: 11px 14px; border-radius: 10px;
  transition: background .2s ease, color .2s ease;
}
.rail-item:hover { background: color-mix(in srgb, var(--surface) 47.84%, transparent); color: var(--deep-earth); }
/* On the wax panel the selected row reads as a lit cell of fresh
   comb — white lifts off the tint far better than more honey would */
.rail-item.on {
  background: color-mix(in srgb, var(--surface) 94.90%, transparent); color: var(--honey-text, var(--honey)); font-weight: 600;
  box-shadow: 0 1px 5px #5B3E1F14;
}
.rail-ic { display: inline-flex; width: 18px; justify-content: center; opacity: .8; }
.rail-item.on .rail-ic { opacity: 1; }
.rail-content { grid-area: content; min-width: 0; position: relative; z-index: 1; }

/* ── Plain page title ─────────────────────────────────────────
   Every inner page opens with this instead of the full-width
   earth-gradient band it replaced: just a serif title and its
   subtitle. The band cost most of the first screen before a visitor
   reached anything they came for. Left-aligned beside a rail
   (Events, Resources); centred on the pages that have none, whose
   bodies are centred compositions. In the rail grid it needs no
   grid-area: the rail and the content claim their cells by name, so
   the title auto-places into the one that is left. */
.page-head-wrap { padding: clamp(28px, 2.6vw, 52px) 0 0; }
.page-head-title {
  font-family: var(--font-serif); font-weight: 400;
  font-size: clamp(27px, 2.6vw, 48px); line-height: 1.12;
  color: var(--deep-earth); text-align: left; margin: 0 0 clamp(6px, 0.6vw, 12px);
}
.page-head-sub {
  font-size: clamp(15px, 0.18vw + 14.4px, 18px); color: var(--text-light); line-height: 1.7;
  text-align: left; margin: 0; max-width: 72ch;
}
.page-head--center { text-align: center; }
.page-head--center .page-head-title { text-align: center; }
.page-head--center .page-head-sub { text-align: center; margin-left: auto; margin-right: auto; }
.page-head-sub--wide { max-width: none; }
/* A quiet qualifier under a page's introduction — smaller and
   dimmer than the subtitle, because it is a clarification rather
   than part of the welcome. */
.page-head-note {
  /* No measure cap. The note is one sentence meant to sit on ONE
     line on a desktop — it needs about 722px, and a 72ch cap held
     it to 667 and folded it in two at every width. Left to fit
     naturally rather than forced with white-space: nowrap, which
     would overflow the page on the frame before Montserrat loads
     and the wider fallback is still measuring it. Below roughly
     790px of column it wraps, which is tablet and phone. */
  margin: clamp(10px, 1vw, 16px) 0 0;
  /* Flat 13px, not a clamp up to 14: beside the rail the column is
     only about two thirds of the viewport, so at 14px the sentence
     needed 722px and still folded on a 1024-wide laptop. At 13px it
     needs 670 and clears every width where the rail is present. */
  font-size: 13px; line-height: 1.65;
  /* No opacity dimming: at this size it would drop the note to
     3.95:1, under AA. It is already secondary by size and position,
     which is enough. */
  color: var(--text-light); text-align: left;
  font-family: var(--font-sans);
}
.page-head--center .page-head-note { text-align: center; margin-inline: auto; }
.page-head-action { margin-top: clamp(16px, 1.6vw, 28px); }
/* An event's own name runs longer than a page title, so it starts a
   step smaller and the chips above it carry the colour */
.page-head-title--event { font-size: clamp(25px, 2.3vw, 42px); }

/* Inside a rail column the content reads as one left-aligned
   column, so the shared centred section headings align left too */
.rail-content .section-head { text-align: left; margin-bottom: clamp(22px, 2.4vw, 44px); }
.rail-content .section-head .overline, .rail-content .res-subheading { text-align: left; }
/* The shared rule caps this at 68ch and centres it for full-width
   sections; beside a rail the column is already the measure, so the
   paragraph spans its parent instead of stopping short of it. */
.rail-content .section-head .prose {
  text-align: left; margin-left: 0; margin-right: 0; max-width: none;
}

@media (max-width: 999.98px) {
  .rail-layout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "head" "rail" "content";
    row-gap: 20px; padding-top: 28px;
  }
  .rail-layout--flush { grid-template-areas: "rail" "content"; }
  /* Stacked, there is no left column for the wax to line — a band
     across the top would read as decoration, so it steps aside */
  .rail-layout::before, .rail-layout::after { display: none; }
  .rail { position: static; }
  .rail--nav {
    flex-direction: row; overflow-x: auto;
    gap: 8px; padding: 2px; margin-left: 0;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
  }
  .rail--nav::-webkit-scrollbar { display: none; }
  .rail--nav .rail-label { display: none; }
  .rail--nav .rail-item {
    flex: 0 0 auto; width: auto;
    background: var(--surface); border: 1px solid #E8C06035;
    border-radius: 50px; padding: 9px 16px;
  }
  .rail--nav .rail-item.on { border-color: var(--honey); }

  /* ── Resources on a phone (founder, 11 Sep 2026 — F110, F111) ──
     Every section in view. The strip ran ten pills off the side of
     the screen (two visible, the current one often hidden); F110 put
     them behind one button, which did not read as a menu. Now the
     chips wrap onto a few short lines, nothing to open and nothing
     hidden, and the one you are in is filled with honey. Icons and
     counts step aside here so the ten fit in about four short lines;
     the names are what you choose by. 44px tall (rule 8). Same
     tokens; no new colour. */
  .rail--nav.rail--wrap { flex-wrap: wrap; overflow: visible; gap: 6px; padding: 0; }
  .rail--wrap .rail-item {
    min-height: 44px; padding: 7px 12px; gap: 0;
    font-size: 13px; line-height: 1.2;
  }
  .rail--wrap .rail-ic, .rail--wrap .rail-count { display: none; }
  .rail--wrap .rail-item.on {
    background: color-mix(in srgb, var(--honey) 32%, var(--surface));
    border-color: var(--honey); color: var(--deep-earth); box-shadow: none;
  }
  /* Search first, then browse: on a phone the name search is what
     the page is for, and a grid of 26 letters above it buries the
     one control most people want. */
  .rail-layout--guides { grid-template-areas: "head" "search" "rail" "content"; }
  /* Stacked, the A–Z index is ONE compact row that scrolls sideways
     rather than a block three rows deep — the letters keep their
     place in a single line the thumb can sweep, and the facilitators
     themselves start within the first screen. */
  .rail--alpha { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px; }
  .rail--alpha .rail-label { width: 100%; padding-bottom: 0; }
  .alpha-all {
    width: auto; margin-left: 0; flex: 0 0 auto;
    border: 1px solid #E8C06035; background: var(--surface); border-radius: 50px;
    padding: 9px 16px;
  }
  .alpha-all.on { border-color: var(--honey); }
  /* Two shallow rows of thirteen — every letter on screen, none of
     them behind a gesture.
     This was one sideways-scrolling row for half a day, and it was a
     mistake: past about H the letters sat off-screen, and reaching
     them meant landing a horizontal swipe on a 44px strip that the
     page's vertical scroll (or Safari's back-swipe, at scrollLeft 0)
     takes just as readily. The founder could not get to the later
     letters at all. An index whose whole job is "jump to S" cannot
     put S behind a gesture that competes with two others, so the
     letters come back on screen — still one compact block, still
     light, just no longer scrolling. */
  .alpha-grid {
    flex: 1 1 100%;
    /* As many columns as fit at a thumb-sized width — about nine on a
       360px phone, so the block is three shallow rows. Thirteen
       across would fit in two, but at 22px a letter is narrower than
       the accessible minimum and its neighbours are 3px away. */
    grid-template-columns: repeat(auto-fill, minmax(30px, 1fr));
    gap: 3px;
  }
  .alpha-btn { aspect-ratio: auto; height: 44px; font-size: 13px; }
}
@media (max-width: 767.98px) {
  /* Keep the title compact on a phone so the content still starts
     within the first screen */
  .rail-layout { padding-top: 22px; row-gap: 16px; }
  .page-head-sub { font-size: 15px; line-height: 1.6; }
}
.res-subheading { font-family: var(--font-serif); font-size: clamp(20px, 2vw, 36px); font-weight: 400; color: var(--deep-earth); margin-bottom: 10px; text-align: center; }
.res-empty { color: var(--text-light); font-style: normal; text-align: center; }
.res-cta { margin-top: clamp(44px, 4.4vw, 84px); padding: clamp(32px, 3.2vw, 60px); text-align: center; background: linear-gradient(135deg, var(--deep-earth), var(--mid-bg)); border-radius: 20px; position: relative; overflow: hidden; }
.res-cta-quote { font-family: var(--font-serif); font-size: clamp(17px, 1.5vw, 26px); font-style: normal; color: var(--cream); line-height: 1.75; max-width: min(100%, clamp(560px, 42vw, 760px)); margin: 0 auto 16px; }
.res-cta-ref { font-size: 12px; color: var(--saffron); letter-spacing: .14em; margin-bottom: 28px; }

/* ── The Śrīla Prabhupāda page ────────────────────────────────
   /resources/srila-prabhupada/ — a Resources category whose content
   is a page about a person, so it opens with a real page title and
   then reads as plain sections rather than a grid of cards. It uses
   the rail column's full width (the intro paragraphs cap themselves
   at a readable measure) so a large display is not left with a thin
   ribbon of text beside an empty rail. */
.roots-page-intro {
  display: flex; align-items: flex-start; gap: clamp(20px, 2.6vw, 48px);
  flex-wrap: wrap; margin: clamp(22px, 2.2vw, 40px) 0 0;
}
.roots-page-intro > div { flex: 1 1 clamp(300px, 40vw, 640px); max-width: 72ch; }
.roots-page-intro .prose:last-child { margin-bottom: 0; }
/* Beside the running text the portrait steps down a size — the page
   is an introduction, not a memorial wall */
.roots-portrait--page { width: clamp(120px, 11vw, 176px); }
.roots-sec { margin-top: clamp(38px, 3.6vw, 68px); }
.roots-sec .prose { max-width: 72ch; }
/* The subheading is shared with the Sacred Texts tab, where it is a
   centred h3; here it opens a section of a page, so it aligns with
   the column like everything else in the rail (see the
   .rail-content rule that already does this for the whole column). */
.roots-sec .res-subheading { margin-bottom: clamp(10px, 1vw, 16px); }
/* A link standing alone is not a full-width pill; it keeps
   the height of every other pill on the site so it stays easy to tap */
.roots-sec > .pill-link {
  display: inline-flex; align-items: center; justify-content: center;
  width: auto; padding-inline: clamp(22px, 2vw, 34px);
}

/* Sacred text cards */
.text-card { container-type: inline-size; background: var(--page-soft); border-radius: 14px; padding: clamp(20px, 1.8vw, 34px) clamp(22px, 1.9vw, 36px); border: 1px solid #E8C06030; border-left: 3px solid var(--honey); display: flex; flex-direction: column; text-align: left; }
.text-card--sage { background: var(--surface); border-left-color: var(--sage); }
.text-title { font-family: var(--font-serif); font-size: 19px; font-weight: 600; color: var(--deep-earth); margin-bottom: 4px; }
.text-author { font-size: 13px; color: var(--honey); margin-bottom: 10px; font-weight: 600; font-family: var(--font-sans); }
.text-card--sage .text-author { color: var(--sage); }
.text-desc { font-size: 14px; color: var(--text-mid); line-height: 1.65; margin-bottom: 18px; flex: 1; font-family: var(--font-sans); }
.text-card .pill-link { --c: var(--honey); }
.text-card--sage .pill-link { --c: var(--sage); }
.text-title { font-size: clamp(19px, 5cqi, 23px); }
.text-desc { font-size: clamp(14px, 3.8cqi, 16px); }

/* ── Guide directory ──────────────────────────────────────────
   The list is a container, so the rows restyle themselves from the
   list's own width: the same directory is a compact stack on a phone
   and an open, generously spaced index on a large display, with the
   avatar, the row padding and the expanded bio's indent all moving
   together (--guide-av is the single number they share). */
.guide-list { container-type: inline-size; border: 1px solid #E8C06025; border-radius: 16px; overflow: hidden; --guide-av: 52px; --guide-pad: 24px; }
.guide-item { border-bottom: 1px solid #E8C06020; transition: background .2s; background: transparent; text-align: left; }
.guide-item.is-open { background: var(--hover); }
.guide-row { padding: 22px var(--guide-pad); cursor: pointer; display: flex; align-items: center; gap: clamp(14px, 1.4vw, 26px); }
.guide-item:not(.is-open) .guide-row:hover { background: color-mix(in srgb, var(--hover) 50.20%, transparent); }
/* --guide-av is set on .guide-list; the event page shows the same
   portrait outside that container, so both carry the 52px default
   the list starts from — without it the picture fell back to its
   natural size and pushed the card around as it loaded. */
.guide-photo {
  width: var(--guide-av, 52px); height: var(--guide-av, 52px);
  border-radius: 50%; flex-shrink: 0;
  /* Portraits are square and cropped to fill, never squashed */
  object-fit: cover; object-position: center;
  border: 2px solid #D4A14150;
  /* A neutral ground while the picture is still on its way, so
     the circle is never a bright empty hole */
  background: var(--photo-ph);
}
.guide-avatar {
  width: var(--guide-av, 52px); height: var(--guide-av, 52px); border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(135deg, #D4A14180, #E8C06060);
  align-items: center; justify-content: center;
  font-size: calc(var(--guide-av) * .38); color: var(--deep-earth); font-family: var(--font-sans); font-weight: 700;
  border: 2px solid #D4A14130;
}
.guide-id { flex: 1; min-width: 0; }
.guide-name { font-family: var(--font-serif); font-size: 19px; font-weight: 600; color: var(--deep-earth); margin-bottom: 2px; }
.guide-role { font-size: 13px; color: var(--honey); margin-bottom: 2px; }
.guide-country { font-size: 12px; color: var(--text-light); }
.guide-side { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
/* The badge's place, for a facilitator BeeBhakti has nothing listed
   for. It is a note, not a label: the same quiet weight and colour as
   the country line under the name, never a chip, so it reads as an
   absence rather than as a second thing to look at. It is also the one
   thing in the row that may wrap, so the side is allowed to give width
   back to the name instead of squeezing it. */
.guide-side:has(.guide-none) { flex-shrink: 1; min-width: 0; }
.guide-none {
  font-size: 12px; line-height: 1.35; color: var(--text-light);
  text-align: right; text-wrap: balance; opacity: .85;
  max-width: 15em; min-width: 0;
}
/* On a phone the row has no width to spare. Left at its desktop
   measure this note took 190px of a 360px row and squeezed the name
   column to nothing — the opposite of not competing with the name. So
   it narrows to about the width the "N upcoming" badge occupies and
   takes another line or two instead, which costs height nobody is
   short of and keeps the name whole. */
@media (max-width: 599.98px) {
  .guide-none { max-width: 8.5em; font-size: 11.5px; }
}
/* The newest "What's new" item, in the same place when nothing is
   upcoming (F95, 11 Sep 2026). Two short lines at the note's measure,
   right-aligned like it: the kind in the honey the profile's links
   use, the title beneath at most two lines, so a long one can never
   make the row taller than the portrait. Its own link, above the
   row's stretched profile link, with a 44px tap height. */
.guide-side:has(.guide-update) { flex-shrink: 1; min-width: 0; }
.guide-update {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; justify-content: center;
  min-height: 44px; min-width: 44px;
  /* The note's own measure: 12px × 15em, and 11.5px × 8.5em on a
     phone, so the name column keeps exactly the width it had. */
  font-size: 12px; max-width: 15em;
  text-align: right; color: inherit; text-decoration: none;
}
.guide-update-kind {
  font-size: 11px; font-weight: 700; letter-spacing: .04em; line-height: 1.3;
  color: var(--honey-text);
}
.guide-update-title {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font-size: 13px; font-weight: 600; line-height: 1.35; color: var(--text-mid);
  overflow-wrap: anywhere;
}
.guide-update:hover .guide-update-title { color: var(--honey-text); }
@media (max-width: 599.98px) {
  .guide-update { max-width: 8.5em; font-size: 11.5px; }
  .guide-update-title { font-size: 12px; }
}
.guide-chevron { font-size: 18px; color: var(--text-light); transition: transform .25s; transform: rotate(0deg); }
.guide-item.is-open .guide-chevron { transform: rotate(180deg); }
/* Everything the row is built from is a share of the LIST's width
   (cqi), so the directory opens up smoothly from a 335px phone
   column to a 1280px desktop column instead of snapping at two
   breakpoints. Declared on .guide-item rather than .guide-list: an
   element is never its own query container, so setting them on the
   list itself would silently do nothing. */
/* Guarded: a custom property holding an unknown unit is only caught
   when it is substituted, and it then falls back to the property's
   INITIAL value (width: auto), not to the default on .guide-list.
   The font sizes below need no guard — they fall back to the plain
   rules above them. */
@supports (container-type: inline-size) {
  .guide-item {
    --guide-av:  clamp(52px, 5.3cqi, 68px);
    --guide-pad: clamp(24px, 3cqi, 38px);
  }
}
.guide-row { padding-block: clamp(22px, 2.4cqi, 30px); }
.guide-name { font-size: clamp(19px, calc(15px + 0.65cqi), 23px); }
.guide-role { font-size: clamp(13px, calc(11.5px + 0.2cqi), 14px); }
.guide-country { font-size: clamp(12px, calc(11px + 0.16cqi), 13px); }
.chip-row { display: flex; gap: 8px; flex-wrap: wrap; }
.chip-row--links { gap: 10px; align-items: center; }
.chip-link { display: inline-flex; align-items: center; gap: 6px; padding: 7px 16px; border-radius: 50px; border: 1px solid #E8C06045; color: var(--text-mid); text-decoration: none; font-size: 14px; font-family: var(--font-sans); transition: all .2s; }
.chip-link:hover { border-color: var(--honey); color: var(--honey); }

.guides-invite { margin-top: clamp(44px, 4.4vw, 84px); padding: clamp(28px, 3vw, 56px); text-align: center; }
.invite-title { font-family: var(--font-serif); font-size: 22px; color: var(--deep-earth); font-style: normal; margin-bottom: 8px; }
.invite-sub { font-size: 15px; color: var(--text-light); margin-bottom: 24px; font-style: normal; }

/* Search field (guides page) */
.search-wrap { margin-bottom: clamp(22px, 2.4vw, 44px); position: relative; }
.search-icon { position: absolute; left: 16px; top: 50%; transform: translateY(-50%); opacity: .6; pointer-events: none; display: flex; align-items: center; }
.search-clear { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; font-size: 18px; color: var(--text-light); line-height: 1; }
.result-note { font-size: 14px; color: var(--text-light); font-style: normal; margin-bottom: 20px; }
.guide-empty { text-align: center; padding: 48px 20px; color: var(--text-light); font-family: var(--font-serif); font-size: 16px; }

/* Map / events page — every filter lives in the shared left rail
   (see "Rail layout"), map + results in the column beside it. The
   panel itself is plain: the rail is the container, so a card
   inside it would only add a second border. */
.filter-panel { text-align: left; display: none; flex-direction: column; gap: clamp(18px, 1.7vw, 30px); align-items: flex-start; }
.filter-panel.is-open { display: flex; }
.filter-group { display: flex; flex-direction: column; gap: 10px; width: 100%; }
.filter-pills { display: flex; flex-wrap: wrap; gap: 8px; }
/* The panel's own heading would repeat the word the bar above it
   already says, so the bar is the heading and this steps aside. It
   stays in the markup for screen readers reaching the panel directly. */
.filter-panel .rail-label { display: none; }

/* ── The Filters bar ──────────────────────────────────────────
   One control on every viewport, because it is one idea: fold the
   filters away, get the width (or the screen) back. The whole bar
   is the button — sliders on the left so it reads as filtering at a
   glance, the count of what is still narrowing the list in the
   middle, and a chevron on the right pointing the way it will move.
   Nothing it hides is cleared: the panel is only out of sight. */
.filter-toggle {
  display: flex; align-items: center; gap: 9px;
  width: 100%; min-height: 44px; padding: 10px 13px;
  border-radius: 12px; border: 1px solid #E8C06040;
  background: color-mix(in srgb, var(--surface) 65.88%, transparent);
  font-family: var(--font-sans); font-size: 13px; font-weight: 600;
  letter-spacing: .04em; color: var(--deep-earth); cursor: pointer;
  transition: border-color .2s, background .2s, box-shadow .2s;
}
.filter-toggle:hover { border-color: var(--honey); background: var(--surface); }
.filter-toggle .ic { display: block; }
.filter-toggle-ic { display: inline-flex; flex-shrink: 0; }
.filter-toggle-label { flex: 1 1 auto; text-align: left; }
.filter-toggle-chev {
  display: inline-flex; flex-shrink: 0; margin-left: auto;
  transition: transform .25s ease;
}

/* Desktop: the bar heads a sidebar it can fold to a narrow handle */
@media (min-width: 1000px) {
  /* The rail takes its own height so the bar stays put at the top and
     the filters scroll under it. Only when there are more filters
     than the window is tall does a scrollbar appear at all — the last
     group is never stranded below the fold on a short laptop. */
  .rail--filters {
    display: flex; flex-direction: column;
    max-height: calc(100svh - 104px);
  }
  .rail--filters .filter-panel {
    min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    width: 100%; padding: 15px 10px 4px 0; margin-top: 11px;
    /* The hairline belongs to the scroll box, so it holds its place
       while the filters travel under it — the bar stays a bar, and a
       group half in view reads as more to come rather than as a
       group that got cut. */
    border-top: 1px solid #E8C06033;
    scrollbar-width: thin; scrollbar-color: #D4A14159 transparent;
  }
  .rail--filters .filter-panel::-webkit-scrollbar { width: 8px; }
  .rail--filters .filter-panel::-webkit-scrollbar-track { background: transparent; }
  .rail--filters .filter-panel::-webkit-scrollbar-thumb {
    background: #D4A14140; border-radius: 50px;
  }
  .rail--filters .filter-panel:hover::-webkit-scrollbar-thumb { background: #D4A1416B; }
  /* Open, the chevron points back at the column it would fold into;
     shut, it points out at the width it would take back. */
  .filter-toggle-chev { transform: rotate(-90deg); }
  .filter-toggle.is-open .filter-toggle-chev { transform: rotate(90deg); }
  /* Folded: the column narrows to the handle, and the map and the
     results grow into everything it gives up. The bar stands up
     rather than shrinking to a mystery icon — the same word, turned
     on its side, so what the handle opens is never in doubt at 56px
     wide. Under it the count of what is still narrowing the list. */
  .rail-layout--wide.rail-layout--collapsed { --rail-w: 56px; }
  .rail-layout--collapsed .filter-toggle {
    flex-direction: column; justify-content: flex-start;
    gap: 12px; padding: 14px 4px 12px; margin-top: 2px;
  }
  .rail-layout--collapsed .filter-toggle-label {
    flex: 0 0 auto;
    writing-mode: vertical-rl; transform: rotate(180deg);
    letter-spacing: .16em; text-transform: uppercase; font-size: 11px;
  }
  .rail-layout--collapsed .filter-toggle-chev { margin-left: 0; }
}
/* The column resizes rather than jumping when the sidebar folds */
.rail-layout { transition: grid-template-columns .3s ease; }
@media (prefers-reduced-motion: reduce) {
  .rail-layout, .filter-toggle-chev { transition: none; }
}
/* The map folds away while the Online format filter is active
   (online gatherings have no place on a map): a 1fr→0fr grid row
   animates the height smoothly, no max-height guesswork, and the
   fade keeps the fold from feeling abrupt. */
.map-reveal {
  display: grid; grid-template-rows: 1fr; opacity: 1;
  transition: grid-template-rows .45s ease, opacity .35s ease;
}
.map-reveal-inner { overflow: hidden; min-height: 0; }
.map-reveal--off {
  grid-template-rows: 0fr; opacity: 0; pointer-events: none;
}
.map-panel { background: linear-gradient(180deg, var(--page-soft) 0%, var(--page) 100%); border: 1px solid #E8C06025; border-radius: 16px; padding: 8px 8px 14px; margin-bottom: var(--gap-lg); }

/* Guide filter: searchable combobox listing guides that currently
   have published events */
.combo { position: relative; width: 100%; }
.combo .combo-input { padding: 10px 36px 10px 14px; font-size: 14px; border-radius: 10px; background: var(--surface); }
.combo-clear { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; font-size: 16px; color: var(--text-light); line-height: 1; padding: 2px; }
.combo-list { position: absolute; top: calc(100% + 6px); left: 0; right: 0; background: var(--surface); border: 1px solid #E8C06040; border-radius: 12px; box-shadow: 0 10px 30px rgba(91, 62, 31, 0.14); max-height: 220px; overflow-y: auto; z-index: 20; padding: 6px; }
.combo-option { display: block; width: 100%; text-align: left; background: none; border: none; cursor: pointer; padding: 9px 12px; border-radius: 8px; font-family: var(--font-sans); font-size: 14px; color: var(--text-mid); }
.combo-option:hover { background: var(--hover); }
/* The share form's roster: tall enough to browse, about seven rows (F89). */
.combo-list--roster { max-height: 300px; }
.combo-option.on { color: var(--honey); font-weight: 600; }
/* "Facilitator not listed", always the last row. A hairline above it
   separates the way OUT of the list from the names in it, so it does
   not read as one more facilitator called "not listed". Reuses the
   existing line and text tokens; no new colour. Added 24 Aug 2026. */
/* Context after the guide's name: role (when they have a profile) and
   how many gatherings they are leading */
.combo-meta { color: var(--text-light); font-size: 13px; font-weight: 400; }
.combo-option.on .combo-meta { color: var(--honey); }
.combo-empty { padding: 9px 12px; font-size: 13px; color: var(--text-light); font-style: normal; }

.map-hint { font-size: 12px; color: var(--text-light); letter-spacing: .14em; font-family: var(--font-sans); text-align: center; margin-top: 10px; }
/* Invitation under the upcoming-events trio on the home page */
/* Collapse/expand control for the globe panel */
.globe-toggle {
  display: block; margin: 2px 6px 0 auto;
  background: none; border: 1px solid #D4A14150; border-radius: 50px;
  padding: 6px 15px; cursor: pointer;
  font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-light);
  transition: all .2s;
}
.globe-toggle:hover { color: var(--honey); border-color: var(--honey); }
.map-panel--collapsed { padding: 10px; }
.map-panel--collapsed .globe-toggle { margin: 0 auto; }

/* Interactive 3D globe: same footprint as the static artwork, square
   so the WebGL canvas always matches its container */
/* The live globe fades in over the artwork instead of snapping */
@keyframes globeIn{ from { opacity: 0; } to { opacity: 1; } }
/* The brand bee flies the cursor over the globe. Mouse/trackpad only
   (touch devices have no cursor); hotspot at the bee's centre so
   dragging and clicking stay accurate. The image-set overrides give
   retina screens the sharp 2x bitmap where supported. */
/* Lotus gathering markers on the 3D globe: small ivory lotus with a
   honey glow, centred on its location by the globe's HTML layer */
/* No cursor of its own: the marker inherits the globe's bee cursor
   so the pointer never flips back to a hand inside the globe area.
   The symmetric padding grows the tap target (a finger-friendly
   ~36px) without moving the lotus off its location. */
/* Hover tooltip over a gathering's lotus */

/* Visually hidden, read by screen readers */
.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; }

/* Globe pins carry the same count badge as the filter panel's region
   pills, one size down so each pin still sits over its own landmass. */
.region-count {
  font-family: var(--font-mono);
  background: var(--page-cream); color: var(--text-light);
  border-radius: 50px;
  min-width: 18px; height: 18px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 5px;
  font-size: 11px; font-weight: 500;
  border: 1px solid #D4A14140;
}
.region-count.has { background: var(--honey); color: var(--on-accent-strong); border: none; }

.type-label { font-size: 11px; color: var(--text-light); letter-spacing: .12em; font-family: var(--font-sans); margin-right: 4px; flex-shrink: 0; }
.type-pill { display: inline-flex; align-items: center; gap: 6px; padding: 5px 16px; border-radius: 50px; cursor: pointer; font-size: 12px; font-family: var(--font-sans); font-weight: 500; transition: all .2s; border: none; background: var(--surface); color: var(--text-mid); box-shadow: inset 0 0 0 1.5px #D4A14135; }
.type-pill.on { background: color-mix(in srgb, var(--c, var(--honey)) var(--fill-share, 100%), var(--text-dark)); color: var(--on-accent); box-shadow: 0 2px 10px color-mix(in srgb, var(--c, var(--honey)) 31%, transparent); }
/* The count sits in a pale patch of the surface laid over the fill,
   so it is dark writing on a light bubble in either appearance. */
.type-pill.on .region-count { background: color-mix(in srgb, var(--surface) 35.00%, transparent); color: var(--on-accent-strong); border: none; }
.type-pill.on .type-dot { background: var(--surface); }

/* The submission form borrows the Gatherings filter's type pills, so an
   organiser picks from exactly what a visitor will filter by. One
   difference: a filter is a guess you can retry in a second, a form
   field is something you must hit, so here they carry the full 44px
   target rule 8 asks for. Scoped to .field, which only the form uses —
   the filter panel's own density is untouched. */
.field .filter-pills { gap: 10px; }
.field .filter-pills .type-pill {
  min-height: 44px; padding: 10px 18px; font-size: 13px;
}

/* A field that only exists because of the answer above it — today just
   the one Other opens under Gathering Type. Indented so it reads as
   part of that question rather than as the next one, and given the
   spacing the pills leave rather than a field's full margin, which
   would put it closer to the field below than to the choice that
   raised it. No new colour, no new token: the rule is margins and a
   hairline in the honey the form already uses for its inputs.

   Rule 8: the input inside keeps .inp, so its own 44px target and the
   full-width behaviour at 360px are untouched. */
.field .field--sub {
  margin: 14px 0 0; padding-left: clamp(10px, 2vw, 16px);
  border-left: 2px solid #D4A14135;
}

/* Colour swatch dot shown in filter pills and the map legend */
.type-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--c, var(--honey)); flex-shrink: 0; }

/* Online events: pink indicator in the card's location slot */
.card-loc.is-online { color: color-mix(in srgb, var(--type-online) var(--type-ink, 100%), var(--text-dark)); font-weight: 600; }

.result-count { font-size: 13px; color: var(--text-light); font-family: var(--font-sans); margin-bottom: 20px; }
.map-empty { text-align: center; padding: 60px 0; color: var(--text-light); font-style: normal; font-family: var(--font-serif); }

.map-card { container-type: inline-size; background: var(--surface); border: 1.5px solid #D4A14122; border-radius: 16px; padding: clamp(18px, 1.5vw, 30px) clamp(20px, 1.6vw, 32px); cursor: pointer; transition: all .3s; position: relative; overflow: hidden; box-shadow: none; display: flex; flex-direction: column; text-align: left; }
.map-card:hover { transform: translateY(-3px); box-shadow: 0 8px 28px #D4A14122; }
.map-card .card-top { margin-bottom: 12px; gap: 8px; }
.map-card .card-tags { gap: 6px; }
/* flex-shrink stays 0: the place keeps the width it needs and the
   tags wrap around it. What stops a long city running off the card
   is the max-width and ellipsis above, not squeezing (F75). */
.map-card .card-loc { font-size: 11px; flex-shrink: 0; font-family: var(--font-sans); font-style: inherit; }
.map-card .card-title { font-size: 18px; margin-bottom: 6px; line-height: 1.25; }
.map-card .card-date { font-family: var(--font-sans); margin-bottom: 8px; }
.map-card .card-desc { font-size: 13px; line-height: 1.6; font-family: var(--font-sans); margin-bottom: 0; }

/* ── Inside an event card ─────────────────────────────────────
   The type is measured in cqi — percent of THE CARD's own width, not
   the window's. So a card sets its own scale continuously wherever
   it lands: full width on a phone, one of four in a wide events
   grid, one of three beside the homepage calendar. The clamps hold
   it between the sizes the cards use today and a comfortable
   ceiling, so nothing shrinks anywhere it used to be bigger.
   Placed after .map-card's rules above so the two-class selectors
   match on specificity and win on source order. */
.ec .card-title { font-size: clamp(20px, 5.2cqi, 25px); }
.ec .card-desc { font-size: clamp(14px, 3.8cqi, 16px); }
.map-card .card-title { font-size: clamp(18px, 4.9cqi, 22px); }
.map-card .card-desc { font-size: clamp(13px, 3.5cqi, 15.5px); }
/* One more line of the description once the card is wide enough to
   make a three- or four-line block read as a paragraph */
@container (min-width: 420px) {
  .ec .clamp-2, .map-card .clamp-2 { -webkit-line-clamp: 3; }
  .ec .clamp-resp, .map-card .clamp-resp { -webkit-line-clamp: 4; }
}

/* Event hub */
/* Key-facts card: the essentials, large and scannable */
/* .event-facts / .event-fact / .event-fact-icon were the gathering
   page's eight icon tiles. Retired Aug 2026 — see "The gathering page,
   quieted" at the end of this file. .event-fact-label survives: the
   resource card in "Continue exploring" still wears it. */
.event-fact-label {
  font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  letter-spacing: .14em; color: var(--text-light); margin-bottom: 4px;
}
.event-fact-value {
  font-family: var(--font-sans); font-size: 17px; font-weight: 600;
  color: var(--deep-earth); line-height: 1.4; overflow-wrap: break-word;
}
/* .event-body was the gathering page's second two-column grid, sitting
   under the intro's first one with different column widths. Retired
   Aug 2026 for a single spine — see the end of this file. */
.panel { background: var(--surface); border: 1px solid #E8C06030; border-radius: 18px; padding: clamp(20px, 1.9vw, 36px) clamp(18px, 1.8vw, 34px); }
.panel-note { font-size: 13px; color: var(--text-light); line-height: 1.7; margin-top: 16px; }

/* What-is-seva items (Support page) */
.support-item { background: var(--surface); border-radius: 14px; padding: 20px; text-align: center; border: 1px solid #E8C06025; }
.support-icon { font-size: 28px; margin-bottom: 8px; }
.support-label { font-size: 15px; color: var(--text-mid); font-family: var(--font-sans); font-weight: 600; }
.support-note { text-align: center; font-size: 14px; color: var(--text-light); margin-top: 20px; font-style: normal; }
.trust-quote { background: var(--page-soft); border-radius: 16px; padding: clamp(20px, 2vw, 36px) clamp(24px, 2.4vw, 44px); border: 1px solid #E8C06030; font-family: var(--font-serif); font-style: normal; font-size: clamp(17px, 0.2vw + 16.3px, 21px); color: var(--deep-earth); line-height: 1.6; max-width: min(100%, clamp(760px, 54vw, 960px)); margin: 0 auto; text-align: center; }

/* About page */
/* The statement and the invitation under it belong to the opening
   composition, so they sit close to the subtitle above rather than a
   fixed 32px clear of it at every size */
/* Type curve is the original one — only the ceiling is lifted a
   little so the statement keeps growing past a laptop instead of
   freezing at 30px. Below ~1130px the sizes are unchanged. */
/* The size and line height are .prose's own since 13 Sep 2026 (founder:
   the statement the same size as "The bhakti world is full of life"). */
.about-lede { font-family: var(--font-serif); font-size: clamp(17px, 0.13vw + 16.4px, 18.5px); font-weight: 400; color: var(--deep-earth); line-height: 1.85; margin: clamp(12px, 0.7vw + 6px, 22px) auto 0; max-width: min(100%, 760px); }
.about-block { margin-bottom: 52px; }

/* Newsletter */
.news-title { font-family: var(--font-serif); font-size: clamp(20px, 3vw, 28px); font-weight: 400; color: var(--deep-earth); margin: 14px 0 10px; }
.news-desc { font-size: 14px; color: var(--text-mid); line-height: 1.8; margin-bottom: 24px; font-family: var(--font-sans); }
.news-row { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.news-input { padding: 12px 20px; border-radius: 50px; border: 1.5px solid #D4A14150; background: var(--surface); font-size: 14px; font-family: var(--font-sans); color: var(--text-dark); outline: none; min-width: 240px; }

/* ── 9. Forms ─────────────────────────────────────────────────── */
.inp { width: 100%; padding: 12px 16px; border: 1.5px solid #E8C06040; border-radius: 12px; font-family: var(--font-sans); font-size: 16px; color: var(--text-dark); background: var(--field); outline: none; transition: border-color .2s; }
.inp:focus { border-color: var(--honey); }
/* .inp and .news-input each set `outline: none`, and the shared
   focus rule above is written with :where(), which contributes no
   specificity at all — so on a tie the later rule won and a text
   field had no ring, only a border that changed colour. The guidance
   is explicit that a focus indicator must not rest on colour alone.
   (F69, 8 Sep 2026) */
.inp:focus-visible, .news-input:focus-visible {
  outline: 2px solid var(--honey-text); outline-offset: 2px;
}
.inp--search { padding-left: 44px; font-size: 15px; }
.inp--area { resize: vertical; }

/* Submit flow */
.submit-done { min-height: 100svh; background: var(--panel); display: flex; align-items: center; justify-content: center; padding: clamp(96px, 10vh, 160px) var(--page-edge); }
.submit-done-inner { text-align: center; max-width: min(100%, clamp(520px, 40vw, 700px)); }
.submit-globe { height: 90px; width: auto; mix-blend-mode: multiply; margin-bottom: 24px; }
.submit-title { font-family: var(--font-serif); font-size: clamp(26px, 4vw, 40px); font-weight: 400; color: var(--deep-earth); margin-bottom: 16px; line-height: 1.2; }
.submit-p { font-size: 16px; color: var(--text-mid); line-height: 1.85; margin-bottom: 12px; font-family: var(--font-sans); }
/* No nowrap: at 320px this sentence is wider than the screen */
.submit-small { font-size: 14px; color: var(--text-light); line-height: 1.8; margin-bottom: 32px; font-family: var(--font-sans); }

.form-wrap { width: min(100% - var(--page-edge) * 2, clamp(640px, 46vw, 820px)); margin: 0 auto; padding-block: clamp(36px, 3.6vw, 68px); }
.form-head { text-align: center; margin-bottom: clamp(26px, 2.6vw, 46px); }
.form-heading { font-family: var(--font-serif); font-size: clamp(26px, 2vw, 36px); color: var(--deep-earth); font-style: normal; margin-top: 18px; }

/* Stepper */
.stepper { display: flex; gap: 6px; justify-content: center; margin-bottom: 40px; }
.step { display: flex; align-items: center; gap: 6px; }
.step-col { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.step-dot { width: 32px; height: 32px; border-radius: 50%; background: #D4A1411A; display: flex; align-items: center; justify-content: center; color: var(--honey); font-size: 14px; font-weight: 600; transition: all .3s; }
.step-dot.done { background: var(--honey); color: var(--on-accent-strong); }
.step-label { font-size: 10px; letter-spacing: .04em; white-space: nowrap; font-family: var(--font-sans); color: #87683C99; font-weight: 400; transition: all .3s; }
.step-label.on { color: var(--deep-earth); font-weight: 600; }
.step-line { width: clamp(10px, 3vw, 26px); height: 1px; margin-bottom: 15px; background: #D4A14128; }
.step-line.done { background: var(--honey); }
.step-note { text-align: center; font-size: 11px; letter-spacing: .2em; color: var(--honey); white-space: nowrap; font-family: var(--font-sans); margin: 0 0 18px; }

/* Form card */
.form-card { background: var(--surface); border-radius: 20px; padding: clamp(24px, 2.8vw, 52px); border: 1px solid #E8C06028; box-shadow: 0 8px 40px #D4A1410E; animation: fadeUp .4s ease; text-align: left; }
.form-title { font-family: var(--font-sans); font-size: 21px; font-weight: 600; color: var(--deep-earth); margin-bottom: 6px; }
.form-title--tight { margin-bottom: 12px; font-style: normal; }
/* Air above as well as below (founder, 11 Sep 2026): the line sat
   almost on its title, and in the F105 gateway, where the title is a
   <legend>, it touched it. */
.form-sub { font-size: 14px; color: var(--text-light); font-style: normal; margin-top: 12px; margin-bottom: 28px; }
.field { margin-bottom: 22px; }
/* The share form's optional time pair keeps the same vertical rhythm
   as the .field rows around it. */
.date-range--times { margin-bottom: 22px; }
.field-label { display: block; font-size: 14px; color: var(--text-mid); margin-bottom: 7px; font-weight: 600; }
.fmt-fieldset { border: none; padding: 0; margin: 0 0 var(--gap-field, 18px); min-inline-size: 0; }
.fmt-fieldset > .field-label { padding: 0; margin-bottom: 8px; display: block; }
.fmt-row { display: flex; gap: 12px; }
.fmt-opt {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 16px; border-radius: 12px; cursor: pointer;
  border: 1.5px solid #E8C06038; font-size: 14px; color: var(--text-mid);
  background: transparent;
  transition: border-color .2s, background .2s, color .2s;
}
.fmt-opt:hover { border-color: #D4A14180; }
/* The selected state. Without this nothing on screen changed when an
   option was clicked — the radio was display:none, so there was no
   :checked to style and no way to tell what had been chosen. */
.fmt-opt.on {
  border-color: var(--honey);
  background: color-mix(in srgb, var(--honey) 8%, var(--surface));
  color: var(--deep-earth); font-weight: 600;
}
.fmt-opt.on .fmt-icon { color: var(--honey); }
/* The radio still exists and is still focusable — it is only moved
   out of sight. :focus-within puts the ring on the card the visitor
   can actually see. */
.fmt-opt:focus-within { outline: 2px solid var(--honey); outline-offset: 2px; }
.fmt-icon { font-size: 22px; }
.fmt-label { line-height: 1; }
/* Reachable by keyboard and to a screen reader, invisible on screen —
   unlike display:none, which removes a control from the tab order
   altogether. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.hidden { display: none; }
/* Native date control, dressed to match the text fields beside it.
   The whole field is clickable (see the onClick in app.jsx), so it
   gets the pointer cursor rather than a text caret, and the calendar
   icon is enlarged and tinted so it reads as the affordance it is. */
.inp--date { font-family: var(--font-sans); cursor: pointer; }
.inp--date::-webkit-calendar-picker-indicator {
  cursor: pointer; opacity: .75; padding: 2px; width: 18px; height: 18px;
  filter: sepia(1) saturate(2.2) hue-rotate(354deg) brightness(.82);
}
.inp--date::-webkit-calendar-picker-indicator:hover { opacity: 1; }

/* Final review step */
.form-lead { font-size: 15px; color: var(--text-mid); line-height: 1.75; margin-bottom: 28px; }
.tier-box { background: var(--page-soft); border-radius: 12px; padding: 18px; margin-bottom: 28px; border: 1px solid #E8C06028; text-align: left; }
.tier-box-head { text-align: left; margin-bottom: 24px; }
.tier-box-label { display: block; font-size: 14px; color: var(--text-mid); margin-bottom: 12px; font-weight: 600; font-family: var(--font-sans); }
.tier-opt { display: flex; align-items: center; gap: 12px; padding: 13px 16px; margin-bottom: 10px; border-radius: 12px; cursor: pointer; border: 1.5px solid #E8C06035; background: var(--surface); transition: all .2s; }
.tier-opt.on { border-color: var(--honey); background: #D4A14112; }
.tier-radio { width: 18px; height: 18px; border-radius: 50%; flex-shrink: 0; border: 2px solid #E8C06050; background: transparent; box-shadow: none; transition: all .2s; }
.tier-opt.on .tier-radio { border-color: var(--honey); background: var(--honey); box-shadow: inset 0 0 0 3px var(--surface); }
.tier-opt-label { font-size: 14px; color: var(--text-mid); font-weight: 400; font-family: var(--font-sans); }
.tier-opt.on .tier-opt-label { font-weight: 600; }
.tier-note { font-size: 13px; color: var(--text-light); line-height: 1.6; margin-top: 6px; font-family: var(--font-sans); }
.next-label { font-size: 12px; color: var(--text-light); letter-spacing: .12em; margin-bottom: 8px; white-space: nowrap; }
.next-item { font-size: 14px; color: var(--text-mid); margin-bottom: 8px; display: flex; align-items: flex-start; gap: 8px; }
.next-star { color: var(--honey); margin-top: 1px; }
.form-error { color: var(--error); font-size: 14px; margin-top: 20px; text-align: center; font-family: var(--font-sans); }
/* The list of what is still missing, under the summary line. Reuses
   .form-error's colour and face — no new token — and only stops the
   text being centred, because a centred list of field names is harder
   to read down than a left-aligned one. Added 24 Aug 2026. */
.form-error-list { margin: 8px auto 0; padding-left: 1.2em; text-align: left; display: table; }
.form-error-list li { margin-top: 2px; }
/* M-VAL-04 beside the field it is about, rather than centred under the
   whole form. Same colour, one step smaller, tight to the control. */
.field-error { color: var(--error); font-size: 13px; margin-top: 6px; font-family: var(--font-sans); }
/* Quiet privacy reassurance under the submit button */
.form-privacy { font-size: 12.5px; color: var(--text-light); line-height: 1.6; text-align: center; margin-top: 22px; font-family: var(--font-sans); }
/* ── The Review step's summary (pre-launch review, 24 Aug 2026) ──
   What was typed, one quiet row per answer, before "what happens
   next". Left-aligned inside a centred step: reading data is not a
   ceremony. On a phone the three cells stack. */
.review-summary {
  text-align: left; margin: 18px 0 26px; padding: 16px 18px;
  background: var(--panel); border: 1px solid #E8C06055;
  border-radius: 14px; display: flex; flex-direction: column; gap: 10px;
}
.review-row {
  display: flex; align-items: baseline; gap: 10px; min-width: 0;
  font-size: 14px; line-height: 1.55;
}
.review-label {
  flex: 0 0 34%; max-width: 200px; font-family: var(--font-sans);
  font-size: 10.5px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-light);
}
.review-value { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; color: var(--text-mid); }
.review-edit { flex: 0 0 auto; font-size: 12.5px; }
@media (max-width: 560px) {
  .review-row { flex-wrap: wrap; row-gap: 2px; }
  .review-label { flex-basis: 100%; max-width: none; }
  .review-value { flex: 1 1 auto; }
}

.form-nav { display: flex; justify-content: space-between; margin-top: 28px; gap: 12px; }

/* ── 10. Footer ───────────────────────────────────────────────── */
.footer { background: var(--dark-bg); padding: clamp(44px, 4.4vw, 84px) var(--page-pad-x) clamp(28px, 2.6vw, 44px); color: #F5EFE680; text-align: left; }
/* A grid, not space-between: at 1600px the flex version pushed the
   four columns to opposite ends of the footer with a lake of dark
   between them. The brand block takes a wider track than the link
   columns, and the whole set collapses to two, then one. */
.footer-grid {
  display: grid;
  grid-template-columns: minmax(240px, 1.4fr) repeat(3, minmax(150px, 1fr));
  gap: var(--gap-xl); margin-bottom: 0;
}
@media (max-width: 860px) { .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 460px) { .footer-grid { grid-template-columns: minmax(0, 1fr); } }
.footer-brand { max-width: 340px; }
.footer-brand-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.footer-tagline { font-size: 9px; letter-spacing: .22em; color: #F5EFE660; text-transform: uppercase; white-space: nowrap; font-family: var(--font-sans); }
.footer-quote { font-size: 13px; font-style: normal; color: #E8C06075; white-space: nowrap; }
.footer-cta { background: transparent; border: 1px solid #D4A14145; color: var(--honey); padding: 8px 20px; border-radius: 50px; font-family: var(--font-sans); font-size: 13px; cursor: pointer; transition: all .3s; }
.footer-col-title { font-size: 11px; letter-spacing: .2em; color: var(--honey); margin-bottom: 16px; }
.footer-link { font-size: 14px; margin-bottom: 10px; cursor: pointer; transition: color .2s; }
.footer-link:hover { color: var(--cream); }
/* A line of thanks, quieter than the navigation above it: smaller
   type, dimmer than the links, sitting on its own above the legal
   line. An acknowledgement, not a section — and deliberately no
   heading, no border and no claim of an organisational tie. */
.footer-gratitude {
  /* No measure cap: the line is meant to sit on ONE line across a
     desktop, and it needs about 927px to do so — a 78ch cap folded
     it in two at every width. It is left to fit naturally rather
     than forced with white-space: nowrap, which would overflow the
     page horizontally on the frame before Montserrat has loaded and
     the wider fallback is still measuring the text. Below roughly
     1030px wide it simply wraps, which is where phones and tablets
     live anyway. */
  margin: clamp(26px, 2.6vw, 44px) 0 0;
  font-size: 12.5px; line-height: 1.75; color: #F5EFE680;
  font-family: var(--font-sans); text-wrap: pretty;
}
.footer-bottom { padding-top: 22px; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px; font-size: 13px; }

/* ── 11. Utilities ────────────────────────────────────────────── */
.tac { text-align: center; }
.tal { text-align: left; }
.nowrap { white-space: nowrap; }
.mt-20 { margin-top: 20px; }
.mt-32 { margin-top: 32px; }
.mt-40 { margin-top: 40px; }
.mb-14 { margin-bottom: 14px; }
.mt-14 { margin-top: 14px; }
.mb-16 { margin-bottom: 16px; }
.mb-22 { margin-bottom: 22px; }
.mb-32 { margin-bottom: 32px; }
.mb-36 { margin-bottom: 36px; }
.mb-56 { margin-bottom: 56px; }
.mb-64 { margin-bottom: 64px; }

/* ── 12. Responsive styles ────────────────────────────────────── */
/* Tablet: the rail stacks (see the .rail-layout media block), so the
   filters collapse behind their toggle button and the globe is capped
   to stay in proportion across the full page width */
@media (max-width: 999.98px) {
  /* Stacked, the bar is the panel's whole frontage, so it is drawn to
     be pressed: a full-width card with a raised edge, the sliders and
     the count on the left, the chevron on the right — down while the
     filters are folded, up while they are open, and the same bar
     closes them again. */
  .filter-toggle {
    padding: 13px 16px; font-size: 14px;
    border-width: 1.5px; background: var(--surface);
    box-shadow: 0 1px 3px #5B3E1F0F;
  }
  .filter-toggle:active { background: var(--hover); }
  .filter-toggle.is-open { border-color: var(--honey); }
  .filter-toggle.is-open .filter-toggle-chev { transform: rotate(180deg); }
  .filter-panel.is-open {
    margin-top: 14px;
    background: var(--surface); border: 1px solid #E8C06030;
    border-radius: 14px; padding: 18px 16px;
  }
}

/* Mobile */
@media (max-width: 767.98px) {
  /* On the phone-sized globe the pills span up to a quarter of its
     width, so two labels need their own safe anchor points (!important
     because base positions arrive as inline styles). N. America shifts
     right to stay off the bee; Oceania tucks in from the rim. */
  /* Keeps the half-on, half-off straddle of the limb (see MAP_REGIONS),
     lifted a little further clear of the lotus below */
  /* The count badge widens both pills, and at this size Europe and Asia
     sit only a few percent apart — give them a little more air so they
     stay legible side by side. */
  .clamp-resp { -webkit-line-clamp: 2; }
}

/* ── Sacred Food directory ──────────────────────────────────────
   Compact place cards, country/type filters, city chips, and the
   full-detail modal (a bottom sheet on mobile). */
.search-wrap--tight { margin-bottom: 12px; }
.food-controls { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 14px; }
.inp--select { width: auto; flex: 1 1 200px; max-width: 280px; font-size: 14px; padding: 11px 14px; cursor: pointer; color: var(--text-mid); }
.food-chips { display: flex; gap: 8px; flex-wrap: wrap; margin: 2px 0 18px; }
.chip {
  padding: 7px 15px; border-radius: 50px; border: 1px solid #E8C06050;
  background: var(--surface); font-family: var(--font-sans); font-size: 13px;
  color: var(--text-mid); cursor: pointer; transition: all .2s; line-height: 1.3;
}
.chip:hover { border-color: var(--honey); color: var(--deep-earth); }
.chip.on { background: var(--honey); border-color: var(--honey); color: var(--on-accent-strong); font-weight: 600; }
.chip--clear { border-style: dashed; color: var(--text-light); flex: 0 0 auto; }

.food-country { margin-bottom: 48px; }
.food-country-head {
  display: flex; align-items: baseline; gap: 10px; text-align: left;
  margin-bottom: 18px; padding-bottom: 10px; border-bottom: 1px solid #E8C06035;
}
.food-country-count { font-family: var(--font-sans); font-size: 13px; color: var(--text-light); }

.place-city { font-size: 13px; color: var(--text-light); margin-bottom: 8px; }
.place-type { font-size: 13px; margin-bottom: 10px; }
.place-short {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
button.pill-link { background: transparent; cursor: pointer; width: 100%; }

/* Place detail modal */
.place-modal-backdrop {
  position: fixed; inset: 0; z-index: 400; background: #231204A8;
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.place-modal {
  background: var(--panel); border-radius: 20px; width: 100%;
  max-width: min(100%, clamp(620px, 46vw, 820px)); max-height: min(88svh, 900px); overflow-y: auto;
  position: relative; text-align: left; box-shadow: 0 24px 80px #23120466;
  animation: placeModalIn .25s ease;
}
@keyframes placeModalIn{ from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.place-modal-close {
  position: absolute; top: 14px; right: 14px; z-index: 2;
  width: 38px; height: 38px; border-radius: 50%; border: none;
  background: #231204B8; color: var(--cream); font-size: 20px; line-height: 1;
  cursor: pointer; transition: background .2s;
}
.place-modal-close:hover { background: var(--deep-earth); }
.place-modal-body { padding: 24px 28px 30px; }
.place-modal-title { margin: 12px 0 4px; }
.place-sec { margin-top: 20px; }
.place-sec-title {
  font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; color: var(--honey);
  margin-bottom: 6px;
}
.place-sec-text { font-size: 15px; color: var(--text-mid); line-height: 1.7; }
.place-links { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 26px; }
.place-links .pill-link { flex: 1 1 160px; }

@media (max-width: 767.98px) {
  .inp--select { max-width: none; flex: 1 1 40%; }
  /* The modal becomes a bottom sheet: full width, thumb-reachable close */
  .place-modal-backdrop { padding: 0; align-items: flex-end; }
  .place-modal { max-width: none; max-height: 92dvh; border-radius: 22px 22px 0 0; animation-name: placeSheetIn; }
  @keyframes placeSheetIn{ from { transform: translateY(40px); opacity: .6; } to { transform: none; opacity: 1; } }
  .place-modal-body { padding: 20px 20px 30px; }
}

/* ── Bee cursor ─────────────────────────────────────────────────
   The bee mascot flies as the pointer everywhere. Hotspot sits on
   the bee's head (front-right of the artwork). The image-set rule
   upgrades to the sharper @2x on retina screens where supported. */
*, *::before, *::after {
  cursor: url("img/bee-cursor.png") 27 14, auto !important;
}
*, *::before, *::after {
  cursor: -webkit-image-set(url("img/bee-cursor.png") 1x, url("img/bee-cursor@2x.png") 2x) 27 14, auto !important;
}
/* The standard spelling, for Firefox, which ignores the prefixed one
   and was showing the soft 1x bee on retina screens (F84). */
*, *::before, *::after {
  cursor: image-set(url("img/bee-cursor.png") 1x, url("img/bee-cursor@2x.png") 2x) 27 14, auto !important;
}

/* …except where a cursor has a job to do (30 Aug 2026).
   The rule above is `!important` on `*`, so it beat everything: the
   browser's own I-beam on a text field, and all 54 `cursor: pointer`
   declarations in this stylesheet. The founder noticed it on the log
   in page, which is the worst case — two text fields and two buttons,
   and the bee over every one of them.

   A bee over a paragraph is the mascot. A bee over a password box is a
   pointer that will not tell you where the caret lands, and its
   hotspot is at 27,14 — the bee's head, right of and below the click —
   so it actively misleads. Typing is the one place the joke costs
   something.

   Narrow on purpose: text entry only. Buttons and links keep the bee,
   because flying everywhere is the point of it. */
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="submit"]):not([type="button"]),
textarea,
[contenteditable="true"] {
  cursor: text !important;
}

/* ── Launch-audit fixes ─────────────────────────────────────────
   Contrast: gold is kept for borders and accents, but text set in
   gold moves to a darker shade (--honey-text) that passes WCAG AA
   on cream/white; gold-gradient buttons carry dark brown text.

   SECOND PASS, 25 Aug 2026. The founder asked for contrast that is
   "comfortably readable rather than only technically acceptable", and
   said to judge it at low screen brightness. Measured on the rendered
   page rather than from the palette:

     --text-light  #87683C   4.51 on cream — passing AA by 0.01
     .type-pill.on white on the honey gradient   2.34 — failing

   The first is the one the founder felt: it sets the page subtitles,
   the map hint, the result count and the map toggle, and 4.51 is the
   number you get when a colour was chosen by eye against a bright
   screen. It is now --dusk's value, #7A5535, which was ALREADY in the
   palette — 5.78 on cream, 6.61 on white — so no new colour enters the
   system and the hierarchy holds: still visibly lighter than
   --text-mid at 8.53.

   The second is a live control. White on gold is 2.34, worse than the
   gold-on-cream this block was originally written to fix. It takes the
   same #3A200A the gold buttons above already use: 6.45 on the darker
   end of the gradient, 8.19 on the lighter. */
:root { --honey-text: #8A6516; }
.overline { color: var(--honey-text); }
.seva--dark .overline { color: var(--saffron); }
.card-date { color: var(--honey-text); }
.bg-g, .nav-cta, .seva-cta, .mobile-menu-cta { color: var(--on-accent-strong); }
.chip.on { color: var(--on-accent-strong); }
/* The ordering control and the filter type pills, when active: the same
   gold gradient as the buttons, so the same dark brown on top of it. */
.type-pill.on { color: var(--on-fill, var(--on-accent-strong)); }

/* Footer links are real anchors now */
a.footer-link { display: block; color: inherit; text-decoration: none; }
a.footer-cta { display: inline-block; color: var(--honey); text-decoration: none; }

/* Newsletter form states */
.news-input.is-invalid { border-color: #B3261E; }
.news-msg { flex-basis: 100%; font-size: 13px; color: #B3261E; margin: 4px 0 0; }
.news-confirm { font-size: 15px; color: var(--deep-earth); background: var(--page-soft); border: 1px solid #E8C06040; border-radius: 12px; padding: 14px 22px; display: inline-block; }

/* Category tag pills hug their text on every resource card */
.res-card-body > .tag { align-self: flex-start; }

/* Clear-all inside the events filter panel */
.filter-clear-all { margin-top: 4px; align-self: flex-start; }

/* Comfortable touch targets */
.nav-burger { padding: 12px 10px; }
.footer-cta { padding: 11px 22px; }



/* ── Offering contexts ───────────────────────────────────────────
   Each offering context carries a subtle colour identity that runs
   from the homepage cards to the event-card badges, the submission
   form and the membership page: beginning = fresh honey gold,
   deepening = warm terracotta, developing = deep earth,
   invitation = quiet lavender. */
:root {
  --lvl-open-to-all:  #C99A2E;   /* fresh honey gold */
  --lvl-deepening:  #A66A44;   /* warm terracotta */
  --lvl-developing: #6E4F23;   /* deep earth */
  --lvl-invitation: #7E6591;   /* quiet lavender */
  /* "New to bhakti" (FS-01, 6 Sep 2026): the founder's choice among
     three existing colours — the warm rose-brick the site already
     uses for the Follow button, the presale badge, the holy-month
     calendar mark and the Membership card. Not a new colour: named
     here so the badge, the form option and the glossary entry read
     one token. Warm and apart from honey gold, terracotta and deep
     earth, from every type chip, and from the amber button. */
  --lvl-new-to-bhakti: var(--ember);
}
.lvl-open-to-all { --c: var(--lvl-open-to-all); }
.lvl-deepening { --c: var(--lvl-deepening); }
.lvl-developing { --c: var(--lvl-developing); }
.lvl-invitation { --c: var(--lvl-invitation); }
.lvl-new-to-bhakti { --c: var(--lvl-new-to-bhakti); }

/* Small level badge on event cards; understated, colour-coded */
.lvl-badge {
  display: inline-flex; align-items: center;
  padding: 2.5px 9px; border-radius: 20px;
  font-size: 10px; font-weight: 700; letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--c); border: 1px solid color-mix(in srgb, var(--c) 45%, transparent);
  background: color-mix(in srgb, var(--c) 9%, var(--surface));
  white-space: nowrap;
}

/* Homepage journey block: the primary way into the events list,
   living inside the hero right after the globe and proof line */
.hero-journey { width: 100%; max-width: min(100%, clamp(960px, 68vw, 1280px)); margin-top: clamp(24px, 3vh, 46px); text-align: center; }
.hero-journey .overline { margin-bottom: 8px; }
.hero-journey-title { margin-bottom: clamp(14px, 1.6vw, 26px); }
.journey-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap-md);
}
.journey-card {
  container-type: inline-size;
  position: relative; overflow: hidden; cursor: pointer;
  background: var(--surface); border: 1px solid #E8C06033; border-radius: 16px;
  padding: clamp(22px, 2vw, 38px) clamp(20px, 1.8vw, 34px) clamp(18px, 1.7vw, 32px);
  display: flex; flex-direction: column;
  gap: 8px; text-align: left;
  transition: transform .25s, box-shadow .25s, border-color .25s;
}
.journey-card:hover {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--c) 55%, transparent);
  box-shadow: 0 12px 28px color-mix(in srgb, var(--c) 18%, transparent);
}
/* Keyboard focus gets an unmistakable ring, never just the hover
   lift — a border-colour change is not a focus indicator. */
.journey-card:focus-visible {
  outline: 3px solid var(--honey); outline-offset: 3px;
}
.journey-accent {
  position: absolute; top: 0; left: 0; right: 0; height: 4px;
  background: linear-gradient(90deg, var(--c), color-mix(in srgb, var(--c) 45%, #E8B84B));
}
.journey-title { font-family: var(--font-serif); font-size: 24px; color: var(--c); }
.journey-tagline { font-size: 14.5px; color: var(--text-mid); line-height: 1.5; flex: 1; }
.journey-cta { font-size: 13px; font-weight: 700; color: var(--c); letter-spacing: .3px; }
/* A door with more width says where it leads a little more loudly.
   The compact hero band keeps its own smaller sizes below — those
   selectors are two classes deep, so they still win. */
.journey-title { font-size: clamp(23px, 6.4cqi, 28px); }
.journey-tagline { font-size: clamp(14.5px, 4.2cqi, 16.5px); }
/* Compact band variant (hero): accent runs down the left edge, the
   label and tagline sit in one short stack, and the CTA shrinks to
   an arrow — the three levels keep their prominence without pushing
   the rest of the homepage down. */
/* Three level cards across need roughly 270px each to stay legible;
   below that they stack rather than squeeze (was 760px, where each
   card had fallen to about 226px) */
@media (max-width: 860px) {
  .journey-grid { grid-template-columns: minmax(0, 1fr); gap: 13px; }
  .journey-card { padding: 20px 18px 17px; }
}

/* Journey-level chips on the submission form (1–2 selections) */
.lvl-opts { display: flex; flex-direction: column; gap: 9px; margin-top: 6px; }
.lvl-opt {
  display: flex; align-items: flex-start; gap: 11px; cursor: pointer;
  border: 1.5px solid #E8C06044; border-radius: 12px; padding: 11px 14px;
  transition: border-color .2s, background .2s;
}
.lvl-opt:hover { border-color: color-mix(in srgb, var(--c) 50%, transparent); }
/* The checkbox is sr-only now rather than display:none, so it can be
   tabbed to; the ring goes on the card the visitor actually sees. */
.lvl-opt:focus-within { outline: 2px solid var(--c); outline-offset: 2px; }
.lvl-opt.on {
  border-color: var(--c);
  background: color-mix(in srgb, var(--c) 7%, var(--surface));
}
.lvl-opt-check {
  flex-shrink: 0; width: 17px; height: 17px; margin-top: 1.5px;
  border: 2px solid color-mix(in srgb, var(--c) 60%, transparent);
  border-radius: 50%; position: relative; transition: all .2s;
}
.lvl-opt.on .lvl-opt-check { background: var(--c); border-color: var(--c); }
.lvl-opt.on .lvl-opt-check::after {
  content: "✓"; position: absolute; inset: 0; display: flex;
  align-items: center; justify-content: center;
  color: var(--on-accent); font-size: 10.5px; font-weight: 800;
}
.lvl-opt-text { font-size: 13.5px; color: var(--text-mid); line-height: 1.5; }
/* The share form's suitability options are radios since 3 Sep 2026
   (suitability brief §7.2): one of three, and the drawn box says so
   by being round. The alerts keep their square checkboxes. */
.lvl-opt--radio .lvl-opt-check,
.lvl-opt--radio.on .lvl-opt-check { border-radius: 50%; }
.lvl-opt-text strong { color: var(--c); }

/* ── Editorial pages: About, Become a Honeybee ───────────────────
   Both are columns of running text rather than grids of cards. The
   sitewide --section-pad-y is tuned for card sections, where a card
   needs real air around it; on a page of paragraphs the same value
   reads as a lake of empty space between two sentences (200px sat
   between the opening statement and THE STORY at 1920px).

   Redefining the token on the page wrapper is all it takes: every
   section inside — .about-sec, .section-support, .seva, .about-cta,
   .hb-welcome — picks up the tighter rhythm through the cascade,
   and no page outside these two is touched.

   The middle term is `Xvw + Ypx`, not plain vw: a pure-vw clamp of
   this size hits its floor around 1180px and then sits flat all the
   way down to a phone, so tablet and mobile stop responding
   entirely. The shallow slope keeps it moving across the whole
   range — roughly 34 → 39 → 48 → 58 → 68px from 375 to 2560. */
.page--about, .page--honeybee { --section-pad-y: clamp(34px, 2.2vw + 16px, 68px); }
/* The personalise page after saving holds one small thank-you card,
   and .page's min-height (100svh) left a tall blank band beneath its
   section (pre-launch review, 24 Aug 2026). The section stretches to
   the foot instead, so the space belongs to the page rather than
   dangling after it. */
.page--honeybee { display: flex; flex-direction: column; }
.page--honeybee > .section-support { flex: 1 0 auto; }

/* The About page opens as ONE composition — title, subtitle, the
   central statement, the invitation — not four blocks with a
   section break between each. The first band continues the header
   instead of restarting after it. */
.page--about .page-head-wrap + .about-sec { padding-top: clamp(14px, 1vw + 6px, 30px); }

/* A heading that introduces running text sits closer to it than one
   introducing a grid of cards (the shared .section-head spacing is
   set for the latter). Scoped to the prose columns on these pages. */
.page--about .mw-780 .section-head, .page--honeybee .mw-780 .section-head, .page--honeybee .mw-960 .section-head { margin-bottom: clamp(16px, 0.9vw + 7px, 30px); }

/* The last paragraph in a group keeps its trailing margin, which
   then stacks on top of the section's own padding — a 19px surprise
   on every band boundary. Paragraphs inside a group stay connected;
   the group's edge is the section's job. */
.page--about .prose:last-child, .page--honeybee .prose:last-child { margin-bottom: 0; }

/* ── About and New to bhakti?: one editorial system ──────────────
   Both pages carry .page--about. Before this they agreed on almost
   nothing: About ran three container widths and three left edges on a
   desktop (786/1089/1270 at left 360/209/118, all centred), while New
   to bhakti? ran one width, left-aligned. The rules below are the
   shared part; the few genuine differences are marked at the end.

   THE SHELL. Every section is centred on one measure, and the section
   itself carries it as inline padding, so the shell is a real box that
   the containers inside can align to rather than each centring on its
   own width. Card sections fill it; prose keeps a readable measure and
   sits on its LEFT edge. That is what uses the desktop width without
   letting a paragraph run to 100 characters: the sections got wider,
   the prose did not. */
.page--about { --w-editorial: var(--w-mid); }
.page--about .about-sec,
.page--about .section-philosophy,
.page--about .about-cta {
  padding-inline: max(var(--page-pad-x), (100% - var(--w-editorial)) / 2);
}
.page--about .about-sec > .container,
.page--about .section-philosophy > .container,
.page--about .about-cta > .container { max-width: 100%; margin-inline: 0; }
/* Prose columns. Two things, and they pull against each other: the
   column had 303px of nothing to its right because it sat on the
   shell's left edge, and it cannot simply be widened to close that —
   measured at 1512px it was already 65ch (77 average characters),
   the top of the comfortable range, and a longer line is harder to
   read, not more balanced.
   So it grows a little, to about 70ch, and is CENTRED on the shell
   instead of hugging its left edge. The margin is the same on both
   sides, which is what makes a reading column look placed rather than
   pushed. Every prose column is the same width, so they still share
   one left edge with each other; the card sections keep the full
   shell, because cards are the part that genuinely can use the
   width. */
.page--about { --w-editorial-read: clamp(780px, 56vw, 900px); }
.page--about .about-sec > .container.mw-780 {
  max-width: min(100%, var(--w-editorial-read));
  margin-inline: auto;
}

/* A card section's grid wants the whole shell, but its label and
   heading are reading matter like everything else — so they sit in the
   same column as the prose and only the cards reach past it. That is
   what keeps ONE edge running down the page while the widest content
   still uses the width. */
.page--about .about-sec > .container.mw-1100 > .section-head {
  max-width: min(100%, var(--w-editorial-read));
  margin-inline: auto;
}

/* ONE ALIGNMENT. .overline and .h2 are centred site-wide and .prose is
   left, so a label and heading floated over body copy that began
   somewhere else. Everything below the hero now shares the shell's
   left edge. */
.page--about .about-sec .section-head,
.page--about .about-sec .overline,
.page--about .about-sec .h2,
.page--about .about-sec .container.tac,
.page--about .about-sec .prose.tac { text-align: left; }
.page--about .roots-card { justify-items: start; text-align: left; }
.page--about .about-sec .btn-row--center { justify-content: flex-start; }
/* .roots-text caps itself at 62ch, which suited it beside a portrait
   on the homepage. Here it gave one section its own right edge. */
.page--about .roots-text { max-width: none; }

/* ONE VERTICAL RHYTHM: label → heading → paragraph → action. These
   were inherited from four unrelated rules, so no two sections
   matched. The action rule has to out-rank the paragraph rule, or
   .roots-prose takes the paragraph gap and the two CTAs land at
   different distances below their text. */
.page--about .about-sec .overline { margin-bottom: 10px; }
.page--about .about-sec .section-head { margin-bottom: clamp(18px, 1vw + 8px, 28px); }
.page--about .about-sec .prose { margin-bottom: clamp(16px, 0.6vw + 8px, 22px); }
.page--about .about-sec .roots-prose { margin-bottom: clamp(22px, 1.2vw + 10px, 30px); }
.page--about .about-sec .btn-row { margin-top: clamp(22px, 1.2vw + 10px, 30px); }

/* ONE SECTION RHYTHM. A boundary is two paddings stacked, so the
   sitewide --section-pad-y (tuned for card sections, where a change of
   background marks the break) put 157px of nothing between two
   paragraphs. Symmetric, so a coloured band keeps equal air top and
   bottom; and the gap under the hero, which is the one that reads as
   too tight, keeps the full site measure. */
.page--about { --section-pad-y: clamp(40px, 3.4vw, 72px); }
.page--about .page-head-wrap + .about-sec { padding-top: clamp(48px, 5.2vw, 108px); }

/* THE EXCEPTIONS, and the only ones: About's three statement blocks.
   A one-sentence lede, "Be like a honey bee" and the closing CTA are
   written to be read as declarations, not as body copy, and stay
   centred on the shell. Founder's decision, 23 Aug 2026. */
.page--about .about-sec > .container.mw-780.tac { margin-inline: auto; text-align: center; }
/* The lede carries its own 760px cap, from before the reading column
   existed. It made the one paragraph on the page with a private width
   and a private left edge — 760 against the body's 847, starting at
   374 against 330. It keeps its size and its centring; it just stops
   measuring itself. */
.page--about .about-lede { max-width: none; }
/* Founder, 13 Sep 2026: the statement sits on the Fly card's white
   (.value-card), and the subtitle under "Why BeeBhakti?" reads at the
   story's size. Not the New to bhakti page, which shares page--about. */
.about-statement .about-lede:first-child { margin-top: 0; }
.page--about:not(.page--welcome) .page-head-sub { font-size: clamp(17px, 0.13vw + 16.4px, 18.5px); line-height: 1.85; }
.page--about .about-sec > .container.mw-780.tac .prose { text-align: center; }
.page--about .section-philosophy .section-head,
.page--about .section-philosophy .h2,
.page--about .about-cta .container { text-align: center; }
.page--about .section-philosophy > .container,
.page--about .about-cta > .container { margin-inline: auto; }
/* New to bhakti? has no statement blocks: its last section is markup
   from before this system and its .tac is not a declaration, so it
   stays with the body copy. */
.page--about.page--welcome .about-sec > .container.mw-780.tac {
  /* Centred on the shell like every other reading column — only the
     text inside it stays left. Pinned to margin-inline:0 it sat on the
     shell edge at 233 while its neighbours sat at 388, which is one
     section out of line down the whole page. */
  margin-inline: auto; text-align: left;
}
.page--about.page--welcome .about-sec > .container.mw-780.tac .prose { text-align: left; }

/* ── About page ──────────────────────────────────────────────────
   Banded sections in the site's shared rhythm: white → petal →
   white → petal → dusk CTA. Nav cards reuse the journey-card
   system; the fly/bee metaphor gets a side-by-side pair. */
.about-sec { padding: var(--section-pad-y) var(--page-pad-x); }
.about-sec--petal { background: var(--page-soft); }
.about-sec .section-head { text-align: center; }

.duo-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-md);
  max-width: min(100%, clamp(860px, 62vw, 1120px)); margin: 0 auto;
}
.duo-card {
  container-type: inline-size;
  position: relative; overflow: hidden; background: var(--surface);
  border: 1px solid #E8C06033; border-radius: 16px;
  padding: clamp(22px, 2vw, 38px) clamp(20px, 1.9vw, 36px); text-align: left;
}
   /* muted, faded — the fly's world */
.duo-accent {
  position: absolute; top: 0; left: 0; right: 0; height: 4px;
  background: linear-gradient(90deg, var(--c), color-mix(in srgb, var(--c) 40%, transparent));
}
.duo-title { font-family: var(--font-serif); font-size: 22px; color: var(--c); margin-bottom: 10px; }
.duo-text { font-size: 14.5px; line-height: 1.7; color: var(--text-mid); }
.duo-title { font-size: clamp(22px, 5.4cqi, 27px); }
.duo-text { font-size: clamp(14.5px, 3.9cqi, 16.5px); }

.about-cta {
  position: relative; overflow: hidden; text-align: center;
  padding: calc(var(--section-pad-y) * 1.15) var(--page-pad-x);
  background: linear-gradient(160deg, var(--dusk), var(--deep-earth));
}
.about-cta-title { font-family: var(--font-serif); font-weight: 300; font-size: clamp(26px, 3vw, 48px); color: var(--cream); margin-bottom: 10px; }
.about-cta-sub { font-size: clamp(15px, 0.18vw + 14.4px, 18px); color: #F5EFE685; margin-bottom: clamp(24px, 2.4vw, 40px); }
.about-cta-row { display: flex; gap: var(--gap-sm); justify-content: center; flex-wrap: wrap; }

@media (max-width: 700px) {
  .duo-grid { grid-template-columns: 1fr; gap: 14px; }
}

/* Trust facts on the About page: four cards. Two by two on a laptop,
   four across once each one can still hold a readable paragraph —
   held at 2×2 they became 660px-wide cards with three lines in them.
   Fixed counts, not auto-fit: with exactly four cards an auto grid
   lands on three and leaves one alone on a second row. */
.duo-grid--wide { max-width: min(100%, clamp(1000px, 74vw, 1400px)); }
@media (min-width: 1560px) {
  .duo-grid--wide { grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: min(100%, var(--w-mid)); }
}

/* ── Consistent vertical rhythm ─────────────────────────────────
   Every homepage content section breathes the same amount: one
   shared vertical padding (the hero and footer keep their own
   proportions). --section-pad-y is defined once in the token block
   as clamp(48px, 5.2vw, 108px), so the rhythm opens up continuously
   from a phone to a large display rather than switching between two
   fixed values at 700px. Horizontal padding is untouched. */
.section-featured, .section-philosophy, .section-bhakti, .section-verse, .seva, .about-sec, .listing, .section-support {
  padding-top: var(--section-pad-y);
  padding-bottom: var(--section-pad-y);
}

/* "All Levels": gatherings open to every stage of the journey */
:root { --lvl-all: #6E9DB8; }
.lvl-all { --c: var(--lvl-all); }

/* ── A category colour used as a solid FILL ──────────────────────
   A selected type pill and an active filter chip paint themselves in
   the category's own colour and write on top of it. Neither white nor
   the deep brown clears 4.5:1 on all sixteen: white fails on sage
   (2.9), the brown fails on festival (3.4). So the fill deepens —
   64% of the colour and 36% of --text-dark — and the writing takes
   --on-accent. Both tokens flip with the theme, so by day the chip is
   a deeper version of its colour under white letters (4.6:1 at worst)
   and at night a lighter version under near-black ones (10.2:1 at
   worst). The tint on a badge, the accent bar and the dot are
   untouched: this is only where the colour becomes a background for
   words (F70, 8 Sep 2026). */
.t-festival, .t-retreat, .t-workshop, .t-kirtan, .t-course, .t-temple,
.t-satsang, .t-pilgrimage, .t-online, .t-yoga, .t-other,
.lvl-open-to-all, .lvl-deepening, .lvl-developing, .lvl-invitation,
.lvl-new-to-bhakti, .lvl-all {
  --fill-share: 64%;
  --on-fill: var(--on-accent);
}

/* ═══ Membership & member preview (Phase 2) ══════════════════════ */

/* Presale badge on event cards — lotus pink, shaped like lvl-badge */
.presale-badge {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2.5px 9px; border-radius: 20px;
  font-size: 10px; font-weight: 700; letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--ember); border: 1px solid var(--ember)55;
  background: #F7C8C030;
  white-space: nowrap;
}
.panel-note--presale { color: var(--deep-earth); background: #F7C8C022; border-radius: 12px; padding: 12px 14px; }

/* Inline text link (buttons that read as links) */
.link-plain {
  background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; font-weight: 600; color: var(--honey);
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
}
.link-plain:hover { color: var(--deep-earth); }

/* Follow button on guide profiles (member preview) */
.follow-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 16px; border-radius: 50px; cursor: pointer;
  border: 1px solid var(--ember)55; background: var(--surface);
  color: var(--ember); font-size: 14px; font-family: var(--font-sans);
  transition: all .2s;
}
.follow-btn:hover { border-color: var(--ember); background: #F7C8C018; }
.follow-btn.on { background: var(--ember); border-color: var(--ember); color: var(--on-accent); font-weight: 600; }
.guide-heart { color: var(--ember); font-size: 15px; line-height: 1; }

/* MY GUIDES strip on the guides page */
.my-guides {
  background: var(--surface); border: 1.5px solid #E8C06035; border-radius: 16px;
  padding: 18px 20px; margin-bottom: 26px;
}
.my-guides-head {
  font-family: var(--font-sans); font-size: 12px; font-weight: 700;
  letter-spacing: .14em; color: var(--deep-earth); margin-bottom: 12px;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.my-guides-badge {
  font-size: 10px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ember);
  border: 1px solid var(--ember)45; background: #F7C8C025;
  border-radius: 20px; padding: 2.5px 9px;
}
.my-guides-sub { font-size: 13.5px; color: var(--text-light); margin: 12px 0 0; line-height: 1.55; }

/* ── The welcome ──────────────────────────────────────────────
   The invitation opens on a soft wax surface — the same comb the
   rails use, so joining feels like stepping into the hive rather
   than reading a pitch panel. The texture melts away downward so
   the page carries on without a seam. */
.hb-welcome {
  position: relative; overflow: hidden;
  padding: var(--section-pad-y) var(--page-edge) calc(var(--section-pad-y) * .85);
}
.hb-welcome::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background-color: #E8D5AE24;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='34.64' viewBox='0 0 30 34.64'%3E%3Cg fill='none' stroke='%23A87C2E' stroke-width='0.85' opacity='0.055'%3E%3Cpolygon points='15,2 28,9.5 28,25 15,32 2,25 2,9.5'/%3E%3Cpolygon points='30,19 43,26.5 43,42 30,49.5 17,42 17,26.5'/%3E%3C/g%3E%3C/svg%3E"),
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--surface) 54.90%, transparent) 0%, #FFFFFF00 70%);
  background-size: 46px 53.1px, auto;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 100%);
}
/* The composition takes a proper share of a wide screen while each
   block inside it keeps its own reading measure: the headline may
   use the full width, the paragraphs stay near 64ch, the quote
   narrower still. Capped at 880px before, which left the whole
   invitation stranded in a column down the middle of a 1920 display
   with 500px of empty page on either side. */
.hb-welcome-inner {
  position: relative; z-index: 1; text-align: center;
  width: min(100%, 1200px); max-width: none; margin-inline: auto;
}
.hb-welcome-title {
  font-family: var(--font-serif); font-weight: 400;
  font-size: clamp(28px, 3vw, 52px); line-height: 1.15;
  color: var(--deep-earth); margin: 0 auto clamp(16px, 1.5vw, 28px);
  /* Its own measure inside the wider composition, so it never runs
     the full 1200px as a single very long line */
  max-width: min(100%, 1000px);
}
/* The first line carries the honeybee image, so it is given a
   little more air and weight than the explanation beneath it */
.hb-welcome-lead {
  font-size: 16.5px; line-height: 1.85; color: var(--text-mid);
  margin: 0 auto 16px; max-width: 64ch;
}
.hb-welcome-lead--first {
  font-family: var(--font-serif); font-size: clamp(18px, 2.2vw, 21px);
  line-height: 1.7; color: var(--deep-earth); margin-bottom: 20px;
}
.hb-welcome-lead:last-child { margin-bottom: 0; }

.hb-join { margin-top: 34px; display: flex; flex-direction: column; align-items: center; gap: 0; }
.bg--lg { padding: 16px 34px; font-size: 16px; }
.hb-join-support {
  font-family: var(--font-serif); font-style: normal;
  font-size: 16px; color: var(--text-mid); margin: 16px 0 0;
}
.hb-join-price { font-size: 13px; color: var(--text-light); margin: 6px 0 0; }
.hb-join-signin { font-size: 13.5px; color: var(--text-light); margin: 18px 0 0; }
/* The door at the foot of the membership page (pre-launch review,
   24 Aug 2026): same button, same words as the homepage's. */
.jh-close-join { margin-top: 22px; }
/* Delete my account, at the foot where it belongs — quiet, centred,
   under Log out. */
.account-delete { margin: 16px auto 0; max-width: 52ch; font-size: 13px; }

/* ── Why there is a membership — the open answer ───────────────
   A plain accordion: one question visible at a time, the first
   already open. Bordered rows rather than cards, so the section
   stays calm next to the benefit tiles above it. *//* Founding Honeybees — early members and supporters */
.founding-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, clamp(150px, 11vw, 210px)), 1fr));
  gap: var(--gap-md); max-width: min(100%, clamp(720px, 52vw, 1100px)); margin: 0 auto;
}
.founding-card {
  background: var(--surface); border: 1.5px solid #E8C06035; border-radius: 18px;
  padding: 22px 16px; text-align: center;
  box-shadow: 0 2px 10px #5B3E1F08;
  transition: transform .2s ease, box-shadow .2s ease;
}
.founding-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 22px #5B3E1F14;
}
.founding-photo {
  width: 72px; height: 72px; border-radius: 50%; object-fit: cover;
  margin: 0 auto 12px; display: block; border: 2px solid #E8C06055;
}
.founding-photo--ph {
  background: var(--grad-honey);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-serif); font-size: 28px; color: var(--on-dark);
}
.founding-name { font-family: var(--font-sans); font-weight: 600; font-size: 15px; color: var(--deep-earth); }
.founding-line { font-size: 13px; color: var(--text-light); margin-top: 3px; line-height: 1.5; }

/* Members' Monthly Gathering card (My Account) */
.gathering-topic { margin: 0; font-family: var(--font-serif); font-size: 19px; color: var(--text-dark); line-height: 1.35; }
.gathering-guest { margin: 0; font-size: 14px; font-weight: 600; color: var(--honey-text, var(--honey)); }

/* ═══ Listing tiers & add-ons (Phase 3) ══════════════════════════ */
/* Four durations now (14 / 30 / 60 / 90). Fixed column counts rather
   than auto-fit, so the set never breaks into a lonely orphan row —
   4 across, then 2×2, then a single column on phones. */
.listing-grid--four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Four across only once each plan can still show its price and
   feature list comfortably (~250px); below that, two by two */
@media (max-width: 1149.98px) { .listing-grid--four { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 559.98px) { .listing-grid--four { grid-template-columns: 1fr; } }
/* At four across the cards are narrower — ease the padding and let
   the price note wrap rather than overflow */
.listing-grid--four .plan-price-note { white-space: normal; }
/* A listing card given more room states its price larger, rather
   than leaving the extra width blank — scaled off the card itself */
.plan-price { font-size: clamp(34px, 11cqi, 50px); }
.plan-for { font-size: clamp(14px, 4cqi, 16px); }

/* What happens when a listing period ends — stated before payment,
   never left to be discovered afterwards. Sits on the same centred
   measure as the intro above it, so the section reads down one
   spine instead of stepping in and out. */
.listing-ends {
  display: flex; align-items: flex-start; gap: 12px;
  max-width: var(--listing-measure, min(100%, 800px));
  margin: var(--listing-step, 40px) auto 0;
  padding: clamp(16px, 1.4vw, 26px) clamp(18px, 1.7vw, 32px); border-radius: 16px;
  background: #E8C0601A; border: 1px solid #E8C06038; text-align: left;
}
.listing-ends-star { color: var(--honey-text); font-size: 14px; line-height: 1.75; flex: none; }
.listing-ends-text { margin: 0; font-size: 14px; line-height: 1.75; color: var(--text-mid); }
.listing-ends-text strong { color: var(--deep-earth); font-weight: 600; }

/* The add-on block is a continuation of the pricing block, not a
   separate island: its heading uses the section's own step, and the
   gap under it matches the gap under the section heading. */

/* The chosen listing, restated where the decision is made: price and
   duration on one line, then what happens when the days run out. */
.tier-summary {
  margin: 16px 0 4px; padding: 16px 18px; border-radius: 12px;
  background: var(--surface); border: 1.5px solid var(--honey);
}
.tier-summary-price {
  font-family: var(--font-mono); font-size: 19px; font-weight: 600;
  color: var(--deep-earth); letter-spacing: -.01em; margin-bottom: 8px;
}
.tier-summary-ends { margin: 0; font-size: 13px; line-height: 1.7; color: var(--text-mid); }


/* Official-directory pointer at the top of the Sacred Places tab */
.places-official {
  background: #E8C06012; border: 1px dashed #E8C06045; border-radius: 12px;
  padding: 14px 18px; margin: -8px 0 30px;
  font-size: 14px; color: var(--text-mid); line-height: 1.6; text-align: center;
}
.places-official a { color: var(--honey); font-weight: 600; white-space: nowrap; }
.guide-empty-more { margin: 14px 0 0; font-size: 14px; }
.guide-empty-more a { color: var(--honey); font-weight: 600; }

/* ═══ Flat event map (Leaflet prototype) ═════════════════════════ */
.map-view-row {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 12px; margin-bottom: 10px;
}

.map-flat { position: relative; }
.map-flat-canvas {
  /* Sized by the window it is in, both ways: taller on a large
     display, shorter on a laptop in a half-height window, so the
     results list below it is never pushed entirely off-screen. svh
     keeps mobile browser chrome out of the calculation. */
  height: clamp(340px, 56svh, 720px); width: 100%;
  border-radius: 18px; overflow: hidden;
  /* The one blue line: the map's frame carries the globe's blue,
     while the canvas itself stays neutral for legibility */
  border: 2px solid #6E9DB8;
  box-shadow: 0 0 0 4px #6E9DB818, 0 6px 20px #295B8E14;
  background: #EDEAE2; /* holds the space while tiles arrive */
  z-index: 0;          /* keep Leaflet's panes under the site nav */
}
/* The basemap stays deliberately neutral (tried a blue-tinted
   version; it fought the markers and labels): on the quiet grey
   canvas the honey clusters and pink lotuses carry the brand. */
/* Place-name lettering stays UNTINTED (Esri's native near-black):
   a blue tint was tried and read poorly on phones — dark text is
   the legible choice, and the blue lives in the map's frame. */
.map-flat-loading {
  position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; pointer-events: none;
  font-family: var(--font-sans); font-size: 14px; color: var(--text-light);
  letter-spacing: .06em;
  /* Above Leaflet's panes (they stack 200–700): since 25 Aug 2026
     this overlay also covers the wait for the gatherings, when the
     map beneath it is already alive. Contained by .rail-content's
     own stacking context, so it can never rise over the site nav. */
  z-index: 800;
}

/* Lotus pins: the same artwork as the globe, sized for the map */
.bb-lotus-pin { background: none; border: none; }
.bb-lotus-pin svg { width: 34px; height: 34px; display: block; margin: 5px; filter: drop-shadow(0 2px 3px rgba(58,32,10,.35)); }

/* Cluster bubbles: honey gold with a soft bloom */
.bb-cluster { background: none; border: none; }
.bb-cluster div {
  width: 42px; height: 42px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 32% 30%, #E8B84B, #C9952E);
  border: 2.5px solid #FBF6EE;
  box-shadow: 0 3px 10px rgba(91,62,31,.35), 0 0 0 5px rgba(212,161,65,.18);
  /* White on this honey reads 1.84:1 at the gradient's light end and
     2.68:1 at its dark end — a number that has been live since the
     baseline and fails AA in both appearances. The same ink the site
     already puts on a honey fill reads 8.19:1 and 5.62:1 by day,
     10.08:1 and 6.92:1 at night (D379).

     The cream border and the honey itself are deliberately NOT
     themed: the map keeps its daylight tiles at night, so a bubble
     sits on a pale ground whichever appearance is on. */
  color: var(--on-accent-strong); font-family: var(--font-sans); font-weight: 700; font-size: 14.5px;
}

/* Marker tooltip in the brand voice */
.bb-map-tip {
  background: #FBF6EE; border: 1px solid #E8C06055; border-radius: 10px;
  color: var(--text-dark); font-family: var(--font-sans); font-size: 12.5px;
  line-height: 1.45; padding: 7px 11px;
  box-shadow: 0 4px 14px rgba(91,62,31,.18);
}
.bb-map-tip strong { color: var(--deep-earth); }
/* Leaflet's own stylesheet is injected at runtime (app.jsx loadStyle),
   so it lands AFTER this file, and its `.leaflet-tooltip { color: #222 }`
   ties with `.bb-map-tip` on specificity — later wins, so the tip's
   second line has always been #222 whatever the rule above asked for.
   On cream that is an ordinary dark grey and nobody saw it. On the
   night surface it is 1.11:1, which is invisible. The compound
   selector outranks Leaflet's instead of relying on file order; the
   `:root[data-theme="dark"]` rule further down still outranks this. */
.leaflet-tooltip.bb-map-tip { color: var(--text-dark); }
.bb-map-tip::before { border-top-color: #E8C06055; }

/* Leaflet chrome, softened to the brand */
.map-flat .leaflet-control-zoom a {
  color: var(--deep-earth); border-color: #E8C06045;
}
.map-flat .leaflet-control-attribution {
  background: rgba(251,246,238,.85); color: var(--text-light);
  font-size: 10px; border-radius: 8px 0 0 0;
}
.map-flat .leaflet-control-attribution a { color: var(--text-mid); }

@media (max-width: 700px) {
  .map-flat-canvas { height: clamp(320px, 50svh, 480px); border-radius: 14px; }
}

/* One lotus per city: count badge + the city's gathering list */
.bb-lotus-count {
  position: absolute; top: -2px; right: -4px;
  min-width: 19px; height: 19px; padding: 0 5px;
  border-radius: 12px; display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 32% 30%, #E8B84B, #C9952E);
  border: 1.5px solid #FBF6EE;
  /* Same white-on-honey as the cluster bubble, and worse: 11px is
     small text, so AA asks 4.5:1 and it was reading 1.84:1 (D379). */
  color: var(--on-accent-strong); font-family: var(--font-sans); font-weight: 700; font-size: 11px;
  box-shadow: 0 2px 6px rgba(91,62,31,.35);
}
.bb-city-popup .leaflet-popup-content-wrapper {
  background: #FBF6EE; border: 1px solid #E8C06055; border-radius: 14px;
  box-shadow: 0 10px 30px rgba(91,62,31,.25);
}
.bb-city-popup .leaflet-popup-content { margin: 10px 12px; }
.bb-city-popup .leaflet-popup-tip { background: #FBF6EE; border: 1px solid #E8C06055; }
.bb-city-pop { display: flex; flex-direction: column; gap: 6px; min-width: 210px; }
/* The heading stays put and the list scrolls under it. Without a
   height limit the box grew past the map and the last of twenty
   gatherings at Govardhan Ecovillage was simply unreachable.
   50vh keeps it inside the map on a phone; 360px stops it becoming a
   column of its own on a desktop. */
.bb-city-pop-head { flex: none; }
.bb-city-pop-list {
  display: flex; flex-direction: column; gap: 6px;
  /* Fallback only — app.jsx sets an exact pixel height from the map's
     own size when it opens the popup. This is what applies if that
     ever fails to run. */
  max-height: min(50vh, 360px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  /* Room for the scrollbar so it never sits on top of a card's edge. */
  padding-right: 2px;
}
.bb-city-pop-head {
  font-family: var(--font-sans); font-size: 12px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--deep-earth);
  padding: 2px 4px 6px; border-bottom: 1px solid #E8C06035;
}
.bb-city-pop-item {
  display: flex; flex-direction: column; gap: 2px; text-align: left;
  background: var(--surface); border: 1px solid #E8C06035; border-radius: 10px;
  padding: 9px 11px; cursor: pointer; transition: all .18s;
  font-family: var(--font-sans);
}
.bb-city-pop-item:hover { border-color: var(--honey); transform: translateY(-1px); }
/* The handoff out of the popup and into the list below the map. Reads
   as a link rather than another card, so it is not mistaken for a
   fifth gathering. */
.bb-city-pop-all {
  flex: none; margin-top: 2px; padding: 8px 4px;
  background: none; border: none; cursor: pointer;
  font-family: var(--font-sans); font-size: 12.5px; font-weight: 600;
  color: var(--honey); text-align: left; line-height: 1.4;
}
.bb-city-pop-all:hover { color: var(--deep-earth); }
/* The heading the popup sends people to, clear of the sticky nav. */
#gathering-results { scroll-margin-top: 96px; }
.bb-city-pop-item strong { font-size: 13.5px; color: var(--deep-earth); line-height: 1.35; }
.bb-city-pop-item span { font-size: 12px; color: var(--text-light); font-family: var(--font-mono); }

/* About page: four doors into the site, two by two — and four across
   once the page is wide enough to give each one a real card */
.journey-grid--four { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: min(100%, clamp(860px, 62vw, 1120px)); margin: 0 auto; }
@media (min-width: 1500px) { .journey-grid--four { grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: min(100%, var(--w-mid)); } }
@media (max-width: 700px) { .journey-grid--four { grid-template-columns: minmax(0, 1fr); } }

/* Member sign-in (beta) */
.signin-card {
  background: var(--surface); border: 1.5px solid #E8C06035; border-radius: 18px;
  padding: clamp(26px, 2.4vw, 44px) clamp(24px, 2.2vw, 40px); max-width: min(100%, clamp(420px, 32vw, 560px)); margin: 0 auto;
  display: flex; flex-direction: column; gap: 4px;
}
/* ═══ Account menu (nav) ═════════════════════════════════════════ */
/* One avatar entry point in the nav; My Account and Sign out live
   in its dropdown — the profile-menu pattern every member knows. */
.account-menu { position: relative; display: flex; align-items: center; }
.account-btn {
  display: flex; align-items: center;
  background: none; border: none; cursor: pointer; padding: 0;
}
.account-avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: 0 0 30px;
  background: var(--grad-honey); color: var(--on-accent-strong);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-sans); font-weight: 700; font-size: 14px;
  box-shadow: 0 2px 8px #D4A14140;
}
.account-btn:hover .account-avatar { box-shadow: 0 3px 12px #D4A14170; }
.account-btn.on .account-avatar { outline: 2px solid var(--honey); outline-offset: 2px; }
/* Signed out, the same button wears an outlined person instead of an
   avatar — the one door to Log in and Membership, so the nav row
   itself stays purely the site's own pages */
.account-icon {
  width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-mid); border: 1.5px solid #8B623030;
  transition: color .2s ease, border-color .2s ease, background .2s ease;
}
.account-btn--icon:hover .account-icon, .account-btn--icon[aria-expanded="true"] .account-icon {
  color: var(--honey-text, var(--honey)); border-color: var(--honey); background: #E8C06018;
}
.account-btn--icon.on .account-icon {
  color: var(--honey-text, var(--honey)); border-color: var(--honey);
}
/* The day/night switch (F67, 7 Sep 2026): one tap flips it. The
   icon is the mode it switches TO — a moon by day, a sun by night —
   the same shape as the account door beside it, with a 44px target
   round a 34px ring. In the drawer it is a row with the word. */
.theme-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin: -5px 0; padding: 0;
  background: none; border: none; cursor: pointer; color: var(--text-mid);
}
.theme-icon {
  width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid #8B623030;
  transition: color .2s ease, border-color .2s ease, background .2s ease;
}
.theme-btn:hover .theme-icon { color: var(--honey-text, var(--honey)); border-color: var(--honey); background: #E8C06018; }
.mobile-menu-link--theme { gap: 12px; }
.mobile-menu-link--theme .theme-ic { display: inline-flex; color: var(--honey); }
.account-dropdown {
  position: absolute; top: calc(100% + 14px); right: 0; min-width: 200px;
  background: var(--surface); border: 1px solid #E8C06040; border-radius: 14px;
  box-shadow: 0 12px 36px #5B3E1F22; padding: 8px; z-index: 300;
  animation: acct-in .16s ease;
}
@keyframes acct-in{
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
.account-dropdown-head {
  font-size: 12px; color: var(--text-light); padding: 8px 12px 10px;
  border-bottom: 1px solid #8B623015; margin-bottom: 6px; white-space: nowrap;
}
.account-dropdown-head strong { color: var(--deep-earth); font-weight: 600; }
.account-dropdown-item {
  display: block; width: 100%; text-align: left;
  background: none; border: none; cursor: pointer;
  font-family: var(--font-sans); font-size: 14px; color: var(--text-mid);
  padding: 10px 12px; border-radius: 9px; transition: background .15s ease;
  text-decoration: none;
}
.account-dropdown-item:hover { background: #E8C06018; color: var(--deep-earth); }
.account-dropdown-item.on { color: var(--honey-text, var(--honey)); font-weight: 600; }
.account-dropdown-item--signout { color: var(--text-light); }

/* My Account */
.account-body { display: flex; flex-direction: column; gap: 18px; }
.account-card {
  background: var(--surface); border: 1.5px solid #E8C06035; border-radius: 18px;
  padding: 24px 26px; display: flex; flex-direction: column; gap: 12px;
  align-items: flex-start;
  box-shadow: 0 2px 10px #5B3E1F08;
}
.account-card-head {
  font-family: var(--font-sans); font-size: 12px; font-weight: 700;
  letter-spacing: .14em; color: var(--text-light);
}
.account-line { margin: 0; font-size: 15px; color: var(--text-mid); }
.account-status { color: #7A8C5E; font-weight: 600; }
.account-dim { margin: 0; font-size: 14px; color: var(--text-light); line-height: 1.6; }

/* ═══ Sacred calendar strip ══════════════════════════════════════ */
.sacred-strip {
  position: relative; overflow: hidden;
  background: var(--page-soft);
  padding-top: var(--section-pad-y); padding-bottom: var(--section-pad-y);
}
/* The calendar as plain content inside the Resources column — no
   tinted strip, no heading of its own (the category supplies it) */
.sacred-bare { position: relative; }
.sacred-card {
  background: var(--surface); border-radius: 16px; padding: clamp(18px, 1.6vw, 30px) clamp(20px, 1.7vw, 32px);
  border: 1px solid color-mix(in srgb, var(--c, var(--honey)) 22%, transparent);
  border-left: 4px solid var(--c, var(--honey));
  display: flex; flex-direction: column; gap: 7px; align-items: flex-start;
}
.sacred-when { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.sacred-date {
  font-family: var(--font-mono); font-size: 13px; font-weight: 600;
  color: var(--deep-earth); letter-spacing: .04em; text-transform: uppercase;
}
.sacred-in { font-size: 12px; font-weight: 700; color: var(--c, var(--honey)); }
.sacred-name { font-family: var(--font-serif); font-size: 19px; color: var(--text-dark); line-height: 1.3; }
.sacred-note-text { font-size: 13.5px; color: var(--text-light); line-height: 1.55; }
.sacred-note { font-size: 13px; color: var(--text-light); text-align: center; margin: 0; }
/* Ekadasi dates for where you are (F97): one quiet control under the
   calendar, and the break fast on each Ekadasi card once it applies.
   Honey text for the time, as the calendar's own "in N days" uses. */
.sacred-place {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  margin: 0 auto clamp(12px, 1.4vw, 18px); text-align: center; max-width: 60ch;
}
.sacred-place-btn { min-height: 44px; }
.sacred-place-line { margin: 0; font-size: 14px; color: var(--text-mid); line-height: 1.6; }
.sacred-place-ic { display: inline-flex; vertical-align: -2px; margin-right: 6px; }
.sacred-place-hint { margin: 0; font-size: 12.5px; color: var(--text-light); line-height: 1.5; }
.sacred-parana { margin-top: 4px; font-size: 13px; font-weight: 600; color: var(--honey-text); }
/* On the account card the control sits left, with the card's text. */
.account-card .sacred-place { align-items: flex-start; text-align: left; margin: 0; }

/* Month-grid calendar */
/* The month grid keeps a sensible proportion of the row as the page
   widens rather than staying a fixed slab beside a stretching list */
.cal-wrap { display: grid; grid-template-columns: minmax(280px, clamp(340px, 26vw, 480px)) minmax(0, 1fr); gap: var(--gap-lg); margin-bottom: 22px; align-items: start; }
@media (max-width: 760px) { .cal-wrap { grid-template-columns: minmax(0, 1fr); } }
.cal {
  background: var(--surface); border: 1.5px solid #E8C06035; border-radius: 18px;
  padding: clamp(16px, 1.4vw, 26px) clamp(16px, 1.4vw, 26px) clamp(12px, 1.1vw, 20px);
}
.cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.cal-month { font-family: var(--font-serif); font-size: 19px; color: var(--deep-earth); }
.cal-nav {
  width: 34px; height: 34px; border-radius: 50%; border: 1px solid #E8C06055;
  background: var(--surface); color: var(--deep-earth); font-size: 18px; cursor: pointer;
  display: flex; align-items: center; justify-content: center; transition: all .2s;
}
.cal-nav:hover:not(:disabled) { border-color: var(--honey); color: var(--honey); }
.cal-nav:disabled { opacity: .3; cursor: default; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.cal-dow {
  text-align: center; font-family: var(--font-sans); font-size: 10.5px;
  font-weight: 700; letter-spacing: .08em; color: var(--text-light); padding: 4px 0 6px;
}
.cal-blank { height: 40px; }
.cal-day {
  position: relative; height: 40px; border-radius: 10px; border: none;
  background: none; font-family: var(--font-sans); font-size: 13.5px;
  color: var(--text-mid); display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px; cursor: default;
}
.cal-day.has {
  cursor: pointer;
  background: color-mix(in srgb, var(--c, var(--honey)) 12%, var(--surface));
  color: var(--deep-earth); font-weight: 700;
}
.cal-day.has:hover { background: color-mix(in srgb, var(--c, var(--honey)) 22%, var(--surface)); }
.cal-day.on { outline: 2px solid var(--c, var(--honey)); }
.cal-day.today .cal-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  border: 1.5px solid var(--honey); color: var(--deep-earth); font-weight: 700;
}
.cal-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--c, var(--honey)); }
.cal-legend { display: flex; gap: 14px; justify-content: center; margin-top: 12px; flex-wrap: wrap; }
.cal-legend-item { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-light); }
.cal-legend-dot { width: 8px; height: 8px; border-radius: 50%; }
.cal-list { display: flex; flex-direction: column; gap: 12px; }
.cal-empty { margin: 0; font-size: 14px; color: var(--text-light); line-height: 1.6; }
.sacred-card.is-past { opacity: .55; }

/* Homepage upcoming-events calendar: month grid on the left, the
   three next gatherings (or the chosen day's) stacked on the right.
   The grid itself reuses the .cal-* rules above. */
.ucal-wrap {
  display: grid; grid-template-columns: minmax(280px, clamp(340px, 25vw, 460px)) minmax(0, 1fr);
  gap: var(--gap-xl); align-items: start;
}
@media (max-width: 900px) { .ucal-wrap { grid-template-columns: minmax(0, 1fr); } }
.ucal-hint {
  margin: 12px 0 0; text-align: center; font-size: 12.5px;
  color: var(--text-light); line-height: 1.5;
}
/* The three next gatherings beside the month grid. A column while
   the space is narrow; as the panel widens they lay out two or three
   across instead of becoming 1000px-wide banners with two lines in
   them — and the block ends up a similar height to the calendar. */
.ucal-list {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: var(--gap-grid); align-content: start;
}

/* ── The calendar's list of gatherings (founder, 12 Sep 2026 — F117) ──
   Three picture cards showed three gatherings; a day can hold twenty.
   One tappable line each — where it is, what it is, when — so a day is
   read at a glance and every line still opens the gathering. Two lines
   on a phone (name, then place), one line from 768px up. Same tokens;
   no new colour. */
/* One gathering per line, reading down. The container was a grid of
   card columns (auto-fit, 320px minimum), which put two rows side by
   side on a wide screen and squeezed every name. */
.ucal-list { grid-template-columns: minmax(0, 1fr); gap: 0; }
/* F118 (founder, 13 Sep 2026): each row simplified to three quiet
   lines — the place; the name with its time on the right; who holds it,
   smaller and softer. The day's heading already says the date, so the
   right-hand side no longer repeats it (calendarRowWhen in app.jsx
   decides what goes there). */
.ucal-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 1px 12px;
  align-items: baseline; min-height: 44px; padding: 7px 2px;
  border-bottom: 1px solid #E8C06035; text-decoration: none; color: inherit;
}
.ucal-row:last-child { border-bottom: 0; }
.ucal-row:hover .ucal-row-name { color: var(--honey-text, var(--honey)); }
.ucal-row-where {
  grid-column: 1 / -1; grid-row: 1; min-width: 0; font-size: 12.5px; line-height: 1.35;
  color: var(--text-light); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ucal-row-where .card-flag { margin-right: 6px; }
.ucal-row-name {
  grid-column: 1; grid-row: 2; min-width: 0; font-weight: 600; font-size: 15px; line-height: 1.3;
  color: var(--deep-earth); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.skel--row { height: 16px; width: min(70%, 320px); border-radius: 8px; }
.ucal-row-when {
  grid-column: 2; grid-row: 2; text-align: right;
  font-size: 13px; color: var(--text-mid); white-space: nowrap;
  font-variant-numeric: tabular-nums;
  /* Short by construction now — "18:30", "3-day retreat", "Until
     Sunday" — but still bounded, so the name is never the one to give
     way to it. */
  max-width: 45vw; overflow: hidden; text-overflow: ellipsis;
}
.ucal-row-hosts {
  grid-column: 1 / -1; grid-row: 3; min-width: 0; font-size: 12.5px; line-height: 1.35;
  color: var(--text-light); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* "On mobile, always prefer one name + X more": both of a pair are
   named only where there is room. */
.ucal-row-hosts-full { display: none; }
@media (min-width: 768px) {
  .ucal-row { padding: 10px 2px; }
  .ucal-row-name { font-size: 16px; }
  .ucal-row-when { max-width: 220px; }
  .ucal-row-hosts-short { display: none; }
  .ucal-row-hosts-full { display: inline; }
}
/* The chosen day's header is a HEADER, not a card: it has to span the
   whole row. Without this it takes one grid cell like a gathering
   would, which pushed the cards into a staggered arrangement and left
   a card-sized hole beside the date. */
/* The optional way past the personalisation step, set apart from the
   save button so it reads as the quieter of the two choices. */
/* The flyer picker. The native control is left in place (it is the
   one widget every device already knows how to drive, including
   "take a photo" on a phone) and only dressed to match the fields
   above it. */
.inp--file {
  padding: 11px 14px; cursor: pointer; line-height: 1.4;
}
.inp--file::file-selector-button {
  margin-right: 12px; padding: 7px 14px; border-radius: 20px;
  border: 1px solid #D4A14155; background: var(--page-soft);
  font-family: var(--font-sans); font-size: 13px; font-weight: 600;
  color: var(--deep-earth); cursor: pointer;
  transition: background .2s, border-color .2s;
}
.inp--file::file-selector-button:hover {
  background: var(--hover); border-color: var(--honey);
}

.pf-skip { margin: 14px 0 0; text-align: center; font-size: 13.5px; }

/* The chosen day's header. It held a second element until 8 Sep 2026
   — a button out to the default list — which is what the flex row and
   its space-between were arranging. Now it is one date, so the row is
   simply a row that spans the grid: .ucal-list is a card grid, and
   without the span this would take a gathering's cell and sit beside
   two cards. */
.ucal-daybar {
  grid-column: 1 / -1;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 12px;
  /* F117: the list below it is a single column with no gap, so the
     header keeps the air it used to get from the grid. */
  margin-bottom: 8px;
}
.ucal-dayname { font-family: var(--font-serif); font-size: 19px; color: var(--deep-earth); }

/* Forward and back through the sets of three under the calendar
   (founder, 8 Sep 2026). Spans the whole row like the day header
   above it, for the same reason: it is not a gathering, so it must
   not take a gathering's grid cell.

   The buttons reuse the day bar's own type and colour rather than
   introducing a control style — rule 2. Previous sits left and Next
   right when both are present; with only one, `space-between` would
   pin a lone Next to the left, so the row starts at the end and
   Previous pushes itself over with `margin-right: auto`. */
.ucal-steps {
  grid-column: 1 / -1;
  display: flex; align-items: center; justify-content: flex-end;
  gap: 12px; flex-wrap: wrap; margin-top: 4px;
}
.ucal-step {
  background: none; border: none; padding: 14px 4px; margin: -14px 0;
  cursor: pointer;
  font-family: var(--font-sans); font-size: 13px; font-weight: 600;
  /* --honey-text, not --honey. This was copied from .ucal-reset — the
     day header's own link, since removed — and copying its base rule
     was not enough: that rule was overridden further down by the
     contrast block ("gold text moves to the darker text gold"). Raw
     honey on cream measured 2.18:1 here before this line existed. The
     darker gold reads 4.94:1 by day and 8.95:1 at night. */
  color: var(--honey-text, var(--honey));
}
.ucal-step:hover { text-decoration: underline; }
.ucal-step:not(.ucal-step--fwd) { margin-right: auto; }

/* The transition the founder asked to keep "smooth and consistent
   with the existing BeeBhakti design": the site's own fade, on the
   cards only. Each set carries different gathering ids, so React
   swaps the elements and the entrance runs by itself — no key
   juggling, and the calendar beside it never remounts.

   fadeIn rather than fadeUp: fadeUp lifts 20px, and three cards
   sliding up under a fixed grid reads as the page moving rather than
   the cards arriving. */
.ucal-list > .ec { animation: fadeIn .3s ease-out both; }


/* Share options under the Share button */
.share-options { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 10px; }
button.chip-link { background: var(--surface); cursor: pointer; font-size: 14px; }

/* ═══ UX restructure (Aug 2026): intent shortcuts, suitability,
   memberships, free accounts, sheets, gated notice ═══════════════ */

/* (The homepage intent shortcuts have their own .intent-card system —
   see the "What are you looking for?" block at the end of this file.) */

/* Save button on a gathering page */
.save-btn.on { border-color: var(--honey); color: var(--deep-earth); background: var(--selected); }

/* The two contextual sheets — small, dismissible, bottom-anchored on
   a phone, centred on a desktop. The only prompts on the site. */
/* ── The sign-out farewell (pre-launch review, 24 Aug 2026) ──
   The site's one transient notice: says goodbye, leaves by itself,
   blocks nothing. Fixed to the foot so it works from any page. */
.signout-toast {
  /* Centred by margins, not transform: the fadeUp keyframe animates
     transform and would override a translateX(-50%) mid-animation. */
  position: fixed; left: 0; right: 0; bottom: 26px;
  width: fit-content;
  z-index: 300; max-width: min(92vw, 420px); margin: 0 auto;
  padding: 12px 22px; border-radius: 50px; text-align: center;
  background: var(--deep-earth); color: var(--warm-white);
  font-family: var(--font-sans); font-size: 13.5px; line-height: 1.5;
  box-shadow: 0 6px 24px rgba(58,32,10,.30);
  animation: fadeUp .35s ease both;
}

.sheet-scrim {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(35, 18, 4, 0.42);
  display: flex; align-items: flex-end; justify-content: center;
  padding: 0; animation: fadeIn .18s ease;
}
.sheet {
  background: var(--panel); border-radius: 18px 18px 0 0;
  padding: 26px 22px 30px; width: 100%; max-width: 520px;
  box-shadow: 0 -12px 40px rgba(58, 32, 10, 0.25);
  text-align: center;
}
@media (min-width: 700px) {
  .sheet-scrim { align-items: center; padding: 24px; }
  .sheet { border-radius: 18px; padding: 30px 32px; }
}
.sheet-title { font-family: var(--font-serif); font-weight: 400; font-size: 22px; color: var(--deep-earth); margin-bottom: 8px; }
.sheet-text { font-size: 14.5px; line-height: 1.6; color: var(--text-mid); margin-bottom: 18px; }
.sheet-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.sheet-foot { margin-top: 14px; font-size: 13.5px; color: var(--text-light); }

/* Sign-in page: the free-account card under the log-in card */
.signin-card--signup { margin-top: 26px; }
.signin-signup-sub { font-size: 14px; line-height: 1.6; color: var(--text-mid); margin-bottom: 16px; }
.signin-notice {
  font-size: 14px; line-height: 1.6; color: var(--deep-earth);
  background: var(--selected); border: 1px solid #E8C06055; border-radius: 12px;
  padding: 11px 14px; margin-bottom: 14px;
}

/* ═══ Membership page — "One membership. Personalised to your
   Bhakti journey." (the 2026 redesign) ═══════════════════════════
   One model, said once and repeated: same membership, same price,
   access matched to your practice. Honeybee and Bumblebee are
   access paths — warm honey and soft lavender surfaces, the same
   bee artwork on both — never pricing tiers, so the cards carry
   no prices and no hierarchy cues. */

/* The membership hero pill, the two access-path cards and the old
   three-step journey were removed with the Become Honeybee redesign
   (Aug 2026): the invitation now leads on a Free-membership panel,
   six benefit cards and a four-step "How it works", all under
   .jh-* below. The context cards, the role note and the closing
   band survive, because the member's own page still uses them. */

/* ── Different offerings, different contexts ──
   The three context labels, each on its own quiet card in its
   context colour. Facts about offerings, never about people.
   Three across on a desktop (founder, 2 Sep 2026: "the 3 labels on
   the same line") — the two-column grid they had left the third
   card alone on a second row. One column on a phone, as before. */
.mp-contexts {
  /* Four entries since FS-01 (6 Sep 2026): four across on a desktop,
     two by two on a tablet, one column on a phone. Each entry is
     styled exactly as before. */
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(12px, 1.6vw, 18px);
  max-width: min(100%, 1000px); margin: 0 auto;
}
@media (max-width: 899.98px) {
  .mp-contexts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.mp-context {
  background: var(--surface); border: 1px solid #E8C06044; border-radius: 16px;
  border-left: 4px solid var(--c, var(--honey));
  padding: clamp(16px, 1.8vw, 22px);
  text-align: left;
}
.mp-context-label {
  font-family: var(--font-sans); font-size: 14.5px; font-weight: 700;
  color: color-mix(in srgb, var(--c, var(--deep-earth)) var(--type-ink, 100%), var(--text-dark));
  margin-bottom: 6px;
}
.mp-context-desc {
  font-size: 13.5px; line-height: 1.6; color: var(--text-mid); margin: 0;
}
@media (max-width: 639.98px) {
  .mp-contexts { grid-template-columns: minmax(0, 1fr); }
}

/* BeeBhakti's role, under the practitioner preference: quiet,
   centred, a little apart from the states above it — and the
   positive principle lifted out as a pull quote below it */
.mp-role {
  text-align: center; font-size: 13.5px; line-height: 1.7;
  color: var(--text-light); max-width: 68ch;
  margin: clamp(20px, 2.4vw, 32px) auto 0;
}
.mp-role-quote { margin-top: clamp(16px, 2vw, 26px); }

/* The closing band: the model restated in one line */
.mp-close {
  background: #FBF3E2; border-top: 1px solid #E8C06033;
  padding: clamp(22px, 2.6vw, 34px) var(--page-pad-x);
}
.mp-close-inner {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 14px 18px;
  max-width: 900px; margin: 0 auto; text-align: center;
}
.mp-close-ic { display: inline-flex; align-items: center; }
.mp-close-line {
  font-family: var(--font-serif); font-size: clamp(16px, 1.6vw, 20px);
  line-height: 1.5; color: var(--deep-earth); margin: 0;
  text-wrap: balance;
  /* Shrink to a readable measure so the lotus and the bee sit
     either side of the line on one row */
  flex: 0 1 auto; max-width: 52ch;
}


/* ═══ Become Honeybee — the membership invitation ════════════════
   The signed-out /membership/ page. Its job is a decision, not a
   read: the name, one line of why, one line of what, the word
   "Free" at headline size, and a button. Everything below it is
   scannable (six benefit cards, four steps, one closing line), so
   the page carries almost no running prose. The signed-in version
   of the same route is the member's account and keeps the older
   editorial rhythm above.

   Nothing here invents colour: the surfaces are the site's wax and
   cream, the accents its honey, the headings its Montserrat. */

/* ── The hero ───────────────────────────────────────────────────
   Two columns on a wide screen — offer left, artwork right — on the
   same soft honeycomb wax the rest of the hive uses. The comb melts
   away downward so the benefits section begins without a seam. */
.jh-hero {
  position: relative; overflow: hidden;
  padding: clamp(26px, 3.6vw, 68px) var(--page-edge) clamp(30px, 4vw, 72px);
}
.jh-hero::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background-color: #E8D5AE24;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='34.64' viewBox='0 0 30 34.64'%3E%3Cg fill='none' stroke='%23A87C2E' stroke-width='0.85' opacity='0.055'%3E%3Cpolygon points='15,2 28,9.5 28,25 15,32 2,25 2,9.5'/%3E%3Cpolygon points='30,19 43,26.5 43,42 30,49.5 17,42 17,26.5'/%3E%3C/g%3E%3C/svg%3E"),
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--surface) 54.90%, transparent) 0%, #FFFFFF00 70%);
  background-size: 46px 53.1px, auto;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 100%);
}
.jh-hero-inner {
  position: relative; z-index: 1;
  width: min(100%, var(--w-wide)); margin-inline: auto;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.88fr);
  align-items: center; gap: clamp(18px, 2.6vw, 56px);
}
.jh-hero-copy { text-align: left; }
.jh-title {
  font-family: var(--font-serif); font-weight: 400;
  font-size: clamp(34px, 4.3vw, 68px); line-height: 1.04;
  letter-spacing: -0.012em; color: var(--deep-earth); margin: 0;
}
.jh-sub {
  font-family: var(--font-serif); font-weight: 400;
  font-size: clamp(17px, 1.7vw, 25px); line-height: 1.4;
  color: var(--text-mid); margin: clamp(10px, 1.1vw, 16px) 0 0;
}
/* The one supporting sentence, kept to a short measure so it stays
   a sentence and never grows into a paragraph */
.jh-lead {
  font-size: clamp(14px, 0.5vw + 12.6px, 16.5px); line-height: 1.65;
  color: var(--text-light); margin: clamp(9px, 0.9vw, 14px) 0 0;
  max-width: 44ch;
}

/* The offer: free first, then the single button that acts on it */
/* A panel rather than a shrink-wrapped label: it holds the width of
   the sentence above it, so "Free" reads as the page's offer and
   not as a chip tucked under the copy. */
.jh-offer {
  display: flex; flex-direction: column; align-items: center;
  width: min(100%, 420px);
  margin-top: clamp(18px, 2.2vw, 34px);
  background: linear-gradient(160deg, #FFFDF6, #FCF4E2);
  border: 1px solid #E8C06077; border-radius: 20px;
  padding: clamp(16px, 1.8vw, 26px) clamp(20px, 2.4vw, 38px);
  box-shadow: 0 12px 34px #8B623014;
  text-align: center;
}
.jh-free {
  font-family: var(--font-serif); font-weight: 400;
  font-size: clamp(19px, 1.7vw, 27px); line-height: 1.1;
  color: var(--text-mid); margin: 0 0 clamp(12px, 1.3vw, 18px);
  white-space: nowrap;
}
.jh-free-word {
  font-family: var(--font-serif); font-size: clamp(27px, 2.9vw, 44px);
  color: var(--deep-earth);
}
/* Exactly the header's "Share an event" pill (.nav-cta): same
   padding, size, weight and gap, sized to its own label. One button
   shape across the site, so the invitation's call to action never
   reads louder than the one in the header above it. */
.jh-btn {
  width: auto; gap: 8px; letter-spacing: .04em;
  padding: 9px 20px; font-size: 13px; font-weight: 500;
}
.jh-btn-arrow { transition: transform .3s; }
.jh-btn:hover .jh-btn-arrow { transform: translateX(4px); }
.jh-signin { font-size: 13px; color: var(--text-light); margin: 22px 0 0; }

/* ── The artwork ────────────────────────────────────────────────
   The mascot and the lotus, the two pieces of Bee Bhakti's own
   imagery, arranged as the bee arriving at the bloom. Decorative
   only: it carries no information the copy does not already say. */
.jh-hero-art {
  position: relative; align-self: center;
  aspect-ratio: 1 / 0.82; min-height: 210px;
}
.jh-art-glow {
  position: absolute; inset: 4% 2% 0; border-radius: 50%;
  background: radial-gradient(closest-side, #F3DFB255 0%, #F3DFB200 74%);
}
.jh-art-lotus {
  position: absolute; left: 10%; bottom: 1%; width: 70%; height: auto;
  filter: drop-shadow(0 16px 26px #8B623020);
}
.jh-art-bee-wrap {
  position: absolute; right: 3%; top: 5%; width: 44%;
  animation: jhBeeFloat 7s ease-in-out infinite;
}
.jh-art-bee {
  display: block; width: 100%; height: auto;
  transform: scaleX(-1) rotate(6deg);
  filter: drop-shadow(0 10px 18px #8B623026);
}
/* The float rides the wrapper, so the flip and the shadow on the
   image itself are rasterised once and only moved (F84). */
@keyframes jhBeeFloat{
  0%, 100% { transform: translateY(0)     rotate(0deg); }
  42%      { transform: translateY(-15px) rotate(-9deg); }
  74%      { transform: translateY(-5px)  rotate(-4deg); }
}
@media (prefers-reduced-motion: reduce) {
  .jh-art-bee-wrap { animation: none; }
}

/* ── Membership includes ────────────────────────────────────────
   Six cards, one row on a wide screen. Icon, two or three words,
   one short line: the section is read by scanning, not by reading. */
.jh-includes {
  position: relative; overflow: hidden; background: var(--page);
  padding: clamp(32px, 3.8vw, 74px) var(--page-pad-x);
}
.jh-steps {
  position: relative; background: var(--page-soft);
  padding: clamp(32px, 3.8vw, 74px) var(--page-pad-x);
}
/* Heading plus the small bee ornament beneath it, shared by both
   scannable sections so they read as a pair */
.jh-head {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  margin-bottom: clamp(20px, 2.2vw, 40px);
}
.jh-h2 { margin-top: 0; }
.jh-flourish { display: inline-flex; opacity: .45; }

.jh-grid {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--gap-grid); align-items: stretch;
}
.jh-card {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: 7px;
  background: color-mix(in srgb, var(--surface) 76.86%, transparent); border: 1px solid #E8C06055; border-radius: 16px;
  padding: clamp(15px, 1.5vw, 24px) clamp(9px, 0.9vw, 15px);
  transition: transform .3s, box-shadow .3s, border-color .3s;
}
.jh-card:hover {
  transform: translateY(-3px); border-color: #D4A14177;
  box-shadow: 0 10px 24px #8B623016;
}
.jh-card-ic { display: inline-flex; margin-bottom: 3px; }
/* Two of the six titles need a second line. Reserving it on all of
   them keeps every description on the same baseline, so the row
   still scans as one band rather than a ragged one. */
.jh-card-title {
  font-family: var(--font-sans); font-size: clamp(13px, 0.2vw + 12.4px, 14.5px);
  font-weight: 700; line-height: 1.25; color: var(--deep-earth); margin: 0;
  min-height: 2.5em;
  display: flex; align-items: center; justify-content: center;
}
/* A live benefit's icon sits to the left of its title (F57, 6 Sep 2026) */
.jh-card-title-ic { display: inline-flex; align-items: center; margin-right: 9px; flex-shrink: 0; }
.jh-card-desc {
  font-size: clamp(11.5px, 0.16vw + 11px, 13px); line-height: 1.5;
  color: var(--text-light); margin: 0;
}
/* What is not live yet says so, quietly. The account page carries
   the same list, and the two must never promise different things. */
.jh-soon {
  margin-top: auto; padding-top: 6px;
  font-family: var(--font-sans); font-size: 9.5px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--honey-text);
}
/* What is not live yet stands a step behind what is: same cards, same
   words, quieter presence. Opacity rather than any new colour. */
.jh-card--soon { opacity: .62; }
.jh-card--soon .jh-card-ic { opacity: .75; }
.jh-includes-foot {
  font-size: 13px; line-height: 1.6; color: var(--text-light);
  text-align: center; max-width: 66ch;
  margin: clamp(16px, 1.8vw, 26px) auto 0;
}

/* ── How it works ───────────────────────────────────────────────
   Four steps on one line, joined by the same dashed thread the
   member journey uses elsewhere. */
.jh-flow {
  list-style: none; margin: 0 auto; padding: 0;
  max-width: min(100%, 1080px);
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(16px, 3.4vw, 62px);
}
.jh-step {
  position: relative;
  display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: 8px;
}
/* The thread fills exactly the grid gap, so it starts and ends on
   the discs rather than floating between them */
.jh-step:not(:first-child)::before {
  content: ""; position: absolute; top: 29px; right: 100%;
  width: clamp(16px, 3.4vw, 62px);
  border-top: 2px dashed #D4A14166;
}
.jh-step-disc {
  position: relative; width: 58px; height: 58px; border-radius: 50%;
  background: var(--surface); border: 1px solid #E8C06066;
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: 0 3px 12px #5B3E1F0D;
}
.jh-step-n {
  position: absolute; top: -6px; left: -6px;
  width: 23px; height: 23px; border-radius: 50%;
  background: var(--grad-honey); color: var(--on-accent-strong);
  font-family: var(--font-sans); font-size: 12px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 7px #D4A14155;
}
.jh-step-title {
  font-family: var(--font-sans); font-size: 14px; font-weight: 700;
  line-height: 1.3; color: var(--deep-earth);
}
.jh-step-desc {
  font-size: 12.5px; line-height: 1.5; color: var(--text-light);
  max-width: 21ch;
}

/* ── The membership page on a desktop (F52, 6 Sep 2026) ─────────
   The founder brought a model and asked for its structure "with a
   clear background like it is right now", keeping the current text.
   So, from 900px up: the offer loses its box and "Free membership"
   becomes a note beside the bee with a dashed thread to the bloom;
   each heading carries a short rule and the bee ornament rests; the
   three live benefits wear icon discs and stand alone, the three
   coming later sit on one quiet row under a "Soon" divider; the
   open-to-everyone line is a band; the steps are numbered in their
   titles with bigger icon circles. Every word, colour, image and
   control is the one already here; below 900px nothing applies and
   the page is as it was. Scoped to .page--join, so the signed-in
   account view is untouched. docs/build-log.md D358. */
@media (min-width: 900px) {
  /* Hero */
  .page--join .jh-hero-inner { position: relative; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .page--join .jh-title { font-size: clamp(48px, 5.2vw, 78px); }
  .page--join .jh-lead { max-width: 48ch; font-size: 16px; color: var(--text-mid); }
  .page--join .jh-offer { background: none; border: 0; box-shadow: none; padding: 0; margin-top: 26px; max-width: none; align-items: flex-start; text-align: left; }
  .page--join .jh-btn { padding: 15px 34px; font-size: 16px; }
  .page--join .jh-signin { text-align: left; font-size: 14px; }
  /* "Free membership" as a note beside the bee, with a dashed thread to the bloom */
  .page--join .jh-free {
    position: absolute; right: 0; top: 4%; z-index: 2; margin: 0; width: 150px;
    font-style: italic; text-align: center; line-height: 1.15; white-space: normal;
    font-size: 21px;
  }
  .page--join .jh-free-word { display: block; font-size: 24px; font-style: italic; color: var(--text-mid); }
  .page--join .jh-free::after {
    content: ""; display: block; width: 74px; height: 40px; margin: 6px auto 0;
    border-right: 2px dashed #D4A14188; border-bottom: 2px dashed #D4A14188;
    border-radius: 0 0 40px 0; transform: translateX(-30px);
  }
  .page--join .jh-hero-art { aspect-ratio: 1 / 0.9; }
  .page--join .jh-art-lotus { width: 84%; left: 0; }
  .page--join .jh-art-bee { width: 38%; right: 20%; top: 8%; }
  /* Section headings: a short rule beneath, the bee ornament rests */
  .page--join .jh-includes, .page--join .jh-steps { padding-top: clamp(56px, 5.4vw, 100px); padding-bottom: clamp(56px, 5.4vw, 100px); }
  .page--join .jh-head { margin-bottom: clamp(30px, 3vw, 52px); }
  .page--join .jh-flourish { display: none; }
  .page--join .jh-h2::after { content: ""; display: block; width: 44px; margin: 14px auto 0; border-top: 1.5px solid var(--honey); }
  /* Membership includes: icon discs, four live cards across, then the
     "Soon" band. Four since F96 (11 Sep 2026): "Your sacred calendar"
     went live and "Member offers" went, leaving one Soon card, which
     sits centred on its own row under the band. */
  .page--join .jh-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(18px, 1.8vw, 28px); max-width: 1080px; margin: 0 auto; row-gap: 22px; }
  .page--join .jh-card--soon { grid-column: 1 / -1; justify-self: center; width: auto; max-width: 100%; }
  .page--join .jh-card { padding: clamp(26px, 2.4vw, 36px) clamp(18px, 1.8vw, 28px); gap: 10px; border-radius: 18px; }
  .page--join .jh-card-ic {
    width: 66px; height: 66px; border-radius: 50%; margin-bottom: 8px;
    align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--honey) 12%, var(--surface));
  }
  .page--join .jh-card-ic svg { width: 28px; height: 28px; }
  .page--join .jh-card-title { font-size: 18px; min-height: 0; }
  .page--join .jh-card-desc { font-size: 14.5px; line-height: 1.6; color: var(--text-mid); max-width: 26ch; }
  .page--join .jh-grid::before {
    content: "Soon"; grid-column: 1 / -1; grid-row: 2; margin-top: 8px;
    text-align: center; font-family: var(--font-sans); font-size: 10px; font-weight: 700;
    letter-spacing: .18em; text-transform: uppercase; color: var(--honey-deep);
    background:
      linear-gradient(#E8C06077, #E8C06077) left center / calc(50% - 52px) 1px no-repeat,
      linear-gradient(#E8C06077, #E8C06077) right center / calc(50% - 52px) 1px no-repeat;
  }
  .page--join .jh-card--soon {
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "ic title soon" "ic desc soon";
    column-gap: 14px; row-gap: 2px; align-items: center; text-align: left;
    padding: 16px 20px; border-radius: 14px; opacity: .8;
    background: color-mix(in srgb, var(--honey) 5%, var(--surface)); border-color: #E8C06044;
  }
  .page--join .jh-card--soon .jh-card-ic { grid-area: ic; width: 40px; height: 40px; margin: 0; }
  .page--join .jh-card--soon .jh-card-ic svg { width: 20px; height: 20px; }
  .page--join .jh-card--soon .jh-card-title { grid-area: title; font-size: 14.5px; justify-content: flex-start; }
  .page--join .jh-card--soon .jh-card-desc { grid-area: desc; font-size: 13px; max-width: none; }
  .page--join .jh-card--soon .jh-soon { grid-area: soon; margin: 0 0 0 10px; padding: 0; }
  /* The promise, as a band */
  .page--join .jh-includes-foot {
    max-width: 1080px; margin-top: clamp(26px, 2.6vw, 40px);
    padding: 16px 24px; border: 1px solid #E8C06055; border-radius: 14px; background: color-mix(in srgb, var(--surface) 76.86%, transparent);
    text-align: left; font-size: 15px; color: var(--text-mid);
  }
  /* How it works: numbered titles, bigger discs */
  .page--join .jh-flow { counter-reset: step; max-width: 1120px; }
  .page--join .jh-step { counter-increment: step; }
  .page--join .jh-step-n { display: none; }
  .page--join .jh-step-disc { width: 76px; height: 76px; border: 1.5px solid #E8C06099; }
  .page--join .jh-step-disc svg { width: 28px; height: 28px; }
  .page--join .jh-step:not(:first-child)::before { top: 38px; }
  .page--join .jh-step-title { font-size: 17px; font-family: var(--font-serif); font-weight: 600; margin-top: 6px; }
  .page--join .jh-step-title::before { content: counter(step) ". "; }
  .page--join .jh-step-desc { font-size: 14px; max-width: 24ch; }
}

/* ── The membership page, fluid (F58, 6 Sep 2026) ───────────────
   The founder's second pass, with onepeloton.com/app-membership as
   the reference: "make this page fluid like this one". Read as full-
   width bands rather than boxes, bigger type, one moment of contrast.
   These rules sit AFTER the model pass above and override it where
   they differ: the hero fills its band without a fixed height, the
   three live benefits lose their cards and stand as open columns, the
   Soon row is a plain list, and the closing invitation moves onto the
   deep-earth band the site already owns. Still 900px up, still
   .page--join, still every word and image as before; tightened twice
   on the founder's "too much free space". docs/build-log.md D358. */
@media (min-width: 900px) {
  .page--join .jh-hero { padding-top: clamp(16px, 2vw, 34px); padding-bottom: clamp(16px, 2vw, 34px); min-height: 0; display: flex; align-items: center; }
  .page--join .jh-hero-inner { grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); gap: clamp(24px, 4vw, 80px); width: min(100%, 1280px); }
  .page--join .jh-title { font-size: clamp(44px, 4.8vw, 68px); line-height: 0.98; }
  .page--join .jh-sub { font-size: clamp(19px, 1.7vw, 25px); margin-top: 14px; }
  .page--join .jh-lead { font-size: 17px; max-width: 46ch; margin-top: 16px; }
  .page--join .jh-free-word { font-size: 26px; }
  .page--join .jh-hero-art { aspect-ratio: 1 / 0.78; max-width: 600px; width: 100%; margin-left: auto; }
  .page--join .jh-art-lotus { width: 82%; left: 0; bottom: 0; }
  .page--join .jh-art-bee { width: 36%; right: 14%; top: 2%; z-index: 2; }
  .page--join .jh-art-lotus { z-index: 1; }
  /* Benefits: no boxes — three open columns on a wide band */
  .page--join .jh-includes { padding-top: clamp(44px, 4.4vw, 76px); padding-bottom: clamp(40px, 4vw, 68px); }
  .page--join .jh-includes::before { opacity: .5; }
  .page--join .jh-h2 { font-size: clamp(36px, 3.4vw, 52px); }
  .page--join .jh-grid { max-width: 1240px; gap: clamp(28px, 3.4vw, 64px); row-gap: 26px; }
  .page--join .jh-card { background: none; border: 0; box-shadow: none; padding: 0; align-items: flex-start; text-align: left; }
  .page--join .jh-card:hover { transform: none; box-shadow: none; }
  .page--join .jh-card-ic { width: 60px; height: 60px; }
  .page--join .jh-card-title { font-size: 22px; font-weight: 600; justify-content: flex-start; }
  .page--join .jh-card-desc { font-size: 16.5px; line-height: 1.65; max-width: 30ch; }
  .page--join .jh-grid::before { content: "Soon"; margin-top: 12px; background:
      linear-gradient(#E8C06077, #E8C06077) left center / calc(50% - 44px) 1px no-repeat,
      linear-gradient(#E8C06077, #E8C06077) right center / calc(50% - 44px) 1px no-repeat; }
  .page--join .jh-card--soon { background: none; border: 0; padding: 4px 0; opacity: .85; column-gap: 12px; }
  .page--join .jh-card--soon .jh-card-ic { width: 34px; height: 34px; background: none; }
  .page--join .jh-card--soon .jh-card-title { font-size: 15px; }
  .page--join .jh-card--soon .jh-card-desc { font-size: 13.5px; }
  /* How it works: on the light band, wide */
  .page--join .jh-steps { padding-top: clamp(44px, 4.4vw, 76px); padding-bottom: clamp(40px, 4vw, 68px); }
  .page--join .jh-flow { max-width: 1240px; }
  /* The close: one dark band, the one moment of contrast */
  .page--join .jh-close { background: var(--grad-earth); border-top: 0; padding: clamp(40px, 4.4vw, 72px) var(--page-pad-x); }
  .page--join .jh-close::before, .page--join .jh-close::after { opacity: .35; }
  .page--join .jh-close-inner { flex-direction: column; gap: 22px; text-align: center; }
  .page--join .jh-close-line { color: var(--cream); font-size: clamp(30px, 3vw, 46px); font-family: var(--font-serif); font-weight: 400; line-height: 1.15; max-width: 22ch; margin: 0; }
  .page--join .jh-close-join { margin: 0; }
  .page--join .jh-close .hb-join-signin, .page--join .jh-close .jh-signin { color: color-mix(in srgb, var(--cream) 80%, transparent); }
  .page--join .jh-close .link-plain { color: var(--cream); }
}
@media (min-width: 900px) {
  .page--join .jh-head { margin-bottom: clamp(22px, 2.4vw, 40px); }
  .page--join .jh-steps#contexts { padding-top: clamp(40px, 4vw, 64px); }
}

/* ── The closing invitation ─────────────────────────────────────
   One line and the same button, on a warmer band with the comb
   fading in from both edges. */
.jh-close {
  position: relative; overflow: hidden;
  background: linear-gradient(180deg, #FBF3E2, #F8EACE);
  border-top: 1px solid #E8C06044;
  padding: clamp(24px, 3vw, 46px) var(--page-pad-x);
}
.jh-close::before, .jh-close::after {
  content: ""; position: absolute; top: 0; bottom: 0;
  width: clamp(80px, 15vw, 240px); pointer-events: none;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='34.64' viewBox='0 0 30 34.64'%3E%3Cg fill='none' stroke='%23A87C2E' stroke-width='0.9' opacity='0.13'%3E%3Cpolygon points='15,2 28,9.5 28,25 15,32 2,25 2,9.5'/%3E%3Cpolygon points='30,19 43,26.5 43,42 30,49.5 17,42 17,26.5'/%3E%3C/g%3E%3C/svg%3E");
  background-size: 46px 53.1px;
}
.jh-close::before {
  left: 0;
  -webkit-mask-image: linear-gradient(90deg, #000, transparent);
          mask-image: linear-gradient(90deg, #000, transparent);
}
.jh-close::after {
  right: 0;
  -webkit-mask-image: linear-gradient(270deg, #000, transparent);
          mask-image: linear-gradient(270deg, #000, transparent);
}
.jh-close-inner {
  position: relative; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: clamp(14px, 2vw, 34px);
  max-width: min(100%, 1000px); margin: 0 auto;
}
.jh-close-line {
  font-family: var(--font-serif); font-weight: 400;
  font-size: clamp(20px, 2.2vw, 32px); line-height: 1.3;
  color: var(--deep-earth); margin: 0; text-wrap: balance;
}

/* On the invitation, the practitioner block is a footnote rather
   than a chapter: the visitor came to join, and the gated-event
   notice deep-links here for one short answer. Signed in, the same
   section keeps its full explanation and its pull quote. */
.page--join .hb-bumblebee {
  background: var(--page); border-top: 1px solid #8B623014;
  padding-block: clamp(24px, 2.8vw, 50px);
}
.page--join .hb-bumblebee .h2 { font-size: clamp(19px, 1.5vw, 26px); margin-bottom: clamp(10px, 1.2vw, 16px); }
.page--join .hb-bumblebee .prose { font-size: 13.5px; line-height: 1.7; color: var(--text-light); }
.page--join .bb-state { margin-top: clamp(14px, 1.6vw, 22px); padding: clamp(16px, 1.6vw, 24px); }
.page--join .bb-state-lead { font-size: 14px; }

/* ── Tablet: six across becomes three, and the hero's two columns
   keep their proportions a little longer ─────────────────────── */
@media (max-width: 1119.98px) {
  .jh-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ── Phone: an intentionally different page, not a squeezed one ──
   The artwork moves to the top-right corner and the heading block
   holds itself clear of it, so the hero stays one compact screen:
   name, line, sentence, and the free offer all above the fold. The
   benefit cards go two across, the steps two by two, and their
   dashed thread is dropped because it no longer joins anything. */
@media (max-width: 899.98px) {
  .jh-hero {
    padding-top: clamp(16px, 3.6vw, 28px);
    padding-bottom: clamp(20px, 4vw, 36px);
  }
  .jh-hero-inner { grid-template-columns: minmax(0, 1fr); gap: 0; }
  /* Only the two lines that sit level with the artwork hold back
     from it; the supporting sentence starts below the bloom and
     takes the full measure, which is a line and a half less to
     scroll past on a phone. */
  .jh-title, .jh-sub { padding-right: clamp(96px, 30vw, 168px); }
  .jh-lead { max-width: none; }
  /* Everything below the hero draws in as well, so the offer, the
     cards and the steps land inside two screens rather than four */
  .jh-includes, .jh-steps { padding-block: clamp(26px, 5.6vw, 46px); }
  .jh-offer { width: 100%; max-width: 460px; margin-inline: auto; }
  .jh-hero-art {
    position: absolute; top: 0; right: 0; z-index: -1;
    width: clamp(104px, 31vw, 180px); min-height: 0;
    aspect-ratio: 1 / 1;
  }
  .jh-art-lotus { left: 2%; bottom: 6%; width: 74%; }
  .jh-art-bee { right: 0; top: 0; width: 52%; }
}
@media (max-width: 759.98px) {
  .jh-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .jh-flow { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 14px; }
  .jh-step:not(:first-child)::before { display: none; }
  /* Two across, so the longer step titles need their second line
     reserved as well or the pair falls out of step */
  .jh-step-title {
    min-height: 2.6em;
    display: flex; align-items: center; justify-content: center;
  }
  .jh-close-inner { flex-direction: column; gap: 18px; }
  .jh-close-line { text-align: center; }
}
/* Very narrow phones: the offer must never be the thing that
   introduces a horizontal scrollbar */
@media (max-width: 419.98px) {
  .jh-free { white-space: normal; }
  /* Two cards across leave about 120px for a title, and "Personal
     recommendations" with its icon beside it needed 150: the word ran
     4px out of its card at 360px (live before F96, found while
     checking it). The icon goes above the title here instead. */
  .jh-card-title { flex-direction: column; gap: 6px; }
  .jh-card-title-ic { margin-right: 0; }
  .jh-title, .jh-sub { padding-right: clamp(78px, 27vw, 110px); }
}

/* The long membership overlines are wider than a phone: let them
   wrap there instead of clipping at the page edge */
@media (max-width: 560px) {
  .page--honeybee .overline { white-space: normal; }
}

/* Below the wide layout the four live benefits pair up two by two
   (three across left one on its own), and the Soon card takes the
   row beneath them. */
@media (max-width: 899.98px) {
  .page--join .jh-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .page--join .jh-card--soon { grid-column: 1 / -1; }
}

/* ── A glimpse of the member's page (F96, 11 Sep 2026) ───────────
   Words on the left, a phone on the right; stacked on a phone, the
   picture under its heading. The phone is drawn from the account
   page's own pieces (card head, chips) at a smaller size, so it
   looks like the real thing because it is made of it. Every colour
   is a token or one already in use for those pieces. */
.jh-glimpse {
  position: relative; background: var(--page-soft);
  padding: clamp(32px, 3.8vw, 74px) var(--page-pad-x);
}
.jh-glimpse-inner {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(28px, 5vw, 96px); align-items: center; max-width: 1080px;
}
.jh-glimpse-copy { text-align: left; }
.jh-glimpse .jh-h2 { margin: 0; text-align: inherit; }
.page--join .jh-glimpse .jh-h2::after { margin-left: 0; }
.jh-glimpse-line {
  margin: 16px 0 0; max-width: 44ch;
  font-size: clamp(15px, 0.3vw + 14px, 18px); line-height: 1.65; color: var(--text-mid);
}
.jh-phone {
  width: 300px; max-width: 100%; padding: 10px; border-radius: 42px;
  background: var(--deep-earth); box-shadow: 0 24px 60px #5B3E1F26;
  pointer-events: none; user-select: none;
}
.jh-phone-screen {
  position: relative; display: flex; flex-direction: column; gap: 10px;
  min-height: 470px; padding: 38px 14px 20px; border-radius: 33px;
  background: var(--page); overflow: hidden;
}
.jh-phone-notch {
  position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
  width: 86px; height: 22px; border-radius: 12px; background: var(--deep-earth);
}
.jh-phone-title {
  margin: 4px 4px 2px; font-family: var(--font-serif); font-size: 22px; font-weight: 600;
  color: var(--deep-earth);
}
.jh-phone-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  padding: 12px; border-radius: 14px; background: var(--surface);
  border: 1.5px solid #E8C06035; box-shadow: 0 2px 10px #5B3E1F08;
}
.jh-phone-card .account-card-head { font-size: 9.5px; letter-spacing: .12em; }
.jh-phone-chips { display: flex; flex-wrap: wrap; gap: 6px; max-width: 100%; }
.jh-phone .chip, .jh-phone .chip-link {
  min-height: 0; padding: 5px 10px; font-size: 11.5px; gap: 4px;
}
.jh-phone-chip {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.jh-phone-day {
  display: flex; align-items: center; gap: 8px; width: 100%;
  font-size: 12.5px; color: var(--text-dark);
}
.jh-phone-day-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.jh-phone-day-date { color: var(--text-light); white-space: nowrap; }
.jh-phone-bar { display: block; width: 70%; height: 22px; border-radius: 11px; background: var(--photo-ph); }
@media (max-width: 759.98px) {
  .jh-glimpse { padding-block: clamp(26px, 5.6vw, 46px); }
  .jh-glimpse-inner { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  .jh-glimpse-copy { text-align: center; }
  .page--join .jh-glimpse .jh-h2::after { margin-left: auto; }
  .jh-glimpse-line { margin-inline: auto; }
  .jh-phone { width: 280px; }
  .jh-phone-screen { min-height: 440px; }
}

/* ── "Your sacred calendar" on the account page (F96) ─────────── */
.calfeed-choices {
  display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 0; padding: 0; border: 0;
}
.calfeed-choice {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
  font-size: 14.5px; color: var(--text-mid); cursor: pointer;
}
.calfeed-choice input { width: 18px; height: 18px; margin: 0; accent-color: var(--honey-text); cursor: pointer; }
/* The same dot the Sacred Calendar's legend uses for each kind;
   honey for the saved gatherings, which have no kind of their own. */
.calfeed-dot {
  display: inline-block; flex-shrink: 0; width: 9px; height: 9px; border-radius: 50%;
  background: var(--honey);
}
.calfeed-links { justify-content: flex-start; margin-top: 0; }
.calfeed-links .chip-link { min-height: 44px; }
.calfeed-note { font-size: 13px; }

/* ── "Make BeeBhakti yours" — personalisation ─────────────────
   The Honeybee onboarding form and the homepage invitation.
   Friendly and light, never a questionnaire: existing field, pill
   and chip primitives, plus three calm cards for the experience
   self-descriptions. */
.pf-form { text-align: left; }
.pf-intro {
  font-size: 14.5px; line-height: 1.65; color: var(--text-mid);
  margin-bottom: clamp(18px, 2vw, 26px);
}
.pf-group { margin-bottom: clamp(18px, 2vw, 26px); }
.pf-exp { display: flex; flex-direction: column; gap: 10px; margin-top: 6px; }
.pf-exp-option {
  text-align: left; background: var(--surface); border: 1px solid #E8C06044;
  border-radius: 14px; padding: 13px 16px; cursor: pointer;
  transition: border-color .2s, box-shadow .2s;
}
.pf-exp-option:hover { border-color: #E8C060AA; }
.pf-exp-option.on {
  border-color: var(--honey);
  box-shadow: 0 0 0 1px var(--honey) inset;
}
.pf-exp-title {
  display: block; font-family: var(--font-sans); font-weight: 700;
  font-size: 14.5px; color: var(--deep-earth); margin-bottom: 3px;
}
.pf-exp-desc { font-size: 13.5px; line-height: 1.55; color: var(--text-light); margin: 0; }
.pf-hint { font-size: 14px; line-height: 1.65; color: var(--text-mid); margin: 4px 0 0; }

/* The three answers wear the share form's radio mark (F51, 6 Sep 2026):
   until then they were plain boxes with a sentence in them, and nothing
   on screen said "choose one". Same mark, same tint, same tokens as
   "Who is this gathering for?"; the control is still the button it was. */
.pf-exp-option {
  display: flex; align-items: flex-start; gap: 11px;
  border: 1.5px solid #E8C06044; border-radius: 12px; padding: 11px 14px;
}
.pf-exp-option::before {
  content: ""; flex-shrink: 0; width: 17px; height: 17px; margin-top: 1.5px;
  border-radius: 50%; background: var(--surface);
  border: 2px solid color-mix(in srgb, var(--honey) 60%, transparent);
  transition: all .2s;
}
.pf-exp-option.on {
  box-shadow: none;
  background: color-mix(in srgb, var(--honey) 7%, var(--surface));
}
.pf-exp-option.on::before {
  content: "✓"; background: var(--honey); border-color: var(--honey);
  color: var(--on-accent-strong); font-size: 10.5px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}
.pf-exp-option:focus-visible { outline: 2px solid var(--honey); outline-offset: 2px; }
.pf-exp-title { font-weight: 600; margin: 0; line-height: 1.5; }

/* On a desktop the form is a settings sheet, not a phone card floating
   in empty space (founder, 6 Sep 2026 — F51: "A"). Each question is a
   row — the question on the left, the answer on the right, a hairline
   between rows — and the button sits bottom-right. Below 900px nothing
   here applies and the single column is exactly as it was. */
@media (min-width: 900px) {
  .page--honeybee .signin-card.pf-form {
    max-width: min(100%, 940px); padding: 36px 48px 40px; gap: 0;
  }
  .page--honeybee .pf-intro { max-width: 62ch; margin-bottom: 8px; }
  .page--honeybee .pf-group {
    display: grid; grid-template-columns: 230px minmax(0, 1fr);
    column-gap: 36px; row-gap: 8px; align-items: start;
    margin: 0; padding: 24px 0; border-top: 1px solid #E8C06033;
  }
  .page--honeybee .pf-group > .field-label {
    grid-column: 1; margin: 0; padding-top: 3px; font-size: 15px;
  }
  .page--honeybee .pf-group > :not(.field-label) { grid-column: 2; }
  .page--honeybee .pf-group > .pf-hint { margin: 0; }
  .page--honeybee .pf-exp-option { padding: 12px 16px; }
  .page--honeybee .pf-form > .bg--block {
    width: auto; align-self: flex-end; min-width: 260px;
    margin-top: 28px; padding: 13px 34px;
  }
  .page--honeybee .pf-skip { text-align: right; }
}

/* The homepage invitation */
.home-hb-line {
  font-size: 15.5px; line-height: 1.75; color: var(--text-mid);
  max-width: 58ch; margin: 0 auto;
}
.home-hb-join { margin-top: 24px; }

/* "Tell us about your practice" (the request flow) keeps the
   deeper wax band: its own layer of the same hive, never a
   "premium" surface */
.hb-bumblebee {
  background: linear-gradient(180deg, #F5ECDA 0%, #F2E7D1 100%);
  border-top: 1px solid #8B62301A;
  padding: var(--section-pad-y) var(--page-pad-x);
}
.hb-bumblebee-inner { text-align: left; }
.hb-bumblebee-inner .overline, .hb-bumblebee-inner .h2, .hb-bumblebee-inner > .prose { text-align: center; }
.hb-bumblebee-inner .h2 { margin-bottom: clamp(16px, 2vw, 28px); }
.hb-join--bb { margin-top: clamp(20px, 2.4vw, 34px); }

/* Request flow states: one calm card per state */
.bb-state {
  background: var(--surface); border: 1px solid #E8C06044; border-radius: 16px;
  padding: clamp(20px, 2vw, 30px); margin-top: clamp(20px, 2.4vw, 34px);
  text-align: center;
}
.bb-state--welcome { border-color: color-mix(in srgb, var(--honey) 55%, transparent); }
.bb-state-lead { font-size: 15.5px; line-height: 1.7; color: var(--text-mid); margin-bottom: 14px; }
.bb-state .account-card-head { margin-bottom: 8px; }
.bb-form { margin-top: clamp(20px, 2.4vw, 34px); }

/* ── A gathering that has passed (F123) ────────────────────────
   An old shared link lands here. One calm card in the request flow's
   own shape, centred: the gathering's name so the visitor knows they
   reached the right one, what has happened, and the way on. */
.event-passed { padding-bottom: clamp(48px, 5vw, 96px); }
.event-passed-card { margin-top: 0; padding: 0 clamp(20px, 3vw, 48px) clamp(28px, 3vw, 48px); overflow: hidden; }
/* The alert: a honey band across the top of the card, edge to edge,
   with a stronger honey rule on its left — the site's gold, tinted, so
   it reads as news rather than as an error. */
.event-passed-alert {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  margin: 0 calc(-1 * clamp(20px, 3vw, 48px)) clamp(24px, 2.6vw, 36px);
  padding: 14px clamp(16px, 2vw, 24px);
  background: color-mix(in srgb, var(--honey) 22%, var(--surface));
  border-bottom: 1px solid color-mix(in srgb, var(--honey) 45%, transparent);
  box-shadow: inset 4px 0 0 var(--honey);
  font-family: var(--font-sans); font-size: clamp(16px, 0.3vw + 15px, 19px); font-weight: 700;
  line-height: 1.35; color: var(--deep-earth); text-align: left;
}
.event-passed-alert-icon { display: inline-flex; flex: 0 0 auto; color: var(--honey-text); }
.event-passed-name { text-align: center; margin-bottom: clamp(10px, 1vw, 14px); overflow-wrap: anywhere; }
.event-passed-lead { max-width: 52ch; margin-inline: auto; margin-bottom: clamp(20px, 2vw, 28px); }
.event-passed-card .bg { min-height: 48px; padding: 12px 28px; }
.bb-form-intro { font-size: 14.5px; line-height: 1.65; color: var(--text-mid); margin-bottom: 18px; }

/* ── Confirm your email (/confirm-email/) ──────────────────────
   The sign-up's most important moment, given a page of its own. The
   order down the screen is the order of the questions a person
   actually has — did it work, where did it go, and what if it never
   arrives — so the address is the largest thing after the title and
   the help sits under a hairline, a size smaller. Nothing new is
   introduced here: the card, the honey hairline, the petal surface
   and both buttons are the ones the account journey already wears. */
.confirm-mark {
  display: flex; align-items: center; justify-content: center;
  width: 62px; height: 62px; flex: 0 0 62px;
  margin: 0 auto clamp(14px, 1.4vw, 20px);
  border-radius: 50%;
  background: var(--page-soft); border: 1px solid #E8C06055;
}
.confirm-state .bb-state-lead { margin-bottom: clamp(16px, 1.8vw, 22px); }
/* The address, second only to the title. It is the one thing on this
   page a visitor can check for themselves, and a mistyped address is
   the commonest reason no email ever arrives — so it is set large,
   and it breaks anywhere rather than overflowing a 360px phone. */
.confirm-address {
  display: block; text-align: center;
  background: var(--page-soft); border: 1px solid #E8C06055; border-radius: 14px;
  padding: clamp(14px, 1.4vw, 18px) clamp(14px, 1.6vw, 20px);
}
.confirm-address-label {
  display: block;
  font-family: var(--font-sans); font-size: 12px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-light); margin-bottom: 6px;
}
.confirm-address-value {
  display: block;
  font-family: var(--font-sans); font-weight: 600;
  font-size: clamp(16.5px, 1.1vw + 12px, 21px); line-height: 1.35;
  color: var(--text-dark);
  overflow-wrap: anywhere; word-break: break-word;
}
/* Tertiary. Everything below the rule is for the visitor whose email
   did not arrive; for everyone else it must not compete with the
   instruction above it. */
.confirm-help {
  margin-top: clamp(18px, 2vw, 26px);
  padding-top: clamp(18px, 2vw, 26px);
  border-top: 1px solid #E8C06035;
  text-align: center;
}
/* With nothing above it to be separated from — an expired link on a
   device that never signed up — the rule is separating the help from
   the envelope, which is not a division worth drawing. */
.confirm-help--alone { margin-top: 0; padding-top: 0; border-top: none; }
.confirm-help-title {
  font-family: var(--font-sans); font-size: 15px; font-weight: 600;
  color: var(--text-dark); margin: 0 0 6px;
}
.confirm-help-text {
  font-size: 14px; line-height: 1.65; color: var(--text-mid);
  margin: 0 0 clamp(12px, 1.4vw, 18px);
}
.confirm-help .bg--block { width: 100%; min-height: 44px; }
.confirm-help .bg:disabled {
  opacity: .55; cursor: default; transform: none; box-shadow: none;
  background: transparent; color: var(--honey);
}
.confirm-help .signin-recover-row .bg { min-height: 44px; }
.confirm-said { font-size: 13.5px; line-height: 1.6; color: var(--text-mid); margin: 12px 0 0; }
.confirm-help .form-error { margin: 12px 0 0; }
.confirm-back { margin: 14px 0 0; font-size: 13.5px; }
/* A 44px target for the two plain-text controls, without giving them
   a button's weight (§ mobile-first: tap targets >= 44px). */
.confirm-back .link-plain { display: inline-flex; align-items: center; min-height: 44px; }
/* On a phone the field and its button are about 150px each side by
   side, which is neither a usable field nor a readable button. */
@media (max-width: 520px) {
  .confirm-help .signin-recover-row { flex-direction: column; }
  .confirm-help .signin-recover-row .bg { width: 100%; }
}

/* Gated practitioner-gathering notice */

/* Centred button rows (New to bhakti page) */
.btn-row--center { justify-content: center; }

/* Hero refinements (Aug 2026): one primary visitor CTA, a
   clean four-type shortcut row with two softer paths under it, and a
   gently compressed vertical rhythm (~10–15%) so discovery arrives
   sooner. The globe keeps its size — it is part of the identity. */
.hero { min-height: 88svh; padding-top: clamp(72px, 6vh, 104px); padding-bottom: clamp(36px, 4vh, 72px); }
.hero-subline { margin-bottom: clamp(12px, 1.4vw, 22px); }
.hero-cta { margin-bottom: clamp(2px, 0.6vh, 8px); }
.hero-proof { margin-top: clamp(10px, 1.2vw, 20px); }
.hero-journey { margin-top: clamp(18px, 2.2vh, 36px); }
/* (.intent-grid / .hero-paths are defined in the "What are you
   looking for?" block at the end of this file.) */

/* ── "What are you looking for?" (homepage), matched to the owner's
   reference ─────────────────────────────────────────────────────
   Four equal compact cards on one row: white, a whisper of warm
   border, soft corners; inside each, a circular pastel icon, the
   category name, and an arrow pushed to the far edge. Below them,
   two visually LIGHTER plain-text links with small outline icons
   and a quiet vertical divider between them. */
.hero-journey-title { margin-bottom: clamp(14px, 1.6vw, 22px); }
.intent-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(14px, 1.6vw, 24px);
  max-width: min(100%, 1060px); margin: 0 auto;
}
.intent-card {
  display: flex; align-items: center; gap: 14px;
  background: var(--surface); border: 1px solid #E8C06033; border-radius: 14px;
  padding: 14px 18px; cursor: pointer; text-align: left;
  transition: transform .25s, box-shadow .25s, border-color .25s;
}
.intent-card:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--c) 45%, transparent);
  box-shadow: 0 10px 24px color-mix(in srgb, var(--c) 15%, transparent);
}
/* A clear ring for keyboard users — the lift alone is too subtle */
.intent-card:focus-visible {
  outline: 3px solid var(--honey); outline-offset: 3px;
}
.intent-icon {
  flex: 0 0 auto; width: 46px; height: 46px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  /* A flat pastel disc, as in the reference — no ring around it */
  background: color-mix(in srgb, var(--c) 13%, var(--surface));
}
.intent-name {
  font-family: var(--font-serif); font-size: 19px; color: var(--c);
  line-height: 1.2; white-space: nowrap;
}
.intent-arrow {
  margin-left: auto; font-size: 17px; line-height: 1; color: var(--c);
  transition: transform .25s;
}
.intent-card:hover .intent-arrow { transform: translateX(3px); }

/* The two secondary links: lighter than the cards, one line each,
   separated by a subtle vertical divider on desktop */
.hero-paths {
  display: flex; justify-content: center; align-items: center;
  flex-wrap: wrap; margin-top: clamp(14px, 1.6vh, 24px);
}
.hero-path {
  background: none; border: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px clamp(16px, 2vw, 30px);
  /* The supporting-label voice (sans, bold), not the serif display
     voice — quiet wayfinding lines, not headings */
  font-family: var(--font-sans); font-size: 14px; font-weight: 700;
  color: var(--text-mid);
  transition: color .2s;
}
.hero-path:hover { color: var(--honey); }
.hero-path-ic { display: inline-flex; align-items: center; }
.hero-path-arrow { font-size: 15px; line-height: 1; transition: transform .25s; }
.hero-path:hover .hero-path-arrow { transform: translateX(3px); }
.hero-path + .hero-path { border-left: 1px solid #D4A14138; }

/* Two-up on a tablet, single column on a phone; the divider only
   makes sense while the links share one row */
@media (max-width: 1000px) {
  .intent-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .intent-grid { grid-template-columns: minmax(0, 1fr); }
  .hero-paths { flex-direction: column; gap: 6px; }
  .hero-path + .hero-path { border-left: none; }
}

/* ═══ UX review implementation (Aug 2026) ════════════════════════
   Contrast, tap targets, real links, discovery tools, the event
   page's single primary action, facilitator profile pages, the
   resources landing, and the login/join split. Appended last so
   equal-specificity fixes win on source order. */

/* ── Contrast: gold text moves to the darker text gold ──────────
   The bright gold stays for fills, borders and large display type;
   TEXT set in gold uses --honey-text (#8A6516, AA on cream/white).
   Data-driven accent text darkens through a color-mix, so each
   category keeps its hue while its small text passes. */
.card-open { color: var(--honey-text); font-size: 13px; }
.bg-o { color: var(--honey-text); }
.bg-o:hover { background: var(--honey); color: var(--on-accent-strong); }
.link-plain { color: var(--honey-text); }
.nl:hover, .nl.on { color: var(--honey-text); }
.guide-role { color: var(--honey-text); }
.text-author { color: var(--honey-text); }
.plan-tier { color: var(--honey-text); }
.step-note { color: var(--honey-text); }
.tier-amount { color: var(--honey-text); }
.tier--highlight .tier-amount { color: var(--on-dark); }
.hero-path:hover { color: var(--honey-text); }
.places-official a, .guide-empty-more a { color: var(--honey-text); }
.combo-option.on, .combo-option.on .combo-meta { color: var(--honey-text); }
/* These four write a resource's own colour as text. The share was a
   flat 58%, chosen when there was only daylight; at night the mix
   target is the ivory, and 58% of a book's gold left it at 4.2:1.
   They now read --ink-data, the same 52% the data-coloured tags use,
   which clears 4.6:1 in both appearances (F69, 8 Sep 2026). */
.pill-link { color: color-mix(in srgb, var(--c, var(--honey)) var(--ink-data), var(--text-dark)); }
.pill-link:hover { color: var(--on-accent); }
.res-author, .res-host { color: color-mix(in srgb, var(--c, var(--honey)) var(--ink-data), var(--text-dark)); }
.intent-name, .intent-arrow { color: color-mix(in srgb, var(--c) 55%, var(--ink-deep)); }
.journey-cta { color: color-mix(in srgb, var(--c) 58%, var(--ink-deep)); }
.journey-title { color: color-mix(in srgb, var(--c) 78%, var(--ink-deep)); }
.duo-title { color: color-mix(in srgb, var(--c) 78%, var(--ink-deep)); }
.sacred-in { color: color-mix(in srgb, var(--c, var(--honey)) var(--ink-data), var(--text-dark)); }
/* The reassurance line inside the philosophy cards carries the
   card's meaning — same size as the body copy, not a footnote. */
.value-note { font-size: clamp(15px, 4.1cqi, 17px); color: var(--text-mid); }

/* ── Real links: cards and rows are anchors now ────────────────── */
a.map-card, a.ec, a.journey-card, a.intent-card, a.res-overview-card, a.rail-item, a.nav-brand, a.mobile-menu-link, a.people-card {
  color: inherit; text-decoration: none;
}
a.nl { display: inline-block; }
a.nav-cta { text-decoration: none; }
a.hero-path { text-decoration: none; }

/* ── Tap targets ───────────────────────────────────────────────── */
.type-pill { padding: 8px 16px; min-height: 36px; }
.chip { padding: 9px 16px; min-height: 36px; }
a.footer-link { padding: 8px 0; margin-bottom: 2px; }
.map-flat .leaflet-control-zoom a {
  width: 38px; height: 38px; line-height: 38px; font-size: 20px;
}
@media (pointer: coarse) {
  .type-pill, .chip, .alpha-all { min-height: 44px; }
  .map-flat .leaflet-control-zoom a { width: 44px; height: 44px; line-height: 44px; }
  a.footer-link { padding: 11px 0; }

  /* The hero's two wayfinding lines were 25px tall. Wide enough to be
     hard to miss sideways, but a fingertip covers more than that
     vertically, so the row they sit in decides whether the tap lands. */
  .hero-path { min-height: 44px; }

  /* The month arrows on the calendar: 34px, just under. */
  .cal-nav { width: 44px; height: 44px; }

  /* The verse dots are the awkward case. They are 8px by design and
     making them look like buttons would spoil the band, so the DOT
     keeps its size and an invisible box around it takes the tap.
     The gap widens to 20px at the same time, which is what makes the
     boxes fit side by side: 8px dot + 20px gap = 28px of room each,
     so no dot can steal its neighbour's tap. */
  .verse-dots { gap: 20px; }
  .verse-dot { position: relative; }
  .verse-dot::after {
    content: ""; position: absolute;
    left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: 28px; height: 44px;
  }
  .verse-dot.on::after { width: 46px; }

  /* .link-plain is deliberately NOT here. Those are links inside
     sentences ("…follow the ones who speak to your heart. Discover the
     benefits →"), and WCAG exempts inline targets for good reason:
     giving them 44px would prise the lines of every paragraph apart.
     The sentence around them is the target. */

  /* .chip-link is a standalone pill — Save, Add to Calendar, Share,
     the share and calendar choices, the gathering-website link — and
     it was 33px on a phone, under the 44px §8 asks for. It sets a
     min-height rather than more padding so the text stays centred and
     the pill keeps its shape. */
  .chip-link { min-height: 44px; }
  /* The bar that rides the bottom of a phone screen: 40px, just
     under, and it is the one control a thumb reaches for most. */
  .event-stickybar-cta, .event-stickybar-save { min-height: 44px; }
}

/* ── Hero: CTA after the credibility signals ──────────────────── */
.hero-cta--after { margin-top: clamp(14px, 1.8vh, 26px); }
/* The three counters hold one row on a phone instead of wrapping
   2 + 1; the long "shared to date" label may wrap inside its cell. */
.stat-label { white-space: normal; max-width: 16ch; margin-inline: auto; }
@media (max-width: 560px) {
  .hero-stats { display: grid; grid-template-columns: repeat(3, auto); gap: 16px; justify-content: center; align-items: start; }
  .stat-label { font-size: 10px; }
}

/* The newcomer's door: one warm, full-width card under the four
   type cards — the site's most important audience gets card-level
   prominence, not a tertiary link. */

/* The next-sacred-day line under the upcoming gatherings */
.sacred-next {
  margin-top: clamp(20px, 2.2vw, 34px); font-size: 14px;
  color: var(--text-mid); line-height: 1.7;
}
.sacred-next-label {
  font-size: 11px; font-weight: 700; letter-spacing: .16em;
  color: var(--honey-text); margin-right: 6px;
}
.sacred-next a { white-space: nowrap; }

/* Homepage: on a phone the month grid comes BEFORE the gatherings it
   filters. Reading order is the argument: the calendar is the control,
   and a control that sits underneath its own results asks the visitor
   to scroll back up to use it. On desktop the two sit side by side, so
   neither is "first" and the source order stands. */
@media (max-width: 900px) {
  .ucal-wrap > .cal { order: 1; }
  .ucal-wrap > .ucal-list { order: 2; }
}

/* ── Events page: the discovery rail ───────────────────────────── */
.search-wrap--rail { margin-bottom: 0; }
.inp--rail { font-size: 14px; padding-top: 10px; padding-bottom: 10px; background: var(--surface); border-radius: 10px; }
.search-wrap--rail .search-icon { left: 13px; }
.inp--rail.inp--search { padding-left: 38px; }
/* ── Date fields, wherever they appear ─────────────────────────────
   One pair of rules for every date field on the site: the Gatherings
   filter panel, the Share a Gathering form, and the organiser's edit
   sheet. The two places the founder reported were the same rules twice,
   so the fix belongs here rather than on either page.

   The DESKTOP rules below are exactly as they were. The filter rail is
   238px and gives each field 115px, which is narrower than the 151px a
   date input would prefer — but the browser compresses rather than
   clips at that size, and it has read fine for months. "Keep the
   current desktop layout" means keeping it, including this. Everything
   that changed is inside the mobile query. */
.date-range { display: flex; gap: 8px; }
.date-range-field { flex: 1 1 0; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.date-range-label { font-size: 10.5px; letter-spacing: .1em; color: var(--text-light); font-family: var(--font-sans); }
.inp--date { font-size: 13px; padding: 8px 10px; border-radius: 10px; background: var(--surface); min-width: 0; max-width: 100%; }

/* On a phone the same field needs three things it does not need on a
   desktop. All three are about the finger and the viewport.

   WIDTH. `flex: 1 1 0` with `min-width: 0` lets two date inputs shrink
   without limit. At a 320px viewport each was getting 119px against
   the 178px one wants at the size below — the value and the calendar
   indicator competing for the same strip, which is the "overlapping or
   too cramped" that was reported. They now WRAP: side by side while
   both can have their room, one per row when they cannot. `min()`
   keeps the basis from ever exceeding the container, so a very narrow
   screen stacks rather than scrolling sideways.

   FONT SIZE. `.inp` is 16px deliberately — iOS Safari zooms the whole
   page when a focused input is smaller, and the way back is a pinch.
   `.inp--date` was overriding that to 13px on EVERY screen, so tapping
   any date field on an iPhone zoomed the page. That is most of what
   "cramped" looks like from the outside, and it happened on the Share
   form too, where the fields are already full width and nothing
   overlaps — which is why that page was reported as well.

   HEIGHT. The compact padding gives about 33px against rule 8's 44px,
   and the calendar indicator is the smallest target on the field. */
@media (max-width: 767.98px) {
  .date-range { flex-wrap: wrap; gap: 12px; }
  .date-range-field {
    flex: 1 1 min(178px, 100%); min-width: min(178px, 100%);
    /* A flex item cannot exceed the row it wrapped onto. */
    max-width: 100%;
  }
  .date-range-label { font-size: 11px; }
  .inp--date {
    font-size: 16px; padding: 11px 12px; min-height: 44px;
    /* THE ONE THAT MATTERED. iOS Safari renders a date input as a
       native control sized to ITS OWN CONTENT, and that control does
       not honour `width: 100%` — so a filled field like "24 Aug 2026"
       grew past the right edge of the filter panel while every other
       input on the same panel sat neatly inside it. The giveaway in
       the founder's screenshot was the value being CENTRED when
       nothing else on the page is.
       Desktop Chrome does not do this, which is why measuring there
       said the layout was fine when it was not. */
    -webkit-appearance: none; appearance: none;
    /* With the native control gone the value aligns like every other
       field's, instead of sitting in the middle of its box. */
    text-align: left;
  }
}

/* "Show N gatherings" lives only where the panel hides the results */
.filter-show-results { display: none; }
@media (max-width: 999.98px) {
  .filter-panel.is-open .filter-show-results { display: inline-flex; width: 100%; margin-top: 4px; }
  /* The Filters button rides along while the visitor scrolls the
     list, so refining is never a twelve-screen journey away */
  .filter-toggle { position: sticky; top: 74px; z-index: 60; box-shadow: 0 4px 14px #5B3E1F14; }
}
.result-count { font-family: var(--font-sans); font-size: 13px; font-weight: 400; color: var(--text-light); margin-bottom: 20px; }
h2.result-count { font-family: var(--font-sans); }

/* Back to top — appears once the visitor is deep in the list */
.back-to-top {
  position: fixed; right: 18px; bottom: 18px; z-index: 150;
  padding: 11px 18px; border-radius: 50px; border: 1px solid #D4A14155;
  /* The cream was a literal, so at night the pill stayed pale while
     --deep-earth flipped to ivory and the label vanished into it
     (founder, 8 Sep 2026). It is --panel now, at the same 95%: the
     identical cream by day, the elevated brown at night, which is
     what a control floating over the page should be either way. */
  background: color-mix(in srgb, var(--panel) 94.90%, transparent);
  color: var(--deep-earth);
  font-family: var(--font-sans); font-size: 13px; font-weight: 600;
  box-shadow: 0 6px 20px #5B3E1F22; cursor: pointer;
  animation: fadeIn .2s ease;
}
.back-to-top:hover { border-color: var(--honey); }
/* A gathering page puts its Register bar along the bottom of a phone
   screen (.event-stickybar, fixed, z-index 180). Left alone the two
   controls would occupy the same corner and the bar — painting above
   — would swallow this one. So it steps up over the bar, by the bar's
   own height plus the home-indicator inset the bar also allows for.
   Only on the viewport where that bar exists, and only when the page
   actually renders one (it needs a registration link). */
@media (max-width: 767.98px) {
  body:has(.event-stickybar) .back-to-top {
    bottom: calc(84px + env(safe-area-inset-bottom, 0px));
  }
}

/* Event image on cards and the gathering page.

   object-position: top, on the founder's instruction of 24 Aug 2026.
   The default is centre, and a gathering poster is almost never
   composed for a centre crop: the title sits at the top and the
   teacher's face just below it, so a 180px window taken from the middle
   of a tall poster removed exactly the two things that identify it.
   Heads in particular — the complaint that started this.

   Nothing else changes. The card keeps its size, the image keeps
   `cover` so it still fills the width without distortion, and the
   aspect ratio is untouched: only WHICH part of the picture survives
   the crop. There is one rule for .card-img and no responsive override,
   so this holds at every width. */
.card-img {
  width: calc(100% + 2 * clamp(20px, 1.6vw, 32px));
  margin: -12px calc(-1 * clamp(20px, 1.6vw, 32px)) 14px;
  /* A RATIO, not a ceiling. `max-height: 180px` capped a tall poster
     and did nothing at all to a wide one, so the image area was a
     different height on every card: measured live at 1280px, portraits
     and squares came out at 180px while two landscape posters rendered
     145px and 152px. Cards in the same row then disagreed about where
     their text began. */
  aspect-ratio: 16 / 9;

  /* CONTAIN, not cover (founder, 25 Aug 2026): "maybe we can just
     reduce it so that it fits fully in the card even if there are some
     margin on the right and left. That's okay."

     Nothing is cropped any more. A poster is a designed thing — the
     title, the date and the teacher's face are all placed on purpose —
     and three of the four live posters are portrait, so `cover` in a
     16:9 window was always going to lose most of one.

     This is only tolerable because of the ground behind it. The margins
     fall on the same honeycomb the empty-card placeholder uses, so a
     tall poster reads as FRAMED rather than as an image that failed to
     fill its box. On blank white it would look like a mistake.

     `object-position: top` from 24 Aug is gone with the crop it was
     steering: when nothing is cut, there is no part of the picture to
     choose, and centred is what the founder asked for. */
  object-fit: contain;
  object-position: center;
  display: block;

  /* The ground, shared with the placeholder below. On a card WITH a
     poster it shows only in the margins; on one without, it is the
     whole area and the logo sits on top of it. */
  background-color: var(--petal);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='34.64'%3E%3Cg fill='none' stroke='%23D4A141' stroke-width='1' opacity='0.16'%3E%3Cpolygon points='15,2 28,9.5 28,25 15,32 2,25 2,9.5'/%3E%3C/g%3E%3C/svg%3E"),
    linear-gradient(150deg,
      color-mix(in srgb, var(--saffron) 30%, var(--petal)),
      var(--petal) 55%,
      color-mix(in srgb, var(--cream) 88%, var(--honey)));
  background-repeat: repeat, no-repeat;
  background-position: center, center;
  background-size: 30px 34.64px, cover;
  border-bottom: 1px solid #E8C06040;
}

/* The stand-in, for a gathering with no picture and for one whose
   picture would not load. Three quarters of the live gatherings have no
   image, so this is the ordinary case rather than the exception.

   It shows the LOGO — the globe with the bee, the same mark as the
   header. The first attempt used the bee alone and the founder's
   verdict was "too blank": a small insect floating in cream reads as
   something MISSING, where the brand mark reads as a choice.

   Only the logo layer is added here; the ground is inherited from the
   rule above, so the empty card and a portrait poster's margins are
   the same surface. The mark is sized at 40% of the card's own width
   rather than in pixels — the area is 261px across in a desktop grid
   column and 317px on a phone, so a fixed size would sit
   proportionally smaller on the wider one, and a media query is
   exactly what this rule has always avoided. */
.card-img--bee {
  background-image:
    url("/img/card-logo.webp"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='34.64'%3E%3Cg fill='none' stroke='%23D4A141' stroke-width='1' opacity='0.16'%3E%3Cpolygon points='15,2 28,9.5 28,25 15,32 2,25 2,9.5'/%3E%3C/g%3E%3C/svg%3E"),
    linear-gradient(150deg,
      color-mix(in srgb, var(--saffron) 30%, var(--petal)),
      var(--petal) 55%,
      color-mix(in srgb, var(--cream) 88%, var(--honey)));
  background-repeat: no-repeat, repeat, no-repeat;
  background-size: 40% auto, 30px 34.64px, cover;
}
.event-img {
  width: 100%; max-height: 340px; object-fit: cover;
  border-radius: 12px; margin-bottom: clamp(16px, 1.6vw, 26px); display: block;
}

/* ── The gathering page: one primary action ────────────────────── */
.event-actions { display: flex; flex-direction: column; gap: 12px; }
.event-primary { font-size: 15px; padding: 14px 18px; }
.event-secondary { display: flex; gap: 8px; flex-wrap: wrap; }
.event-secondary .chip-link { flex: 0 0 auto; }
.event-sitelink { align-self: flex-start; }
button.save-btn { background: var(--surface); }
button.save-btn.on { border-color: var(--honey); color: var(--deep-earth); background: var(--selected); }

/* The page branches instead of ending */
.event-continue { padding-bottom: clamp(56px, 6vw, 110px); }
.event-continue-title {
  font-family: var(--font-serif); font-weight: 400;
  font-size: clamp(21px, 1.8vw, 30px); color: var(--deep-earth);
  margin: 0 0 clamp(14px, 1.4vw, 24px);
}
.event-continue-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, clamp(260px, 17vw, 320px)), 1fr));
  gap: var(--gap-grid);
}
.event-res-card { background: var(--page-soft); }

/* The primary action rides at the bottom of a phone screen */
.event-stickybar { display: none; }
@media (max-width: 767.98px) {
  .event-stickybar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 180;
    display: flex; gap: 10px; align-items: stretch;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom, 0px));
    /* Themed for the same reason as .back-to-top above: a bar fixed
       over the page is elevated, and a cream literal would have left
       the Register button's surroundings pale at night. */
    background: color-mix(in srgb, var(--panel) 96.08%, transparent); backdrop-filter: blur(10px);
    border-top: 1px solid #D4A14130;
  }
  .event-stickybar-cta { flex: 1 1 auto; justify-content: center; }
  .event-stickybar-save { flex: 0 0 52px; font-size: 18px; padding: 0; }

  /* Room for the bar — and ONLY while the bar is there. The bar now
     appears just once the real action row has scrolled away (see
     EventStickyBar), so when it is absent it is not in the document at
     all and neither of these applies. */
  body:has(.event-stickybar) .event-continue { padding-bottom: 120px; }

  /* This padding used to live on .event-continue alone, with a comment
     claiming it kept the footer's last line clear. It did not: the
     FOOTER comes after .event-continue, so padding that block pushed
     the footer down and left it exactly as covered as before. Measured
     24 Aug 2026 at 375x812 with the bar up — the copyright line and the
     visit count were both underneath it.
     Padding the footer rather than the body on purpose: the footer
     carries its own dark background, and padding the body would show a
     pale strip beneath it. 104px clears a 65px bar with room to spare,
     and the safe-area term covers the taller bar a notched phone gets. */
  body:has(.event-stickybar) .footer {
    padding-bottom: calc(104px + env(safe-area-inset-bottom, 0px));
  }
}

/* ── Facilitator profile pages ─────────────────────────────────── */
.fac-hero { display: flex; align-items: flex-start; gap: clamp(18px, 2.4vw, 36px); flex-wrap: wrap; }
.fac-photo {
  width: clamp(96px, 11vw, 160px); height: clamp(96px, 11vw, 160px);
  border-radius: 50%; object-fit: cover; object-position: center;
  background: var(--photo-ph); border: 3px solid #E8C06055;
  box-shadow: 0 8px 26px #5B3E1F14; flex: 0 0 auto;
}
.fac-avatar {
  width: clamp(96px, 11vw, 160px); height: clamp(96px, 11vw, 160px);
  font-size: clamp(36px, 4vw, 56px); flex: 0 0 auto;
}
.fac-head { flex: 1 1 300px; min-width: 0; }
.fac-role { font-size: 15px; color: var(--text-mid); margin: 4px 0 14px; }
.fac-body { padding: clamp(28px, 3vw, 56px) 0 clamp(56px, 6vw, 110px); }
.fac-bio { max-width: 78ch; margin-bottom: clamp(28px, 3vw, 48px); }
.fac-body .event-continue-title { margin-top: 0; }
.fac-body .card-grid { margin-bottom: clamp(24px, 2.4vw, 40px); }
.fac-note { max-width: none; }

/* "What's new" (F86, 9 Sep 2026): up to three compact cards between
   About and the gatherings. Thumbnail left, words right, the whole
   card one link. Quieter than a gathering card on purpose: the same
   surface and radius, no gold accent bar. Every colour is a token or
   a mix of one, so the night theme needs no rule of its own. */
.fac-updates {
  list-style: none; margin: 0 0 clamp(28px, 3vw, 48px); padding: 0;
  display: grid; gap: 12px; max-width: 78ch;
}
.fac-update {
  display: flex; gap: 14px; align-items: flex-start; min-height: 44px;
  padding: 14px 16px; border-radius: 16px; background: var(--surface);
  border: 1.5px solid color-mix(in srgb, var(--honey) 13.3%, transparent);
  color: inherit; text-decoration: none;
  transition: border-color .2s, box-shadow .2s;
}
.fac-update:hover {
  border-color: color-mix(in srgb, var(--honey) 33.3%, transparent);
  box-shadow: 0 8px 26px color-mix(in srgb, var(--honey) 9.4%, transparent);
}
.fac-update-thumb {
  width: 64px; height: 64px; border-radius: 10px; object-fit: cover;
  flex: 0 0 auto; background: var(--photo-ph);
}
.fac-update-main { display: block; min-width: 0; flex: 1 1 auto; }
.fac-update-title {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  margin: 6px 0 3px; font-family: var(--font-sans); font-size: 16px; font-weight: 600;
  color: var(--text-dark); line-height: 1.35;
}
.fac-update-body {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  margin: 0 0 8px; font-size: 14px; color: var(--text-mid); line-height: 1.5;
}
.fac-update-foot {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 8px 14px; flex-wrap: wrap; font-size: 13px;
}
.fac-update-date { color: var(--text-light); }
.fac-update-link { color: var(--honey-text); font-weight: 600; white-space: nowrap; }
@media (max-width: 479.98px) {
  .fac-update { gap: 12px; padding: 12px 14px; }
  .fac-update-thumb { width: 56px; height: 56px; }
}

/* Directory rows as links */
/* Since F95 the row is a <div> and the name's link (.guide-open) stretches over all of it, so the whole
   row still opens the profile while an update link can sit on top.
   isolation keeps those layers inside the row. The keyboard ring
   goes round the row, where the old row-link drew it. */
.guide-row--link { border-bottom: 1px solid #E8C06020; position: relative; isolation: isolate; }
.guide-list .guide-row--link:last-child { border-bottom: none; }
.guide-open { color: inherit; text-decoration: none; }
.guide-open::after { content: ""; position: absolute; inset: 0; z-index: 1; }
@supports selector(:has(a)) {
  .guide-open:focus-visible { outline: none; }
  .guide-row--link:has(.guide-open:focus-visible) {
    outline: 2px solid var(--honey-text); outline-offset: -2px;
  }
}
.guide-filter-group { display: flex; flex-direction: column; gap: 7px; margin-bottom: 14px; }
/* A little more air above WHERE now that the letters below the All
   row are quieter and closer together — the gap is what separates
   the two controls, not a border. */
.rail--alpha .guide-filter-group { margin-top: 6px; }
/* flex: none — .inp--select's 1 1 200px basis is horizontal in the
   food controls but VERTICAL inside this column, where it stretched
   each select to a 200px-tall box */
.inp--rail-select { width: 100%; max-width: none; background: var(--surface); flex: 0 0 auto; }
/* Lighter to match the letters it now sits under: a hairline rather
   than a full-weight field border, and the same 8px corner. */
.rail--alpha .inp--rail-select {
  border-color: #E8C06038; border-radius: 8px; padding: 10px 12px; font-size: 13.5px;
}
.rail--alpha .inp--rail-select:hover { border-color: #D4A14170; }
@media (max-width: 999.98px) {
  .rail--alpha .guide-filter-group { flex: 1 1 220px; margin-bottom: 0; }
  /* Clear all shares this line with the Where group, which is a
     LABEL STACKED ON A SELECT. The button's own align-self is
     flex-start — right for the desktop column, where it means "hug
     the left edge", but in this row it means "hug the top", which
     floated it up beside the word WHERE with nothing to line up
     against. Its bottom edge belongs on the select's. */
  .rail--alpha .filter-clear-all { align-self: flex-end; margin-top: 0; }
}

/* ── Resources: landing page, rail counts, chip-rail affordance ── */
.rail-count {
  margin-left: auto; font-family: var(--font-mono); font-size: 11.5px;
  color: var(--text-light); background: #E8C06022; border-radius: 50px;
  padding: 2px 8px;
}
.rail-item.on .rail-count { background: #E8C06033; color: var(--honey-text); }
.res-overview-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, clamp(280px, 20vw, 360px)), 1fr));
  gap: var(--gap-grid); margin-top: clamp(20px, 2vw, 32px);
}
.res-overview-card {
  display: flex; align-items: flex-start; gap: 14px;
  background: var(--surface); border: 1px solid #E8C06033; border-radius: 14px;
  padding: 18px 20px; text-align: left; color: var(--honey-text);
  transition: transform .25s, box-shadow .25s, border-color .25s;
}
.res-overview-card:hover {
  transform: translateY(-2px); border-color: #D4A14180;
  box-shadow: 0 10px 24px #D4A14118;
}
.res-overview-ic {
  flex: 0 0 auto; width: 42px; height: 42px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: #E8C0601A; border: 1px solid #E8C06035;
}
.res-overview-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.res-overview-title {
  font-family: var(--font-serif); font-size: 19px; color: var(--deep-earth);
  display: inline-flex; align-items: baseline; gap: 8px; line-height: 1.25;
}
.res-overview-count { font-family: var(--font-mono); font-size: 12px; color: var(--text-light); }
.res-overview-desc { font-size: 13.5px; color: var(--text-mid); line-height: 1.55; }
.res-overview-arrow { margin-left: auto; align-self: center; font-size: 17px; }
/* The stacked chip rail fades at its right edge, so the categories
   past the fold announce themselves instead of being cut mid-word.
   Not the wrapping rail (F111): nothing is past the fold there, and
   the fade only dimmed the chips that happen to end a line. */
@media (max-width: 999.98px) {
  .rail--nav:not(.rail--wrap) {
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 34px), transparent);
            mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 34px), transparent);
  }
}

/* ── Login / Join ──────────────────────────────────────────────── */
.field-hint { font-size: 12.5px; color: var(--text-light); margin: 6px 0 0; line-height: 1.5; }
.signin-forgot { margin: 14px 0 0; text-align: center; font-size: 13.5px; }
.signin-recover { margin-top: 16px; padding-top: 16px; border-top: 1px solid #E8C06035; }
.signin-recover-row { display: flex; gap: 8px; align-items: stretch; }
.signin-recover-row .inp { flex: 1 1 auto; min-width: 0; }
.signin-recover-row .bg { flex: 0 0 auto; white-space: nowrap; }
.signin-switch { margin: 18px auto 0; text-align: center; font-size: 14px; color: var(--text-mid); max-width: min(100%, clamp(420px, 32vw, 560px)); }

/* ── Contact us ────────────────────────────────────────
   One page, one form, one address under it. The card is the sign-in
   card given room for a message box, so the page borrows the site's
   existing language rather than inventing one of its own. */
.contact-card { max-width: min(100%, clamp(420px, 44vw, 640px)); }
.contact-lead {
  font-family: var(--font-serif); font-size: clamp(16.5px, 1.5vw, 19px);
  line-height: 1.55; color: var(--deep-earth); margin: 0 0 24px;
}
.contact-card .inp--area { min-height: 150px; }
/* A button that is mid-send says so rather than inviting a second tap */
.contact-card .bg:disabled { opacity: .62; cursor: default; transform: none; box-shadow: none; }

/* A message belongs beside the field it is about, not at the foot of
   the form: on a phone the button and the field are rarely on screen
   together, so a single summary line would be advice nobody sees. */
.field-error {
  font-family: var(--font-sans); font-size: 13px; line-height: 1.5;
  color: var(--error); margin: 7px 0 0;
}
.inp[aria-invalid="true"] { border-color: var(--error); }
.inp[aria-invalid="true"]:focus { border-color: var(--error); }

/* Off-screen rather than display:none: the scripts worth catching
   skip the inputs that are not there. Never focusable, never read. */
.contact-trap {
  position: absolute; left: -9999px; top: auto;
  width: 1px; height: 1px; opacity: 0; pointer-events: none;
}

.contact-done {
  background: var(--surface); border: 1.5px solid #E8C06035; border-radius: 18px;
  padding: clamp(30px, 3vw, 48px) clamp(24px, 2.2vw, 40px);
  max-width: min(100%, clamp(420px, 44vw, 640px)); margin: 0 auto;
  text-align: center;
}
.contact-done-mark { font-size: 34px; line-height: 1; margin-bottom: 14px; }
.contact-done-title {
  font-family: var(--font-serif); font-size: clamp(19px, 2vw, 25px);
  line-height: 1.35; color: var(--deep-earth); margin: 0 0 12px;
}
.contact-done-text {
  font-size: 15px; line-height: 1.7; color: var(--text-mid);
  margin: 0 auto 24px; max-width: 46ch; overflow-wrap: anywhere;
}

@media (max-width: 560px) {
  .contact-card .inp--area { min-height: 128px; }
}
/* Send message is this page's whole purpose, so on a touch screen it
   gets the full 44px target rather than the 40px a .bg normally is. */
@media (pointer: coarse) {
  .contact-card .bg--block { min-height: 44px; }
}

/* ── Organiser page: value before price ────────────────────────── */
.org-stats {
  display: flex; gap: clamp(24px, 4vw, 70px); justify-content: center;
  flex-wrap: wrap; margin-bottom: clamp(26px, 2.6vw, 44px);
}
.org-value-grid { margin-top: 0; }
.org-bonus {
  text-align: center; font-size: 14px; color: var(--text-light);
  line-height: 1.7; max-width: 68ch; margin: clamp(18px, 1.8vw, 28px) auto 0;
}
.org-next { max-width: min(100%, 800px); }
/* Audience choices are checkboxes, so they look like checkboxes —
   circular controls read as pick-one radios. */
.lvl-opt-check { border-radius: 5px; }
.lvl-opt.on .lvl-opt-check { border-radius: 5px; }
/* The Event Type select inside the form card */
.inp--form-select { width: 100%; max-width: none; }

/* ── Donate: the tiers say they are buttons ────────────────────── */
button.tier { font-family: var(--font-sans); display: block; }
.tier-cta {
  margin-top: 12px; font-size: 13px; font-weight: 700;
  color: var(--honey-text); letter-spacing: .03em;
}
.tier--highlight .tier-cta { color: var(--on-dark); }
.seva-opened {
  display: inline-block; margin: 0 auto 22px; padding: 11px 20px;
  border-radius: 50px; background: var(--page-soft);
  border: 1px solid #D4A14150; font-size: 14px; color: var(--deep-earth);
}
.support-note--entity { font-size: 12.5px; margin-top: 10px; }

/* ── Filter-flow refinements (events page) ──────────────────────
   The panel reads as one journey (What → Where → When → Who it's
   for → Facilitator); the date fields carry real labels; and the
   rarer offering contexts wear a small badge on the cards, so a
   filtered list explains itself. */
.date-range-label {
  font-size: 11px; font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-mid);
  font-family: var(--font-sans);
}
.date-hint,
.filter-hint {
  margin: 2px 0 0; font-size: 12px; line-height: 1.5;
  color: var(--text-light); font-family: var(--font-sans);
}
/* The line under WHO IT'S FOR (suitability brief §3.6): the date
   hint's voice, with the way to the definitions on the end of it. */
.filter-hint .link-plain {
  font-size: inherit;
  /* Same 44px tap box as the gathering page's caption link, by the
     same trick: padding out, margin back, nothing moves. */
  display: inline-block; padding: 14px 0; margin: -14px 0;
}
/* The suitability badge on event cards: the lvl-badge pill, sized
   to sit on the date line. Text darkened for small-size contrast
   while the border keeps the context colour. */
.card-suits-badge {
  /* Pushed to the card's right edge, under the country (F36).
     Left under the date it read as a second, competing date line and
     was easy to miss. On the right it lands beneath the country in
     .card-top — both are secondary facts about the offering, both sit
     on the same edge, and the eye reads one column of them down the
     right while the name and date hold the left.
     `margin-left: auto` is what does it: it takes the free space on
     the flex line, so the badge finishes flush with the card's
     content edge whether it shares the date's line or wraps below it
     on a narrow card. */
  margin: 0 0 0 auto;
  color: color-mix(in srgb, var(--c) 72%, var(--ink-deep));
  /* Spoken at half the volume (F36). This was the only UPPERCASE,
     700-weight, hard-bordered thing on a card — the loudest voice on
     the page saying its least important fact, directly under two type
     tags that are calm and sentence-case. The words are unchanged and
     it is still a pill, so a filtered list still shows why each card
     is in it; it simply stops competing with the gathering's own name.
     Same tokens throughout: sentence case like the tags above, a
     lighter weight than theirs because it matters less, and a
     hairline where a 45% border used to be. */
  text-transform: none;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .01em;
  padding: 3px 10px;
  border-color: color-mix(in srgb, var(--c) 18%, transparent);
  background: color-mix(in srgb, var(--c) 6.5%, var(--surface));
}
.ec .card-foot .card-suits-badge { margin-left: 0; }
/* A gathering with two labels wears two pills (F100), in one group
   that takes the single pill's place: pushed to the right edge, and
   wrapping as a pair — together on the date's line when they fit,
   together on the next when they do not. */
.card-suits-pair {
  margin: 0 0 0 auto;
  display: inline-flex; flex-wrap: wrap; justify-content: flex-end;
  gap: 6px;
}
.card-suits-pair .card-suits-badge { margin-left: 0; }
.ec .card-foot .card-suits-pair { margin-left: 0; justify-content: flex-start; }
/* "Open to all", the ordinary case, wears the same pill in the same
   place at lower weight still (suitability brief §3.5, 2 Sep 2026).
   Until then it wore nothing, so the badge only ever appeared as a
   caution. The two deeper labels keep their tint; this one steps
   down to the quiet text colour, a hairline at a quarter of the
   strength, and the lightest wash — visibly a badge, audibly a
   murmur. Same tokens, no new colour. */
.card-suits-badge--open {
  color: var(--text-light);
  font-weight: 400;
  border-color: color-mix(in srgb, var(--c) 10%, transparent);
  background: color-mix(in srgb, var(--c) 3%, var(--surface));
}

/* ── Cost chip (spec §5.0 S-LABEL) ─────────────────────────────
   "Free", "By donation" or "Paid", in the same pill shape as the
   suitability badge so the two sit together on the date line
   without competing.

   Deliberately ONE neutral colour for all three values, taken from
   the existing earth token rather than a new one: a green "Free"
   beside a red "Paid" would rank the offerings, and §0.3 rule 5
   and §5.0 both forbid any styling that implies a hierarchy. No
   icon, for the same reason. */
.cost-chip {
  display: inline-flex; align-items: center;
  margin-left: 10px; vertical-align: 1px;
  padding: 2.5px 9px; border-radius: 20px;
  font-size: 10px; font-weight: 700; letter-spacing: .4px;
  text-transform: uppercase; white-space: nowrap;
  color: var(--text-mid);
  border: 1px solid #5B3E1F3D;
  background: #5B3E1F0F;
}
/* In the chip row on a gathering's own page the chips are laid out
   by the row's own gap, so the card's left margin would double it. */
.chip-row .cost-chip { margin-left: 0; vertical-align: baseline; }

/* ── One-off / monthly (spec §4.9) ─────────────────────────────
   Two pills above the amounts, reusing .type-pill exactly as the
   filter rail does, so nothing new is introduced to look at. */
.seva-when {
  display: flex; justify-content: center; flex-wrap: wrap;
  gap: 10px; margin: 0 0 22px;
}

/* A saved gathering that has already happened stays in the member's
   list and says so (spec §7.1 S-STATE, M-ST-01), rather than quietly
   disappearing the morning after. */
.chip-state { opacity: .72; font-weight: 400; }

/* ── Status banner (spec §5.0 S-STATE) ─────────────────────────
   Full width above the CTA on a gathering that has taken place. A
   statement of fact, in the existing earth token — not a warning,
   and not a colour the site does not already use. */
/* THE FEATURED SLOT (§4.6, §5.2, §14 EPIC 11).
   A strip above the results, never a reordering of them. On a phone it
   scrolls horizontally, as §5.0's component table asks; on a wider
   screen the three sit side by side. No new colour: the chip borrows
   the accent already used for the presale badge's tone. */
.featured-slot { margin: 0 0 26px; }
.featured-slot-head {
  text-transform: uppercase; letter-spacing: .8px;
  font-size: 11px; font-weight: 800; opacity: .6;
  margin: 0 0 10px;
}
.featured-strip {
  display: grid;
  grid-auto-flow: column;
  /* Never wider than a third each, never narrower than a readable
     card. At 360px one card fills the width and the rest scroll. */
  grid-auto-columns: minmax(min(85%, 280px), 1fr);
  gap: 14px;
  overflow-x: auto;
  /* Cards snap, so a half-card is never the resting state. */
  scroll-snap-type: x mandatory;
  padding-bottom: 4px;
  -webkit-overflow-scrolling: touch;
}
.featured-strip > * { scroll-snap-align: start; }
@media (min-width: 860px) {
  /* Three across, and no scrolling: the slot is capped at three. */
  .featured-strip { grid-auto-flow: row; grid-template-columns: repeat(3, 1fr); overflow-x: visible; }
}
.featured-chip {
  display: inline-flex; align-items: center;
  padding: 2px 9px; border-radius: 20px;
  font-size: 10px; font-weight: 800; letter-spacing: .5px;
  text-transform: uppercase;
  border: 1px solid currentColor;
}

/* "Cancel this gathering?" — asked inline rather than in a browser
   confirm(), which cannot be styled, cannot be read by a screen reader
   in context, and on iOS appears above the fold with no relation to the
   row it belongs to. Wraps on a narrow screen so nothing overflows. */
.confirm-inline {
  display: inline-flex; flex-wrap: wrap; align-items: center;
  gap: 4px 10px; font-size: .82rem;
}

/* Lifecycle chips (§14 EPIC 10, strings M-ST-02 / M-ST-03 / M-REC-01).
   Same shape as the cost chip beside them — no new colour, no new
   typeface. "Cancelled" is the one that needs to stop the eye, so it
   takes the existing error tone rather than a new one. */
.state-chip, .recur-chip {
  display: inline-flex; align-items: center;
  padding: 2px 8px; border-radius: 20px;
  font-size: 11px; font-weight: 700; letter-spacing: .2px;
  border: 1px solid currentColor;
  opacity: .85;
}
.state-chip.is-cancelled { color: var(--error); opacity: 1; }
.status-banner.is-cancelled { color: var(--error); font-weight: 700; }

.status-banner {
  margin: 0 0 14px; padding: 10px 14px; border-radius: 12px;
  background: #5B3E1F0F; border: 1px solid #5B3E1F26;
  color: var(--text-mid); font-size: .92rem; line-height: 1.5; text-align: center;
}

/* ── My gatherings (spec §5.7) ─────────────────────────────────── */
.my-gatherings { display: grid; gap: 12px; margin: 4px 0 16px; }
.my-gathering {
  display: flex; flex-wrap: wrap; gap: 10px 16px;
  align-items: flex-start; justify-content: space-between;
  padding: 12px 0; border-top: 1px solid #5B3E1F1A;
}
.my-gathering:first-child { border-top: 0; }
.my-gathering-main { display: grid; gap: 3px; min-width: min(100%, 220px); flex: 1 1 220px; }
.my-gathering-name { font-size: .98rem; }
.my-gathering-meta { font-size: .82rem; opacity: .75; line-height: 1.45; }
.my-gathering-side { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; }

/* What the gathering did (§14 EPIC 9). A four-column grid rather than a
   sentence, so the two windows line up under one set of headings and
   the numbers can be read down as well as across. No new colour and no
   new typeface: it inherits both. */
.gathering-stats { margin-top: 8px; }
.gathering-stats-grid {
  display: grid;
  /* The label column takes what it needs; the three number columns
     share the rest equally, so they stay aligned whatever the counts
     grow to. At 360px this is about 92px + 3 x 54px, well inside the
     card. */
  grid-template-columns: auto repeat(3, minmax(2.5rem, 1fr));
  gap: 2px 10px;
  font-size: .78rem;
  /* Digits of equal width, so 111 sits directly under 9. */
  font-variant-numeric: tabular-nums;
  max-width: 20rem;
}
.gathering-stats-head {
  text-transform: uppercase; letter-spacing: .4px;
  font-size: 9px; font-weight: 700; opacity: .55;
}
.gathering-stats-when { opacity: .75; padding-right: 4px; }
/* One neutral chip for every state. A green "Published" beside a red
   "Not published" would read as a verdict on the organiser rather than
   a fact about the listing. */
.status-chip {
  display: inline-flex; align-items: center;
  padding: 3px 10px; border-radius: 20px;
  font-size: 10px; font-weight: 700; letter-spacing: .4px;
  text-transform: uppercase; white-space: nowrap;
  color: var(--text-mid); border: 1px solid #5B3E1F3D; background: #5B3E1F0F;
}
.sheet--edit { max-height: 86vh; overflow-y: auto; }

/* ── Soonest / For you (spec §5.0 S-FORYOU) ────────────────────
   Two pills beside the result count, reusing .type-pill so the
   ordering control looks like every other choice on the page. */
.ordering { display: inline-flex; flex-wrap: wrap; gap: 8px; margin-left: 14px; vertical-align: middle; }
/* The signed-out For you teaser (founder's F25, 24 Aug 2026): the
   chip is quieter than a live control, and both it and the line open
   the join page — nothing here does nothing. */
.type-pill--tease { opacity: .55; }
/* Once three types are chosen, the rest stop responding. Dimmed rather
   than silently inert, so a tap that does nothing looks like a rule and
   not a bug. Still focusable and still announced, because the cap can
   be undone by deselecting one. */
.type-pill--full { opacity: .42; }
.ordering-tease { font-size: 12px; margin-left: 4px; }
/* Clear, beside the result count. Quiet enough not to compete with the
   count itself, close enough to be the obvious way back. */
.result-clear { font-size: 12.5px; margin-left: 12px; white-space: nowrap; }
.ordering-note { margin: 0 0 14px; color: var(--text-mid); opacity: .85; font-size: .9rem; line-height: 1.5; }

/* The new-visitor strip above the results (suitability brief §4.1,
   2 Sep 2026). One quiet line in the panel's own cream, the way in
   for a newcomer on the left, the visitor's "actually, no" and the
   dismiss on the right. Existing tokens throughout; the two small
   controls carry 44px tap boxes without moving the line. */
.newcomer-strip {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 16px;
  margin: 0 0 14px; padding: 8px 6px 8px 14px;
  background: var(--page-cream); border: 1px solid #D4A14140; border-radius: 12px;
  font-family: var(--font-sans); font-size: 14px; line-height: 1.5;
  color: var(--text-mid);
}
.newcomer-strip-text { margin: 0; flex: 1 1 260px; min-width: 0; }
.newcomer-strip-link { color: var(--deep-earth); text-decoration: underline; text-underline-offset: 2px; }
.newcomer-strip-link:hover { color: var(--honey-text); }
.newcomer-strip-pref {
  font-size: 13px; color: var(--text-light);
  display: inline-block; padding: 12px 0; margin: -12px 0;
}
.newcomer-strip-close {
  width: 44px; height: 44px; margin: -8px 0;
  background: none; border: none; border-radius: 50%; cursor: pointer;
  font-size: 22px; line-height: 1; color: var(--text-light);
}
.newcomer-strip-close:hover { color: var(--deep-earth); background: var(--surface); }
@media (max-width: 640px) {
  .ordering { display: flex; margin: 10px 0 0; }
}






/* The active filters, named right in the results heading */

/* ── Active-filter chips above the results ──────────────────────
   The applied filters, restated where the results are — visible on
   every viewport, each chip removable. Type chips keep their
   category colour via the shared .t-* classes. */
.active-filters {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 8px; margin-bottom: 14px;
}
.active-filters-label {
  font-size: 11px; font-weight: 700; letter-spacing: .14em;
  color: var(--text-light); font-family: var(--font-sans);
  margin-right: 2px;
}
/* Doubled with .chip.on so the per-type --c wins over the generic
   honey fill that .chip.on applies */
.chip.on.active-filter-chip {
  background: color-mix(in srgb, var(--c, var(--honey)) var(--fill-share, 100%), var(--text-dark));
  border-color: color-mix(in srgb, var(--c, var(--honey)) var(--fill-share, 100%), var(--text-dark));
  color: var(--on-fill, var(--on-accent-strong));
}
.active-filter-chip span { opacity: .75; margin-left: 2px; }
.active-filter-chip:hover { opacity: .88; color: var(--on-fill, var(--on-accent-strong)); }
/* Colored type chips need readable text on their own fill */
.active-filter-chip.t-festival, .active-filter-chip.t-retreat, .active-filter-chip.t-workshop, .active-filter-chip.t-kirtan, .active-filter-chip.t-course, .active-filter-chip.t-temple, .active-filter-chip.t-satsang, .active-filter-chip.t-pilgrimage, .active-filter-chip.t-yoga, .active-filter-chip.t-other, .active-filter-chip.t-online { color: var(--on-accent); }

/* A selected filter pill says so in words a glance can't miss: the
   colour dot gives way to a checkmark, and the label turns bold. */
.type-pill.on::before { content: "✓"; font-weight: 800; }
.type-pill.on .type-dot { display: none; }
.type-pill.on { font-weight: 700; }

/* ── Event flyer beside the intro ───────────────────────────────
   Optional per gathering (flyerImage / the events.image column).
   Portrait, shown WHOLE at its own ratio — never cropped — with
   soft corners and a quiet shadow. Text left, flyer right on
   desktop; on a phone the flyer follows the description, before
   the details card. Without a flyer the grid is one column and
   nothing reserves space. */

/* ══ Homepage: the Event Facilitator band ════════════════════════
   A door to /event-facilitators/ that shows who is actually behind
   the gatherings, sat between the upcoming events and "What is
   bhakti?". Petal, so it separates the two warm-white sections
   around it rather than merging with them. Nothing new is invented
   here: the portraits are the directory's own .guide-photo circles,
   resized through --guide-av, and the button is the same .bg .bg-o
   the rest of the homepage uses. */
.section-people {
  padding: var(--section-pad-y) var(--page-pad-x);
  background: var(--page-soft); position: relative; overflow: hidden;
}
.h2--people { font-size: clamp(26px, 2.7vw, 48px); line-height: 1.18; }

/* Six faces: one row on a desktop, two rows of three on a tablet,
   three rows of two on a phone. Flex rather than a grid, so a short band (fewer
   than six facilitators have anything coming up) centres its last
   row instead of leaving a hole on the right. Items stretch, so
   every card in a row matches the tallest name in it. */
.people-row {
  --guide-av: clamp(60px, 5.4vw, 76px);
  --people-gap: clamp(10px, 1.2vw, 18px);
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--people-gap);
  margin-top: clamp(18px, 2vw, 32px);
}
.people-card { flex: 0 1 calc((100% - 5 * var(--people-gap)) / 6); }
/* The same two steps the hero's intent cards take (1000px, 560px),
   so the homepage changes shape once, not twice, on the way down. */
@media (max-width: 1000px) {
  .people-card { flex-basis: calc((100% - 2 * var(--people-gap)) / 3); }
}
@media (max-width: 560px) {
  .people-card { flex-basis: calc((100% - var(--people-gap)) / 2); }
}

.people-card {
  display: flex; flex-direction: column; align-items: center;
  gap: 9px; text-align: center;
  /* Comfortably past the 44px coarse-pointer minimum on every side */
  padding: clamp(14px, 1.4vw, 20px) 8px;
  background: color-mix(in srgb, var(--surface) 67.84%, transparent); border: 1px solid #E8C06040; border-radius: 14px;
  transition: transform .25s, box-shadow .25s, border-color .25s;
}
.people-card:hover {
  transform: translateY(-2px); border-color: var(--honey);
  box-shadow: 0 10px 24px #D4A14122;
}
.people-card:focus-visible { outline: 3px solid var(--honey); outline-offset: 3px; }
/* The directory's fallback initial (shown when a facilitator has no
   portrait stored) is a block by default, so here the circle has to
   centre its letter on its own. Scoped to the avatar: the <img> case
   must stay a replaced element. */
.guide-avatar.people-photo { display: flex; }
.people-name {
  font-family: var(--font-serif); font-size: clamp(14.5px, 1.05vw, 17px);
  font-weight: 600; color: var(--deep-earth); line-height: 1.25;
  /* Long devotional names are the norm, not the exception: two lines
     are allowed, and the cards stay the same height because the grid
     stretches them. */
  overflow-wrap: anywhere;
}
.people-count {
  font-family: var(--font-sans); font-size: 11.5px; font-weight: 700;
  letter-spacing: .04em; color: var(--honey-text);
}
.people-more { margin-top: clamp(18px, 2vw, 30px); text-align: center; }
.people-note { margin-top: 10px; font-size: 13.5px; color: var(--text-mid); }

/* ══ Homepage: the newsletter, inside the membership band ═══════
   It used to be a section of its own at the foot of the page, which
   made three consecutive asks. Here it is the quieter half of one
   "stay connected" block, so it needs a rule above it when the
   membership pitch is present and none when it stands alone. */
.home-news--under {
  margin-top: clamp(28px, 3vw, 44px);
  padding-top: clamp(24px, 2.6vw, 38px);
  border-top: 1px solid #E8C06055;
}

/* ══ Homepage: a paragraph held to two lines on desktop ═════════
   It reads as a single spoken sentence pair, and a third line that
   carried only three or four words made it look like an accident
   rather than a statement. On a desktop it is given enough measure to
   break cleanly in two, and `balance` splits it evenly instead of
   leaving a short tail.

   Desktop only: below 1000px the phone's narrow column decides the
   wrapping, and forcing anything there would just push the text off
   the side. The breakpoint is the one the hero's intent cards and
   the facilitator band already use. */
@media (min-width: 1000px) {
  /* "Make BeeBhakti yours": 58ch was three lines inside a 780px
     container that had the room for two. */
  .home-hb-line { max-width: min(100%, 76ch); text-wrap: balance; }

  /* The roots of Bhakti moved to /new-to-bhakti/ (Aug 2026), where the
     page's own 780px reading column sets the measure. The homepage
     override that used to force two lines here is gone with it; only
     the balancing remains, so whatever lines it takes are even. */
  .roots-prose { text-wrap: balance; }
}

/* ══ Search/no-JavaScript fallback ═══════════════════════════════
   build.py puts meaningful route content in #root before React starts.
   React replaces it immediately for ordinary visitors; if JavaScript is
   unavailable, this remains a calm, usable version of the page. */
.seo-fallback {
  width: min(880px, calc(100% - 36px));
  margin: 0 auto;
  padding: clamp(28px, 6vw, 72px) 0;
  color: var(--deep-earth);
}
.seo-fallback nav {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  margin-bottom: clamp(36px, 7vw, 80px);
  font: 700 13px/1.4 var(--font-sans);
}
.seo-fallback nav a, .seo-fallback a { color: var(--honey-text); }
.seo-fallback h1, .seo-fallback h2 { font-family: var(--font-serif); }
.seo-fallback h1 {
  max-width: 760px;
  margin-bottom: 18px;
  font-size: clamp(34px, 7vw, 66px);
  line-height: 1.03;
}
.seo-fallback h2 { margin: 24px 0 7px; font-size: 23px; }
.seo-fallback p, .seo-fallback li { font: 400 17px/1.7 var(--font-sans); }
.seo-fallback > p, .seo-fallback article > p { max-width: 760px; }
.seo-list { margin: 30px 0 0; padding-left: 22px; }
.seo-list li { margin-bottom: 12px; }

/* ── Home headline on a narrow screen ────────────────────────────
   One line only works while the column is wide enough to hold one.
   Below 1000px it is not: holding the line would set the h1 at 44px
   and falling, down to 17.5px at 360px — an h1 smaller than the body
   text under it, and clipped the moment a phone browser's text
   autosizing pushes it back up.

   So below 1000px the line breaks instead. The accent span becomes
   its own line, so the break always falls at "around the world"
   rather than wherever the string happens to run out of room, and
   the size is free to be a headline again. */
@media (max-width: 999.98px) {
  .hero-title {
    white-space: normal;
    font-size: clamp(24px, 7.4vw, 40px);
    line-height: 1.18;
    text-wrap: balance;
  }
  .hero-title-accent { display: block; }
}

/* ── Prose pages on a phone ──────────────────────────────────────
   Every vertical measure on About and New to bhakti is a clamp, and
   on a phone every one of them sits on its floor at once: 28px above
   the title, 6px under it, 14px before the first overline, 16px under
   a section heading and 14px between paragraphs — against a 1.85 line
   height, which means the gap between two paragraphs is smaller than
   the gap between two lines. Read at arm's length it runs together.

   The floors are raised here and only here; the clamps still govern
   from tablet up, so nothing above 768px moves. */
@media (max-width: 767.98px) {
  .page-head-wrap { padding-top: 34px; }
  .page-head-title { margin-bottom: 12px; }

  /* Membership keeps these floors. About and New to bhakti? no longer
     do: their spacing is set by the shared editorial system above,
     whose clamps already bottom out at phone widths. Left in the
     shared selector these rules quietly won on mobile — same
     specificity, later in the file — and put the hero gap back to
     28px and the section boundary to 92px, undoing the very thing the
     system exists to standardise. */
  .page--honeybee { --section-pad-y: 46px; }
  .page--honeybee .mw-780 .section-head,
  .page--honeybee .mw-960 .section-head { margin-bottom: 22px; }
  .page--honeybee .overline { margin-bottom: 11px; }
  .page--honeybee .prose { margin-bottom: 20px; }
}

/* ── Footer, restructured (Aug 2026) ─────────────────────────────
   Three tracks: the brand and its two offers, then Discover and
   Connect. Sharing a gathering used to be a column of its own holding
   a single link, which left one short stack of text beside two full
   ones. It is a button beside Donate now, and the grid drops from
   four tracks to three. No copy left the site: the link keeps its
   words, and "Share" is still on every event card's share button.

   Plain, on the founder's instruction (23 Aug 2026): no rules between
   the links, no ornament above the columns, nothing dividing the
   thanks from the navigation or the count from the copyright. The
   footer is set in one quiet tone on the dark ground, and the spacing
   does the separating. */
.footer-grid { grid-template-columns: minmax(260px, 1.25fr) repeat(2, minmax(160px, 1fr)); }
/* Three tracks do not halve. Below 860px the brand takes a row of its
   own and the two link columns share the next one — the old two-up
   rule was written for four columns and, with three, left Connect
   alone beside an empty half. */
@media (max-width: 860px) {
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer-brand { grid-column: 1 / -1; max-width: none; }
}
@media (max-width: 560px) {
  .footer-grid { grid-template-columns: minmax(0, 1fr); row-gap: clamp(26px, 6vw, 40px); }
  .footer-brand { grid-column: auto; }
}
.footer-brand { max-width: 360px; }

/* The verse wraps now that it shares the column with a button row;
   nowrap held it to one line and set the width of the whole block. */
.footer-quote { white-space: normal; font-size: clamp(13.5px, 0.5vw + 12px, 15px); line-height: 1.7; text-wrap: balance; }

/* Donate and Share a gathering, side by side: one filled, one
   outlined, so the pair reads as a primary and a secondary rather
   than two equal choices. */
.footer-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
a.footer-cta--solid { background: var(--grad-honey); border-color: transparent; color: var(--dark-bg); font-weight: 600; }
a.footer-cta--solid:hover { filter: brightness(1.07); }
a.footer-cta:hover { border-color: #D4A14180; }

.footer-col-title { margin-bottom: 14px; }
.footer-gratitude { margin-top: clamp(30px, 3vw, 50px); }
.footer-bottom { margin-top: clamp(18px, 1.8vw, 28px); align-items: center; }

/* ── The gathering page, quieted (Aug 2026) ──────────────────────
   What made it heavy, in the order it was felt:

   1. The flyer is the ORGANISER'S POSTER, not a photograph. It
      carries the gathering's title, its dates, its place and often a
      QR code and a "book now" — every one of them already on this
      page in the page's own voice. Given a hero's size it repeated
      the h1 in a louder typeface, in its own colours, on a cream
      page it had no relationship with.
   2. It was capped by WIDTH (340px), so a portrait A4 became a 469px
      tower next to a 218px block of text: 251px of dead space beside
      the description on a desktop, and a whole screenful of scroll on
      a phone before the first fact. A landscape photograph had the
      opposite problem.
   3. TWO two-column grids, stacked, with different column widths —
      text 736 | flyer 333, then facts 774 | actions 307. Nothing
      shared an edge, so the page had no spine.
   4. Eight facts, each in a 44px tinted icon chip with a tracked
      label and a 17px semibold value, inside a bordered white card.
      When and Where — the two questions a visitor actually arrives
      with — looked exactly like Format and Who it's for.

   The answers: one spine, three essentials set as type, the rest as
   a quiet list, no cards, and a flyer capped by height. */

.event-top-wrap { padding-top: clamp(20px, 2vw, 34px); }
.page--event .page-head-title--event { margin-bottom: clamp(14px, 1.4vw, 22px); }

/* One grid for the whole page, and the reading column is made of
   grid ITEMS rather than one wrapper — head, flyer, lead, details.
   That is what lets the poster sit between the essentials and the
   description on a phone (source order) and in the rail on a desktop
   (explicit placement) without being written into the page twice.

   Row gap stays 0: the blocks carry their own margins, and a grid gap
   on top of them would double every space on the page. */
.event-top {
  display: grid; grid-template-columns: minmax(0, 1fr);
  column-gap: clamp(26px, 3vw, 54px); row-gap: 0;
  align-items: start;
}
.event-head, .event-lead, .event-details { min-width: 0; max-width: 68ch; }
@media (min-width: 1000px) {
  /* The poster rail, widened 25 Aug 2026. The founder: the image "can
     feel too small while there is unused space available".

     Measured at 1440px before the change: the grid gave the text
     column 906px, the text is capped at 68ch — 720px — so 186px of
     that column was empty, and 247px of the row was unused in total.
     The poster sat at 241x340 beside it.

     So the rail grows into space nothing was using. The reading
     measure is untouched, deliberately: 68ch is the width prose is
     comfortable at, and widening THAT would trade a real quality for
     a bigger picture. At 1440 the text column still lands at ~820px,
     which is more than the 720px cap needs, so the paragraphs do not
     move at all — only the poster does. */
  .event-top--flyer { grid-template-columns: minmax(0, 1fr) clamp(230px, 24vw, 360px); }
  .event-top--flyer > .event-head,
  .event-top--flyer > .event-lead,
  .event-top--flyer > .event-details { grid-column: 1; }
  /* The rail spans all three rows of the reading column rather than
     sitting in the first. Placed in row 1 alone, a 342px poster makes
     row 1 342px tall — and the 198px head block that shares it leaves
     a 144px hole above the description. Spanning, the rows are sized
     by the left column and the poster simply starts at the top. */
  .event-top--flyer > .event-flyer { grid-column: 2; grid-row: 1 / span 3; align-self: start; }
}

/* The three a visitor is scanning for. No icon, no chip, no box:
   the label is small and quiet, the value is the size of the answer.
   They sit in one row on a desktop and stack on a phone, where a row
   of three would set each value in a 100px column. */
.event-essentials {
  display: flex; flex-wrap: wrap;
  gap: clamp(18px, 2.6vw, 46px);
  margin: 0 0 clamp(20px, 2vw, 30px);
}
.event-essential { min-width: 0; }
.event-essentials dt {
  font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-light); margin-bottom: 5px;
}
.event-essentials dd {
  font-family: var(--font-sans); font-size: clamp(17px, 0.5vw + 15px, 21px);
  font-weight: 600; color: var(--deep-earth); line-height: 1.35;
  margin: 0; overflow-wrap: break-word;
}
/* "Who it's for" joined the essentials on 2 Sep 2026 (suitability
   brief §3.1). Under the two deeper labels the definition is set as a
   sentence, not as a second answer: body size, ordinary weight, the
   reading colour. The reassurance beneath it is the existing note,
   now also the link to the three definitions. */
.event-essential-def {
  display: block; margin-top: 4px; max-width: 42ch;
  font-size: 14px; font-weight: 400; line-height: 1.5;
  color: var(--text-mid);
}
.event-essentials .event-detail-note { margin-top: 5px; }
/* FS-01 FR-4: under the WHO IT'S FOR row of a "New to bhakti"
   gathering, the conditional sentence and, beneath it, the organiser's
   own note at the same prominence. The note wears the threshold
   screen's existing quote block; the sentence is set at that block's
   size so the two read as one voice. Existing tokens only. */
.event-newcomer { margin-top: 14px; max-width: 62ch; }
.event-newcomer-line {
  margin: 0 0 12px; font-size: 15.5px; line-height: 1.6;
  color: var(--text-mid);
}
.event-newcomer-note { margin: 0; }
.event-newcomer-from {
  display: block; margin-bottom: 4px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-light);
}
/* FS-01 FR-7: the one link at the foot of /new-to-bhakti/, beneath the
   two buttons. A 44px tap box by the same padding trick the filter
   hint's link uses. */
.newcomer-path { margin: 14px 0 0; text-align: center; }
.newcomer-path-link {
  display: inline-block; padding: 12px 6px;
  font-weight: 600; font-size: 15px;
}
.event-detail-note--link {
  color: var(--text-light); text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--text-light) 45%, transparent);
  text-underline-offset: 2px;
}
.event-detail-note--link:hover { color: var(--deep-earth); }
/* A 12px italic line is a 16px tap box. CLAUDE.md rule 8 wants 44:
   the padding grows the box and the negative margin gives the space
   straight back — 5px of it was the note's own gap above, so the
   page does not move by a pixel. Two classes, and after the two-class
   margin rule above, because `.event-detail-note` further down sets
   display and margin at one class and would otherwise win on order. */
.event-essentials .event-detail-note--link {
  display: inline-block; padding: 14px 0; margin: -9px 0 -14px;
}

.event-desc {
  font-size: clamp(16px, 0.2vw + 15.2px, 18px); line-height: 1.8;
  color: var(--text-mid); margin: 0 0 clamp(24px, 2.4vw, 38px);
  max-width: 62ch;
  /* Organisers write their description with paragraphs, and until
     28 Aug 2026 HTML threw every one of them away: a run of newlines
     is whitespace, and whitespace collapses. Gita Fest 2026 arrived
     with 39 line breaks and rendered as one wall of text.
     `pre-line` keeps the newlines and still wraps normally — a blank
     line stays a blank line, and a run of spaces still collapses, so
     an organiser who indents or double-spaces does not get it back on
     the page. The list CARD deliberately does not do this: it is
     clamped to a couple of lines, where hard breaks would spend the
     clamp on half-empty lines. */
  white-space: pre-line;
}

/* ── The threshold screen (suitability brief §6, 3 Sep 2026) ──
   The gathering page's own reading column, with the page's own
   voices: the badge the cards wear, the description's measure for
   the two sentences, the card grid from Continue exploring, the
   primary button. Nothing new to learn; one screen, then on. */
.threshold { max-width: 68ch; }
.threshold-back { margin-bottom: 22px; }
.threshold-label {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  margin: 0 0 18px; font-family: var(--font-sans);
  font-size: 15px; line-height: 1.5; color: var(--text-mid);
}
/* The card badge pushes itself to a card's right edge; here it leads
   the line. */
.threshold-label .card-suits-badge { margin-left: 0; }
.threshold-note {
  margin: 0 0 18px; padding: 12px 16px;
  border-left: 3px solid var(--honey); background: var(--page-cream);
  border-radius: 0 12px 12px 0;
  font-size: 15.5px; line-height: 1.6; color: var(--text-mid);
  white-space: pre-line;
}
.threshold-text {
  font-size: clamp(16px, 0.2vw + 15.2px, 18px); line-height: 1.8;
  color: var(--text-mid); margin: 0 0 18px; max-width: 62ch;
}
.threshold-picks { margin: 0 0 24px; }
.threshold-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  margin: 0 0 18px;
}
/* The small link is the visitor telling us the opposite; 44px tap
   box by the usual trick, nothing moves. */
.threshold-pref {
  font-size: 14px; display: inline-block; padding: 12px 0; margin: -12px 0;
}

/* One primary action, then everything else on one quiet row. */
.event-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; }
.event-primary { font-size: 15px; padding: 14px 26px; align-self: flex-start; }
.event-secondary { display: flex; gap: 8px; flex-wrap: wrap; }

/* The fine print. A list, not a card: label and value on one row,
   separated by space rather than by a rule or a border. */
.event-details { margin: clamp(30px, 3vw, 48px) 0 0; }
.event-detail-list {
  margin: 0; display: grid; gap: clamp(12px, 1.1vw, 18px);
  max-width: 56ch;
}
/* The reassurance under a label that could read as a bar to clear:
   same words as the account page and the share form, set quietly. */
.event-detail-note {
  display: block; margin-top: 3px;
  font-size: 12px; font-style: italic; color: var(--text-light);
}

.event-detail { display: grid; grid-template-columns: clamp(120px, 13vw, 168px) minmax(0, 1fr); gap: 8px 20px; align-items: baseline; }
.event-detail-list dt {
  font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--text-light);
}
.event-detail-list dd {
  margin: 0; font-family: var(--font-sans); font-size: 15.5px;
  color: var(--text-mid); line-height: 1.55; overflow-wrap: break-word;
}
/* The Event Facilitator's name is the way to their profile now that
   the "Holding the space" card is gone. Underlined rather than
   recoloured, so the list keeps one voice and the link is still
   obvious without colour alone carrying it (WCAG 1.4.1). */
.event-detail-link {
  color: inherit; text-decoration: underline;
  text-decoration-color: #D4A14170; text-underline-offset: 3px;
  transition: color .2s, text-decoration-color .2s;
}
.event-detail-link:hover { color: var(--honey-text); text-decoration-color: var(--honey); }
/* Under about 560px the two columns leave the value 90px, so the
   label steps above it instead. */
@media (max-width: 559.98px) {
  .event-detail { grid-template-columns: minmax(0, 1fr); gap: 3px; }
}

/* Capped by HEIGHT, so the aspect ratio the organiser happened to
   upload stops deciding the page. A portrait A4 reads at about
   240×340 and a wide photograph at its natural height — neither
   becomes a tower, and neither floats in an empty frame. */
.event-flyer {
  display: block; border-radius: 12px; overflow: hidden;
  border: 1px solid #E8C06033;
  transition: transform .25s, box-shadow .25s;
  justify-self: start; max-width: 100%;
}
.event-flyer img {
  display: block; width: auto; height: auto;
  /* Grown with the rail. A portrait poster is the common case (three of
     the four live ones), and its height is what decides its presence —
     capped at 340px it could only ever be 241px wide however much room
     the rail had. */
  max-width: 100%; max-height: clamp(300px, 34vw, 460px);
}
.event-flyer:hover { transform: translateY(-2px); box-shadow: 0 10px 26px #5B3E1F1F; }

/* On a phone the poster must not sit between the visitor and the
   facts, and it does not: the stack is

     1. type, title, WHEN, WHERE, DURATION   (.event-head)
     2. the poster                            (.event-flyer)
     3. the description                       (.event-lead)
     4. facilitator, who it's for, format     (.event-details)

   — identity and the three answers first, then the picture, then the
   prose, then the fine print. Reviewed on the founder's instruction of
   25 Aug 2026 and deliberately KEPT.

   This comment used to claim "order 2 puts it after the details". No
   `order` property has ever existed here, and the poster is second of
   four, not last: the comment described an arrangement the CSS never
   made. Corrected rather than left, since the next person to read it
   would have gone looking for a rule that is not there.

   The height cap below is the real mobile control — a third of the
   screen rather than all of it. It is left where it is: the desktop
   rail grew on 25 Aug because desktop had 186px of measurably unused
   space beside the text, and a phone has none to give. */
/* Stacked, the poster sits between the essentials and the
   description and has to carry its own air; in the desktop rail it
   has none, because the grid gap is already there. */
@media (max-width: 999.98px) {
  .event-flyer { justify-self: center; margin: 0 0 clamp(22px, 4vw, 34px); }
  /* Taller than the desktop rail allows, because stacked it is no
     longer an aside squeezed beside the title — the founder asked for
     it above the description, where it is the gathering's own face and
     wants to be seen. Still a third of a phone screen, not all of it. */
  .event-flyer img { max-height: 320px; }
}

/* The gathering's own continue-exploring band keeps its cards: they
   are the site's shared card, and they are links away from here
   rather than more of this page. */
.event-continue { padding-top: clamp(40px, 4vw, 72px); }

/* ── Loading, error and offline states (25 Aug 2026) ─────────────
   One family, used everywhere something waits on the database. The
   skeletons wear the real components' own classes (.map-card, .ec,
   .card-img, .guide-photo), so their dimensions come from the same
   rules the content uses and nothing jumps when it lands. */

/* The placeholder block itself: quiet parchment with a slow sheen.
   No new colours — these are the existing cream/honey values at low
   strength. */
.skel {
  position: relative; overflow: hidden; display: block;
  background: var(--skeleton); border-radius: 8px;
}
.skel::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--panel) 74.90%, transparent), transparent);
  animation: bbShimmer 1.8s ease-in-out .2s infinite;
}
@keyframes bbShimmer { to { transform: translateX(100%); } }

/* Anti-flash: every loading state fades in after a beat, so an
   answer that arrives quickly never shows a loader at all. The
   delay is the debounce — no timers in the app code. */
.skel-fade, .nectar-loading {
  opacity: 0; animation: bbSkelIn .3s ease .4s forwards;
}
@keyframes bbSkelIn { to { opacity: 1; } }

/* Skeleton cards keep the real card's box; only its own hover and
   accent are softened, and the pointer stays a pointer nowhere. */
.skel-card { cursor: default; }
.skel-card:hover { transform: none; box-shadow: none; }
.skel-card .card-accent { opacity: .35; }

/* The pieces, sized to the text lines they stand in for */
.skel--img    { border-radius: 0; }
.skel--tag    { width: 70px; height: 20px; border-radius: 20px; }
.skel--loc    { width: 54px; height: 12px; margin-left: auto; }
.skel--title  { height: 19px; width: 75%; margin-bottom: 10px; }
.skel--line   { height: 12px; width: 100%; margin-bottom: 8px; }
.skel--line-short { width: 60%; }
.skel--date   { height: 12px; width: 45%; margin-top: 6px; }
.skel--circle { border-radius: 50%; }
.skel--name    { height: 17px; width: 200px; max-width: 60%; margin-bottom: 8px; }
.skel--country { height: 11px; width: 90px; max-width: 40%; }
.skel--result  { height: 13px; width: 220px; max-width: 60%; margin-bottom: 20px; }
.skel--stat    { display: inline-block; width: 2.1ch; height: .9em;
                 vertical-align: baseline; background: #E8C06052; }
.skel--cal     { min-height: 380px; border-radius: 18px; }

/* The branded loader: the lotus breathing, the bee keeping it
   company. Centred wherever it is placed; the overlay form sits on
   the map as a small parchment card so the world stays visible
   behind it. */
.nectar-loading {
  display: flex; flex-direction: column; align-items: center;
  gap: 8px; text-align: center; padding: 26px 16px;
  color: var(--text-mid); font-family: var(--font-sans);
  font-size: 14px; letter-spacing: .04em;
}
.nectar-loading--overlay {
  background: color-mix(in srgb, var(--panel) 87.06%, transparent); border: 1px solid #E8C06055;
  border-radius: 14px; padding: 16px 26px 14px;
  box-shadow: 0 4px 16px #5B3E1F1F;
  backdrop-filter: blur(2px);
}
.nectar-art { position: relative; display: block; width: 44px; height: 44px; }
.nectar-lotus, .nectar-lotus svg { display: block; width: 44px; height: 44px; }
.nectar-lotus { animation: bbLotusBreathe 2.8s ease-in-out infinite; transform-origin: 50% 80%; }
@keyframes bbLotusBreathe {
  0%, 100% { transform: scale(1);    opacity: .85; }
  50%      { transform: scale(1.07); opacity: 1; }
}
.nectar-bee {
  position: absolute; top: -7px; right: -13px;
  animation: bbBeeSip 3.6s ease-in-out infinite;
}
@keyframes bbBeeSip {
  0%, 100% { transform: translate(0, 0)      rotate(-6deg); }
  35%      { transform: translate(-5px, 5px) rotate(4deg); }
  70%      { transform: translate(2px, -3px) rotate(-2deg); }
}
.nectar-loading-slow, .load-slow {
  font-size: 12.5px; color: var(--text-light); letter-spacing: 0;
  line-height: 1.5; max-width: 340px;
}
.load-slow { text-align: center; margin: 14px auto 0; font-family: var(--font-sans); }

/* The error state: one sentence (M-ERR-01) and the retry the spec
   pairs with it. The button is the site's own. */
.load-error {
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  text-align: center; padding: 44px 16px;
}
.load-error-text {
  margin: 0; color: var(--text-mid);
  font-family: var(--font-serif); font-size: 16px;
}

/* Try again inside the red data banner: white outline on the red,
   tall enough to tap (rule 8). */
.data-banner-retry {
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: 12px; min-height: 34px; padding: 2px 16px;
  background: transparent; border: 1.5px solid color-mix(in srgb, var(--surface) 80.00%, transparent); border-radius: 999px;
  color: var(--on-dark); font: inherit; font-weight: 600; cursor: pointer;
  transition: background .2s;
}
.data-banner-retry:hover { background: color-mix(in srgb, var(--surface) 13.33%, transparent); }
@media (pointer: coarse) { .data-banner-retry { min-height: 44px; } }

/* The offline pill: a quiet statement at the foot of the screen,
   never a blocker. Amber dot while offline; it pulses only while
   actively reconnecting. */
.offline-pill {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  z-index: 260; display: flex; align-items: center; gap: 9px;
  max-width: calc(100vw - 32px); box-sizing: border-box;
  background: var(--dark-bg); color: var(--warm-white);
  border: 1px solid #E8C06033; border-radius: 999px; padding: 9px 16px;
  font-family: var(--font-sans); font-size: 13px; line-height: 1.4;
  box-shadow: 0 6px 20px #23120459;
}
.offline-dot {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
  background: var(--honey); animation: bbOfflinePulse 2.2s ease-in-out infinite;
}
@keyframes bbOfflinePulse {
  0%, 100% { opacity: .45; }
  50%      { opacity: 1; }
}

/* Reduced motion: everything above holds still. The fade-in keeps
   its delay (that is the anti-flash debounce) but becomes an
   instant appearance rather than a movement. */
@media (prefers-reduced-motion: reduce) {
  .skel::after { animation: none; }
  .nectar-lotus, .nectar-bee, .offline-dot { animation: none; }
  .ucal-list > .ec { animation: none; }
  .skel-fade, .nectar-loading { animation-duration: .01s; }
}

/* CLAUDE.md rule 8, ≥44px — the rest of them.
   These were measured in a browser at 360px on 27 Aug 2026, not read
   off this stylesheet, which is how they stayed 4-6px short while the
   suite passed: the tests that guard 44px grep the CSS for
   `min-height: 44px` on particular components, and none of these had
   one. .nav-burger was 40, .footer-cta 40, .footer-link 39,
   .nav-brand 38, .globe-toggle 28, .ordering-tease 15.
   Scoped to the mobile width so the desktop layout is untouched.
   Placed at the END of the stylesheet on purpose: .link-plain and the
   .bg button rules are defined further down than the touch-target
   block above, so an override written up there loses to them — the
   inline tease stayed 28px until this moved. Last one wins. */
@media (max-width: 767.98px) {
  /* The generic inline text-button, used all over — 16-35px depending
     on its font size. Padded to 44 and pulled back by the same amount
     so nothing on the page moves. FIRST in this block on purpose: the
     rules further down that name a particular .link-plain need to win
     over it, and equal specificity means last one wins. */
  .link-plain { display: inline-block; padding: 14px 4px; margin: -14px 0; }
  /* Form controls: the facilitator filter select was 42. */
  .inp, .inp--select { min-height: 44px; box-sizing: border-box; }
  /* The Resources category rail was 39. */
  .rail-item { min-height: 44px; box-sizing: border-box; display: flex; align-items: center; }
  .nav-burger  { min-height: 44px; box-sizing: border-box; justify-content: center; }
  a.footer-cta { min-height: 44px; box-sizing: border-box; display: inline-flex; align-items: center; }
  /* 39 + 10 of margin became 44 + 5, so the column keeps its rhythm. */
  a.footer-link { min-height: 44px; display: flex; align-items: center; margin-bottom: 5px; }
  .nav-brand   { min-height: 44px; }
  /* Kept display:block — .map-panel--collapsed centres it with
     `margin: 0 auto`, which an inline-flex box would ignore. The
     height comes from padding instead. */
  .globe-toggle { padding: 15px 15px; }
  /* An inline word inside a running sentence. Growing the box would
     push the line apart, so the padding that makes the target 44px is
     cancelled by an equal negative margin: identical on screen, and
     the finger gets all 44px. */
  .ordering-tease { display: inline-block; padding: 15px 6px; margin: -15px 2px -15px 4px; }
  /* "Show more gatherings" was 41px. */
  button.bg, a.bg { min-height: 44px; box-sizing: border-box; }
  /* The calendar grid: 31 day cells at 40px. The height is set here;
     the WIDTH needs the two rules under it.

     That comment used to end "the cells are ~47 wide at 360, so only
     the height was short", and it stopped being true when the rail
     narrowed. Measured on 8 Sep 2026 they were 38 wide: the rail is
     320 at a 360 viewport, the card takes 16 either side, and seven
     columns share the 288 that is left. Rule 8 asks 44, and seven of
     those plus six 3px gaps need 326.

     So the calendar — and only the calendar — reaches back over the
     rail's 20px margin and drops its own padding to 8. That buys 328,
     the cells come out at 44.3, and nothing else on the page moves. */
  .cal-day { min-height: 44px; box-sizing: border-box; }
  /* On the bleed itself rather than on .cal-wrap: the resources page
     wraps the card, the home page's strip does not, and putting it on
     the card covers both without either one bleeding twice. */
  .cal { margin-left: -12px; margin-right: -12px; padding-left: 8px; padding-right: 8px; }
  /* 328px of room, six gaps: at 3px the columns landed on 43.85 and
     missed by a sixth of a pixel. At 2px they are 45.1. */
  .cal-grid { gap: 2px; }
  /* "View the Sacred Calendar →", the one .link-plain sitting on its
     own line rather than inside a sentence, was 17px. Padded and
     pulled back like the tease above, so the line does not move. */
  .sacred-next .link-plain { display: inline-block; padding: 14px 4px; margin: -14px 0; }
  /* The verse carousel dots are 8px BY DESIGN — five quiet marks under
     a verse, and drawing them at 44 would turn them into buttons. The
     dot keeps its size; the touch box around it grows instead, which
     is the whole point of rule 8. */
  /* content-box on purpose: the sheet sets border-box globally, so
     with it the 36px of padding simply ate the 8px dot and the box
     came out 36 rather than 44. */
  .verse-dot { box-sizing: content-box; padding: 18px 9px; margin: -18px -9px; background-clip: content-box; }
}

/* The explicit agreement on the last step of the offering form
   (30 Aug 2026). A row, not a block: the tick and its sentence read as
   one thing, and the box keeps its own 44px touch area on a phone
   without the sentence inheriting it. */
.form-terms {
  display: flex; align-items: flex-start; gap: 10px;
  max-width: 62ch; margin: 0 auto clamp(16px, 2vw, 24px);
  font-size: 15px; line-height: 1.6; color: var(--text-mid);
  text-align: left; cursor: pointer;
}
/* Back on the Review step since F105 (11 Sep 2026), under the summary
   it vouches for, with air between the two. */
.form-terms--review { margin-top: clamp(20px, 2.2vw, 30px); margin-bottom: 0; }
.form-terms input[type="checkbox"] {
  flex: 0 0 auto; width: 18px; height: 18px; margin-top: 3px;
  accent-color: var(--honey); cursor: pointer;
}
@media (max-width: 767.98px) {
  /* This used to pad the checkbox and pull it back with a negative
     margin, the trick that works for the verse dots. It does NOT work
     here: browsers ignore padding on a NATIVE checkbox — computed
     padding came back 0px while the negative margin applied anyway, so
     the box was dragged up and sideways into its own sentence and
     gained no target at all. The founder found it (30 Aug 2026).
     Nothing to replace it with: clicking a <label> already toggles its
     control, and this label is a full-width row well over 44px, so the
     whole row IS the touch target and always was.

     The inline link inside it needs the opposite treatment. The
     site-wide mobile rule gives every .link-plain a 44px tap area, and
     inside this one sentence that made "terms of submission" a 76px
     box overlapping the row — so a tap meant for the tick hit the link
     and scrolled the page instead. Here it stays the size of its
     words. */
  .form-terms .link-plain {
    padding: 0; margin: 0; display: inline;
  }
}

/* ══════════════════════════════════════════════════════════════════
   SHARE PAGE — "Sharing a Gathering on BeeBhakti"
   ------------------------------------------------------------------
   This section borrowed .place-sec-title / .place-sec-text from the
   holy-places MODAL (.place-modal-body — a 24px-padded popup, where
   15px/1.7 and an 11px label are correct). At page scale they read as
   undersized, and .place-sec-text has NO paragraph margin at all, so
   fourteen paragraphs ran together as one block. Everything below
   re-uses primitives that already exist in this stylesheet — .prose,
   .overline, .duo-card, .duo-accent, .duo-title, .duo-text, the
   .listing-ends panel treatment, .bg .bg-g — and adds no new tokens,
   colours, radii or type sizes.

   DO NOT edit .place-sec-title / .place-sec-text themselves: they are
   still used by the place modal (t.desc / t.address / t.hours /
   t.notes / t.visiting).
   ══════════════════════════════════════════════════════════════════ */

/* ── SECTION TRANSITION ───────────────────────────────────────────
   Two --petal sections stacked read as one continuous band. The
   editorial pages already alternate page background against --petal
   (.about-sec vs .about-sec--petal); this does the same thing. */
.section-support--plain { background: var(--page); }

/* ── ONE VERTICAL RHYTHM: label → heading → lede → paragraph →
   block → action. Mirrors the .page--about rhythm rules. ────────── */
.share-guide .overline         { margin-bottom: 10px; }
.share-guide .section-head     { margin-bottom: clamp(20px, 1vw + 10px, 32px); }
.share-guide .prose            { margin-bottom: clamp(14px, 0.6vw + 8px, 20px); }
.share-guide .prose:last-child { margin-bottom: 0; }

/* ── THE FOCAL POINT ──────────────────────────────────────────────
   One centred lede at the top of the type scale, so the eye lands
   somewhere before the body copy starts. Same device as About's
   centred statement blocks.
   NOTE: the lede must be a SIBLING of .section-head, not a child —
   `.section-head .prose` (0,2,0) would otherwise out-rank this class
   and force 68ch + centre at every width. */
.share-guide-lede {
  font-size: clamp(18px, 0.22vw + 17.2px, 21px);
  line-height: 1.7;
  color: var(--deep-earth);
  text-align: center;
  max-width: 56ch;
  margin-inline: auto;
  margin-bottom: clamp(22px, 1.4vw + 10px, 34px);
}

/* ── SUB-BLOCKS ───────────────────────────────────────────────────
   Stacked full-measure .duo-cards: identical white fill, #E8C06033
   hairline, 16px radius and 4px --c accent as the cards in the
   section above, so the two sections read as one family. Single
   column at every width — this is running prose, not a feature grid,
   and the reading measure must not be halved. */
.share-guide-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap-md);
  margin-top: clamp(26px, 2vw + 8px, 44px);
}
.share-guide-grid .duo-card  { padding: clamp(24px, 2vw, 38px) clamp(22px, 2vw, 36px); }
.share-guide-grid .duo-title { margin-bottom: 14px; }
.share-guide-grid p.duo-text + p.duo-text { margin-top: 14px; }

/* ── TERMS ────────────────────────────────────────────────────────
   The one genuinely different object in the section, so it takes the
   honey-tint panel already used by .listing-ends on this page rather
   than a third white card. */
.share-terms-panel {
  margin-top: clamp(26px, 2vw + 8px, 44px);
  padding: clamp(22px, 1.8vw, 34px) clamp(20px, 1.9vw, 36px);
  border-radius: 16px;
  background: #E8C0601A;
  border: 1px solid #E8C06038;
}
.share-terms-panel .duo-title { color: var(--deep-earth); margin-bottom: 10px; }
.share-terms-intro {
  margin: 0 0 20px;
  font-size: clamp(15px, 0.1vw + 14.6px, 16.5px);
  line-height: 1.75;
  color: var(--text-mid);
}

/* Checklist, not a bullet list. .seo-list is the footer-SEO component
   and left these items at 16px with line-height:normal inside 15px/1.7
   copy — three type treatments in one section. */
.share-terms-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.share-terms-list li {
  position: relative;
  padding-left: 28px;
  font-size: clamp(15px, 0.1vw + 14.6px, 16.5px);
  line-height: 1.75;
  color: var(--text-mid);
}
.share-terms-list li::before {
  content: "\2726";                 /* the ✦ already used by .listing-ends-star */
  position: absolute; left: 0; top: 0;
  color: var(--honey);
  font-size: 13px;
  line-height: 1.95;
}

/* ── THE HANDOFF ──────────────────────────────────────────────────
   The section previously ran straight into the form with no
   transition. Existing pill components, no new button styles. */
.share-guide-cta {
  margin-top: clamp(28px, 2.2vw + 10px, 48px);
  display: flex; justify-content: center; flex-wrap: wrap; gap: 12px;
}

/* The fixed nav is 64px; keep the heading clear of it. Both targets,
   because the CTA above goes to whichever exists — signed out there is
   no #offerForm, only the account panel. scroll-margin-top is inert
   until something scrolls to the element, so this adds a landing
   position and changes no rendering. */
#offerForm, .share-signin-state, .share-terms-panel { scroll-margin-top: 96px; }

/* ── About the events we share (F98, 11 Sep 2026) ───────────────
   The founder's statement, set as part of BeeBhakti's story rather
   than as terms: running prose at the reading measure on the page's
   own ground, no card, no border, no accent bar. The heading and first
   line are the page hero above. (The small bee that closed it came
   off at the founder's word, 11 Sep 2026: "no need".) */
.share-policy { padding-top: clamp(16px, 2vw, 30px); }
.share-policy .container { display: flex; flex-direction: column; }
.share-policy-p { max-width: 64ch; margin-inline: auto; }
.share-policy-p:last-of-type { margin-bottom: 0; }
/* Who the form is for, and the terms, just above it (signed in). */
.share-circle { padding-bottom: 0; }
.share-circle-line {
  margin: 0 auto clamp(18px, 1.6vw, 26px); max-width: 64ch; text-align: center;
  font-size: clamp(16px, 0.2vw + 15px, 18px); font-weight: 600; color: var(--deep-earth);
}
/* The terms are as wide as the form box below them, at every width
   (founder, 11 Sep 2026): the same ceiling as .form-wrap, inside the
   same page edge, so the two boxes line up as one column. */
.share-circle > .container { max-width: clamp(640px, 46vw, 820px); }
.share-circle .share-terms-panel { max-width: none; }

/* ── The gateway (F105) ───────────────────────────────────────────
   The question stands before the form in the form's own box and width,
   so the journey reads as one column: question, then terms, then form.
   Its title and hint are the form's step title and sub. The two
   answers are the "How is it held?" radios, stacked on a phone where
   the longer words need the width. */
.share-gate { padding-block: clamp(8px, 1.4vw, 20px) clamp(20px, 2.4vw, 36px); }
.share-gate .listed-gate { margin-bottom: 0; }
.share-gate .listed-gate > .form-title { padding: 0; }
.share-gate .not-listed { margin-top: clamp(18px, 1.8vw, 26px); }
.share-gate .fmt-label { text-align: center; }
@media (max-width: 560px) {
  .share-gate .listed-choices { flex-direction: column; }
}

/* ── Is the facilitator already on BeeBhakti? (F103) ───────────────
   The form's first question, in the "How is it held?" radios, its hint
   between the question and the choices. "No" opens the founder's note
   on writing first: plain text in the form card, no box of its own,
   the address in the link colour the site already uses. */
.listed-gate > .field-hint { margin: 0 0 12px; }
.listed-gate .fmt-opt { justify-content: center; }
/* The two answers wear the "Share a gathering" button (.nav-cta): the
   founder, 13 Sep 2026 — "it's hard to know they are buttons, let's
   keep consistency". Same honey gradient, pill, shadow and lift. The
   chosen one keeps a ring, and the other steps back, so the page still
   says which was picked. */
.listed-gate .fmt-opt {
  min-height: 48px; padding: 12px 24px; border-radius: 50px; border: none;
  background: var(--grad-honey); color: var(--on-accent-strong);
  font-family: var(--font-sans); font-size: 14px; font-weight: 600; letter-spacing: .02em;
  box-shadow: 0 3px 14px color-mix(in srgb, var(--honey) 25%, transparent);
  transition: transform .3s, box-shadow .3s, opacity .2s;
}
.listed-gate .fmt-opt:hover { transform: translateY(-1px); box-shadow: 0 6px 20px color-mix(in srgb, var(--honey) 33%, transparent); }
.listed-gate .fmt-opt.on {
  background: var(--grad-honey); color: var(--on-accent-strong);
  box-shadow: 0 0 0 3px var(--surface), 0 0 0 5px var(--honey-text, var(--honey));
}
.listed-choices:has(.fmt-opt.on) .fmt-opt:not(.on) { opacity: .6; }
/* The focus ring for the keyboard only: a click also focuses the
   hidden radio, and the ring stacked on the chosen ring read as three. */
.listed-gate .fmt-opt:focus-within { outline: none; }
.listed-gate .fmt-opt:has(:focus-visible) { outline: 2px solid var(--honey); outline-offset: 7px; }
.listed-gate .fmt-label { line-height: 1.35; }
.not-listed { margin-top: 4px; font-size: 14.5px; line-height: 1.6; color: var(--text-mid); }
.not-listed p { margin: 0 0 12px; }
.not-listed p:last-child { margin-bottom: 0; }
.not-listed ul { margin: 0 0 12px; padding-left: 1.25em; }
.not-listed li { margin: 3px 0; }
.not-listed a { color: var(--honey-text); font-weight: 600; overflow-wrap: anywhere; }

@media (max-width: 640px) {
  /* A centred 8-line ragged block is hard to read on a phone. */
  .share-guide-lede { text-align: left; margin-inline: 0; max-width: none; }
  .share-guide-cta .bg { width: 100%; }
}

@media (prefers-reduced-motion: no-preference) {
  .share-guide-cta .bg { transition: all .3s; }   /* already on .bg; kept explicit */
}

/* The extra weekdays a weekly gathering runs on (§5.5 "weekday(s)").
   Seven small tick boxes on one row, wrapping at narrow widths. No new
   tokens: the same border, radius and honey the form controls already
   use. */
.repeat-days { grid-column: 1 / -1; }
.repeat-days-row { display: flex; flex-wrap: wrap; gap: 6px; }
.repeat-day {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 7px 10px; border: 1px solid #E8C06055; border-radius: 10px;
  background: var(--surface); cursor: pointer;
  font-size: 13px; color: var(--text-mid); line-height: 1;
  /* 44px on a phone, the site-wide tap-target rule (spec §19, rule 8) */
  min-height: 38px;
}
.repeat-day:has(input:checked) {
  border-color: var(--honey); background: #E8C0601A; color: var(--deep-earth);
}
.repeat-day input { margin: 0; accent-color: var(--honey); }
@media (max-width: 640px) { .repeat-day { min-height: 44px; } }


/* ── 13. Night ────────────────────────────────────────────────
   The founder's dark theme (F64, 7 Sep 2026): "the same website at
   night, rather than a completely different brand". Deep warm brown,
   never black; warm ivory, never white; honey kept for buttons,
   links, selected states, icons and small highlights; photographs
   and artwork left colourful against the quiet ground.

   Applied by data-theme="dark" on <html>. A head script build.py
   writes (hashed into the CSP, and copied by hand into 404.html) sets
   the attribute before first paint — from the visitor's saved choice
   in localStorage, else from the system preference — so nothing
   flashes. The switch in the header and the drawer flips it and saves
   it: "Dark mode" / "Light mode", the founder's words (F67, 7 Sep
   2026). Every rule here is scoped to that attribute; the media query
   is read only by the head script.

   How it works: section 1 names the ROLE each colour plays (--page,
   --surface, --on-accent…) with light values identical to the old
   literals. This block gives every role its night value, and remaps
   the brand tokens that stand for "ink" and "honey" to the founder's
   nine. Honey and saffron at low alpha — most of the stylesheet's
   remaining literals — need nothing: over #17130F a 20% saffron line
   resolves to #413621, within a shade of the founder's #3B3127.
   The eleven bands that were dark on the light page (footer, verse,
   the join page's close) become surfaces. The map keeps its daylight
   tiles, as artwork does; only its popups join the night. */
/* ── The bee cursor, alive (F84, 9 Sep 2026) ────────────────────
   See BeeCursor in app.jsx. The native cursor is hidden ONLY while
   the script is running (html.bee-live), and only where a real
   pointer exists; text entry keeps the I-beam, exactly as the static
   bee cursor already did. Everything else about it is transforms on
   a fixed element that nothing can click through. */
/* Not inside a media query on purpose: the class is only ever added
   once the script has confirmed a fine pointer, and a rule that also
   depends on the browser re-evaluating a media query is a rule that
   can drop out for a frame. In Chrome that frame showed the old
   still-picture cursor beside her (founder, 9 Sep 2026). */
/* A transparent PICTURE rather than `none` (Chrome, 9 Sep 2026): when
   the thing under a resting pointer is redrawn — a lotus opening its
   label — Chrome can fall back to the last cursor picture it held,
   which was the still bee, and two bees stood on the map. A real
   cursor image that happens to be invisible is what it falls back to
   now. `none` stays behind it for any browser that refuses the file. */
html.bee-live, html.bee-live *, html.bee-live *::before, html.bee-live *::after {
  cursor: url("img/blank-cursor.png") 0 0, none !important;
}
html.bee-live input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="submit"]):not([type="button"]),
html.bee-live textarea,
html.bee-live [contenteditable="true"] {
  cursor: text !important;
}
.bee-cursor {
  position: fixed; left: 0; top: 0; width: 38px; height: 43px;
  pointer-events: none; z-index: 2147483000;
  will-change: transform; contain: layout style;
  opacity: 0; transition: opacity .18s ease;
  transform: translate3d(-200px, -200px, 0);
}
.bee-cursor.is-on { opacity: 1; }
/* is-native: the browser has the cursor — a scrollbar, a dropdown's
   list, the right-click menu, a drag — and shows its own arrow there,
   so she steps aside rather than sit frozen beside it (11 Sep 2026). */
.bee-cursor.is-away, .bee-cursor.is-text, .bee-cursor.is-native { opacity: 0; }
.bee-cursor-bob { display: block; width: 100%; height: 100%; transform-origin: 87% 59%; }
/* She bobs at rest — but holds still while sitting on something
   pressable, so her body never drifts over a small target (F85). */
.bee-cursor.is-idle:not(.is-hover) .bee-cursor-bob { animation: beeFloat 4.4s ease-in-out infinite; }
.bee-cursor-turn {
  display: block; width: 100%; height: 100%;
  transform-origin: 87% 59%;
  /* Turning round is a turn in space about the head, on its own
     slower, rounder curve than the bank and the tuck below (F85). */
  transform: perspective(160px) rotateY(var(--bee-turn, 0deg));
  transition: transform .7s cubic-bezier(.45, .05, .25, 1);
}
.bee-cursor-fig {
  position: relative; display: block; width: 100%; height: 100%;
  transform-origin: 87% 59%;
  transform: rotate(var(--bee-bank, 0deg)) scale(var(--bee-size, 1));
  transition: transform .32s cubic-bezier(.22, .61, .36, 1);
}
/* Three layers of the one bee (F85): body, wings at rest, wings raised.
   The raised pair fades in and out over the resting pair only while
   she is flying — a shimmer at about five beats a second, soft-edged
   so it never reads as a buzz. At rest the wings hold still. */
.bee-cursor-img {
  position: absolute; inset: 0; display: block; width: 100%; height: 100%; user-select: none;
}
.bee-cursor-wing--up { opacity: 0; }
.bee-cursor.is-flying .bee-cursor-wing--up { animation: beeWingBeat .09s ease-in-out infinite alternate; }
@keyframes beeWingBeat { from { opacity: 0; } to { opacity: 1; } }
.bee-cursor.is-hover { --bee-size: .9; }
.bee-cursor.is-dense { --bee-size: .72; }
.bee-cursor.is-press { --bee-size: .82; }
.bee-cursor.is-dense.is-press { --bee-size: .66; }
@media (prefers-reduced-motion: reduce) {
  .bee-cursor { display: none; }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  /* The founder's palette, revised against Apple's Human Interface
     Guidelines for Dark Mode and accessibilitychecker.org's dark-mode
     guidance (F68, 7 Sep 2026). What was wrong, measured:

       · The ground #241F1B carried 38% saturation. Both guides ask for
         a near-neutral base — "a softer black, such as #121212, or a
         very dark grey", "dimmer background colors" — and Apple's own
         iOS base is 3% saturated. A ground that saturated tints every
         photograph sepia and, at 28°, sat only 12° from the honey
         accent's 40°, so the accent could not separate from the page
         by hue at all. Everything read as one brown.
       · There were two levels where Apple asks for three. It uses
         "base and elevated" background colours, and the elevated one
         specifically "when an interface is in the foreground, such as
         a popover or modal sheet".

     So: the bee's hue is kept, to the degree — every tone below is
     still 26-30°, the brown of img/bee.webp — and the chroma comes
     down to a tenth. The base recedes; the CARDS now sit at L* 17,
     which is where the whole page sat before, so the surfaces a
     reader actually reads are no darker than the founder approved in
     F65. Apple asks to "strive for a contrast ratio of 7:1,
     especially in small text", and every one of the three levels
     clears it: on the base and on the topmost level, ivory reads
     14.3:1 and 11.3:1, the beige 9.5:1 and 7.5:1, honey 9:1 and
     7.1:1, and the button's text 7.3:1 on its honey. Nothing exceeds
     15:1, which is where halation starts to trouble a reader with
     astigmatism. */
  --night-bg:           #241F1B;   /* base: the page, receding */
  --night-surface:      #2F2924;   /* cards, and the bands that were dark */
  --night-elevated:     #383029;   /* Apple's elevated: popovers, sheets, modals */
  --night-text:         #F5EFE5;
  /* The founder's #BEB3A5 read 5.9:1 on a card — AA, not the 7:1
     a reader with poor eyesight is helped by. This beige reaches
     7.2:1 on a popover and 9.5:1 on the ground (F66). */
  --night-text-2:       #CFC4B5;
  --night-accent:       #D9A441;
  --night-accent-hover: #E8B958;
  --night-button:       #D9A441;
  --night-button-text:  #18120B;
  --night-border:       #4A423A;

  /* Roles */
  --page:        var(--night-bg);
  --page-soft:   color-mix(in srgb, var(--night-bg) 55%, var(--night-surface));
  --page-cream:  var(--page-soft);
  --surface:     var(--night-surface);
  --panel:       var(--night-elevated);
  --field:       var(--night-bg);
  --hover:       color-mix(in srgb, var(--night-surface) 88%, var(--night-text));
  --selected:    color-mix(in srgb, var(--night-accent) 16%, var(--night-surface));
  --photo-ph:    var(--night-surface);
  --skeleton:    color-mix(in srgb, var(--night-surface) 80%, var(--night-text));
  --on-accent:   var(--night-button-text);
  --on-accent-strong: var(--night-button-text);
  --on-dark:     var(--night-text);

  /* Brand tokens in their night roles. Honey as TEXT and as a line
     takes the hover honey (#E8B958): the founder's #D9A441 reads
     6.5:1 on the ground and 5.4:1 on a card, AA but short of the
     7:1 a reader with poor eyesight is helped by; the hover honey
     reads 7.5:1 and 6.3:1 (F66). Buttons keep #D9A441 through
     --grad-honey below, as the founder set them. */
  --honey:       var(--night-accent-hover);
  --gold:        var(--night-accent-hover);
  --honey-text:  var(--night-accent-hover);
  --honey-deep:  var(--night-accent-hover);
  --grad-honey:  linear-gradient(135deg, var(--night-button), var(--night-accent-hover));
  /* The type colours are tuned for this ground already, so writing
     one as text needs no further darkening (F69). */
  --type-ink: 100%;
  --deep-earth:  var(--night-text);
  --text-dark:   var(--night-text);
  --text-mid:    var(--night-text);
  --ink-deep:    var(--night-text);
  --text-light:  var(--night-text-2);
  --dusk:        var(--night-text-2);
  --icon-muted:  var(--night-text-2);
  --dark-bg:     var(--night-surface);
  --mid-bg:      var(--night-bg);
  /* Flat, not a gradient (F66): the mobile drawer and the join
     page's closing band read this token, and both carry text. */
  --grad-earth:  var(--night-surface);
  --error:       color-mix(in srgb, #B3261E 50%, var(--night-text));
  --ember:       color-mix(in srgb, #B5544A 54%, var(--night-text));
  /* Badge colours, recomputed on the new ramp (F68). Each takes the
     share of ivory that carries it past 4.7:1 on its own tinted pill,
     against whichever of the three levels it sits on. This is the one
     place that stops at AA rather than Apple's 7:1: at 7 only a third
     of each colour survives and the eleven categories become one
     pastel, and the type is written in words beside the pill anyway. */
    --sage:                color-mix(in srgb, #6E9DB8 76%, var(--night-text));
    --type-festival:       color-mix(in srgb, #9A6794 58%, var(--night-text));
    --type-retreat:        color-mix(in srgb, #5E8CAD 66%, var(--night-text));
    --type-workshop:       color-mix(in srgb, #C2762F 66%, var(--night-text));
    --type-kirtan:         color-mix(in srgb, #C08A28 74%, var(--night-text));
    --type-course:         color-mix(in srgb, #4E938A 66%, var(--night-text));
    --type-temple:         color-mix(in srgb, #6F9060 66%, var(--night-text));
    --type-satsang:        color-mix(in srgb, #7E8A50 64%, var(--night-text));
    --type-pilgrimage:     color-mix(in srgb, #B0684C 60%, var(--night-text));
    --type-online:         color-mix(in srgb, #C0708A 66%, var(--night-text));
    --type-yoga:           color-mix(in srgb, #6E9DB8 76%, var(--night-text));
    --type-other:          color-mix(in srgb, #7A5535 50%, var(--night-text));
    --lvl-open-to-all:       color-mix(in srgb, #C99A2E 84%, var(--night-text));
    --lvl-deepening:       color-mix(in srgb, #A66A44 58%, var(--night-text));
    --lvl-developing:      color-mix(in srgb, #6E4F23 48%, var(--night-text));
    --lvl-invitation:      color-mix(in srgb, #7E6591 56%, var(--night-text));
    --lvl-new-to-bhakti:   color-mix(in srgb, #B5544A 54%, var(--night-text));

/* Added after the first night sweep (7 Sep 2026) */
--earth:       color-mix(in srgb, #8B6230 55%, var(--night-text));
}

/* The fixed header was a cream-at-97% literal; it is the night
   ground at the same depth, with the founder's line beneath. */
:root[data-theme="dark"] .nav { background: color-mix(in srgb, var(--night-bg) 97%, transparent); border-bottom-color: var(--night-border); }
/* The footer's solid Donate read its text from the footer's own
   brown, which is now the surface it sits on. */
:root[data-theme="dark"] a.footer-cta--solid { color: var(--night-button-text); }
/* The map's controls sit on its daylight tiles, so they keep dark ink. */
:root[data-theme="dark"] .map-flat .leaflet-control-zoom a, :root[data-theme="dark"] .map-flat .leaflet-control-attribution, :root[data-theme="dark"] .map-flat .leaflet-control-attribution a { color: var(--night-button-text); }

/* No gradient under text (founder, F66, 7 Sep 2026: "the text
   doesn't read well on it" — a friend with poor eyesight reads the
   site in the evening, and this theme is for her). The hero faded
   from the ground into --warm-white, which stays pale at night
   because it also colours the text on dark bands; the other bands
   shaded between surface and ground. Every band that carries text
   is now one flat tone: the ground for the page-wide ones, the
   surface for the ones that were dark on the light page. */
:root[data-theme="dark"] .hero { background: var(--night-bg); }
:root[data-theme="dark"] .seva, :root[data-theme="dark"] .map-panel { background: var(--night-bg); }
:root[data-theme="dark"] .section-verse, :root[data-theme="dark"] .res-cta, :root[data-theme="dark"] .seva--dark, :root[data-theme="dark"] .about-cta { background: var(--night-surface); }
:root[data-theme="dark"] .place-modal-close:hover, :root[data-theme="dark"] .signout-toast { background: var(--night-surface); }
:root[data-theme="dark"] .nav-burger-bar { background: var(--night-text); }
:root[data-theme="dark"] .nav-burger-label { color: var(--night-text); }

/* The join page's warm panels, flat for the same reason */
:root[data-theme="dark"] .mp-close, :root[data-theme="dark"] .jh-offer, :root[data-theme="dark"] .jh-close, :root[data-theme="dark"] .hb-bumblebee { background: var(--night-surface); }

/* Fields and cards draw the founder's line */
:root[data-theme="dark"] .inp, :root[data-theme="dark"] .form-card { border-color: var(--night-border); }

/* Apple's elevated background, "when an interface is in the
   foreground, such as a popover or modal sheet" (F68). --panel already
   carries the sheets and modals; these three are painted from
   --surface or --grad-earth, so they are named here. */
:root[data-theme="dark"] .account-dropdown,
:root[data-theme="dark"] .combo-list { background: var(--night-elevated); border-color: var(--night-border); }
:root[data-theme="dark"] .mobile-menu { background: var(--night-elevated); }

/* A disabled control at 30% opacity all but vanishes on a dark
   ground; the accessibility guidance asks for disabled states to be
   tested, so it keeps a little more of itself at night (F68). */
:root[data-theme="dark"] .cal-nav:disabled { opacity: .45; }

/* A loading shimmer reads as a band brighter than the placeholder it
   sweeps. In daylight the panel cream is brighter than the
   placeholder; at night it is darker, so the sweep is drawn from the
   ivory instead (8 Sep 2026). */
:root[data-theme="dark"] .skel::after {
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--night-text) 20%, transparent), transparent);
}

/* The map keeps daylight tiles; its popups join the night */
:root[data-theme="dark"] .bb-city-popup .leaflet-popup-content-wrapper, :root[data-theme="dark"] .bb-city-popup .leaflet-popup-tip, :root[data-theme="dark"] .bb-map-tip {
  background: var(--night-surface); border-color: var(--night-border);
}

/* Artwork on a dark ground: no blend, it was there to hide a pale
   halo against cream. The lockup already sat on brown. */
:root[data-theme="dark"] .nav-logo, :root[data-theme="dark"] .hero-globe-img, :root[data-theme="dark"] .submit-globe { mix-blend-mode: normal; }
:root[data-theme="dark"] .brand-logo { mix-blend-mode: normal; opacity: 1; }
:root[data-theme="dark"] ::-webkit-scrollbar-track { background: var(--night-bg); }

/* The card ground — the honeycomb behind a poster's margins and
   under the logo of a card with no picture — mixed cream and petal,
   which stay pale at night because they also colour the text on
   dark bands. The same three-layer ground, on the surface, with
   the honeycomb's honey lines kept. */
:root[data-theme="dark"] .card-img {
  background-color: var(--night-surface);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='34.64'%3E%3Cg fill='none' stroke='%23D9A441' stroke-width='1' opacity='0.16'%3E%3Cpolygon points='15,2 28,9.5 28,25 15,32 2,25 2,9.5'/%3E%3C/g%3E%3C/svg%3E"),
    linear-gradient(150deg,
      color-mix(in srgb, var(--night-accent) 12%, var(--night-surface)),
      var(--night-surface) 55%,
      color-mix(in srgb, var(--night-surface) 92%, var(--night-accent)));
  border-bottom-color: var(--night-border);
}
:root[data-theme="dark"] .card-img--bee {
  background-image:
    url("/img/card-logo.webp"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='34.64'%3E%3Cg fill='none' stroke='%23D9A441' stroke-width='1' opacity='0.16'%3E%3Cpolygon points='15,2 28,9.5 28,25 15,32 2,25 2,9.5'/%3E%3C/g%3E%3C/svg%3E"),
    linear-gradient(150deg,
      color-mix(in srgb, var(--night-accent) 12%, var(--night-surface)),
      var(--night-surface) 55%,
      color-mix(in srgb, var(--night-surface) 92%, var(--night-accent)));
}
