/* ============================================================
   flow.css — the flow experience layout. Loaded LAST so it wins.
   Self-contained: banner heading (Telegraf), the config-driven heart
   tile hooks, the .ru / deck / gate offset below the copy, the
   stage-takeover state, the sign-up gate, and the cinematic ghost cursor.
   ============================================================ */

/* Brand typeface (same source as hero-heart.css / hero-heart-v4.css) */
@font-face {
  font-family: "Telegraf Variable";
  src: url("https://cdn.prod.website-files.com/641819f2e2165d582c58a59e/68556c3238b43469f0f12921_Telegraf-Variable.ttf") format("truetype");
  font-weight: 200 900; font-style: normal; font-display: swap;
}

/* ---------------- Heading + subheading (banner style) ---------------- */
.hh__title {
  font-family: "Telegraf Variable", Arial, sans-serif;
  font-weight: 700;
  font-size: clamp(26px, 4vw, 46px);
  line-height: 1.22;
  letter-spacing: 0;
  text-transform: uppercase;
  color: #050229;
  margin: 0 0 18px;
  text-wrap: balance;
}
.hh__title em {
  font-style: normal;
  background: #0b0b0b;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.hh__sub {
  font-family: "Telegraf Variable", Arial, sans-serif;
  font-weight: 400;
  font-size: clamp(15px, 1.5vw, 18px);
  line-height: 1.6;
  color: #3b3b4e;
  max-width: 64ch;
  margin: 0;
  text-wrap: pretty;
}
.hh__copy { z-index: 20; max-width: 820px; margin-bottom: clamp(18px, 3vw, 30px); }
.hh__prompt { margin-bottom: clamp(6px, 2vw, 18px); }
/* scoped to .hh so these hero rules never leak onto a decorative heart-mark
   band (home Layouts B/C mount one at #network, outside any .hh) */
.hh .hh__stage { margin-top: clamp(8px, 2vw, 22px); position: relative; }

/* ---------------- Config-driven tile look (heart-config.js) ---------------- */
.hh .hh__stage .hh__tile,
.hh .hh__stage .hh__tile--feat,
.hh .hh__stage .hh__tile--feat .hh__tileInner,
.hh .hh__stage .hh__tile--feat img { border-radius: var(--tile-radius, 50%); }
.hh .hh__stage.no-ring .hh__tile { border: 0; box-shadow: none; }
.hh .hh__stage.no-ring .hh__tile--feat { box-shadow: none; }

/* ---------------- Overlays offset below the copy ----------------
   results-ui.css sets `.ru { position:absolute; inset:0 }`. The deck and
   gate share the same offset region so the deck takes over the SAME stage
   the dashboard occupies. --ru-top is measured live by flow-core.js. */
.hh .ru, .hv-flow .ru {
  top: var(--ru-top, 240px);
  border-top-left-radius: 22px;
  border-top-right-radius: 22px;
}
.ru { transform-origin: 50% 38%; }

/* deck takes over the same stage; hidden until openProfile */
.hh .sd-stage, .hv-flow .sd-stage {
  position: absolute;
  left: 0; right: 0;
  top: var(--ru-top, 240px);
  bottom: 0;
  z-index: 6;
  display: none;
  opacity: 0;
  overflow: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.hh .sd-stage::-webkit-scrollbar, .hv-flow .sd-stage::-webkit-scrollbar { display: none; }
.hh .sd-stage.is-open, .hv-flow .sd-stage.is-open { display: block; }
.hh .sd-stage .sd-root, .hv-flow .sd-stage .sd-root { max-width: 1100px; margin: 0 auto; padding: 4px 16px 24px; }
/* size the deck FOR THE FLOW (compose, don't fork the component): the card must
   read at the SAME full-height proportions as figma/studio-card-chat.html — a
   short card compacts the audience rail and squeezes "Popular Posts" under the
   floating control pill. So we use the component's OWN native card height and
   only trim its large native TOP margin (the card sits below the persistent
   heading). At full height the main column leaves natural slack below Popular
   Posts, so the pill (bottom:-34px) floats over that slack — never over content,
   exactly like the standalone. No card-body padding hack (that just recompacts). */
.hh .sd-stage .deck-wrap, .hv-flow .sd-stage .deck-wrap { margin: 6px auto 86px; }
/* Height floor of 820px: the full audience rail (through "Similar Profiles") plus
   enough main-column slack below "Popular Posts" for the floating pill to clear it
   both need ~820px. Below that the rail clips and the pill covers Popular Posts.
   The card content NEVER compacts (Popular Posts is capped at 190px); extra height
   just becomes bottom slack the pill floats over — matching the standalone. */
.hh .sd-stage .deck, .hv-flow .sd-stage .deck { height: var(--sd-card-h); }

/* warm back-glow — the profile-phase backdrop (replaces the scattered
   creators). A soft pink→gold halo behind the deck card; sits below the
   deck (z-index 6) so it only blooms around the card's edges like a
   backlight. Opacity is driven by flow-core (0 → 1 on openProfile). */
.hh .flow-glow, .hv-flow .flow-glow {
  position: absolute;
  left: 50%;
  top: var(--ru-top, 240px);
  transform: translateX(-50%);
  width: min(1240px, 98vw);
  height: clamp(560px, 78vh, 760px);
  z-index: 5;
  opacity: 0;
  pointer-events: none;
  border-radius: 48px;
  background:
    radial-gradient(72% 64% at 50% 44%,
      rgba(11, 11, 11, 0.20) 0%,
      rgba(245, 150, 128, 0.14) 38%,
      rgba(130, 130, 130, 0.08) 60%,
      transparent 78%);
  filter: blur(48px);
}

/* frosted backdrop behind the sign-up gate. Spans the flow region only (starts
   at --ru-top, BELOW the persistent heading) so the heading stays crisp while
   everything behind the popup — the deck, the glow — blurs uniformly. Sits above
   the deck (z6) / glow (z5) and below the gate panel (z12). flow-core fades it.

   The top edge is a mask fade, not a hard cut: --ru-top is an arbitrary line
   mid-background (not a real section boundary — the heading above it and the
   flow below it share the same backdrop), so blur(11px) + a 46%-white wash
   switching on at a hard line reads as a visible seam across that shared
   background the instant the gate opens. Fading both the wash and the blur
   itself in over the first ~64px makes it read as one continuous frosted
   surface instead of two stacked treatments. */
.hh .flow-scrim, .hv-flow .flow-scrim {
  position: absolute;
  left: 0; right: 0;
  top: var(--ru-top, 240px);
  bottom: 0;
  z-index: 10;
  opacity: 0;
  pointer-events: none;
  background: rgba(255, 255, 255, 0.46);
  -webkit-backdrop-filter: blur(11px) saturate(1.04);
          backdrop-filter: blur(11px) saturate(1.04);
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 64px);
          mask-image: linear-gradient(to bottom, transparent, #000 64px);
}
.hh .flow-scrim.is-open, .hv-flow .flow-scrim.is-open { pointer-events: auto; }

/* gate panel — the film's closing ask. Directed 2026-08-20 to read BIGGER and
   dead-centre on the flow canvas (it used to sit small at bottom:7%).
   Centred with inset-0 + margin:auto rather than a translate, deliberately:
   flow-core animates `y` on this element, and a translate(-50%,-50%) would be
   clobbered the moment GSAP writes its own transform. The frosted scrim blurs
   everything behind it. */
.hh .flow-gate, .hv-flow .flow-gate {
  position: absolute;
  inset: 0;
  margin: auto;
  height: fit-content;
  z-index: 12;
  width: min(560px, 92%);
  opacity: 0;
  pointer-events: none;
  background: #fff;
  border: 1px solid var(--line, #ececec);
  border-radius: 22px;
  padding: 34px 38px;
  text-align: center;
  box-shadow: 0 40px 90px -30px rgba(15, 15, 30, .52);
}
.hh .flow-gate.is-open, .hv-flow .flow-gate.is-open { pointer-events: auto; }
/* type scaled up with the panel (directed 2026-08-20) */
.flow-gate__h { font-family: "Manrope", system-ui, sans-serif; font-weight: 800; font-size: clamp(21px, 2.2vw, 26px); line-height: 1.22; margin: 0 0 10px; color: #0b0b0b; }
.flow-gate__h b { background: linear-gradient(90deg, #ed3d7f, #f3c370); -webkit-background-clip: text; background-clip: text; color: transparent; }
.flow-gate__p { font-size: 15px; color: #535353; margin: 0 0 22px; line-height: 1.55; }
.flow-gate__cta { width: 100%; justify-content: center; padding: 15px 22px; font-size: 15px; border-radius: 12px; }
.flow-gate__dismiss { display: block; width: 100%; margin-top: 14px; font-size: 13px; color: #b6b6bd; text-decoration: underline; background: none; border: 0; cursor: pointer; }
.flow-gate__dismiss:hover { color: #8a8a8f; }
.flow-gate__done { margin: 14px 0 0; font-size: 14px; font-weight: 600; color: #16a34a; }

@media (max-width: 720px) {
  .hh .ru, .hv-flow .ru { border-radius: 0; }
}

/* ---- campaign overview — the closing beat's frame. Staged on the same
   canvas the deck used (it takes over once the deck leaves the scene), and
   deliberately BELOW the frosted scrim (z10) so that when the sign-up gate
   opens over it the overview blurs behind the popup exactly like the deck
   did. Its own look lives in flow/campaign-overview.css; this only places
   it in the flow. ---- */
.hh .campaign-overview, .hv-flow .campaign-overview {
  position: absolute;
  left: 0; right: 0;
  top: var(--ru-top, 240px);
  z-index: 8;
  display: none;
  padding: 0 16px;
  pointer-events: none;
}
.hh .campaign-overview.is-open, .hv-flow .campaign-overview.is-open { display: block; }

/* ============================================================
   Flow canvas sizing — directed 2026-08-20.

   1. ONE FIXED HEIGHT for every phase. The flow region must not grow and
      shrink as the film moves from results -> deck -> campaign overview ->
      gate; a canvas that resizes per phase makes the page jump under the
      visitor. --flow-h is that height, and it supersedes flow-core's
      per-phase fitFlowHeight() measuring.

   2. On a phone the flow gets SMALLER, not LONGER. The studio card and the
      results dashboard never reflow their own composition — see the
      no-reflow lock below — so flow-core.js's fitPhaseToCanvas() /
      fitResultsToCanvas() measure each one's true (always-desktop) size
      and scale it down as a single unit (transform: scale(), both axes, so
      nothing gets squashed) until it fits the fixed canvas, both by height
      and by width. A narrow viewport shows the same composition smaller,
      never restacked. The campaign overview needs no such scale — its
      frame already fits the design to whatever width it is given, and only
      its window gets shorter (campaign-overview.css).
   ============================================================ */
.hh, .hv-flow {
  --flow-h: clamp(560px, 88vh, 960px);
  /* the studio card's one true height (desktop AND mobile — see the
     ".deck" rule below). Mobile reuses it as the card's WIDTH too, so the
     card is exactly square there instead of the desktop card's landscape
     shape (directed 2026-09-03: square on mobile, unchanged on desktop). */
  --sd-card-h: clamp(820px, 94vh, 880px);
}

@media (max-width: 720px) {
  /* the gate is the one thing that must NOT shrink — it is the ask */
  .hh .flow-gate, .hv-flow .flow-gate { padding: 26px 22px; border-radius: 18px; }
}

/* ============================================================
   No-reflow lock — directed 2026-09-01.

   studio-deck.css and results-ui.css each carry their own narrow-width
   @media rules that RESTACK their layout (grid-template-columns: 1fr,
   flex-direction: column, …). That's correct for those components used
   elsewhere on their own (e.g. flow-blocks.js's small preview card), but
   inside the cinematic flow it fights fitPhaseToCanvas()/
   fitResultsToCanvas(): the browser reflows the card into a tall single
   column FIRST (a real viewport media query, unaffected by anything on
   this page), and only THEN does flow-core measure and scale that already-
   wrong layout — the studio card ends up both stacked AND shrunk.

   Both files are shared parts (compose, don't fork — see COMPONENTS.md /
   the flow-core.js header), so their breakpoints are neutralized HERE,
   scoped to the flow only, instead of edited there. These rules are
   unconditional (no media query of their own): the desktop composition
   always wins inside the flow, at every viewport, and flow-core.js's JS
   measurement is what makes it fit — never CSS reflow. Higher specificity
   (.hh/.hv-flow ancestor) is what makes them win over the shared files'
   own @media rules regardless of source order. */

/* ---- the studio card (studio-deck.css's @media 880px / 520px) ---- */
.hh .sd-stage .deck-wrap, .hv-flow .sd-stage .deck-wrap {
  /* was width:100% (studio-deck.css) — fixed so it always measures at its
     one true design size; the flow scales the whole box down from there.
     position:absolute (was relative, in normal flow): a transform: scale()
     shrinks paint, never the layout box it shrinks, so a still-in-flow
     deck-wrap kept asking .sd-stage's own scrollable-overflow for room at
     its FULL unscaled size regardless of how small it then painted —
     .sd-stage is overflow:auto (scrollbar hidden by design, but still a
     real scroll, which this flow must never have). Absolute removes it
     from flow sizing entirely, same fix as .ru__grid below. */
  position: absolute;
  top: 0;
  left: 50%;
  width: 1040px;
  max-width: none;
  margin-left: -520px;   /* half of 1040 — centers regardless of overflow */
}
.hh .sd-stage .card, .hv-flow .sd-stage .card { position: absolute; inset: 0; transform-origin: 50% 0; }
.hh .sd-stage .card__body, .hv-flow .sd-stage .card__body { grid-template-columns: 270px 1fr; gap: 0; }
.hh .sd-stage .aud, .hv-flow .sd-stage .aud { overflow: hidden; padding-right: 14px; border-bottom: 0; padding-bottom: 0; }
.hh .sd-stage .grid, .hv-flow .sd-stage .grid { grid-template-columns: repeat(4, 1fr); grid-template-rows: 1fr; height: auto; }
.hh .sd-stage .collabs .grid, .hv-flow .sd-stage .collabs .grid { height: 108px; }
.hh .sd-stage .deliver, .hv-flow .sd-stage .deliver { display: block; }
.hh .sd-stage .head, .hv-flow .sd-stage .head { flex-direction: row; align-items: flex-start; }
.hh .sd-stage .head__id, .hv-flow .sd-stage .head__id {
  width: 130px; flex-direction: column;
  border-right: 1px solid #ededf0; border-bottom: 0;
  padding-right: 16px; padding-bottom: 0;
}
.hh .sd-stage .head__ava, .hv-flow .sd-stage .head__ava { width: 118px; height: 152px; }
.hh .sd-stage .head__name, .hv-flow .sd-stage .head__name,
.hh .sd-stage .head__handle, .hv-flow .sd-stage .head__handle { text-align: center; }
.hh .sd-stage .head__right, .hv-flow .sd-stage .head__right { padding-left: 16px; padding-top: 0; }
.hh .sd-stage .head__btm, .hv-flow .sd-stage .head__btm,
.hh .sd-stage .info, .hv-flow .sd-stage .info { grid-template-columns: 1fr 1fr; }
.hh .sd-stage .stats, .hv-flow .sd-stage .stats { border-right: 1px solid #ededf0; }
.hh .sd-stage .actions, .hv-flow .sd-stage .actions { gap: clamp(8px, 1.4vw, 18px); padding: 15px 22px 13px; }
.hh .sd-stage .act__l, .hv-flow .sd-stage .act__l { display: block; }

/* ---- the results dashboard (results-ui.css's @media 1080px / 520px) ---- */
.hh .ru .ru__inner, .hv-flow .ru .ru__inner {
  /* .ru__grid below moves to position:absolute so its unscaled (natural,
     desktop-sized) layout box never asks .ru__inner's flex algorithm for
     room — a transform: scale() shrinks paint, never the layout box it
     shrinks, so a still-flex .ru__grid would keep stretching .ru__inner
     (and .ru, which is overflow-y:auto) tall enough for its FULL natural
     size regardless of how small it then paints. min-height:100% (against
     the SAME still-flex child) is what let that happen before. */
  position: relative;
  min-height: 0;
  height: 100%;
}
.hh .ru .ru__grid, .hv-flow .ru .ru__grid {
  /* was width:min(1360px,100%) — fixed to its one true design size, same
     reason as .deck-wrap above; flow-core scales the whole box down from
     there. position:absolute (was a flex item) — see .ru__inner above. */
  position: absolute;
  top: 16px;
  left: 50%;
  width: 1360px;
  max-width: none;
  margin-left: -680px;   /* half of 1360 */
  grid-template-columns: 360px minmax(0, 1fr) 360px;
}
.hh .ru .ru__cover, .hv-flow .ru .ru__cover { grid-template-columns: 1fr 1fr; }
.hh .ru .ru__cover .ru__coverCol, .hv-flow .ru .ru__cover .ru__coverCol { display: block; }

/* ---- phone-width design tier — SAME shape, narrower canvas -----------
   The no-reflow lock above pins both to their literal desktop pixel widths
   (1040 / 1360), which is the correct fixed point to scale from — but on a
   ~390px phone that is a ~0.29-0.38x squeeze either way, small enough to
   read as "too small" rather than "the same UI, smaller" (flagged
   2026-09-01). Neither box's own composition changed to get here (still
   two side rails flanking a center column, never 1fr/stacked) — only the
   rails themselves are narrower, closer to what a phone-sized version of
   this same design would actually use, so flow-core.js's JS fit lands on a
   visibly bigger, still fully-visible, still non-reflowed result: roughly
   390/760 (~0.51) for the deck and 390/820 (~0.48) for the dashboard,
   against ~0.375 / ~0.287 at the old desktop-literal widths. */
@media (max-width: 760px) {
  .hh .sd-stage .deck-wrap, .hv-flow .sd-stage .deck-wrap {
    /* square on mobile: width == the card's own height (--sd-card-h),
       instead of the fixed 760px landscape-leaning width. flow-core.js's
       fitBoxToCanvas() already scales uniformly by min(widthFit, heightFit),
       so a wider natural box never overflows — it just settles a touch
       smaller if the viewport is tight. */
    width: var(--sd-card-h);
    margin-left: calc(var(--sd-card-h) / -2);
  }
  .hh .sd-stage .card__body, .hv-flow .sd-stage .card__body { grid-template-columns: 200px 1fr; }
  .hh .sd-stage .head__id, .hv-flow .sd-stage .head__id { width: 96px; padding-right: 10px; }
  .hh .sd-stage .head__ava, .hv-flow .sd-stage .head__ava { width: 84px; height: 108px; }
  .hh .sd-stage .head__right, .hv-flow .sd-stage .head__right { padding-left: 10px; }

  .hh .ru .ru__grid, .hv-flow .ru .ru__grid {
    width: 820px;
    margin-left: -410px;
    grid-template-columns: 210px minmax(0, 1fr) 210px;
  }
}

/* ---- the Collaborate tap (flow/flow-core.js collaborate()). studio-deck's
   .btn-campaign is a <span>, so there is no native pressed state to lean on;
   the press depth comes in as --tap-scale from the config. Scoped to the flow
   so a deck mounted anywhere else is untouched. ---- */
.hh .sd-root .btn-campaign, .hv-flow .sd-root .btn-campaign {
  transition: transform var(--tap-ease, .16s) ease, box-shadow var(--tap-ease, .16s) ease;
}
.hh .sd-root .btn-campaign.is-tapped, .hv-flow .sd-root .btn-campaign.is-tapped {
  transform: scale(var(--tap-scale, .94));
  box-shadow: 0 4px 10px -6px rgba(11, 11, 11, .6);
}

/* the ring that leaves the pill when it is tapped — the visible cause for the
   scene change that follows (R-03). Size/colour/duration come from config. */
.flow-ripple {
  position: absolute;
  width: 0; height: 0;
  border-radius: 999px;
  border: 2px solid var(--flow-ripple-color, rgba(237, 61, 127, .55));
  pointer-events: none;
  z-index: 14;
}

@media (prefers-reduced-motion: reduce) {
  .hh .sd-root .btn-campaign, .hv-flow .sd-root .btn-campaign { transition: none; }
  .flow-ripple { display: none; }
}

/* ============================================================
   film.interactive:false — the flow is an animation, not a widget.
   Directed 2026-09-02. Every surface the film draws into stops taking
   pointer input; the hero's own copy CTAs ("Try it free" / "Talk to us")
   sit outside these hooks and stay fully operable.
   Focusability is handled in flow-core.js / studio-deck.js (tabindex -1 +
   aria-hidden), because pointer-events alone still leaves a tab stop.
   ============================================================ */
.flow-noninteractive [data-promptcard],
.flow-noninteractive [data-results],
.flow-noninteractive [data-deck],
.flow-noninteractive [data-gate] { pointer-events: none; }
.flow-noninteractive [data-input] { cursor: default; user-select: none; }
/* the idle marquees are ambient, not a hover target */
.flow-noninteractive .marquee:hover .marquee__track { animation-play-state: running; }

/* ============================================================
   film.interactive:false — the flow region is an animation, not a widget.
   Scoped to the flow's own surfaces so the hero's real CTA links beside the
   film ("Try it free" / "Talk to us") keep working. The elements stay in the
   DOM because the film animates them; they just stop being targets.
   ============================================================ */
.flow-noninteractive [data-promptcard],
.flow-noninteractive [data-results],
.flow-noninteractive [data-deck],
.flow-noninteractive [data-gate] { pointer-events: none; }
.flow-noninteractive [data-input] { cursor: default; caret-color: transparent; }
.flow-noninteractive [data-submit] { cursor: default; }
/* no hover tell on things that cannot be operated */
.flow-noninteractive .flow-rcard { cursor: default; }
.flow-noninteractive .flow-rcard:hover { transform: none; box-shadow: none; }
/* the idle marquees are ambient motion, not a scrubber */
.flow-noninteractive .marquee:hover .marquee__track { animation-play-state: running; }
