/* Dealy flowline · the horizontal scroll chapter on the Dealy product page.
   Surface is near-black so the accents can actually glow (the two reference
   frames: the green gate on black, and the coloured streams becoming a data
   field on deep blue). Colour grammar is load bearing, not decorative:
     slate      unsolved. Problems arrive with no colour; colour is what Dealy adds.
     teal       incoming context
     periwinkle Dealy-led action
     green      verified completion. One green EDGE in the scene (order → paid);
                everything green after that is downstream of that moment.
   Tokens are declared on the section so this file never depends on
   blueprint.css, which the product pages do not load.                        */

.dealy-flowmap {
  --fm-black: #05080f;
  --fm-panel: rgba(13, 22, 40, .72);
  --fm-slate: #64748b;
  --fm-slate-dim: rgba(148, 163, 184, .30);
  --fm-teal: #2ee8d0;
  --fm-peri: #8b93ff;
  --fm-green: #3ce08c;
  --fm-ink: #f2f6ff;
  --fm-ink-2: rgba(228, 236, 255, .72);
  --fm-ink-3: rgba(228, 236, 255, .45);
  --fm-line: rgba(139, 147, 255, .18);
  --fm-sans: "Inter", Arial, Helvetica, sans-serif;
  --fm-display: "Inter Tight", "Inter", Arial, Helvetica, sans-serif;
  --fm-mono: "IBM Plex Mono", monospace;

  position: relative;
  background: var(--fm-black);
  color: var(--fm-ink);
  isolation: isolate;
}

/* Depth: two soft washes plus a faint survey grid, like the reference frames.
   The grid must stay barely-there — it is texture, not a table.              */
.dealy-flowmap::before {
  position: absolute;
  z-index: 0;
  inset: 0;
  background:
    radial-gradient(110% 70% at 15% 0%, rgba(46, 232, 208, .07), transparent 58%),
    radial-gradient(90% 70% at 85% 100%, rgba(139, 147, 255, .10), transparent 62%),
    linear-gradient(rgba(139, 147, 255, .038) 1px, transparent 1px),
    linear-gradient(90deg, rgba(139, 147, 255, .038) 1px, transparent 1px);
  background-size: auto, auto, 96px 96px, 96px 96px;
  content: "";
  pointer-events: none;
}

.fm-intro {
  position: relative;
  z-index: 2;
  padding: clamp(72px, 8vw, 120px) 0 clamp(28px, 3vw, 44px);
}
.fm-intro .pp-kicker { color: var(--fm-teal); }
.fm-intro h2 { color: var(--fm-ink); font-family: var(--fm-display); }
.fm-intro .fm-lead { max-width: 52ch; margin: 14px 0 0; color: var(--fm-ink-2); font-size: clamp(15px, 1.4vw, 18px); line-height: 1.55; }

/* ── The pinned viewport and the track that slides inside it ─────────────── */
.fm-viewport { position: relative; z-index: 2; overflow: hidden; }

/* The glitter layer rides ABOVE the track, so its glow is never clipped by a
   forming card's own pixel mask. Screen blend makes every dot additive light. */
.fm-glitter {
  position: absolute;
  inset: 0;
  z-index: 4;
  width: 100%;
  height: 100%;
  mix-blend-mode: screen;
  pointer-events: none;
}
.fm-track {
  display: flex;
  align-items: center;
  gap: clamp(64px, 7vw, 132px);
  width: max-content;
  padding: 8px clamp(28px, 6vw, 120px) 48px;
  will-change: transform;
}

/* Edges: a quiet base stroke that draws in, then a halo + bright dash pair
   riding the same geometry — the packets that flow with scroll. No SVG
   filters; the halo IS the glow, wide and translucent under a thin hot core. */
.fm-edges { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 1; }
.fm-edges path { fill: none; stroke-linecap: round; }
.fm-edges path.is-pain { stroke: var(--fm-slate-dim); stroke-width: 1.1; }
.fm-edges path.is-flow { stroke: rgba(46, 232, 208, .34); stroke-width: 1.4; }
.fm-edges path.is-action { stroke: rgba(139, 147, 255, .42); stroke-width: 1.5; }
.fm-edges path.is-money { stroke: rgba(60, 224, 140, .60); stroke-width: 2; }
.fm-edges path.is-loop { stroke: rgba(139, 147, 255, .34); stroke-width: 1.3; }
.fm-edges path.fm-halo { stroke-width: 7; opacity: 0; }
.fm-edges path.fm-halo.is-flow { stroke: rgba(63, 240, 216, .55); }
.fm-edges path.fm-halo.is-action, .fm-edges path.fm-halo.is-loop { stroke: rgba(162, 170, 255, .55); }
.fm-edges path.fm-halo.is-money { stroke: rgba(80, 236, 158, .6); }
.fm-edges path.fm-pulse { stroke-width: 2.2; opacity: 0; }
.fm-edges path.fm-pulse.is-flow { stroke: #52f2dd; }
.fm-edges path.fm-pulse.is-action, .fm-edges path.fm-pulse.is-loop { stroke: #aeb5ff; }
.fm-edges path.fm-pulse.is-money { stroke: #5aef9f; }

/* ── Acts ───────────────────────────────────────────────────────────────── */
.fm-act { position: relative; z-index: 2; display: grid; align-content: center; gap: 14px; flex: 0 0 auto; }
.fm-act-label {
  margin: 0 0 6px;
  color: var(--fm-ink-3);
  font: 500 10px/1 var(--fm-mono);
  letter-spacing: .16em;
  text-transform: uppercase;
}

/* Act 1 — unsolved. Deliberately the only colourless things in the scene. */
.fm-pains { display: grid; gap: 10px; width: clamp(250px, 22vw, 310px); }
.fm-pain {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 15px;
  border: 1px solid rgba(148, 163, 184, .16);
  border-radius: 999px;
  background: rgba(148, 163, 184, .055);
  color: rgba(203, 213, 225, .84);
  font-size: 13px;
  line-height: 1.3;
}
.fm-pain::before {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--fm-slate);
  content: "";
}
.fm-more { padding-left: 15px; color: var(--fm-ink-3); font: 500 11px/1 var(--fm-mono); letter-spacing: .08em; }

/* Act 2 — the core. Channels ride above it as a row of streams dropping in,
   and the left border carries the gate: the slit every pain funnels through. */
.fm-channels { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 22px; }
.fm-channel {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid rgba(46, 232, 208, .34);
  border-radius: 999px;
  background: rgba(46, 232, 208, .05);
  color: var(--fm-teal);
  font: 500 11px/1 var(--fm-mono);
  letter-spacing: .06em;
}
.fm-core {
  position: relative;
  width: clamp(268px, 24vw, 340px);
  padding: 26px 26px 24px;
  border: 1px solid rgba(139, 147, 255, .42);
  border-radius: 22px;
  background: linear-gradient(160deg, rgba(139, 147, 255, .13), rgba(46, 232, 208, .05));
  box-shadow: 0 0 70px -26px rgba(139, 147, 255, .55), inset 0 1px 0 rgba(255, 255, 255, .05);
}
/* The gate. Everything grey converges on this slit and comes out coloured. */
.fm-core::after {
  position: absolute;
  top: 26%;
  left: -2px;
  width: 3px;
  height: 48%;
  border-radius: 3px;
  background: linear-gradient(180deg, rgba(46, 232, 208, .1), var(--fm-teal), rgba(46, 232, 208, .1));
  box-shadow: 0 0 16px rgba(46, 232, 208, .65);
  content: "";
}
.fm-core-mark { display: inline-flex; align-items: center; gap: 8px; color: var(--fm-peri); font: 600 10px/1 var(--fm-mono); letter-spacing: .14em; }
.fm-core h3 { margin: 12px 0 0; color: var(--fm-ink); font-family: var(--fm-display); font-size: clamp(24px, 2.3vw, 31px); font-weight: 700; letter-spacing: -.03em; line-height: 1.05; }
.fm-core p { margin: 10px 0 0; color: var(--fm-ink-2); font-size: 13px; line-height: 1.5; }
.fm-core-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.fm-core-chips span { padding: 5px 10px; border: 1px solid var(--fm-line); border-radius: 999px; color: var(--fm-ink-2); font-size: 11px; }
/* The bloom fires once, when the lines land. */
.fm-core-bloom {
  position: absolute;
  z-index: -1;
  inset: -40%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(139, 147, 255, .38), transparent 62%);
  opacity: 0;
  pointer-events: none;
}

/* Act 3 — the transaction. The money card is the only green-lit object here. */
.fm-steps { display: grid; gap: 12px; width: clamp(230px, 20vw, 280px); }
.fm-step {
  padding: 15px 17px;
  border: 1px solid var(--fm-line);
  border-radius: 16px;
  background: var(--fm-panel);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
.fm-step-n { color: var(--fm-ink-3); font: 600 10px/1 var(--fm-mono); letter-spacing: .12em; }
.fm-step h4 { margin: 9px 0 0; color: var(--fm-ink); font-size: 15px; font-weight: 600; letter-spacing: -.02em; }
.fm-step p { margin: 6px 0 0; color: var(--fm-ink-2); font-size: 12px; line-height: 1.45; }
.fm-step--money {
  border-color: rgba(60, 224, 140, .5);
  background: rgba(60, 224, 140, .07);
  box-shadow: 0 0 44px -14px rgba(60, 224, 140, .4), inset 0 1px 0 rgba(255, 255, 255, .05);
}
.fm-step--money .fm-step-n { color: var(--fm-green); }
.fm-step-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; }
.fm-step-tags span { padding: 4px 8px; border: 1px solid rgba(60, 224, 140, .34); border-radius: 6px; color: var(--fm-green); font: 500 10px/1 var(--fm-mono); }

/* Act 4 — the intelligence. The ledger: every event becomes a lit cell.
   Streams hit the dotted membrane, and past it the record simply exists.    */
.fm-datawrap { display: grid; gap: 14px; width: clamp(230px, 20vw, 272px); }
.fm-data {
  padding: 16px 18px;
  border: 1px dashed rgba(46, 232, 208, .42);
  border-radius: 16px;
  background: rgba(46, 232, 208, .05);
}
.fm-data .fm-step-n { color: var(--fm-teal); }
.fm-data h4 { margin: 8px 0 0; color: var(--fm-ink); font-size: 15px; font-weight: 600; }
.fm-data p { margin: 6px 0 0; color: var(--fm-ink-2); font-size: 12px; line-height: 1.45; }
.fm-ledger {
  display: flex;
  gap: 11px;
  align-items: stretch;
  padding: 11px;
  border: 1px solid rgba(46, 232, 208, .16);
  border-radius: 14px;
  background: rgba(8, 14, 26, .6);
}
.fm-membrane {
  flex: none;
  width: 9px;
  border-radius: 5px;
  background-image:
    radial-gradient(circle, rgba(63, 240, 216, .8) 1.1px, transparent 1.5px),
    radial-gradient(circle, rgba(162, 170, 255, .65) 1px, transparent 1.4px);
  background-position: 1px 0, 4px 5px;
  background-size: 6px 10px, 6px 14px;
}
.fm-ledger-grid { display: block; flex: 1; min-width: 0; height: 126px; }

.fm-reports { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; width: clamp(330px, 30vw, 430px); }
.fm-report {
  padding: 13px 15px;
  border: 1px solid var(--fm-line);
  border-radius: 14px;
  background: var(--fm-panel);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
.fm-report:last-child { grid-column: 1 / -1; }
.fm-report b { display: block; color: var(--fm-ink); font-size: 13px; font-weight: 600; letter-spacing: -.01em; }
.fm-report span { display: block; margin-top: 4px; color: var(--fm-ink-3); font-size: 11px; line-height: 1.4; }
.fm-report--ai { border-color: rgba(139, 147, 255, .3); }
.fm-report--ai b::before { color: var(--fm-peri); content: "✦ "; }

/* Act 5 — the loop. The only edge that travels backwards. */
.fm-loop {
  width: clamp(238px, 21vw, 296px);
  padding: 20px 22px;
  border: 1px solid rgba(139, 147, 255, .42);
  border-radius: 18px;
  background: rgba(139, 147, 255, .08);
  box-shadow: 0 0 54px -20px rgba(139, 147, 255, .5), inset 0 1px 0 rgba(255, 255, 255, .05);
}
.fm-loop h4 { margin: 10px 0 0; color: var(--fm-ink); font-family: var(--fm-display); font-size: 20px; font-weight: 700; letter-spacing: -.025em; }
.fm-loop p { margin: 8px 0 0; color: var(--fm-ink-2); font-size: 12.5px; line-height: 1.5; }

/* Act 6 — what the seller is left with. Downstream of the one green moment. */
.fm-outcomes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; width: clamp(300px, 26vw, 380px); }
.fm-outcome {
  padding: 16px 18px;
  border: 1px solid rgba(60, 224, 140, .3);
  border-radius: 16px;
  background: rgba(60, 224, 140, .055);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
.fm-outcome b {
  display: block;
  color: var(--fm-green);
  font-family: var(--fm-display);
  font-size: clamp(22px, 2vw, 28px);
  font-weight: 700;
  letter-spacing: -.03em;
  text-shadow: 0 0 22px rgba(60, 224, 140, .4);
}
.fm-outcome span { display: block; margin-top: 5px; color: var(--fm-ink-2); font-size: 12px; line-height: 1.4; }

/* ── Progress rail ──────────────────────────────────────────────────────── */
.fm-rail { position: relative; z-index: 3; display: flex; align-items: center; gap: 12px; padding: 0 clamp(28px, 6vw, 120px) clamp(56px, 6vw, 88px); }
.fm-rail-track { position: relative; flex: 1; height: 2px; border-radius: 2px; background: var(--fm-line); overflow: hidden; }
.fm-rail-fill {
  position: absolute;
  inset: 0;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--fm-teal), var(--fm-peri));
  box-shadow: 0 0 12px rgba(46, 232, 208, .5);
  transform: scaleX(0);
  transform-origin: 0 50%;
}
.fm-rail-label { color: var(--fm-ink-3); font: 500 10px/1 var(--fm-mono); letter-spacing: .14em; text-transform: uppercase; white-space: nowrap; }

/* Forming state: while a card materializes, it is masked by a grid of dots
   that grow until they merge — the card assembles from pixels, the same
   15px pitch as the ledger cells. JS drives --fmd (dot radius, px) from the
   scroll scrub and removes the class the moment the card is whole, so the
   mask costs nothing at rest. Guarded by .fm-anim: static and reduced-motion
   renders never form, they simply exist.                                     */
.fm-anim .fm-forming {
  -webkit-mask-image: radial-gradient(circle, #000 calc(var(--fmd, 12) * 1px), transparent calc(var(--fmd, 12) * 1px + .6px));
  -webkit-mask-size: 15px 15px;
  -webkit-mask-repeat: repeat;
  mask-image: radial-gradient(circle, #000 calc(var(--fmd, 12) * 1px), transparent calc(var(--fmd, 12) * 1px + .6px));
  mask-size: 15px 15px;
  mask-repeat: repeat;
}

/* Entry state. JS drives these to their resting values. */
.fm-anim .fm-pain,
.fm-anim .fm-channel,
.fm-anim .fm-core,
.fm-anim .fm-step,
.fm-anim .fm-data,
.fm-anim .fm-ledger,
.fm-anim .fm-more,
.fm-anim .fm-report,
.fm-anim .fm-loop,
.fm-anim .fm-outcome { opacity: 0; transform: translateY(18px) scale(.965); }

@media (max-width: 900px) {
  .fm-reports, .fm-outcomes { grid-template-columns: minmax(0, 1fr); }
}

/* On touch screens this stays a flowline. The shared scroll rig pins this
   compact viewport and advances the track horizontally as the page scrolls. */
@media (max-width: 760px) {
  .fm-viewport {
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 20px;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .fm-viewport::-webkit-scrollbar { display: none; }
  .fm-viewport::after {
    position: absolute;
    z-index: 5;
    top: 0;
    right: 0;
    bottom: 0;
    width: 28px;
    background: linear-gradient(90deg, transparent, var(--fm-black));
    content: "";
    pointer-events: none;
  }
  .fm-track {
    width: max-content;
    min-width: 100%;
    flex-direction: row;
    align-items: stretch;
    gap: 20px;
    padding: 8px 20px 28px;
  }
  .fm-act {
    flex: 0 0 min(82vw, 332px);
    width: min(82vw, 332px);
    min-height: 470px;
    scroll-snap-align: start;
    scroll-snap-stop: always;
  }
  .fm-act[data-act="reports"] { flex-basis: min(88vw, 350px); width: min(88vw, 350px); }
  .fm-pains, .fm-core, .fm-steps, .fm-datawrap, .fm-reports, .fm-loop, .fm-outcomes { width: 100%; }
  .fm-core::after { display: none; }
  .fm-edges { display: none; }
  .fm-glitter { display: none; }
  .fm-rail { padding: 0 20px 48px; }
  .fm-rail-label { font-size: 9px; letter-spacing: .1em; }
  .fm-anim .fm-viewport {
    overflow: hidden;
    overscroll-behavior: auto;
    scroll-snap-type: none;
    touch-action: pan-y;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fm-anim .fm-pain,
  .fm-anim .fm-channel,
  .fm-anim .fm-core,
  .fm-anim .fm-step,
  .fm-anim .fm-data,
  .fm-anim .fm-ledger,
  .fm-anim .fm-more,
  .fm-anim .fm-report,
  .fm-anim .fm-loop,
  .fm-anim .fm-outcome { opacity: 1 !important; transform: none !important; }
  .fm-anim .fm-forming { -webkit-mask-image: none !important; mask-image: none !important; }
  .fm-anim .fm-track :is(.fm-pain, .fm-channel, .fm-core, .fm-step, .fm-data, .fm-ledger, .fm-report, .fm-loop, .fm-outcome) > * { opacity: 1 !important; transform: none !important; filter: none !important; }
  .fm-core-bloom { opacity: .55 !important; }
  .fm-edges path { stroke-dashoffset: 0 !important; }
  .fm-edges path.fm-halo, .fm-edges path.fm-pulse { display: none; }
  .fm-glitter { display: none; }
}

/* ?static renders the finished diagram, same contract as the rest of the site. */
html.static-mode .fm-anim .fm-pain,
html.static-mode .fm-anim .fm-channel,
html.static-mode .fm-anim .fm-core,
html.static-mode .fm-anim .fm-step,
html.static-mode .fm-anim .fm-data,
html.static-mode .fm-anim .fm-ledger,
html.static-mode .fm-anim .fm-more,
html.static-mode .fm-anim .fm-report,
html.static-mode .fm-anim .fm-loop,
html.static-mode .fm-anim .fm-outcome { opacity: 1 !important; transform: none !important; }
html.static-mode .fm-anim .fm-forming { -webkit-mask-image: none !important; mask-image: none !important; }
html.static-mode .fm-anim .fm-track :is(.fm-pain, .fm-channel, .fm-core, .fm-step, .fm-data, .fm-ledger, .fm-report, .fm-loop, .fm-outcome) > * { opacity: 1 !important; transform: none !important; filter: none !important; }
html.static-mode .fm-edges path { stroke-dashoffset: 0 !important; }
html.static-mode .fm-edges path.fm-halo, html.static-mode .fm-edges path.fm-pulse { display: none; }
html.static-mode .fm-glitter { display: none; }
html.static-mode .fm-core-bloom { opacity: .55 !important; }
