/**
 * <FlowMock /> styles.
 *
 * Every rule is scoped under a `.fm` parent, the same convention as
 * AppMock's `.am`: React wraps the mock in `<div className={styles.fm}>`,
 * a static-HTML specimen wraps it in `<div class="fm">` and loads this
 * file as a plain global stylesheet (CSS Modules keeps the literal
 * selector text). `display: contents` keeps the scope wrapper
 * transparent to layout.
 *
 * Tokens only. Node bars: mint = trigger, lavender = steps/approval,
 * vermillion = end. The run-line is mint (--c-mint-500). The run
 * holds ~600ms at the approval node while an orange halo flashes
 * there — "a human decides here" — and that flash is this
 * component's single orange accent.
 */

.fm { display: contents; }

.fm .figure {
  margin: 0;
  display: inline-flex;
  flex-direction: column;
  gap: var(--space-2);
  width: 100%;
  max-width: 100%;
}

.fm .frame {
  width: 100%;
  max-width: 720px;
  aspect-ratio: 16 / 10;
  background: var(--conduction-color-surface-card);
  border: 1px solid var(--c-cobalt-100);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  overflow: hidden;
  position: relative;
}
.fm .size-sm { max-width: 480px; }
.fm .size-md { max-width: 720px; }

.fm .canvas { display: block; width: 100%; height: 100%; }

.fm .caption {
  font-family: var(--conduction-typography-font-family-code);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--conduction-color-text-muted);
  text-transform: uppercase;
  text-align: center;
}

/* ---- Canvas ---- */

.fm .surface { fill: var(--c-cobalt-50); }
.fm .dot { fill: var(--c-cobalt-200); }

/* ---- Edges + pill labels ---- */

.fm .edge {
  fill: none;
  stroke: var(--c-cobalt-200);
  stroke-width: 2;
  stroke-linecap: round;
}

.fm .pill {
  fill: white;
  stroke: var(--c-cobalt-100);
  stroke-width: 1;
}
.fm .pillGreek { fill: var(--c-cobalt-300); }

/* ---- Nodes ---- */

.fm .card {
  fill: white;
  stroke: var(--c-cobalt-100);
  stroke-width: 1;
}

.fm .bar { fill: var(--c-cobalt-300); }
.fm .bar-trigger  { fill: var(--c-mint-500); }
.fm .bar-step     { fill: var(--c-lavender-500); }
.fm .bar-approval { fill: var(--c-lavender-500); }
.fm .bar-end      { fill: var(--c-red-vermillion); }

.fm .kindLabel {
  font-family: var(--conduction-typography-font-family-code);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  fill: var(--c-cobalt-400);
}

.fm .titleGreek { fill: var(--c-cobalt-700); }
.fm .subGreek   { fill: var(--c-cobalt-200); }

/* ---- Run-line animation ----
 *
 * The route path carries pathLength="1", so the dash arithmetic is
 * geometry-independent: a 0.28-long mint segment on a 1.28 period
 * travels the full route once per cycle. Animating the offset from
 * 1.28 to 0 shifts the pattern forward exactly one period, so the
 * loop is seamless (the segment exits the end node as its successor
 * enters the trigger).
 *
 * The offset keyframes are not linear end-to-end: the run reaches the
 * approval node at 58% (offset 1.28 × (1 − 0.62) ≈ 0.487, the node
 * sitting ~62% along the route) and HOLDS there for ~600ms (8.6% of
 * the 7s cycle) — approval is where a human decides — before
 * continuing to the end node. */

.fm .runline {
  fill: none;
  stroke: var(--c-mint-500);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 0.28 1;
  stroke-dashoffset: 1.28;
  animation: fmRun var(--fm-dur, 7s) linear infinite;
}

@keyframes fmRun {
  0%    { stroke-dashoffset: 1.28; }
  58%   { stroke-dashoffset: 0.487; } /* segment reaches the approval node */
  66.6% { stroke-dashoffset: 0.487; } /* ~600ms hold: a human decides */
  100%  { stroke-dashoffset: 0; }
}

/* Halo pulse on the nodes the run-line passes. Delays approximate
   where along the (held) cycle each node sits: trigger 0%, step ~28%,
   approval 58% (the hold), end ~87%. The approval halo is the
   exception: it flashes KNVB orange for the length of the hold — the
   component's one orange accent. */
.fm .halo {
  fill: none;
  stroke: var(--c-mint-500);
  stroke-width: 2;
  opacity: 0;
  animation: fmPulse var(--fm-dur, 7s) linear infinite;
}
.fm .halo-0 { animation-delay: 0s; }
.fm .halo-1 { animation-delay: calc(var(--fm-dur, 7s) * 0.28); }
.fm .halo-2 {
  stroke: var(--c-orange-knvb);
  animation-name: fmPulseHold;
  animation-delay: calc(var(--fm-dur, 7s) * 0.58);
}
.fm .halo-3 { animation-delay: calc(var(--fm-dur, 7s) * 0.87); }

@keyframes fmPulse {
  0%   { opacity: 0; }
  4%   { opacity: 0.55; }
  12%  { opacity: 0; }
  100% { opacity: 0; }
}

/* The approval flash spans the whole ~600ms hold (8.6% of the cycle)
   instead of the quick pass-through pulse. */
@keyframes fmPulseHold {
  0%    { opacity: 0; }
  1.5%  { opacity: 0.8; }
  8%    { opacity: 0.8; }
  11%   { opacity: 0; }
  100%  { opacity: 0; }
}

/* ---- Static renderings ----
 *
 * Both `running={false}` (the .static class) and the user's
 * prefers-reduced-motion setting freeze the mock to the full mint
 * route with no dash travel and no pulse. */

.fm .static .runline {
  animation: none;
  stroke-dasharray: none;
  stroke-dashoffset: 0;
}
.fm .static .halo { animation: none; opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .fm .runline {
    animation: none;
    stroke-dasharray: none;
    stroke-dashoffset: 0;
  }
  .fm .halo { animation: none; opacity: 0; }
}
