/*
  Global stylesheet — single source of truth for the site.

  Structure:
    1) Reset and base
    2) Design tokens (:root) — palette and typography are owned by the
       `brand-guidelines` skill. Spacing, radii, shadows, motion, and layout
       tokens are owned here.
    3) Layout primitives
    4) Components (site-wide reusable primitives only — page-specific
       styles live with their page builds, not here)
    5) Utilities
*/

/* ===== 1) Reset and base ===== */
*, *::before, *::after {
  box-sizing: border-box;
}

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

body {
  margin: 0;
  font-family: var(--font-body);
  line-height: 1.5;
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading);
  line-height: 1.2;
}

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

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
}

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

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ===== 2) Design tokens ===== */
/* Palette and typography are written by the `brand-guidelines` skill from
   `build-assets/0-the-brand/tokens.json`. Spacing, radii, shadows, and
   transitions are owned here. */
:root {
  /* Palette (brand-guidelines) */
  --color-bg: #faf5f3;
  --color-surface: #ffffff;
  --color-surface-soft: #f4e3e7;
  --color-text: #24141a;
  --color-text-soft: #7a5760;
  --color-primary: #7a0c1f;
  --color-primary-dark: #4d0713;
  --color-primary-light: #f0d3d9;
  --color-accent: #a3132c;
  --color-focus: #b0142c;

  /* Typography (brand-guidelines) */
  --font-heading: "Playfair Display", "Georgia", "Times New Roman", serif;
  --font-body: "Poppins", "Segoe UI", "Helvetica Neue", Arial, sans-serif;

  /* Spacing */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;

  /* Radii */
  --radius-sm: 0.5rem;
  --radius-md: 0.875rem;
  --radius-lg: 1.25rem;
  --radius-pill: 999px;

  /* Shadows */
  --shadow-sm: 0 1px 3px rgba(60, 64, 67, 0.12);
  --shadow-md: 0 4px 14px rgba(17, 24, 39, 0.08);
  --shadow-lg: 0 12px 32px rgba(17, 24, 39, 0.12);

  /* Motion */
  --transition-fast: 180ms ease;
  --transition-base: 260ms ease;

  /* Layout */
  --container-max: 72rem;

  /* Aesthetic dials — the `design-system` skill SETS these per brand to diverge
     the look (sharp vs soft, flat vs shadowed, square vs pill). Defaults below are
     a soft/rounded baseline; a brand's design stage should deliberately override
     them so two brands don't look like the same template reskinned. */
  --logo-height: 2.75rem;    /* prominent by default — the logo is a brand asset, not chrome */
  --logo-max-width: 22rem;   /* generous, so wide wordmarks stay tall (not width-starved) */
  --header-bg: #0d0708;   /* header band — design dial, hardcoded black per brand request (not tied to the light body) */
  --header-fg: #f6e9ea;   /* header text/nav colour — hardcoded to pair with the black header band */
  --footer-bg: #0d0708;        /* footer band — design dial, hardcoded black to match the header */
  --footer-fg: #f6e9ea;        /* footer heading/primary text on the black band */
  --footer-fg-soft: #cfa8ae;   /* muted footer text/links — --color-text-soft is tuned for the light body, not a black footer */
  --btn-radius: var(--radius-pill);
  --card-radius: var(--radius-md);
  --card-shadow: var(--shadow-sm);
  --card-border: 1px solid color-mix(in srgb, var(--color-text) 6%, transparent);
  --chip-radius: var(--radius-pill);
}

/* Logo grows on wider screens — override the dial at the breakpoint, never per-page. */
@media (min-width: 1024px) {
  :root { --logo-height: 3.5rem; }
}

/* ===== 3) Layout primitives ===== */
.container {
  width: min(100% - 2rem, var(--container-max));
  margin-inline: auto;
}

.section {
  padding: var(--space-10) 0;
}

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

.grid-2 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(1, minmax(0, 1fr)); }

@media (min-width: 600px) {
  .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 768px) {
  .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ===== 4) Components ===== */

/* Site header */
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--header-bg);
  color: var(--header-fg);
  border-bottom: 1px solid color-mix(in srgb, var(--header-fg) 8%, transparent);
}

.site-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
}

.site-logo {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

/* The header logo is an <img src="{{logo.src}}"> whose REAL file is injected by the CMS
   at upload — its aspect ratio is unknown at build time. HEIGHT is the primary driver
   (a generous --logo-height), so every logo renders at a consistent, prominent height
   regardless of ratio; --logo-max-width is a generous, viewport-relative safety cap that
   only clamps a very wide logo on small screens (it then scales down proportionally, never
   distorts). Never pin width AND height. Tune the dials per brand — never a per-page size. */
.site-logo img {
  height: auto;
  width: auto;
  max-height: var(--logo-height);
  max-width: min(var(--logo-max-width, 22rem), 55vw);
  object-fit: contain;
}

.site-nav {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
}

.site-cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

/* Desktop-only header CTAs — paired with {{menu.navigation.default}}, whose
   drawer already carries its own login/join CTAs on mobile. Hide the header
   pair below the drawer breakpoint so they don't show twice. */
@media (max-width: 1023px) {
  .desktop-only { display: none; }
}

/* Homepage logo bump — the landing wordmark reads slightly larger than the
   site-wide default (see web-page-builder/references/page-types/homepage.md). */
.is-homepage .site-logo img { max-height: 3.25rem; }
@media (min-width: 1024px) {
  .is-homepage .site-logo img { max-height: 3.75rem; }
}

/* CMS canvas-nav (menu.navigation.default) theming — dark drawer to match this
   brand's all-dark palette and its light-on-transparent logo. Every selector
   below uses 2+ classes (0,2,0 specificity) to beat the snippet's own inline
   <style>, which loads after global.css and redeclares the same CSS variables
   at equal specificity (see references/placeholders/menu.navigation.default.md
   — "CSS cascade warning"). Overriding the variables alone would silently fail. */
.hs-canvas-nav .hs-canvas-nav__drawer {
  /* The drawer stays dark to match the (now black) header — the logo it displays is a
     white wordmark that requires a dark background (see brand.md's Logo section) and
     --color-surface is now light. Use --header-bg/--header-fg throughout this block. */
  background: var(--header-bg);
  box-shadow: var(--shadow-lg);
}
.hs-canvas-nav .hs-canvas-nav__overlay {
  /* Dimming scrim behind the drawer — built from --header-bg (dark), not --color-bg
     (now the light body colour, which would no longer dim anything). */
  background: color-mix(in srgb, var(--header-bg) 60%, transparent);
}
.hs-canvas-nav .hs-canvas-nav__cta--primary {
  background: var(--color-primary);
  color: #fff;
}
.hs-canvas-nav .hs-canvas-nav__cta--primary:hover {
  background: var(--color-primary-dark);
}
.hs-canvas-nav .hs-canvas-nav__cta--secondary {
  color: var(--header-fg);
  border-color: color-mix(in srgb, var(--header-fg) 25%, transparent);
}
.hs-canvas-nav .hs-canvas-nav__menu--mobile .hs-canvas-nav__link,
.hs-canvas-nav .hs-canvas-nav__menu--mobile .hs-canvas-nav__summary {
  color: var(--header-fg);
  font-family: var(--font-heading);
}
.hs-canvas-nav .hs-canvas-nav__menu--mobile .hs-canvas-nav__link:hover,
.hs-canvas-nav .hs-canvas-nav__menu--mobile .hs-canvas-nav__summary:hover {
  /* --color-accent is tuned for the light body and fails contrast on a black drawer;
     --color-primary-light (a pale pink) reads clearly against --header-bg. */
  color: var(--color-primary-light);
}
.hs-canvas-nav .hs-canvas-nav__close {
  color: var(--header-fg);
}
.hs-canvas-nav .hs-canvas-nav__menu--desktop .hs-canvas-nav__link {
  color: color-mix(in srgb, var(--header-fg) 80%, transparent);
  font-size: 0.93rem;
  font-weight: 600;
  transition: color var(--transition-fast);
}
.hs-canvas-nav .hs-canvas-nav__menu--desktop .hs-canvas-nav__link:hover {
  color: var(--color-primary-light);
}
.hs-canvas-nav .hs-canvas-nav__logo {
  max-width: 140px;
}
@media (min-width: 1024px) {
  .hs-canvas-nav .hs-canvas-nav__menu--desktop > .hs-canvas-nav__item > .hs-canvas-nav__details > .hs-canvas-nav__submenu {
    border-color: color-mix(in srgb, var(--color-text) 14%, transparent);
    box-shadow: var(--shadow-lg);
  }
}

/* CMS-rendered menus — `{{menu.navigation}}` and `{{menu.footer}}` expand to
   <ul class="canvas-navigation-menu"> / <ul class="canvas-footer-menu"> with
   <li><a> children. Style the generated classes directly. */

.canvas-navigation-menu {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.canvas-navigation-menu > li {
  margin: 0;
}

.canvas-navigation-menu a {
  color: var(--header-fg);
  font-weight: 600;
  font-size: 0.95rem;
  padding: var(--space-2) 0;
  border-bottom: 2px solid transparent;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}

.canvas-navigation-menu a:hover,
.canvas-navigation-menu a:focus-visible {
  color: var(--color-primary);
  border-bottom-color: var(--color-primary);
}

.canvas-footer-menu {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-6);
  margin: 0 0 var(--space-4);
  padding: 0;
  list-style: none;
}

/* Footers can carry many links. With 8+ items, flow them into responsive columns
   (auto-fill grid) instead of one long, sprawling wrapping row — multi-column on wide
   screens, collapsing toward a single column on mobile. Short footer menus keep the
   inline row above. Where :has() is unsupported it harmlessly stays the flex row. */
.canvas-footer-menu:has(> li:nth-child(8)) {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 9rem), 1fr));
  align-items: start;
  gap: var(--space-2) var(--space-5);
}

.canvas-footer-menu > li {
  margin: 0;
}

.canvas-footer-menu a {
  color: var(--footer-fg-soft);
  font-size: 0.9rem;
  transition: color var(--transition-fast);
}

.canvas-footer-menu a:hover,
.canvas-footer-menu a:focus-visible {
  color: var(--color-primary-light);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Footer legal links ({{footerLinks.*}}) — same treatment as the footer menu, on black. */
.footer-legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
  margin: var(--space-4) 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.82rem;
}

.footer-legal a {
  color: var(--footer-fg-soft);
  transition: color var(--transition-fast);
}

.footer-legal a:hover,
.footer-legal a:focus-visible {
  color: var(--color-primary-light);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Breadcrumb */
.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) 0;
  color: var(--color-text-soft);
  font-size: 0.9rem;
}

.breadcrumb a {
  color: var(--color-primary);
}

.breadcrumb a:hover {
  text-decoration: underline;
}

.breadcrumb-separator {
  color: var(--color-text-soft);
  opacity: 0.6;
}

.breadcrumb [aria-current="page"] {
  color: var(--color-text);
  font-weight: 600;
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  border: 0;
  text-decoration: none;
  white-space: nowrap;
  border-radius: var(--btn-radius);
  min-height: 2.75rem;
  padding: 0.78rem 1.4rem;
  font-size: 0.98rem;
  line-height: 1;
  letter-spacing: 0.01em;
  font-weight: 700;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform var(--transition-fast), box-shadow var(--transition-fast), opacity var(--transition-fast);
}

.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn:focus-visible { outline-offset: 3px; }

.btn[disabled],
.btn[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.55;
  pointer-events: none;
  box-shadow: none;
}

.btn-primary {
  background: var(--color-primary);
  color: #fff;
  box-shadow: 0 4px 12px color-mix(in srgb, var(--color-primary) 28%, transparent);
}

.btn-primary:hover {
  background: var(--color-primary-dark);
  box-shadow: 0 6px 16px color-mix(in srgb, var(--color-primary) 40%, transparent);
}

.btn-secondary {
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid color-mix(in srgb, var(--color-text) 16%, transparent);
}

.btn-secondary:hover {
  background: color-mix(in srgb, var(--color-surface-soft) 75%, #fff);
}

.btn-ghost {
  background: transparent;
  color: var(--color-text);
  border: 1px solid color-mix(in srgb, var(--color-text) 20%, transparent);
}

.btn-ghost:hover {
  background: color-mix(in srgb, var(--color-surface-soft) 65%, transparent);
}

/* Header CTAs follow the header foreground so they stay legible on the black header band
   (--header-fg is now a hardcoded dial, decoupled from the body's --color-text). */
.site-header .btn-ghost {
  color: var(--header-fg);
  border-color: color-mix(in srgb, var(--header-fg) 20%, transparent);
}

.btn-sm {
  min-height: 2.2rem;
  padding: 0.55rem 1rem;
  font-size: 0.87rem;
}

.btn-lg {
  min-height: 3rem;
  padding: 0.9rem 1.7rem;
  font-size: 1.04rem;
}

.btn-block { width: 100%; }

.btn-icon {
  width: 2.75rem;
  min-width: 2.75rem;
  padding: 0;
  border-radius: 50%;
}

/* Card */
.card {
  background: var(--color-surface);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  border: var(--card-border);
  padding: var(--space-5);
}

.card-title {
  margin: 0 0 var(--space-2);
  font-size: 1.08rem;
}

.card-text {
  margin: 0;
  color: var(--color-text-soft);
}

/* Chip — pill-shaped tag */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.45rem 0.95rem;
  border-radius: var(--chip-radius);
  background: var(--color-surface);
  color: var(--color-primary);
  font-size: 0.82rem;
  font-weight: 600;
  border: 1px solid color-mix(in srgb, var(--color-primary) 25%, transparent);
}

.chip-row {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* Site footer — black band per brand request, independent of the (now light) body */
.site-footer {
  background: var(--footer-bg);
  color: var(--footer-fg-soft);
  padding: var(--space-10) 0;
  font-size: 0.9rem;
  border-top: 1px solid color-mix(in srgb, var(--footer-fg) 12%, transparent);
}

/* Member profile */
.profile-head {
  display: flex;
  gap: var(--space-5);
  align-items: center;
  margin-bottom: var(--space-6);
}
.profile-avatar {
  width: 7.5rem;
  height: 7.5rem;
  border-radius: var(--radius-pill);
  object-fit: cover;
}
.profile-id {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.profile-headline {
  font-size: 1.15rem;
  font-weight: 600;
}
.profile-bio {
  color: var(--color-text-soft);
  max-width: 60ch;
}
.profile-interests {
  margin-top: var(--space-3);
}

/* Split hero (copy + visual) — landing pages. Token-driven per
   references/patterns/hero-split.md; adapted here with a brand gradient band. */
.hero-split {
  padding: var(--space-12) 0;
  background:
    radial-gradient(circle at 15% 20%, color-mix(in srgb, var(--color-accent) 22%, transparent), transparent 55%),
    linear-gradient(160deg, var(--color-surface), var(--color-bg) 70%);
}
.hero-split-inner {
  display: grid;
  gap: var(--space-8);
  align-items: center;
}
@media (min-width: 768px) {
  .hero-split-inner { grid-template-columns: 1.1fr 0.9fr; gap: var(--space-12); }
}
.hero-title {
  font-family: var(--font-heading);
  font-size: clamp(2.5rem, 2rem + 3vw, 4.25rem);
  line-height: 1.1;
  margin: 0 0 var(--space-4);
}
.hero-sub {
  color: var(--color-text-soft);
  font-size: clamp(1.1rem, 1rem + 0.6vw, 1.4rem);
  max-width: 40ch;
  margin: 0 0 var(--space-8);
}
.hero-cta { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.hero-split-visual {
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  border: var(--card-border);
}
.hero-split-visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

/* Full-bleed photo hero — copy/CTA overlaid on the image behind a dark scrim.
   Used on the homepage in place of .hero-split above. */
.hero-full {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(24rem, 58vw, 34rem);
  overflow: hidden;
}
.hero-full-media,
.hero-full-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.hero-full-media img {
  object-fit: cover;
  object-position: 50% 30%;
}
.hero-full-scrim {
  position: absolute;
  inset: 0;
  /* Strong at the left where the copy sits, fading out toward the right so the
     photo still reads. */
  background: linear-gradient(
    to right,
    color-mix(in srgb, var(--header-bg) 88%, transparent) 0%,
    color-mix(in srgb, var(--header-bg) 60%, transparent) 45%,
    color-mix(in srgb, var(--header-bg) 12%, transparent) 80%
  );
}
.hero-full-inner {
  position: relative;
  z-index: 1;
  padding: var(--space-12) 0;
  /* The shared .container gutter (1rem) reads fine for centered content, but this
     copy is left-aligned, so that alone leaves the headline sitting flush against
     the page edge. Give it its own, larger inset instead of widening .container
     (which every other section on the page also relies on). */
  padding-left: clamp(1.5rem, 6vw, 4.5rem);
  width: 100%;
}
.hero-full-copy { max-width: 34rem; }
.hero-full-copy .hero-title { color: var(--header-fg); }
.hero-full-copy .hero-sub { color: color-mix(in srgb, var(--header-fg) 85%, transparent); }

/* Centered section heading + optional lede, used above a features/steps grid */
.section-intro {
  max-width: 52rem;
  margin: 0 auto var(--space-10);
  text-align: center;
}
.section-intro h2 {
  font-size: clamp(1.75rem, 1.5rem + 1.2vw, 2.5rem);
  margin: 0;
}
.section-intro p {
  color: var(--color-text-soft);
  margin: var(--space-3) 0 0;
}

/* Small icon badge shared by feature cards and tool list items */
.feature-icon {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--card-radius);
  background: color-mix(in srgb, var(--color-primary) 22%, transparent);
  color: var(--color-accent);
}
.feature-icon svg { width: 1.5rem; height: 1.5rem; }

/* Feature card — icon + title + text, equal-height siblings in a grid */
.feature-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* How-it-works numbered steps */
.step {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.step-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: #fff;
  font-family: var(--font-heading);
  font-weight: 700;
}
.step h3 { margin: var(--space-2) 0 0; font-size: 1.05rem; }
.step p { color: var(--color-text-soft); margin: 0; }

/* Tool list item — icon-left, text-right row (distinct from the feature-card grid) */
.tool-item {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
}
.tool-item h3 { margin: 0 0 var(--space-1); font-size: 1.02rem; }
.tool-item p { margin: 0; color: var(--color-text-soft); }

/* CTA band — stacked-and-centered per layout-rules.md's CTA-card guidance */
.cta-band {
  background: linear-gradient(135deg, var(--color-primary-dark), var(--color-primary));
  border-radius: var(--radius-lg);
  padding: var(--space-10);
  text-align: center;
}
.cta-band h2 { margin: 0 0 var(--space-3); color: #fff; }
.cta-band p {
  color: color-mix(in srgb, #fff 85%, transparent);
  max-width: 46rem;
  margin: 0 auto var(--space-6);
}
.cta-band .btn-primary {
  background: #fff;
  color: var(--color-primary-dark);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
}
.cta-band .btn-primary:hover { background: var(--color-surface-soft); }

/* ===== Member loops — see references/placeholders/members.loop.md =====
   Authored with data-members-styles="none": the CMS emits classes and no CSS.

   Colour rule: text colours come from ROLE tokens (--color-text on --color-surface),
   never from shade tokens (--color-primary-dark, --color-primary-light). A shade token
   means "darker than primary", not "the dark-theme value", so text built from one can
   fail contrast on a mid-tone brand and inverts the wrong way in a dark palette. */

[data-members] .lp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(11rem, calc(50% - 0.375rem)), 1fr));
  gap: 0.75rem;
  list-style: none;
  margin: 0 auto;
  padding: 0;
  max-width: calc(6 * 14rem + 5 * 0.75rem);
}

[data-members] .mem-card {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  box-sizing: border-box;
  margin: 0;
  overflow: hidden;
  position: relative;
  padding: 0.5rem;
  background: var(--color-surface, #ffffff);
  border: var(--card-border, 1px solid #e3e1da);
  border-radius: var(--card-radius, 0.875rem);
  box-shadow: var(--card-shadow, none);
}

[data-members] .mem-card img,
[data-members] .mem-card__initial {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-sm, 0.5rem);
  flex: 0 0 auto;
}
[data-members] .mem-card img { display: block; object-fit: cover; object-position: 50% 30%; }
[data-members] .mem-card__initial {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-surface-soft, #f2f0ea);
  color: var(--color-text, #1d2328);
  font-size: 1.75rem;
  font-weight: 600;
  text-transform: uppercase;
}

[data-members] .mem-card__name,
[data-members] .mem-card__where {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
[data-members] .mem-card__name {
  margin: 0.35rem 0 0;
  font-family: var(--font-heading, inherit);
  font-size: 0.9rem;
  line-height: 1.3;
  color: var(--color-text, inherit);
}
[data-members] .mem-card__where {
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.3;
  color: var(--color-text-soft, #6b6f85);
}
[data-members] .mem-card__name:empty,
[data-members] .mem-card__where:empty { display: none; }

[data-members] .mem-card__line {
  margin: 0.15rem 0 0;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--color-text-soft, #6b6f85);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

[data-members] .badge {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  max-width: calc(100% - 1.5rem);
  font-size: 0.75rem;
  padding: 0.1rem 0.4rem;
  border-radius: var(--chip-radius, 999px);
  color: var(--color-text, #1d2328);
  background: var(--color-primary-light, #e4f0ee);
}

[data-members] .mem-card__cta {
  margin-top: auto;
  padding-top: 0.4rem;
  font-size: 0.75rem;
  color: var(--color-text, inherit);
  text-decoration: underline;
  text-underline-offset: 2px;
}

[data-members] a:focus-visible {
  outline: 3px solid var(--color-focus, #b4602c);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px var(--color-surface, #ffffff);
}

[data-members] .mem-card--join { padding: 0; min-height: 8rem; }
[data-members] .mem-card--join .mem-card__cta {
  display: grid;
  place-items: center;
  height: 100%;
  margin: 0;
  padding: 0.75rem;
  text-align: center;
  font-weight: 600;
  background: var(--color-surface-soft, #f2f0ea);
  color: var(--color-text, #1d2328);
}

[data-members] .lp-members__empty {
  margin: 0;
  padding: var(--space-6, 1.5rem) var(--space-4, 1rem);
  color: var(--color-text, inherit);
  font-size: 0.9rem;
  text-align: center;
}

/* Portrait preset — see "Preset: portrait profile cards" in members.loop.md.
   Used here because the ticker below treats members as the content, not a thumbnail strip. */
[data-members] .mem-card {
  padding: 0;
  overflow: hidden;
  box-shadow: var(--shadow-sm, 0 1px 3px rgba(60,64,67,.12));
}
[data-members] .mem-card img {
  aspect-ratio: 3 / 4;
  width: 100%;
  flex: 0 0 auto;
  border-radius: 0;
  object-position: 50% 25%;
}
[data-members] .mem-card .badge {
  position: absolute;
  top: var(--space-2, 0.5rem);
  left: var(--space-2, 0.5rem);
  margin: 0;
  z-index: 1;
}
[data-members] .mem-card:not(.mem-card--join) .mem-card__name,
[data-members] .mem-card:not(.mem-card--join) .mem-card__where,
[data-members] .mem-card:not(.mem-card--join) .mem-card__line,
[data-members] .mem-card:not(.mem-card--join) .mem-card__cta {
  padding-left: var(--space-3, 0.75rem);
  padding-right: var(--space-3, 0.75rem);
}
[data-members] .mem-card__name {
  margin-top: var(--space-3, 0.75rem);
}
[data-members] .mem-card:not(.mem-card--join) .mem-card__cta {
  padding-bottom: var(--space-3, 0.75rem);
}
[data-members] .mem-card:not(.mem-card--join) .mem-card__cta::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
}
[data-members] .mem-card__cta { outline-offset: -2px; }

/* ===== Scrolling ticker (marquee) — see references/design-patterns.md =====
   Pure CSS, no JS. Content is duplicated so translateX(-50%) loops seamlessly. */
.ticker {
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.ticker-row {
  display: flex;
  gap: var(--space-4);
  width: max-content;
  /* Centers the row when its content is narrower than .ticker (e.g. inventory is
     thinner than the requested count) instead of it sitting flush left. Safe with
     the translateX(-50%) loop below: that's relative to the row's OWN width, not
     its position in .ticker, so centering it doesn't change the animation math. */
  margin-inline: auto;
  animation: ticker-scroll 50s linear infinite;
}

.ticker-row.is-reverse { animation-direction: reverse; }
.ticker-row.is-fast    { animation-duration: 35s; }
.ticker-row.is-slow    { animation-duration: 70s; }

@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.ticker:hover .ticker-row,
.ticker:focus-within .ticker-row {
  animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
  .ticker-row {
    animation: none;
    flex-wrap: wrap;
    width: 100%;
    justify-content: center;
  }
}

/* Member showcase ticker — see build-assets/0-the-brand/notes/decisions.md for why this
   is FOUR independent <section data-members> blocks placed side by side inside one
   .ticker-row, rather than the usual hand-duplicated cards. Two reasons stack here:
   (1) the loop's markup is 100% server-generated, so a "lap" cannot be duplicated in the
   DOM the normal way — each lap is its own pair of live queries; (2) the ~90% female
   skew the client asked for has no ratio/weight parameter on the loop itself, so it's
   built from two type-scoped queries per lap (.members-grid--primary = female, the
   majority; .members-grid--minority = male+other, the remaining ~10%) rather than one
   mixed-type query. Each [data-members] block's own .lp-grid becomes the flex row
   (overriding its grid-track layout); the fixed-width cards let all four blocks read as
   one continuous strip. */
.members-ticker [data-members] .lp-grid {
  display: flex;
  flex-wrap: nowrap;
  max-width: none;
  width: max-content;
  margin: 0;
}
.members-ticker [data-members] .mem-card {
  flex: 0 0 7rem;
  width: 7rem;
}
/* Restyled 2026-09-09 to replicate fabflirts.app's "Our Rated Members" strip:
   dark bg, small ring avatar, compact verified badge, name only (no location, no
   blurb, no visible per-card CTA text — one CTA button below the whole strip
   instead). Per-card star ratings on that reference are NOT reproduced: there is
   no rating field in our data-members schema, and inventing one next to a real
   member's real name/photo is exactly the "fake community" pattern the toolkit
   forbids — client confirmed dropping it rather than faking a number.
   This is a different, much sparser card than the shared "portrait profile cards"
   preset above, so most of it is overridden here rather than reused. */
.members-ticker [data-members] .mem-card__line,
.members-ticker [data-members] .mem-card__where {
  display: none;
}
.members-ticker [data-members] .mem-card {
  position: relative;
  aspect-ratio: auto;
  flex: 0 0 4.5rem;
  width: 4.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  padding: 0.1rem 0.1rem 0;
  text-align: center;
  background: transparent;
  border: none;
  box-shadow: none;
  overflow: visible;
}
.members-ticker [data-members] .mem-card--join {
  aspect-ratio: auto;
  min-height: 6.2rem;
  justify-content: center;
}
/* Gradient ring behind the photo. The CMS markup has no wrapper div around <img>,
   so the ring is a ::before on the card itself: slightly larger than the photo and
   centered on it (photo is 3rem/top 0.1rem+... — see decisions.md for the math). */
.members-ticker [data-members] .mem-card::before {
  content: "";
  position: absolute;
  top: 0.1rem;
  left: 50%;
  transform: translateX(-50%);
  width: 3.4rem;
  height: 3.4rem;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--color-primary), var(--color-accent));
}
.members-ticker [data-members] .mem-card--join::before { content: none; }
.members-ticker [data-members] .mem-card img,
.members-ticker [data-members] .mem-card__initial {
  position: relative;
  z-index: 1;
  width: 3rem;
  aspect-ratio: 1 / 1;
  border-radius: 999px;
  border: 2px solid var(--header-bg);
  flex: 0 0 auto;
}
.members-ticker [data-members] .mem-card__initial { font-size: 1rem; }
/* Verified badge moved to the avatar's bottom-right corner (fabflirts uses a check
   icon there; ours stays real text, since the CMS only ever emits "ID verified" as
   a label, never an icon-only mode) instead of the top-left pill used elsewhere. */
.members-ticker [data-members] .mem-card .badge {
  position: absolute;
  top: 2rem;
  left: 50%;
  right: auto;
  transform: translateX(0.5rem);
  max-width: none;
  white-space: nowrap;
  font-size: 0.5rem;
  line-height: 1.2;
  padding: 0.2rem 0.4rem;
  background: var(--color-primary);
  color: #fff;
  border: 2px solid var(--header-bg);
  z-index: 2;
}
.members-ticker [data-members] .mem-card:not(.mem-card--join) .mem-card__name {
  padding: 0;
}
.members-ticker [data-members] .mem-card__name {
  margin: 0;
  font-size: 0.72rem;
  line-height: 1.15;
  color: var(--header-fg);
  max-width: 100%;
}
/* The per-card CTA link stays in the DOM — its ::after (in the shared preset above)
   is what makes the whole card clickable, positioned against .mem-card, not the
   link itself, so hiding the link visually doesn't shrink the click target. That
   matches fabflirts' whole-card-is-a-link pattern without showing per-card CTA
   text, which that reference doesn't show either. */
.members-ticker [data-members] .mem-card:not(.mem-card--join) .mem-card__cta {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.members-ticker [data-members] .mem-card--join .mem-card__cta {
  color: var(--header-fg);
  background: color-mix(in srgb, var(--header-fg) 12%, transparent);
  font-size: 0.72rem;
}
/* The empty-state message replaces the whole block, not just .lp-grid — give it the
   same footprint as a card so a thin/zero result on the 10% minority query doesn't
   collapse into a stray sliver next to the full-height photo cards beside it. */
.members-ticker [data-members] .lp-members__empty {
  flex: 0 0 4.5rem;
  width: 4.5rem;
  min-height: 6.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2);
  color: var(--header-fg);
  font-size: 0.7rem;
}
/* The second lap is the visual "repeat" of the loop (see decisions.md) — hide it from
   assistive tech so members aren't announced twice, matching the ticker convention. */
.members-ticker [data-members][aria-hidden="true"] { pointer-events: none; }

/* If the PRIMARY (female) query comes back thin, don't marquee a half-empty ticker —
   deliberately NOT keyed off the minority query, whose own empty state is expected to
   be unremarkable (it's ~10% of the strip) and shouldn't stop the whole thing animating. */
.members-ticker:has(.members-grid--primary .lp-members__empty) .ticker-row {
  animation: none;
  flex-wrap: wrap;
  justify-content: center;
  width: 100%;
}

/* Section chrome for the fabflirts-style dark showcase strip — see decisions.md. */
.members-showcase {
  background: var(--header-bg);
}
.members-heading {
  max-width: 40rem;
  margin: 0 auto var(--space-8);
  text-align: center;
}
.live-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.9rem;
  margin-bottom: var(--space-3);
  border-radius: var(--radius-pill);
  border: 1px solid color-mix(in srgb, var(--color-accent) 45%, transparent);
  color: var(--color-accent);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.ping-dot {
  position: relative;
  display: inline-flex;
  width: 0.5rem;
  height: 0.5rem;
  flex: 0 0 auto;
}
.ping-dot .dot,
.ping-dot .ping {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: var(--color-accent);
}
.ping-dot .ping { animation: ping-pulse 1.8s cubic-bezier(0, 0, 0.2, 1) infinite; }
@keyframes ping-pulse {
  0% { transform: scale(1); opacity: 0.7; }
  75%, 100% { transform: scale(2.5); opacity: 0; }
}
.members-heading .section-title {
  margin: 0 0 var(--space-2);
  color: var(--header-fg);
  font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.1rem);
}
.members-heading .section-subtext {
  margin: 0;
  color: color-mix(in srgb, var(--header-fg) 78%, transparent);
}
.members-cta {
  text-align: center;
  margin-top: var(--space-6);
}
.members-cta .btn-ghost {
  color: var(--header-fg);
  border-color: color-mix(in srgb, var(--header-fg) 22%, transparent);
  background: color-mix(in srgb, var(--header-fg) 10%, transparent);
}
.members-cta .btn-ghost:hover {
  background: color-mix(in srgb, var(--header-fg) 18%, transparent);
}

/* Fallback pattern for a thin/empty result — see "When there are no results" in
   members.loop.md. Anything inside [data-members] is destroyed at render, so the real
   fallback is a sibling, revealed only via CSS (no JS, so it survives ZIP import).
   Keyed off the primary (female) query only, for the same reason as above. */
.members-block__fallback { display: none; }
.members-block:has(.members-grid--primary .lp-members__empty) .members-block__fallback,
.members-block:has([data-members]:empty) .members-block__fallback { display: block; }

.members-block__caption { display: none; }
.members-block:has(.lp-grid .mem-card:nth-child(4)) .members-block__caption { display: block; }

.members-block__fallback,
.members-block__caption {
  text-align: center;
  color: color-mix(in srgb, var(--header-fg) 70%, transparent);
  margin: var(--space-6) 0 0;
}
.members-block__fallback a { color: var(--color-primary-light); text-decoration: underline; }

/* ===== 5) Utilities ===== */
.text-center { text-align: center; }
.muted { color: var(--color-text-soft); }

.mt-4 { margin-top: var(--space-4); }
.mt-6 { margin-top: var(--space-6); }
.mb-0 { margin-bottom: 0; }
.mb-4 { margin-bottom: var(--space-4); }
.mb-6 { margin-bottom: var(--space-6); }

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