/* =====================================================================
   СМЕЛЧОВЦИ В БЕДА — Landing Page Styles
   PHASE 1 of 5: Hero + Bravies Intro only.
   Section 1 of this file establishes the full design-token system that
   Phases 2–4 will reuse — do not redefine tokens in later phases, extend
   this block instead.

   Breakpoint strategy (per spec §3 "Responsiveness" + explicit tablet
   orientation callouts):
     - Base styles: mobile, < 768px
     - 768px + portrait orientation  → "portrait tablet" layout
     - 1024px, OR 768px + landscape  → "landscape tablet / desktop" layout
     - 1440px  → desktop refinements
   ===================================================================== */

/* ---------------------------------------------------------------------
   0. FONTS (self-hosted — see index.html <head> for the reasoning)
   Dela Gothic One ships one real weight (400) — do not request 700/800/900
   against it anywhere; the browser will synthetic-bold a single-weight
   face and it looks blobby/wrong on an already-heavy display font. Every
   heading rule below has been set to font-weight: 400 for this reason.
--------------------------------------------------------------------- */
@font-face {
  font-family: 'Dela Gothic One';
  src: url('assets/fonts/dela-gothic-one-cyrillic-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Nunito Sans';
  src: url('assets/fonts/nunito-sans-cyrillic-300-normal.woff2') format('woff2');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Nunito Sans';
  src: url('assets/fonts/nunito-sans-cyrillic-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Nunito Sans';
  src: url('assets/fonts/nunito-sans-cyrillic-600-normal.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Nunito Sans';
  src: url('assets/fonts/nunito-sans-cyrillic-700-normal.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Nunito Sans';
  src: url('assets/fonts/nunito-sans-cyrillic-800-normal.woff2') format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------------
   1. DESIGN TOKENS
--------------------------------------------------------------------- */
:root {
  /* --- Brand / Bravies colors (from spec, corrected hex values) --- */
  --color-zaki: #725598;
  --color-vihren: #F68044;
  --color-neda: #FDD43B;
  /* Lighter yellow for inline text highlights (Phase 4.5) — same hue/
     saturation as --color-neda above, just raised lightness (61% → 82%),
     rather than an unrelated pale yellow, so it reads as "a softer
     version of Neda's yellow" rather than a disconnected new color.
     Deliberately NOT reusing --color-neda itself: this token is used as
     TEXT color on the hero's blue background, while --color-neda is
     used as a solid BUTTON background elsewhere — same value in both
     roles would make the new highlight read as "another button" at a
     glance instead of emphasized text. Contrast against the hero
     background (#5080BF): 3.40:1. Documenting honestly rather than
     overclaiming: this clears WCAG AA's 3:1 threshold for large/bold
     text, not the stricter 4.5:1 for small normal text — but note the
     hero's own existing body text color (--color-hero-text, #F8FAFC)
     only reaches 3.87:1 against this same background, so 3.40:1 is
     in the same realistic range the hero already operates in, not a
     new regression relative to what's already shipping. */
  --color-yellow-light: #FEEBA4;
  --color-vesta: #278C5D;
  --color-misho: #E5E1D6;
  /* Мишо's full character palette (60% brand = --color-misho above,
     shirt/overalls) — the other two are for accenting content that
     sits on or near Мишо's beige without clashing, like How It Works'
     titles (see .how-it-works__step-title). */
  --color-misho-accent: #4FA6E0; /* 30% — cap/backpack, sky blue */
  --color-misho-trim: #8B5E3C;   /* 10% — shoes/trim, brown */
  --color-misho-hair: #D4B483;   /* signature hair, sandy dirty-blonde */
  --color-buddy: #2FB6B0; /* turquoise — the Help/Buddy cards, a distinct
    "joker" category not tied to any single Bravie (per feedback: their
    draft card art is already turquoise) */

  /* Deep-toned variants of the same hues, for icon glyphs that should
     read as colorful rather than plain dark/white (per feedback on the
     What It Teaches icons) — a burnt-orange hand, a deep-red runner,
     a deep teal-blue heart. */
  --color-icon-burnt-orange: #A8501A;
  --color-icon-deep-red: #7A2020;
  --color-icon-deep-teal: #0E4749;

  /* --- Hero --- */
  --color-hero-bg: #5080BF;
  --color-hero-text: #F8FAFC;

  /* --- Base surfaces --- */
  --color-surface-white: #F8FAFC;
  --color-text-dark: #1E2433; /* dark text for use on light/bright surfaces */
  --color-text-muted: #5B6478;

  /* --- Feedback colors --- */
  --color-error: #D9402A;
  --color-success: #278C5D; /* reuses Веста's brand green — already reads as "success" */

  /* --- Section background colors (Phase 2) ---
     Bold, straight from the Bravie brand palette — matching the hero's
     full-saturation-block + white-text pattern rather than soft pastel
     tints. Alternates with white per spec, continuing from Bravies'
     white background. */
  --color-section-problem-bg: #725598; /* Заки's purple */
  --color-section-works-bg: var(--color-misho); /* Мишо's beige — was Веста's
    green; changed per feedback. Being light rather than a bold saturated
    color, it needs different text/accent handling than the rest of this
    section's rules assumed — see .how-it-works below. */

  /* --- Type --- */
  --font-display: 'Dela Gothic One', system-ui, sans-serif;  /* thick, chunky poster face — headlines. Single weight (400) only. */
  --font-body: 'Nunito Sans', system-ui, sans-serif; /* warm, friendly — body/UI text */

  /* --- Type scale (fluid, mobile-first) --- */
  --font-size-h1: clamp(2rem, 6vw, 3.75rem);
  --font-size-h2: clamp(1.5rem, 4.5vw, 2.5rem);
  --font-size-body: clamp(1rem, 2vw, 1.15rem);
  --font-size-small: 0.875rem;

  /* --- Spacing scale --- */
  --space-1: 0.5rem;
  --space-2: 1rem;
  --space-3: 1.5rem;
  --space-4: 2.5rem;
  --space-5: 4rem;
  --space-6: 6rem;

  /* --- Radii --- */
  --radius-input: 14px;
  --radius-card: 15px; /* spec-mandated literal value, not a percentage/angle */

  /* --- Card geometry ---
     Spec: 3:5 (width:height) aspect ratio — physical cards are 6cm x 10cm.
     This is intentionally NOT the same ratio explored in earlier drafts;
     6:10 simplifies to 3:5, a much more screen-practical ratio than 1:6. */
  --card-aspect: 3 / 5;
  --card-border-side: 6px; /* uniform frame thickness; the "thicker bottom
    border" from the spec is implemented as the caption panel's own
    background (see .brave-card__caption) rather than a literal CSS
    border, since a border can only ever be a thin stripe — not a
    readable block containing name + bio text. */

  /* Desktop-only: how much of the Bravies section (heading + top of the
     cards) peeks above the fold under the hero (see §3 "top half of
     cards visible on desktop"). Kept as a fixed value (not fluid) so the
     peek amount is predictable regardless of how wide individual cards
     render. Deliberately generous — per project decision, the character
     preview matters more than keeping the hero comfortable on short
     laptop viewports. */
  --card-peek-desktop: 300px;
  --card-peek-desktop-xl: 340px; /* slightly more room available at ≥1440px */
  --card-peek-mobile: 230px;           /* new: same "peek" treatment, tuned smaller for mobile viewports */
  --card-peek-tablet-portrait: 260px;  /* new: portrait tablet cards render larger than mobile */
}

/* ---------------------------------------------------------------------
   2. RESET & BASE
--------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

/* overflow-x: hidden here too, not just on `body` below — the actual
   scrolling root in most browsers is `html`, not `body`, once `body`
   has its own overflow set. This only became load-bearing once the
   Wait-list Signup clouds started bleeding past their section (see
   that section's own comments) — `html` was still `overflow-x: visible`
   by default, so once nothing downstream clipped the wide cloud
   content, the page itself became horizontally scrollable. */
html { scroll-behavior: smooth; overflow-x: hidden; }

body {
  margin: 0;
  background: var(--color-surface-white);
  color: var(--color-text-dark);
  font-family: var(--font-body);
  font-weight: 300; /* light body text, per typography direction — labels,
    citations, and buttons override this explicitly where they need more
    weight; this is the paragraph-text default. */
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden; /* clouds intentionally travel toward/past the viewport edge */
}

h1, h2, h3 { font-family: var(--font-display); font-weight: 400; margin: 0; }
p { margin: 0; }
ul { list-style: none; margin: 0; padding: 0; }
button { font-family: inherit; }

.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;
}

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

a:focus-visible,
button:focus-visible,
input:focus-visible {
  outline: 3px solid var(--color-zaki);
  outline-offset: 3px;
}

/* =====================================================================
   3. HERO SECTION
   ===================================================================== */
.hero {
  position: relative;
  overflow: hidden;
  min-height: calc(100vh - var(--card-peek-mobile)); /* peek: top of the first
    Bravies card is visible above the fold on every breakpoint, not just
    desktop — tuned per breakpoint below */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5) var(--space-2) var(--space-3); /* extra top
    room on mobile — was feeling squeezed against the viewport edge */
  background: var(--color-hero-bg);
  color: var(--color-hero-text);
}

/* --- Clouds ---
   Real artwork (4 supplied PNGs), swapped in for the earlier CSS-blob
   placeholders. Each cloud's outward travel distance/direction is a CSS
   variable so script.js only ever needs to update one shared
   --scroll-progress value (0 at top of hero, 1 at bottom) on the
   container; direction/reversal on scroll-up falls out naturally since
   transform is a direct function of scroll position, not an incremental
   animation.

   Placement: clouds are pinned to the four corners of the hero and
   allowed to bleed slightly past its edges (hero has overflow:hidden),
   rather than floating near the center — this keeps them clear of the
   headline/subhead/form column at every viewport width without needing
   to fade or dim the artwork. z-index sits below .hero__content (1), so
   even if a viewport is narrow enough for some overlap, text always
   renders on top. */
.hero__clouds {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  /* No --scroll-progress default here on purpose: this element must
     INHERIT the live value script.js sets on #hero (its parent). A
     custom property declared directly on an element — even "just a
     fallback" — always wins over an inherited value, regardless of
     specificity. Declaring `--scroll-progress: 0;` here (as a previous
     version did) permanently pinned every cloud to 0 and silently broke
     the entire scroll effect. #hero itself has no declared value either
     until JS sets one, so `var(--scroll-progress, 0)` below is what
     supplies the pre-JS/no-JS fallback instead. */
}

.cloud {
  position: absolute;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  transform: translate(
    calc(var(--scroll-progress, 0) * var(--cloud-distance) * var(--cloud-dir)),
    var(--cloud-y-offset, 0%)
  );
}

.cloud--1 {
  background-image: url('assets/clouds/cloud-1.png');
  width: clamp(190px, 42vw, 320px);
  aspect-ratio: 2.84 / 1;
  top: 2%;
  left: 2%;
  --cloud-dir: -1;
  --cloud-distance: 160px;
}
.cloud--2 {
  background-image: url('assets/clouds/cloud-2.png');
  width: clamp(130px, 26vw, 210px);
  aspect-ratio: 2.31 / 1;
  top: 16%;
  right: 4%;
  transform: scaleX(-1) translateX(calc(var(--scroll-progress, 0) * var(--cloud-distance) * var(--cloud-dir)));
  --cloud-dir: 1;
  --cloud-distance: 190px;
}
.cloud--3 {
  background-image: url('assets/clouds/cloud-3.png');
  width: clamp(180px, 38vw, 300px);
  aspect-ratio: 2.25 / 1;
  bottom: 16%;
  left: 6%;
  --cloud-dir: -1;
  --cloud-distance: 140px;
}
.cloud--4 {
  background-image: url('assets/clouds/cloud-4.png');
  width: clamp(240px, 46vw, 400px);
  aspect-ratio: 3.01 / 1;
  bottom: 6%;
  right: -5%;
  --cloud-dir: 1;
  --cloud-distance: 170px;
}

/* Larger still with more room to spread out once the viewport has real
   side space to spare. */
@media (min-width: 900px) {
  .cloud--1 { top: 4%;  left: 3%;  width: clamp(260px, 20vw, 380px); }
  .cloud--2 { top: 10%; right: 6%; width: clamp(170px, 13vw, 250px); }
  .cloud--3 { bottom: 20%; left: 8%; width: clamp(220px, 22vw, 340px); }
  .cloud--4 { bottom: 8%; right: -3%; width: clamp(320px, 26vw, 480px); }
}

/* Mobile: the hero is already tight (peek behavior above eats into its
   height), so half the clouds are dropped rather than risk crowding the
   headline/form. The two bottom-corner clouds are kept (small), since
   they sit furthest from the centered text/form column. */
@media (max-width: 767px) {
  .cloud--1, .cloud--2 { display: none; }
  .cloud--3 {
    width: clamp(120px, 42vw, 190px);
    bottom: 12%;
    left: -4%;
  }
  .cloud--4 {
    width: clamp(130px, 46vw, 200px);
    bottom: 4%;
    right: -6%;
  }
}

.hero__content {
  position: relative;
  z-index: 1;
  max-width: 640px;
  width: 100%;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

.hero__title {
  font-size: var(--font-size-h1);
  font-weight: 400; /* Dela Gothic One has one real weight */
  line-height: 1.05;
  color: var(--color-hero-text);
}

.hero__subtitle {
  font-size: var(--font-size-body);
  font-weight: 600;
  color: var(--color-hero-text);
  opacity: 0.92;
  max-width: 34ch; /* mobile only — widened back up at ≥768px below */
}

/* Phase 4.5: new tagline line, styled to match .hero__subtitle's
   weight/size (same visual "tier" — a second line of supporting copy,
   not a new hierarchy level) so it doesn't compete with either the H1
   or the subtitle above it. .hero__content is already a flex column
   with `gap`, so this needed no extra margin/spacing rule of its own
   to sit correctly between the subtitle and the form — the existing
   gap handles it.
   Deliberately full opacity (not the subtitle's 0.92) — `opacity`
   dims an element's entire rendered subtree as a single compositing
   step, so if this paragraph inherited that same 0.92, the highlighted
   spans below would ALSO get diluted against the hero background,
   dropping their contrast from the verified 3.40:1 down to ~3.12:1.
   The highlight is the whole point of this line, so it stays
   undiluted; the very slight difference in perceived brightness vs.
   the subtitle above it is not noticeable in practice. */
.hero__tagline {
  font-size: var(--font-size-body);
  font-weight: 600;
  color: var(--color-hero-text);
  max-width: 34ch; /* mobile only — widened back up at ≥768px below */
}
.hero__tagline-highlight {
  color: var(--color-yellow-light);
  font-weight: 800;
}

/* Same fix, same reasoning as .bravies__intro above (search this file
   for that comment): from tablet width upward there's enough room for
   each line to read as one line rather than wrap mid-sentence, so the
   mobile-only 34ch cap is lifted and the line is allowed its natural
   width. Orientation-agnostic on purpose — unlike some of the other
   breakpoint blocks in this file, this needs to apply to BOTH portrait
   and landscape tablet, not just one, so it uses the plain
   `min-width: 768px` query rather than one of the orientation-specific
   ones. */
@media (min-width: 768px) {
  .hero__subtitle,
  .hero__tagline {
    max-width: none;
    white-space: nowrap;
  }
}

/* --- Waitlist form (shared pattern; reused verbatim by the bottom
   Wait-list Signup section in Phase 4) --- */
.waitlist-form { width: 100%; margin-top: var(--space-2); }

.waitlist-form__row {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  width: 100%;
}

.waitlist-form__input {
  width: 100%;
  padding: 0.9rem 1.1rem;
  font-size: 1rem;
  font-family: var(--font-body);
  border-radius: var(--radius-input);
  border: 2px solid rgba(255, 255, 255, 0.4);
  background: rgba(255, 255, 255, 0.15);
  color: var(--color-hero-text);
  transition: border-color 0.2s ease, background 0.2s ease;
}
.waitlist-form__input::placeholder { color: rgba(248, 250, 252, 0.75); }
.waitlist-form__input:focus { border-color: var(--color-neda); background: rgba(255, 255, 255, 0.22); }
.waitlist-form__input.is-invalid { border-color: var(--color-error); }

@media (max-width: 767px) {
  .waitlist-form__input { text-align: center; }
}

/* Light-background variant, for use once the bottom signup section
   (Phase 4) sits on a white or pastel background instead of the hero's
   deep blue. Not applied yet — reserved here so Phase 4 doesn't have to
   touch this rule block again. */
.waitlist-form--on-light .waitlist-form__input {
  border-color: rgba(30, 36, 51, 0.2);
  background: rgba(30, 36, 51, 0.04);
  color: var(--color-text-dark);
}
.waitlist-form--on-light .waitlist-form__input::placeholder { color: var(--color-text-muted); }

/* Neda-yellow variant (Phase 4: Wait-list Signup section). Distinct
   from --on-light above because the problem here isn't just "light
   background" — the section background IS --color-neda, the exact same
   yellow the button's OLD default used as its own background, so a
   plain default button would've blended straight into the section.
   Button uses Zaki's purple + white text (direct request) rather than
   the earlier dark-inverse treatment — purple-on-yellow already reads
   clearly without needing an inverse workaround.
   Input: solid white background + Zaki-purple text (direct request,
   replacing the earlier translucent dark-tinted version) — echoes the
   badge chips above (also white bg / zaki text), tying the input
   visually to that same "light label on yellow" language rather than
   introducing a third treatment on this one section. */
.waitlist-form--on-neda .waitlist-form__input {
  border-color: transparent;
  background: var(--color-surface-white);
  color: var(--color-zaki);
}
/* Without this, the sitewide `.waitlist-form__input.is-invalid` rule
   (border-color: var(--color-error)) and the `border-color:
   transparent` rule right above it end up at EQUAL specificity (two
   classes each) — meaning it'd come down to source order, and this
   block sits later in the file, so the invalid-state red border would
   silently lose and never show up in this section. Matching both
   classes together here (three, not two) guarantees this wins
   regardless of where either rule sits in the file. */
.waitlist-form--on-neda .waitlist-form__input.is-invalid {
  border-color: var(--color-error);
}
.waitlist-form--on-neda .waitlist-form__input::placeholder { color: var(--color-text-muted); }
.waitlist-form--on-neda .waitlist-form__input:focus {
  border-color: var(--color-zaki);
  /* Without this, the sitewide base `.waitlist-form__input:focus` rule
     (background: rgba(255,255,255,0.22), tuned for the hero's dark
     blue background) would still apply on focus — same specificity
     tier as border-color above, just not overridden by it — and the
     input would visibly shift from solid white to translucent the
     moment someone clicks into it. Keeping it pinned to solid white
     here so the focus state matches the resting state. */
  background: var(--color-surface-white);
}
/* Real bug, caught by testing the actual invalid-submit flow rather
   than just the resting/focus states in isolation: script.js calls
   `input.focus()` right after adding `is-invalid` on a failed submit
   (see initWaitlistForm), so BOTH `.is-invalid` and `:focus` are
   active on the input at the same moment a validation error shows.
   The two rules above (`.is-invalid` and `:focus`) tie at equal
   specificity, and `:focus` sits later in the file, so it was silently
   winning — the border rendered Zaki purple instead of the error red
   right when the person most needed to see something was wrong.
   Matching all three together (class + class + pseudo-class) outranks
   both, so the error color correctly takes priority over the focus
   color whenever both apply. */
.waitlist-form--on-neda .waitlist-form__input.is-invalid:focus {
  border-color: var(--color-error);
}
.waitlist-form--on-neda .waitlist-form__button {
  background: var(--color-zaki);
  color: var(--color-surface-white);
}
.waitlist-form--on-neda .waitlist-form__button:hover { background: #5f4680; } /* --color-zaki, darkened ~15% */
.waitlist-form--on-neda .waitlist-form__spinner {
  border-color: rgba(248, 250, 252, 0.35);
  border-top-color: var(--color-surface-white);
}

/* Minimum input width relative to the button, direct request — "at
   least 60–70% of the CTA button's width," scoped to this section's
   row layout only (≥1024px, or ≥768px landscape — same breakpoint
   `.waitlist-form__row` itself switches to a row at, below). Only
   applies there because mobile/portrait-tablet already stacks the
   input at 100% width (which is wider than the button, not narrower —
   already satisfies the intent without any extra rule), so this isn't
   needed below that breakpoint and was confirmed fine to leave as-is.
   CSS has no way to size an element as a literal percentage of a
   SIBLING's rendered width (only of its own containing block), so
   this is a concrete min-width in px instead, calibrated against the
   button's actual current rendered width at this breakpoint (~273px)
   — 190px sits right in the middle of the requested 60–70% band
   (~70% of 273px). If the button's label text changes enough to
   meaningfully change its own width later, re-check this value
   against the new rendered button width rather than assuming it still
   holds. */
@media (min-width: 1024px), (min-width: 768px) and (orientation: landscape) {
  .waitlist-form--on-neda .waitlist-form__input {
    min-width: 190px;
  }
}

.waitlist-form__button {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1rem 1.5rem;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 400; /* Dela Gothic One has one real weight */
  color: var(--color-text-dark);
  background: var(--color-neda);
  border: none;
  border-radius: var(--radius-input);
  cursor: pointer;
  transition: background 0.2s ease, transform 0.15s ease;
}
.waitlist-form__button:hover { background: #ffe27a; }
.waitlist-form__button:active { transform: scale(0.98); }
.waitlist-form__button:disabled { opacity: 0.7; cursor: not-allowed; }

.waitlist-form__spinner {
  display: none;
  width: 16px; height: 16px;
  border-radius: 50%;
  border: 2px solid rgba(30, 36, 51, 0.35);
  border-top-color: var(--color-text-dark);
  animation: spin 0.7s linear infinite;
}
.waitlist-form__button.is-loading .waitlist-form__spinner { display: inline-block; }
.waitlist-form__button.is-loading .waitlist-form__button-label { opacity: 0.85; }
@keyframes spin { to { transform: rotate(360deg); } }

.waitlist-form__error {
  min-height: 1.25rem;
  margin-top: var(--space-1);
  font-size: var(--font-size-small);
  font-weight: 700;
  color: #7F1D1D; /* dark, saturated red for strong contrast against its own white chip */
  text-align: left;
}

/* A solid white chip behind the message guarantees contrast regardless
   of the section's own background color (blue hero today, unknown
   colors in later sections) — a plain light-red text color wasn't
   prominent enough against the hero's blue. Only shown when there's
   actually an error to display, via :not(:empty) (script.js sets/clears
   this element's textContent directly). */
.waitlist-form__error:not(:empty) {
  display: inline-block;
  padding: 0.35rem 0.7rem;
  background: var(--color-surface-white);
  border-radius: 8px;
}

/* --- Success message: fades in once script.js removes [hidden] and adds .is-visible --- */
.success-message {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: var(--space-2);
  padding: 1rem 1.25rem;
  width: 100%;
  border-radius: var(--radius-input);
  background: rgba(39, 140, 93, 0.25); /* --color-success tint */
  border: 1px solid rgba(39, 140, 93, 0.6);
  color: var(--color-hero-text);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
/* Bug fix: `.success-message`'s own `display: flex` (needed once visible)
   was outranking the browser's built-in `[hidden] { display: none }`
   rule in specificity (a class beats a bare attribute selector), so the
   element stayed in the layout — full height reserved — even while
   `hidden` was set. Invisible (opacity: 0) but still taking up space.
   This was hard to notice on the hero (enough surrounding whitespace
   to hide it) but became obvious as unexplained extra height on the
   shorter Wait-list Signup section. `[hidden]` here has higher
   specificity than the plain class above, so it correctly wins and
   collapses the element out of flow until script.js removes the
   attribute. Fixes both instances (hero + Wait-list Signup) at once. */
.success-message[hidden] { display: none; }
.success-message.is-visible { opacity: 1; transform: translateY(0); }
.success-message__icon { width: 22px; height: 22px; flex-shrink: 0; color: #6EE7B7; }
.success-message__text { font-weight: 700; text-align: left; }

/* Light-background variant (Phase 4: Wait-list Signup, on Neda's
   yellow). The default above assumes a dark section — white text
   (--color-hero-text) and a pale mint icon (#6EE7B7) both nearly
   vanish against a bright yellow surface, so both are swapped for
   dark-on-tint equivalents here rather than reusing the default as-is. */
.success-message--on-light {
  color: var(--color-text-dark);
  background: rgba(39, 140, 93, 0.15);
  border-color: rgba(39, 140, 93, 0.55);
}
.success-message--on-light .success-message__icon { color: var(--color-vesta); }

/* =====================================================================
   4. BRAVIES INTRO SECTION
   ===================================================================== */
.bravies {
  position: relative;
  padding: var(--space-3) var(--space-2) var(--space-5);
  background: var(--color-surface-white);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.bravies__intro {
  font-size: var(--font-size-h2);
  font-weight: 700;
  text-align: center;
  max-width: 32ch;
  margin-bottom: var(--space-2);
  color: var(--color-text-dark);
}

/* From portrait-tablet width upward, the heading needs to read as one
   line rather than wrap and compete with the cards for vertical room
   (feedback: it was "too big" relative to the card row). Sized down and
   allowed its natural width instead of wrapping at 32ch. */
@media (min-width: 768px) {
  .bravies__intro {
    font-size: clamp(1.1rem, 2.3vw, 1.6rem);
    max-width: none;
    white-space: nowrap;
  }
}

/* --- Card row: mobile default = single column, one card per row --- */
.card-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
}

/* --- Individual card ---
   Root <li> stays position:relative + overflow:visible so the enlarged
   portrait can escape the card's frame on activation. The colored,
   rounded, thick border is painted on a ::before pseudo-element so the
   real border-radius clips cleanly regardless of inner content. */
.brave-card {
  position: relative;
  width: min(320px, 78vw);
  aspect-ratio: var(--card-aspect);
  min-height: 0; /* .brave-card is itself a flex item of .card-row; without
    this, its default content-based minimum height could override the
    aspect-ratio and make cards different heights depending on how their
    contents happened to render — the same class of bug fixed earlier
    for .brave-card__portrait, one level up */
  flex-shrink: 0;
  overflow: visible;
}

.brave-card::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: var(--radius-card);
  background: var(--color-surface-white);
  border: var(--card-border-side) solid var(--card-color, var(--color-zaki));
  pointer-events: none;
}

/* Per-character accent color, plus a matching text color chosen for
   contrast against that specific accent (some brand colors are light
   enough to need dark text, others need white — see each value below).
   Each also gets a small, individually-tuned tilt — alternating
   positive/negative by a couple of degrees — so the row reads like
   playing cards casually set down on a table rather than a stiff,
   perfectly-aligned grid. Kept deliberately subtle; applied at every
   breakpoint (mobile stack, tablet grid, desktop row) for a consistent
   feel throughout, not just on desktop. */
.brave-card--zaki   { --card-color: var(--color-zaki);   --card-text-on-accent: var(--color-surface-white); transform: rotate(-2.5deg); }
.brave-card--vihren { --card-color: var(--color-vihren); --card-text-on-accent: var(--color-text-dark);   transform: rotate(2deg); }
.brave-card--neda    { --card-color: var(--color-neda);   --card-text-on-accent: var(--color-text-dark);   transform: rotate(-1.5deg); }
.brave-card--vesta   { --card-color: var(--color-vesta);  --card-text-on-accent: var(--color-surface-white); transform: rotate(2.5deg); }
.brave-card--misho   { --card-color: var(--color-misho);  --card-text-on-accent: var(--color-text-dark);   transform: rotate(-2deg); }

.brave-card__trigger {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  text-align: center;
  color: inherit;
}

/* Rectangular character-image placeholder (per spec, not circular).
   Fills the ENTIRE card (not just the space above the caption) and the
   caption sits on top of it as an absolutely-positioned overlay — see
   .brave-card__caption below. The portrait's box is constant regardless
   of caption/hover state, which is what makes sizing reliable (see the
   longer note in the decisions log for the history of bugs this fixed). */
.brave-card__portrait {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: var(--space-2) var(--space-2) 0.5rem;
  overflow: visible; /* allows the character art to pop outside the frame */
}

.brave-card__portrait-img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 6px 10px rgba(30, 36, 51, 0.18));
  /* Small/contained size by default (mobile + both tablet orientations).
     The larger size — and the hover pulse — are desktop-only, added in
     the "landscape tablet / desktop" breakpoint further down. */
  transform: translateY(0) scale(1);
}

/* Scroll-triggered pulse for mobile + portrait tablet, where hover isn't
   a real interaction. Each card pulses individually the first time it
   scrolls into view (JS: initBraveCardScrollPulse() adds .is-pulsing
   per-card via IntersectionObserver, one-shot — same convention as the
   sitewide .reveal system). Uses the small/base transform as its
   resting state, unlike the desktop pulse below which scales up from
   the already-enlarged desktop portrait size. Neutralized again inside
   the desktop breakpoint further down, where hover takes over instead —
   this rule and the desktop hover rule are deliberately mutually
   exclusive, not layered. */
@keyframes brave-card-pulse-mobile {
  0%   { transform: translateY(0) scale(1); }
  50%  { transform: translateY(0) scale(1.08); }
  100% { transform: translateY(0) scale(1); }
}
.brave-card__portrait-img.is-pulsing {
  /* Was 0.6s — doubled per direct request ("pop out and back... twice
     as slower"). Keyframe percentages are unchanged (still 0/50/100),
     so the shape of the motion is identical, just stretched over twice
     the time. */
  animation: brave-card-pulse-mobile 1.2s ease;
}
@media (prefers-reduced-motion: reduce) {
  .brave-card__portrait-img.is-pulsing { animation: none; }
}

/* Caption bar: THIS is the spec's "thicker bottom border" — rather than
   an actual CSS border (which can only ever be a thin stripe, not a
   readable text panel), it's a solid-colored block using the card's
   accent color, sized to sit flush against the card's rounded bottom
   corners and side borders. Always shows the full name + bio (no more
   collapsed/expand states — removed per earlier feedback). */
.brave-card__caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  height: 110px; /* shorter now that Мишо's bio (previously the longest,
    forcing a taller shared height) was trimmed to match the others */
  padding: 0.5rem 0.75rem 0.6rem;
  overflow: hidden;
  background: var(--card-color, var(--color-zaki));
  border-radius: 0 0 var(--radius-card) var(--radius-card);
}

/* Mobile cards are wider (up to 320px vs ~160-220px on desktop), so the
   same bio text wraps to fewer lines and needs less vertical room. */
@media (max-width: 767px) {
  .brave-card__caption { height: 90px; }
}

.brave-card__name {
  font-family: var(--font-display);
  font-weight: 400; /* Dela Gothic One has one real weight */
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--card-text-on-accent, var(--color-text-dark));
}

.brave-card__bio {
  font-size: 0.95rem;
  line-height: 1.32;
  color: var(--card-text-on-accent, var(--color-text-dark));
  opacity: 0.95;
}

.brave-card.is-active,
.brave-card:hover {
  z-index: 5;
}

/* =====================================================================
   5. BREAKPOINT — PORTRAIT TABLET (≥768px, portrait orientation)
   Card grid: 3 rows in a 1 / 2 / 2 pattern — Неда alone, then
   Вихрен+Веста, then Заки+Мишо. This matches DOM order exactly, so no
   visual reordering is needed at this breakpoint.
   ===================================================================== */
@media (min-width: 768px) and (orientation: portrait) {
  .hero {
    min-height: calc(100vh - var(--card-peek-tablet-portrait));
  }

  .card-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(220px, 1fr));
    justify-items: center;
    align-items: start;
    gap: var(--space-4) var(--space-3);
    max-width: 680px;
  }

  /* Неда (first in DOM) spans both columns to form the lone top row */
  .card-row > li:first-child { grid-column: 1 / -1; }

  .brave-card { width: min(300px, 34vw); }
}

/* =====================================================================
   6. BREAKPOINT — LANDSCAPE TABLET / DESKTOP (≥1024px, or ≥768px landscape)
   Cards move to a single row; visual order is remapped to the spec's
   desktop reading order (Заки, Вихрен, Неда, Веста, Мишо) via the CSS
   `order` property — DOM order stays as the mobile/portrait order.
   Hero also gains the "peek" behavior so the top half of the cards is
   visible above the fold.
   ===================================================================== */
@media (min-width: 1024px), (min-width: 768px) and (orientation: landscape) {
  .hero {
    min-height: calc(100vh - var(--card-peek-desktop));
    padding-bottom: var(--space-3);
  }

  /* Tighten the gap between the hero's bottom edge and the Bravies
     heading/cards, so the peek amount above is spent showing actual
     card content rather than being eaten by section padding. */
  .bravies {
    padding-top: var(--space-2);
    gap: var(--space-3);
  }

  .waitlist-form__row { flex-direction: row; align-items: stretch; justify-content: center; }
  .waitlist-form__input { max-width: 320px; } /* was stretching to fill the
    full hero-content width (~700px) — far wider than any real email
    address needs */
  .waitlist-form__input { flex: 1; }
  .waitlist-form__button { flex-shrink: 0; }

  .card-row {
    display: flex;
    flex-direction: row;
    align-items: flex-end;
    justify-content: center;
    flex-wrap: nowrap;
    max-width: none;
    gap: var(--space-3);
  }

  .card-row > li:first-child { grid-column: auto; }

  .brave-card { width: clamp(160px, 13vw, 210px); }

  /* Desktop/landscape-tablet only: portraits render at the larger size
     (moved here from the old universal default — mobile and portrait
     tablet now stay at the small/contained size instead). */
  .brave-card__portrait-img {
    transform: translateY(-14%) scale(1.16);
  }

  /* Replaces the earlier halo/spotlight effect (removed per feedback)
     with a brief "pulse": a small, quick enlarge-then-settle-back on
     hover or when active (Неда by default) — not a persistent size
     change, just a short flourish on top of the desktop base size
     above. Desktop-only, per feedback. */
  @keyframes brave-card-pulse {
    0%   { transform: translateY(-14%) scale(1.16); }
    50%  { transform: translateY(-14%) scale(1.22); }
    100% { transform: translateY(-14%) scale(1.16); }
  }

  .brave-card__trigger:hover .brave-card__portrait-img {
    /* Was 0.5s — doubled per direct request, same reasoning as the
       mobile pulse above (see that rule's comment). */
    animation: brave-card-pulse 1s ease;
  }
  /* Desktop uses hover only — the scroll-triggered .is-pulsing class
     (mobile/portrait-tablet) is neutralized here so the two mechanisms
     never layer or conflict on the same element. */
  .brave-card__portrait-img.is-pulsing {
    animation: none;
  }
  /* Deliberately NOT also keyed to .brave-card.is-active — Неда's card
     carries that class statically from page load (see index.html), so
     tying the animation to it meant the pulse fired once on load and
     then never again: the element's computed animation value never
     actually changed on subsequent hovers (still resolving to the same
     "brave-card-pulse 0.5s ease" the is-active rule already supplied),
     so the browser had nothing to restart. Hover-only fixes it —
     Неда's card now pulses on hover exactly like the other four. */

  /* Desktop/landscape-tablet visual order (see comment above and in
     index.html near the card-row markup) */
  .brave-card--zaki   { order: 1; }
  .brave-card--vihren { order: 2; }
  .brave-card--neda    { order: 3; }
  .brave-card--vesta   { order: 4; }
  .brave-card--misho   { order: 5; }
}

/* =====================================================================
   7. BREAKPOINT — DESKTOP (≥1440px)
   ===================================================================== */
@media (min-width: 1440px) {
  .hero {
    min-height: calc(100vh - var(--card-peek-desktop-xl));
  }

  .hero__content { max-width: 720px; }

  /* Keep the tightened top padding from the previous breakpoint — only
     widen the side/bottom padding here, don't reset padding-top back up. */
  .bravies {
    padding-left: var(--space-5);
    padding-right: var(--space-5);
    padding-bottom: var(--space-6);
  }

  .card-row { gap: var(--space-4); }
  .brave-card { width: clamp(180px, 11vw, 220px); }
}

/* =====================================================================
   PHASE 2 — Problem / What It Teaches / How It Works
   Added additively; nothing above this point was restructured. Reuses
   existing tokens (--font-display, --font-size-h2, --space-*,
   --card-aspect, --radius-card, --color-* brand values) rather than
   introducing a parallel system.
   ===================================================================== */

/* ---------------------------------------------------------------------
   Shared scroll-reveal (Intersection Observer driven, see script.js).
   Starts hidden/offset, animates in once when scrolled into view.
--------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* ---------------------------------------------------------------------
   PROBLEM SECTION
--------------------------------------------------------------------- */
.problem {
  padding: var(--space-5) var(--space-2);
  background: var(--color-section-problem-bg);
  color: var(--color-hero-text);
}

.problem__inner {
  /* Widened from 62ch, per direct request that the heading felt too
     tightly wrapped. Deliberately NOT widening via a bigger `ch`
     value — `ch` here is sized off THIS element's own font
     (Nunito Sans, inherited from body), not the heading's actual
     Dela Gothic One, which is a visibly wider/heavier face; a `ch`-based
     width doesn't track the heading's real rendered width well. Using
     a fixed px value instead, tuned directly against rendered
     screenshots at 768/1024/1440px (this session's test environment
     doesn't have the real self-hosted font files, so headings render
     in a fallback font here — re-verify this wrap once the real Dela
     Gothic One font is loading, since it's chunkier than most fallback
     sans faces and may wrap slightly differently). Body paragraphs
     widen along with the heading since they share this container —
     checked that the prose still reads fine at this width, not just
     the heading.
  */
  max-width: 920px;
  margin: 0 auto;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.problem__heading {
  font-size: var(--font-size-h2);
  font-weight: 400; /* Dela Gothic One has one real weight */
}

/* Accent-colored, oversized quotation marks — turns the heading into a
   visible pull-quote rather than reading as an unmarked headline. */
.problem__quote-mark {
  font-size: 1.4em;
  font-weight: 400; /* inherits Dela Gothic One from parent h2 — one real weight */
  color: var(--color-neda);
  line-height: 0;
  vertical-align: -0.08em;
}

.problem__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--font-size-body);
  line-height: 1.6;
  opacity: 0.96;
  /* Left-aligned, not inherited-center from .problem__inner — centered
     multi-sentence prose has two real readability costs: the eye's
     "return point" (where the next line starts) moves every line
     instead of staying fixed at a left edge, and centered text doesn't
     fill out to the container's width, so it wraps wherever a word
     naturally breaks and looks choppier/shorter than the actual
     measure. The block itself stays centered on the page (this is
     still inside .problem__inner's `margin: 0 auto`) — only the text
     inside it is left-aligned now. Heading/pull-quote above this stays
     centered on purpose: short 1-2 line display text doesn't have the
     same readability cost, and reads better as a centered pull-quote. */
  text-align: left;
}

/* ---------------------------------------------------------------------
   WHAT IT TEACHES SECTION
--------------------------------------------------------------------- */
.teaches {
  padding: var(--space-5) var(--space-2);
  background: var(--color-surface-white);
  color: var(--color-text-dark);
}

.teaches__inner {
  max-width: 1100px; /* wider than Problem's column — needs room for the
    point-tile grid below, not just prose */
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

.teaches__heading {
  font-size: var(--font-size-h2);
  font-weight: 400; /* Dela Gothic One has one real weight */
  text-align: center;
}

.teaches__body {
  /* Fixed px, not `ch` — measured actual line CAPACITY (via canvas
     text measurement of the real font/size, not just counting
     characters in whatever a particular paragraph's word-wrap happened
     to produce) to hit the requested 75-character minimum precisely.
     75ch measured out to ~73 characters of real capacity in testing —
     close, but short — so this uses the same fixed-px approach as
     .problem__inner instead, tuned to the same target. Verified ≥75
     char capacity at 1440px viewport before finalizing this value. */
  max-width: 920px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--font-size-body);
  line-height: 1.6;
  /* Left-aligned — same reasoning as .problem__body above (see that
     comment for the full rationale). Block still centers on the page
     via `margin: 0 auto`; only the text itself is left-aligned. */
  text-align: left;
}

/* Point tiles: each echoes one Bravie's icon + brand color from the
   Bravies Intro section (see index.html comment — names aren't repeated
   here, the color/icon pairing alone is the callback). Colors cycle via
   nth-child in the same order as the Bravies Intro cards' DOM order
   (Неда, Вихрен, Веста, Заки, Мишо) so the two sections visually rhyme;
   written generically (nth-child modulo, same technique as the earlier
   checkmark-bullet version this replaces) so it wouldn't break if a
   point is added or removed later. */
.teaches__points {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  column-gap: var(--space-3);
  --icon-size: 84px;
  /* Row gap needs to be bigger than column gap: each row's icon badges
     poke up 2/3 of their height above their own box, so without extra
     clearance they touch (or overlap) the bottom of the row above. */
  row-gap: calc(var(--icon-size) * 2 / 3 + var(--space-2));
  /* Same clearance need for the very first row, against the paragraph
     above the grid instead of another row. */
  margin-top: calc(var(--icon-size) * 2 / 3 - var(--space-4));
}

.teaches__point {
  --point-color: var(--color-neda);
  /* White per direct request (Phase 4.6) — was --color-icon-burnt-orange.
     The "colorful glyph" reasoning from the original feedback (see the
     comment below) is superseded here for this specific tile by the
     newer, more specific request; Вихрен and the Buddy/turquoise tile
     got the same change, Веста/Заки/Мишо did not (not asked for). */
  --icon-glyph-color: var(--color-surface-white);
  --icon-url: url('assets/icons/resist.png');
  position: relative;
  overflow: visible;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* Top padding leaves room below the icon badge, which overlaps the
     top edge rather than sitting inline (see .teaches__point-icon) —
     only the icon's bottom third needs clearing here. */
  padding: calc(var(--icon-size) / 3 + var(--space-2)) var(--space-2) var(--space-3);
  border-radius: var(--radius-card);
  background: var(--color-surface-white);
  border: 3px solid var(--point-color);
}

/* Icon glyph colors: originally chosen for a colorful result rather
   than reusing the plain dark/white split from each Bravie's card
   caption text (per earlier feedback: "colorful would be better").
   Phase 4.6 direct request reversed that for three of these tiles
   (Неда above, Вихрен + Buddy below) back to white — Веста's and
   Заки's stayed untouched since they were already white and weren't
   part of the request. */
.teaches__point:nth-child(6n+2) {
  --point-color: var(--color-vihren);
  --icon-glyph-color: var(--color-surface-white); /* was --color-icon-deep-red */
  --icon-url: url('assets/icons/running_away.png');
}
.teaches__point:nth-child(6n+3) {
  --point-color: var(--color-vesta);
  --icon-glyph-color: var(--color-surface-white);
  --icon-url: url('assets/icons/tell.png');
}
.teaches__point:nth-child(6n+4) {
  --point-color: var(--color-zaki);
  --icon-glyph-color: var(--color-surface-white);
  --icon-url: url('assets/icons/keyword.png');
}
.teaches__point:nth-child(6n+5) {
  --point-color: var(--color-misho);
  /* Phase 4.6: uses --color-misho-trim (the same dark brown used for
     How It Works' step titles/numbers — see .how-it-works__step-title
     and .how-it-works__number), per direct request. */
  --icon-glyph-color: var(--color-misho-trim);
  /* Real asset, supplied directly: a confused/questioning face icon
     (question mark + worried expression). Solid black line art on a
     transparent background (verified: real alpha channel, not a white
     matte — confirmed via the image's alpha extrema before using it),
     so it works correctly with mask-image tinting like the other 5
     icons. Now added to the nth-child list in the ::after
     content-activation rule below, since there's a real icon to
     activate. One honest flag: this source image is a much more
     detailed illustration (multiple strokes, a full facial expression)
     than the other 5 icons' simple flat single-shape glyphs (a hand, a
     running figure, a megaphone, a key, a shield+heart) — worth a look
     at actual render size (this badge is a small 84px circle) to
     confirm the extra detail stays legible rather than turning into
     visual noise once tinted solid brown and scaled down. */
  --icon-url: url('assets/icons/misho-confused.png');
}
.teaches__point:nth-child(6n+6) {
  --point-color: var(--color-buddy);
  /* White per direct request (Phase 4.6) — this is the "turquoise/
     special cards" tile referenced in that request. Was
     --color-icon-deep-teal. */
  --icon-glyph-color: var(--color-surface-white);
  --icon-url: url('assets/icons/help.png');
}

/* Icon badge: straddles the card's top edge — 2/3 of its height above
   the card, 1/3 inside it — rather than sitting inline above the text.
   The circle itself stays filled with --point-color; the glyph is a
   separate layer on top using CSS mask, which lets one single-color
   source PNG (white shape, transparent background — true of all 5
   confirmed icons) be tinted to whatever --icon-glyph-color contrast
   requires per tile, rather than needing a differently-colored image
   file for every possible pairing. */
.teaches__point-icon {
  position: absolute;
  top: calc(var(--icon-size) * -2 / 3);
  left: 50%;
  transform: translateX(-50%);
  width: var(--icon-size);
  height: var(--icon-size);
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--point-color);
}

.teaches__point-icon::after {
  content: none; /* suppressed by default; tiles with a confirmed icon
    (below) override this to '' to activate the glyph layer — needed
    because mask-image:none does NOT hide an unmasked layer, it just
    removes the mask, which left Мишо's placeholder showing a solid
    unmasked square instead of nothing */
  position: absolute;
  inset: 22%;
  background-color: var(--icon-glyph-color);
  -webkit-mask-image: var(--icon-url);
  mask-image: var(--icon-url);
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

.teaches__point:nth-child(6n+1) .teaches__point-icon::after,
.teaches__point:nth-child(6n+2) .teaches__point-icon::after,
.teaches__point:nth-child(6n+3) .teaches__point-icon::after,
.teaches__point:nth-child(6n+4) .teaches__point-icon::after,
.teaches__point:nth-child(6n+5) .teaches__point-icon::after,
.teaches__point:nth-child(6n+6) .teaches__point-icon::after {
  content: '';
}

.teaches__point p {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.5;
}

.teaches__cta {
  display: flex;
  justify-content: center;
}

/* Reusable CTA button — reuses the hero form button's yellow, since
   that's already the page's established "primary action" color, rather
   than introducing a new one-off CTA color. Written generically (not
   scoped to .teaches) since the Desired State section's "Искам това
   спокойствие" CTA will need the same treatment later. */
.cta-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1rem 2rem;
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 400; /* Dela Gothic One has one real weight */
  color: var(--color-text-dark);
  background: var(--color-neda);
  border-radius: var(--radius-input);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.15s ease;
}
.cta-button:hover { background: #ffe27a; }
.cta-button:active { transform: scale(0.98); }

/* ---------------------------------------------------------------------
   HOW IT WORKS SECTION
--------------------------------------------------------------------- */
.how-it-works {
  padding: var(--space-4) var(--space-2);
  background: var(--color-section-works-bg);
  color: var(--color-text-dark); /* was --color-hero-text (white) — wrong
    once the background changed from Веста's dark green to Мишо's light
    beige; every other color below this point was re-checked against the
    new background too, not just this one line */
}

.how-it-works__inner {
  max-width: 1100px;
  margin: 0 auto;
}

.how-it-works__heading {
  font-size: var(--font-size-h2);
  font-weight: 400; /* Dela Gothic One has one real weight */
  text-align: center;
  /* Direct request: match the numbered step badges' color
     (--color-misho-trim, the same brown used for .how-it-works__number
     and .how-it-works__step-title below — see those rules). Was the
     inherited default text color; margin-bottom moved to the new
     .how-it-works__meta line below it so the heading/subtitle pair
     reads as one tight unit. */
  color: var(--color-misho-trim);
}

/* New subtitle line under the heading — plain, quiet metadata (player
   count / time / age range), not trying to compete with the heading
   for attention. Small, muted weight, tight margin to the heading
   above and the extra space to the steps below via
   .how-it-works__heading no longer carrying margin-bottom itself. */
.how-it-works__meta {
  margin: 0 0 var(--space-4);
  text-align: center;
  /* Was 0.95rem — direct request to match the size of the rest of the
     section's black body text (the step-line paragraphs below, which
     use --font-size-body, the same clamp() every other body-copy
     paragraph on the page uses). Weight (600) and the slight opacity
     dimming (0.75) are left as-is — those weren't part of this
     request, only size — so this line still reads as a distinct,
     slightly muted metadata row rather than becoming visually
     identical to the step descriptions; flag if those should also be
     unified now that the size matches. */
  font-size: var(--font-size-body);
  font-weight: 600;
  color: var(--color-text-dark);
  opacity: 0.75;
}

.how-it-works__steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Zigzag: step 1 and 3 show text-left/card-right (normal row order,
   matching DOM order); step 2 flips to text-right/card-left via
   row-reverse — visual only, so DOM/reading order (text before card)
   stays the same for every step regardless of screen side. */
.how-it-works__step {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
.how-it-works__step--2 {
  flex-direction: row-reverse;
}

.how-it-works__text {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.how-it-works__number {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 400; /* Dela Gothic One has one real weight */
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  /* Was a translucent-white ring, designed to sit on Веста's dark green.
     On the light beige background that would barely be visible — solid
     brown + white number gives real contrast instead. Мишо's own
     trim/shoe color, matching the step titles below — was purple
     (--color-zaki) until now, changed for the same reason as the
     titles: purple was an unrelated accent clashing against Мишо's
     card art in this section. */
  background: var(--color-misho-trim);
  color: var(--color-surface-white);
  margin-bottom: 0.2rem;
}

/* First sentence of each step is its title: uppercase, accent color,
   own line — per feedback, distinguishing it from the plain
   explanatory sentences that follow (each of which also gets its own
   line, rather than running together as one paragraph). Was yellow
   (--color-neda), which read clearly on the section's old dark green
   background but would be too low-contrast on the new light beige one
   — switched to Заки's purple, which also now matches the step-number
   badge for a consistent accent throughout the section. */
.how-it-works__step-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 400; /* Dela Gothic One has one real weight */
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-misho-trim); /* was --color-zaki purple — clashed
    against Мишо-colored card art in this section. Мишо's own trim/shoe
    brown reads as part of the same character instead of an unrelated
    accent. Step-number badges (above, .how-it-works__number) also use
    this same brown now — this comment previously said they were still
    purple, which had gone stale; fixed to match the actual CSS. */
}

.how-it-works__step-line {
  margin: 0;
  font-size: var(--font-size-body);
  line-height: 1.5;
}

.how-it-works__card-wrap {
  flex: 1 1 0;
  min-height: 0; /* same flex/img lesson noted below — applies here too now that real <img> cards exist */
  display: flex;
  justify-content: center;
}

/* Card: reuses the same aspect ratio token as the Bravies cards
   (--card-aspect, 3:5 per spec) and the same "played on a table" tilt
   technique (a small per-step rotate()) rather than inventing a new
   approach. Steps 1 and 2 now use real card art (--img modifier,
   below); step 3 still has no artwork, so it stays the dashed-pattern
   placeholder — sized small deliberately (per feedback the section was
   running 2+ screens tall on desktop; this is the single biggest lever
   on the section's overall height, since the 3:5 aspect ratio means
   every pixel of width becomes 1.67px of height). */
.how-it-works__card {
  width: min(130px, 36vw);
  aspect-ratio: var(--card-aspect);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-2);
  background: var(--color-surface-white);
  border: 3px dashed rgba(30, 36, 51, 0.25);
  border-radius: var(--radius-card);
  color: var(--color-text-muted);
  font-size: var(--font-size-small);
  font-weight: 700;
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.18);
}

/* Real card art. NOTE this corrects an assumption carried over from the
   Bravies-card fix: there, the <img> was a CHILD of a separately-sized
   container, so width/height:100% made it fill that parent. Here, this
   element IS the box (width + aspect-ratio come from the base
   .how-it-works__card rule, above, applied to this same element) — so
   width:100% would instead resolve against the flex parent (card-wrap)
   and blow the card up far past its intended ~130px size, which is
   exactly what happened on first render (measured 530px instead of
   ~130px). Only object-fit is needed here; no explicit width/height. */
.how-it-works__card--img {
  display: block;
  object-fit: cover;
  padding: 0;
  border: none;
  background: none;
}

.how-it-works__step--1 .how-it-works__card { transform: rotate(-3deg); }
.how-it-works__step--2 .how-it-works__card { transform: rotate(2.5deg); }
.how-it-works__step--3 .how-it-works__card { transform: rotate(-2deg); }

/* Mobile: card stacks ABOVE its related text (spec's explicit mobile
   rule) — a visual-only reorder via `order`, DOM/reading order is
   unchanged (still text markup before card markup either way). Zigzag
   direction is dropped in favor of a single stacked column, since
   left/right sides don't mean anything at this width. */
@media (max-width: 767px) {
  .how-it-works__step,
  .how-it-works__step--2 {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
  }

  .how-it-works__card-wrap {
    order: -1;
    /* min-height:0 (set for the desktop row layout, to prevent the
       overflow bug documented above) has the opposite effect here:
       in a COLUMN flex container, flex:1 1 0 with min-height:0 collapses
       the item toward its 0 flex-basis instead of sizing to the image's
       aspect-ratio height, since there's no automatic content-based
       minimum left to fall back on. Confirmed by measuring: the card
       rendered at the correct 130px width but only ~6px tall. Restoring
       auto here fixes it without reintroducing the original overflow
       bug, since that was a row-direction-specific issue. */
    min-height: auto;
    flex: 0 0 auto;
  }

  .how-it-works__text { text-align: center; align-items: center; }
}

/* =====================================================================
   PHASE 3 — Testimonials / Desired State
   Added additively; nothing above this point was restructured. Reuses
   existing tokens (--font-display, --font-size-h2, --space-*,
   --radius-card, --radius-input, --color-* brand values, .reveal,
   .cta-button) rather than introducing a parallel system.
   ===================================================================== */

/* ---------------------------------------------------------------------
   TESTIMONIALS SECTION
--------------------------------------------------------------------- */
.testimonials {
  padding: var(--space-5) var(--space-2);
  background: var(--color-surface-white);
  color: var(--color-text-dark);
}

.testimonials__inner {
  /* Widened from 700px so the heading fits on one line at desktop/
     tablet-landscape, per direct request. Slider/quote content shares
     this container (no independent narrower width of its own — see
     .testimonials__slider), so it gets wider too; checked that the
     quote block still reads fine at this width, not just the heading.
     Tuned against rendered screenshots — see the same font-fallback
     caveat noted on .problem__inner above (this session doesn't have
     the real Dela Gothic One font files, so re-verify once those are
     loading for real). */
  max-width: 980px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

.testimonials__heading {
  font-size: var(--font-size-h2);
  font-weight: 400; /* Dela Gothic One has one real weight */
  text-align: center;
}

.testimonials__slider {
  width: 100%;
}
.testimonials__slider:focus-visible {
  outline: 3px solid var(--color-zaki);
  outline-offset: 4px;
  border-radius: var(--radius-card);
}

.testimonials__viewport {
  overflow: hidden;
}

.testimonials__track {
  display: flex;
  transition: transform 0.5s cubic-bezier(0.65, 0, 0.35, 1);
}
@media (prefers-reduced-motion: reduce) {
  .testimonials__track { transition: none; }
}

.testimonials__slide {
  flex: 0 0 100%;
  width: 100%;
}

/* No card/border — the quote sits directly on the section background.
   Quotation marks flank the text left/right (not stacked above/below —
   stacking ate too much vertical space) and are vertically centered
   against the whole quote block, including the citation line. Each
   slide carries its own --slide-accent (set inline in index.html,
   cycling through the 5 brand colors); the marks pick it up so tone
   shifts quote-to-quote once more are added. */
.testimonials__quote {
  margin: 0;
  padding: 0 var(--space-2);
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
}

.testimonials__quote-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0;
}

.testimonials__mark {
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: 3.5rem;
  line-height: 1;
  font-weight: 400; /* Dela Gothic One has one real weight */
  color: var(--slide-accent, var(--color-vesta));
}
.testimonials__mark--open { align-self: flex-start; }
.testimonials__mark--close { align-self: flex-end; }

.testimonials__quote p {
  margin: 0;
  font-family: var(--font-body); /* deviation from a literal display-font
    swap — Dela Gothic One is a single-weight poster face; a full sentence
    set in it at h2 size reads as shouty, not warm. Body font at 600
    keeps the quote visually prominent while staying readable. Flagging
    since this wasn't explicitly requested — happy to revert if you'd
    rather the whole quote stay in the display face. */
  font-weight: 600;
  font-size: var(--font-size-h2);
  line-height: 1.35;
  color: var(--color-text-dark);
}

.testimonials__cite {
  display: block;
  margin-top: var(--space-2);
  font-style: normal;
  font-size: var(--font-size-small);
  font-weight: 700;
  color: var(--color-text-muted);
}

/* Quote-content animation: plays on initial paint and is explicitly
   replayed by JS (forced reflow) on every interaction, including a
   single-slide self-loop — see initTestimonialsSlider() in script.js. */
.testimonials__quote {
  animation: testimonial-bump 0.5s ease;
}
@keyframes testimonial-bump {
  0% { opacity: 0; transform: translateY(10px) scale(0.98); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .testimonials__quote { animation: none; }
}

/* Dots are the only nav control now (arrows removed per feedback) —
   larger, colored per-slide via --slide-accent, always visible
   (including with a single quote) so the mechanism reads as "alive"
   before quote #2 exists. */
.testimonials__dots {
  display: flex;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.testimonials__dot {
  width: 1rem;
  height: 1rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--dot-accent, var(--color-vesta));
  opacity: 0.35;
  cursor: pointer;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.testimonials__dot:hover { opacity: 0.6; }
.testimonials__dot.is-active {
  opacity: 1;
  transform: scale(1.3);
}

@media (max-width: 480px) {
  .testimonials__mark { font-size: 2.5rem; }
  .testimonials__quote { gap: var(--space-1); }
  .testimonials__quote p { font-size: 1.25rem; }
}

/* ---------------------------------------------------------------------
   DESIRED STATE SECTION
   Background: proposed --color-vihren (Вихрен's orange) — see
   SDD.md "Design System" note; flagged there as a proposal to confirm,
   not a locked decision.
--------------------------------------------------------------------- */
.desired-state {
  padding: var(--space-5) var(--space-2);
  /* Changed from --color-vihren (orange) to --color-vesta (green) —
     direct request/discussion. Orange + dark text is the color pairing
     used for hazard/warning signage (OSHA caution colors, construction
     warning tape), which reads as "alert" at a pre-conscious level —
     the opposite of what this section is saying ("you can exhale
     now"). Green is the closer semantic match for calm/safe/reassurance,
     and it's already present in this exact section via the checkmark
     ticks below — using it for the background turns what used to be a
     near-complementary (orange vs. green) color clash into one
     coherent palette instead of introducing a second relationship to
     manage. White text (not dark) — checked contrast both ways:
     white reaches 4.02:1 against this green, dark text only 3.69:1 —
     and it matches how the Problem section already handles its own
     similarly mid-dark saturated background (purple + white text). */
  background: var(--color-vesta);
  color: var(--color-surface-white);
}

.desired-state__inner {
  /* Widened from 900px to 940px — the child .desired-state__body was
     being bottlenecked by this parent's max-width (900px < the
     child's own 920px), pulling its real capacity just barely under
     the 75-character target (~75.09, cutting it too close). 940px
     gives .desired-state__body's 920px enough room to actually apply. */
  max-width: 940px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Tightened from --space-4 (40px) to --space-3 (24px) — direct
     request to reduce this section's overall height, "especially the
     list." This alone saves 3 gaps × 16px = 48px before the list
     layout change below adds further savings. Still enough room to
     read as separate blocks, just less airy between them. */
  gap: var(--space-3);
}

.desired-state__heading {
  font-size: var(--font-size-h2);
  font-weight: 400; /* Dela Gothic One has one real weight */
  text-align: center;
}

.desired-state__body {
  /* Fixed px, not `ch` — same reasoning/measurement approach as
     .teaches__body above (75ch under-measured to ~73 characters of
     real capacity; this value was verified via canvas text
     measurement against the actual rendered font/size). */
  max-width: 920px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--font-size-body);
  line-height: 1.6;
  /* Left-aligned — same reasoning as .problem__body/.teaches__body
     (see .problem__body's comment for the full rationale). Block still
     centers on the page via `margin: 0 auto`; only the text itself is
     left-aligned. Heading above stays centered — short display text
     doesn't carry the same readability cost as multi-sentence prose. */
  text-align: left;
}

/* Checkmark bullet list. Each item still reveals individually (not as
   one block) via a per-item transition-delay stagger on top of the
   shared .reveal mechanism, so items cascade in rather than popping
   together — unaffected by the layout change below, grid auto-flow
   fills left-to-right/top-to-bottom in the same 1-2-3-4 order the
   stagger delays already assume.
   Mobile/tablet-portrait: single column, tightened gap (—space-3 →
   —space-2) — direct request to reduce height, and this is the one
   change that actually helps on mobile (the grid below only kicks in
   at tablet-landscape+, since 2 columns of wrapped sentence-length
   text has no room to work on a phone). */
.desired-state__list {
  width: 100%;
  max-width: 640px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Tablet-landscape/desktop: 2×2 grid instead of a 4-row stack — cuts
   the list's vertical footprint roughly in half at the breakpoints
   where the section was tallest. Deliberately NOT a card/box grid —
   direct request to keep this as plain tick+text pairs, no borders or
   background boxes per item, so it stays visually identical to the
   single-column version, just arranged in 2 columns instead of 1.
   Widened both the list and its parent .desired-state__inner (900px,
   above) since two columns of full-sentence bullets need more
   horizontal room than the single-column 640px measure did. */
@media (min-width: 1024px), (min-width: 768px) and (orientation: landscape) {
  .desired-state__list {
    max-width: 820px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: var(--space-5);
    row-gap: var(--space-3);
  }
}

.desired-state__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  text-align: left;
}
.desired-state__item:nth-child(1) { transition-delay: 0s; }
.desired-state__item:nth-child(2) { transition-delay: 0.12s; }
.desired-state__item:nth-child(3) { transition-delay: 0.24s; }
.desired-state__item:nth-child(4) { transition-delay: 0.36s; }
@media (prefers-reduced-motion: reduce) {
  .desired-state__item { transition-delay: 0s; }
}

.desired-state__tick {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  /* Inverted from the old green-circle-on-orange (green bg, white
     check) to white-circle-on-green (white bg, green check) — the
     section background is now --color-vesta too (see .desired-state
     above), so the old scheme would have made these circles
     invisible, blending straight into the background they used to
     stand out against. */
  background: var(--color-surface-white);
  color: var(--color-vesta);
  margin-top: 0.15em; /* optical alignment with the first text line */
}
.desired-state__tick svg { width: 1.1rem; height: 1.1rem; }

.desired-state__item p {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 700; /* prominent, per feedback — bullets are the payoff
    of the section, not fine print */
  font-size: 1.15rem;
  line-height: 1.5;
  /* White, not --color-text-dark — matches the rest of the section
     now that the background is green (see .desired-state above);
     dark text here would read at a noticeably lower contrast (~3.7:1
     vs. white's ~4.0:1) and would look inconsistent against the
     already-white heading/body text above it. */
  color: var(--color-surface-white);
}

.desired-state__cta {
  display: flex;
  justify-content: center;
  width: 100%;
}

/* ---------------------------------------------------------------------
   FAQ SECTION
   Background: white (--color-surface-white). Phase 4.6: the section
   immediately before this one changed from Desired State (orange) to
   Testimonials (already white) once Desired State moved earlier in
   the page — see that section's own comments — so this is now white
   directly following white, not continuing a strict alternation.
   Left as-is; flagged in SDD.md as a side-effect of the reorder
   rather than something silently patched here.
--------------------------------------------------------------------- */
.faq {
  padding: var(--space-5) var(--space-2);
  /* Bottom padding gets extra room beyond the shared var(--space-5) —
     the Wait-list Signup section's top-left clouds now intentionally
     bleed up into this section (see that section's own comments), and
     the cloud's resolved height can exceed the standard --space-5
     (64px) padding at wider viewports. This extra margin is what the
     bleed actually has room to happen in without reaching the last
     FAQ answer's text — verified against actual bounding-box overlap
     measurements at 768/900/1200/1440px, not just eyeballed. */
  padding-bottom: 140px;
  background: var(--color-surface-white);
  color: var(--color-text-dark);
}

.faq__inner {
  max-width: 760px;
  margin: 0 auto;
}

.faq__heading {
  font-size: var(--font-size-h2);
  font-weight: 400; /* Dela Gothic One has one real weight */
  text-align: center;
  margin-bottom: var(--space-4);
}

.faq__list {
  display: flex;
  flex-direction: column;
}

.faq__item {
  border-bottom: 1px solid rgba(30, 36, 51, 0.14);
}
.faq__item:first-child { border-top: 1px solid rgba(30, 36, 51, 0.14); }

.faq__question-heading { margin: 0; font-size: 1em; font-weight: 400; }

.faq__question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) 0.25rem;
  background: none;
  border: none;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 1.05rem;
  text-align: left;
  color: var(--color-text-dark);
  cursor: pointer;
}
.faq__question:hover .faq__question-text { color: var(--color-zaki); }
/* Reuses --color-zaki, the same purple already used for the sitewide
   focus outline (see :focus-visible near the top of this file) — the
   established "interactive accent" color, rather than introducing a
   new one just for this section. */
.faq__question:focus-visible { outline: 3px solid var(--color-zaki); outline-offset: 2px; }

.faq__icon {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-zaki);
}
.faq__icon svg {
  width: 100%;
  height: 100%;
  transition: transform 0.25s ease;
}
.faq__item.is-open .faq__icon svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .faq__icon svg { transition: none; }
}

/* Expand/collapse via animatable grid-template-rows (0fr collapsed,
   1fr open) rather than a JS-measured max-height: no scrollHeight
   calculation needed, and it naturally handles answers of any length
   (including the long, list-containing answer #2) without a fixed cap.
   The child (.faq__answer-inner) needs its own `overflow: hidden` for
   the 0fr state to actually clip it — grid items default to
   min-height: auto (content-based), so without that the item would
   refuse to shrink below its content size even inside a 0fr track. This
   is a different mechanism than the flex `min-height: 0` issue
   documented elsewhere in this file (that one's about flex children on
   a MAIN axis; this is a grid ROW track + `overflow: hidden`), but
   checked deliberately given how many times that class of bug has
   already shown up in this project. */
.faq__answer {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.35s ease;
}
.faq__item.is-open .faq__answer { grid-template-rows: 1fr; }
@media (prefers-reduced-motion: reduce) {
  .faq__answer { transition: none; }
}

.faq__answer-inner {
  overflow: hidden;
}

.faq__answer-inner p,
.faq__answer-inner ul {
  margin: 0 0 var(--space-2);
  line-height: 1.6;
  color: var(--color-text-dark);
}
.faq__answer-inner p:last-child,
.faq__answer-inner ul:last-child { margin-bottom: 0; }
.faq__answer-inner p:first-child { padding-top: 0.1rem; } /* small optical gap under the question when first opened */

.faq__answer-list {
  padding-left: 1.3rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.faq__answer-list li { list-style: disc; }

/* ---------------------------------------------------------------------
   WAIT-LIST SIGNUP SECTION
   Background: --color-neda (Неда's yellow) — continues the alternation
   after FAQ's white. `position: relative` + `overflow: hidden` here
   (same pattern as .hero) so the cloud artwork below can bleed past
   the section edges without creating a horizontal scrollbar.
--------------------------------------------------------------------- */
.waitlist-signup {
  position: relative;
  /* No `overflow: hidden` here (deliberately removed) — the clouds
     below are now allowed to bleed upward into the FAQ section above
     rather than being clipped at this section's own top edge (direct
     request: "lay clouds over the previous section too, and not cut
     them"). Horizontal overflow is still safe without a local rule
     here: `body` already sets `overflow-x: hidden` globally, which
     covers the modest left/right bleed these clouds use. */
  /* Padding bumped back up a bit from the previous pass — that pass
     went further than intended (too short), per direct follow-up.
     This also intentionally leaves the bottom noticeably roomier than
     the top: that's reserved space for a future footer row (social
     links / policy links), not padding to be trimmed later — don't
     shrink padding-bottom without checking whether that content has
     landed yet. */
  padding: var(--space-4) var(--space-2) var(--space-6);
  background: var(--color-neda);
  color: var(--color-text-dark);
}

.waitlist-signup__inner {
  position: relative; /* sits above .waitlist-signup__clouds (z-index 0) —
    same stacking pattern as .hero__content / .hero__clouds; verified via
    computed z-index (not just assumed) that this correctly keeps the
    form above the clouds at every breakpoint tested. See the
    max-height media query near the cloud definitions below for the
    separate, genuinely limited-space concern (how much of the cloud
    is visible, not which one paints on top). */
  z-index: 1;
  max-width: 480px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-align: center;
}

/* White + forced single-line per direct request — the section's own
   dark-text default (used elsewhere on light/pale sections) read weak
   at H2 size against this saturated a yellow, and the heading wrapping
   to two lines looked cramped against the short form beneath it.
   `clamp()` here (rather than reusing --font-size-h2 as-is) leaves
   enough room to shrink on narrow phones so "Записването е отворено"
   fits on one line without the wrapping min-width fighting it — check
   this doesn't need a further shrink on very narrow (<340px) devices. */
.waitlist-signup__heading {
  font-size: clamp(1.35rem, 6vw, 2.5rem);
  font-weight: 400; /* Dela Gothic One has one real weight */
  color: var(--color-surface-white);
  white-space: nowrap;
}

/* Phase 4.5 (revised): two tight chips ("Ексклузивен достъп" /
   "Специална цена") instead of one long pill wrapping a full
   sentence — each chip now fits its short phrase snugly, which reads
   much more like a real badge/label than a chip stretched around an
   entire sentence did. White background + --color-zaki text (rather
   than e.g. white text on a solid zaki fill) so it reads as a light,
   secondary label sitting on top of the section, not a second
   call-to-action competing with the button below it. */
/* Redesigned per an earlier direct request: each clause is now ONE
   pill (not a small chip plus bare text beside it) — the connector
   text moves inside the same rounded, colored box as the highlighted
   phrase, highlighted phrase bold via the <strong> in the markup.
   Colors flipped back to white background + --color-zaki text (see
   .waitlist-signup__badge-line below for the current values and the
   reasoning for this latest change) — closer to this pill's original
   Phase 4.5 treatment than the solid-purple version that briefly
   replaced it.
   Layout: `.waitlist-signup__badge-wrap` is a flex container in BOTH
   directions — column (stacked, centered) on mobile/portrait-tablet,
   row (side by side, centered) at the row-layout breakpoint — rather
   than the earlier inline-text-plus-nowrap approach. This is simpler
   and more robust: switching `flex-direction` handles "stack vs. one
   line" directly, so there's no need for the fragile `display: inline`
   / `white-space: nowrap` combination the previous version relied on
   to fake single-line behavior out of plain text flow. `justify-
   content: center` + `align-items: center` center the pills as a
   group at both breakpoints — direct request, replacing the earlier
   left-aligned mobile treatment. */
.waitlist-signup__badge-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-size: var(--font-size-small);
  font-weight: 600;
}
.waitlist-signup__badge-line {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.45rem 1rem;
  border-radius: var(--radius-input);
  /* Flipped per direct request: white background, purple text — was
     solid --color-zaki background + white text. Keeps the submit
     button below as the one saturated-purple element in this section
     (see .waitlist-form--on-neda .waitlist-form__button) rather than
     flipping that too — these two pills are informational/decorative,
     the button is the actual call to action, so keeping it visually
     distinct (still solid purple) rather than matching these now-white
     pills preserves a clear "which thing do I click" hierarchy. Flag
     if the button was meant to flip too. */
  background: var(--color-surface-white);
  color: var(--color-zaki);
  line-height: 1.3;
  text-align: center;
}
.waitlist-signup__badge-line strong { font-weight: 800; }

/* Row-layout breakpoint: the two pills sit side by side on one line
   instead of stacked. `flex-wrap: nowrap` is what actually guarantees
   that — their combined natural width (~500–580px, now that each pill
   carries its own padding) exceeds `.waitlist-signup__inner`'s own
   480px max-width, same situation as before, but this time handled by
   flexbox's own wrap control rather than `white-space: nowrap` on
   plain text. This element has no `overflow` rule (nor does its
   parent), so the row is allowed to render wider than the 480px column
   around it rather than being clipped or squeezed — the heading and
   form below stay at their existing 480px-constrained width; only
   this row intentionally spans wider. `flex-shrink: 0` on the pills
   keeps them from being compressed instead of simply overflowing. */
@media (min-width: 1024px), (min-width: 768px) and (orientation: landscape) {
  .waitlist-signup__badge-wrap {
    flex-direction: row;
    flex-wrap: nowrap;
  }
  .waitlist-signup__badge-line {
    flex-shrink: 0;
  }
}

/* .waitlist-form carries its own margin-top (see shared rule above),
   sized for the hero's plain-block layout where it's the only thing
   separating the form from the subtitle above it. Here it's a flex
   child of .waitlist-signup__inner, which already spaces every child
   via `gap` — the form's own margin-top was stacking on top of that
   gap and adding a redundant ~16px. Zeroed out so spacing between the
   heading and form matches the section's single gap value. */
.waitlist-signup__inner .waitlist-form { margin-top: 0; }

/* ---------------------------------------------------------------------
   WAIT-LIST SIGNUP — CLOUDS
   Reuses the hero's four cloud PNGs (not new artwork) as two
   overlapping pairs: --wl-1/--wl-2 stacked top-left, --wl-3/--wl-4
   stacked bottom-right. Each pair uses a different --cloud-distance so
   the two layers drift at different rates on scroll — the classic
   parallax depth cue (the "nearer" cloud in front moves more than the
   "farther" one behind it), same var-driven transform mechanism as
   .cloud in the hero section, just with this section's OWN
   --scroll-progress (see initWaitlistClouds() in script.js — this
   section isn't pinned to the top of the page like the hero, so its
   progress has to come from the section's own position, not
   window.scrollY directly). Reuses the base `.cloud` class as-is
   (generic position/background/transform rules) — only per-instance
   placement and parallax speed are new here. */
.waitlist-signup__clouds {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* No --scroll-progress default here, same reasoning as
     .hero__clouds: must inherit the live value set on the parent
     .waitlist-signup by JS, not shadow it with a locally-declared
     fallback. */
}

/* --top and --bottom are now two SEPARATE containers (same box, same
   `inset: 0`) rather than one shared one, specifically so they can
   have opposite `overflow` behavior:
   --top holds the top-left pair, which is meant to bleed upward over
   the FAQ section above — stays unclipped.
   --bottom holds the bottom-right pair. Left unclipped (as it briefly
   was), it had nothing below it to bleed into — this is the last
   section on the page — so the hidden portion just extended the
   page's actual scrollable height into blank space past the visible
   content, which read as an empty "second scrollbar" at the very end
   of the page. Clipped here at the section's own edge to fix that;
   the y-offset percentages on --wl-3/--wl-4 already guarantee ≥50% of
   each cloud stays visible above this clip line regardless of the
   cloud's resolved size, so clipping doesn't undo that requirement. */
.waitlist-signup__clouds--top {
  overflow: visible;
}
.waitlist-signup__clouds--bottom {
  overflow: hidden;
}

/* Sizes bumped up (~1.4×) from the first pass per direct request — CSS
   alone can display these bigger with the current image files, no new
   assets required to see this change. Whether they stay crisp at this
   larger size depends on the PNGs' own native pixel dimensions, which
   this project (no cloud assets in this file set) can't check — these
   are `background-size: contain` boxes, so the browser will happily
   upscale a low-res source and it'll look soft. Rule of thumb: for a
   sharp render at up to ~460px CSS width on a retina (2x) screen, the
   source PNG should be at least ~920px wide natively. If the current
   files were exported around the old, smaller sizes (e.g. ~400–500px
   wide, as a rough guess), it's worth re-exporting them larger before
   judging final sharpness here — flagging rather than guaranteeing.

/* Vertical positioning: `top`/`bottom` are just anchor points (0) —
   actual placement comes from `--cloud-y-offset`, read by the shared
   `.cloud` transform (see above).

   TOP-LEFT PAIR (--wl-1/--wl-2): still uses the `calc(-100% + Npx)`
   trick from the previous pass — shows a fixed ~28–36px sliver inside
   THIS section regardless of the cloud's resolved size, which is what
   keeps it clear of the heading at every viewport (full reasoning
   below). What changed this round: the section no longer clips
   anything above its own top edge (see `.waitlist-signup` /
   `.waitlist-signup__clouds`, both lost their `overflow: hidden`), so
   the rest of each cloud — previously just cut off — now bleeds
   upward and renders over the FAQ section above. That's what actually
   fixes "barely visible": most of each cloud was always being thrown
   away by clipping, not because the clouds were too small.

   BOTTOM-RIGHT PAIR (--wl-3/--wl-4): switched to a plain percentage
   (`translateY(40%)`) instead of the px-mixed calc(). Per direct
   request these need to be "at least 50% visible" — a proportion of
   the cloud's own height, not a fixed pixel sliver — so a plain
   percentage is the more direct match: shifting down by 40% of its
   own height leaves the top 60% visible inside the section, at any
   resolved size. This section is the last one on the page, so unlike
   the top pair there's no next section to bleed into; the hidden 40%
   just extends past the page's bottom edge, which is harmless (no
   scrollbar — see the `body { overflow-x: hidden }` / page-height
   note above `.waitlist-signup`).

   Why the top pair keeps the old fixed-px approach instead of also
   switching to a plain percentage: it still has to clear the heading
   INSIDE this section, and that clearance is a fixed pixel budget
   (the section's own top padding), not a proportion of the cloud —
   this is the one placement that actually needs the calc() trick;
   the bottom pair never had that constraint. */
.cloud--wl-1 {
  background-image: url('assets/clouds/cloud-3.png');
  /* Max width reined in from an earlier 460px — at that size, this
     cloud's resolved height (up to ~204px) exceeded the FAQ section's
     available bottom padding even after that padding was increased,
     and/or crossed into the FAQ list's actual text column
     horizontally at tablet widths where that column has little side
     margin. 360px keeps height (up to 160px) within budget at every
     tested width — see the FAQ section's own padding-bottom comment. */
  width: clamp(240px, 38vw, 360px);
  aspect-ratio: 2.25 / 1;
  top: 0;
  left: -6%;
  --cloud-dir: -1;
  --cloud-distance: 50px; /* back layer: slower drift */
  --cloud-y-offset: calc(-100% + 42px);
}
.cloud--wl-2 {
  background-image: url('assets/clouds/cloud-1.png');
  width: clamp(200px, 32vw, 300px); /* same reasoning as --wl-1 above, scaled down to match */
  aspect-ratio: 2.84 / 1;
  top: 0;
  left: 2%;
  --cloud-dir: -1;
  --cloud-distance: 120px; /* front layer: faster drift, overlaps --wl-1 */
  --cloud-y-offset: calc(-100% + 48px);
}
.cloud--wl-3 {
  background-image: url('assets/clouds/cloud-4.png');
  width: clamp(320px, 46vw, 560px);
  aspect-ratio: 3.01 / 1;
  bottom: 0;
  right: -6%;
  --cloud-dir: 1;
  --cloud-distance: 55px; /* back layer: slower drift */
  --cloud-y-offset: 40%; /* shows the top 60% of this cloud — comfortably over the "at least 50%" ask */
}
.cloud--wl-4 {
  background-image: url('assets/clouds/cloud-2.png');
  width: clamp(190px, 28vw, 310px);
  aspect-ratio: 2.31 / 1;
  bottom: 0;
  right: 2%;
  --cloud-dir: 1;
  --cloud-distance: 130px; /* front layer: faster drift, overlaps --wl-3 */
  --cloud-y-offset: 35%; /* front layer shows slightly more (65%) than the back one, for depth */
}

/* Mobile: top-left pair removed entirely (direct request), not just
   shrunk. Two reasons this is a `display: none` rather than a smaller
   size like before: (1) at this width the heading is a nowrap single
   line spanning nearly the full section, so ANY visible cloud sliver
   sits close to it regardless of how small; removing it sidesteps
   that risk entirely rather than continuing to fine-tune around it.
   (2) this was flagged as wanted independent of the collision
   question ("remove the top left clouds from this section on mobile
   anyways") — so it's a deliberate simplification for small screens,
   not just a defensive fix.
   Bottom-right pair: sized up and made MORE visible here, not less —
   direct feedback that they were "barely showing" on an actual device
   (confirmed from a real screenshot, not just a placeholder render).
   Both width AND `--cloud-y-offset` are bumped for mobile specifically
   — width alone wasn't the issue by itself, since the resting ~60–65%
   visible portion (fine at tablet/desktop, where the section has more
   surrounding visual weight) read as visually thin against how much
   empty yellow space sits below the button on a tall phone. Bumping
   visible height to ~78–82% here, on top of larger clamp values,
   gives the corner real presence without needing to touch anything
   above the row-layout breakpoint. */
@media (max-width: 767px) {
  .cloud--wl-1,
  .cloud--wl-2 {
    display: none;
  }
  .cloud--wl-3 {
    width: clamp(260px, 62vw, 400px);
    --cloud-y-offset: 22%; /* ~78% visible, up from the base 60% */
  }
  .cloud--wl-4 {
    width: clamp(210px, 52vw, 320px);
    --cloud-y-offset: 18%; /* ~82% visible, up from the base 65% */
  }
}

/* Short/constrained-height viewports (mobile landscape, a shallow
   browser window, etc.) — direct request to keep clouds visually
   clear of the form specifically "when space is limited." Stacking
   order was already correct here before this rule (`.waitlist-signup__
   clouds` sits at z-index: 0, `.waitlist-signup__inner` — which
   contains the form — sits at z-index: 1, exactly the same pattern
   `.hero__clouds` / `.hero__content` already use; verified via
   computed styles, not just assumed), so this isn't a stacking-order
   fix. What DOES change with less vertical room is how much of the
   bottom-right pair's height is visible at once — the same 60–65%
   visible portion that looks fine in a tall section can end up
   reaching much closer to the form when the section itself is
   short. Cutting the visible portion back to ~25% here keeps a
   comfortable gap regardless of stacking order. 500px covers common
   phones in landscape (~375–430px tall) without affecting normal
   portrait mobile, where height is rarely the constraint. */
@media (max-height: 500px) {
  .cloud--wl-3 { --cloud-y-offset: 75%; }
  .cloud--wl-4 { --cloud-y-offset: 72%; }
}

