/* ---------- standing in for an empty map ----------
   The frame the example wears inside the product, which the landing page does
   not need: there, everything on the page is an argument and nothing could be
   mistaken for the reader's own data. Here it could, so it is held at arm's
   length. Dimmed until hovered, banner above it, and a dashed edge, which is
   the same thing the flow map already uses to mean "not the real path". */
.flow-example { margin: var(--space-4) 0 var(--space-5); }
.flow-example-note {
  display: flex; align-items: baseline; gap: var(--space-3);
  margin: 0 0 var(--space-3);
  color: var(--ink-muted);
  max-width: 74ch;
}
.flow-example-note .chip { flex: none; }
.flow-example-frame {
  margin-top: 0;
  border-style: dashed;
  opacity: 0.86;
  transition: opacity 0.2s ease;
}
.flow-example-frame:hover { opacity: 1; }
/* The second one carries the replay, so it is the longer read and says so by
   standing slightly apart rather than by announcing itself. */
.flow-example-deep { margin-top: var(--space-4); }
@media (prefers-reduced-motion: reduce) {
  .flow-example-frame { opacity: 1; transition: none; }
}

/* The journeys demo: the flow map, drawing itself.
 *
 * Lifted out of landing.css because two surfaces use it now. It was written for
 * the landing page, where it argues that the map needs no configuring, and it
 * does the same job standing in for an empty map inside the product, where the
 * argument is "this is what yours looks like once your app reports in".
 *
 * Self-contained on purpose: every selector here is .jd*, and every colour and
 * measure is a token from cyclopes.css, so this can be dropped onto any page
 * that already has the design system without dragging a landing page with it.
 * Geometry comes from apps/dashboard/journeys_demo.py, movement from
 * static/js/journey-demo.js.
 */

/* ---------- the journeys demo ----------
   A frame the map lives in, so it reads as an instrument on the page rather
   than an illustration of one. Everything below the map holds its height from
   the first frame: the acts arrive by lighting up, never by pushing the page
   around under someone who is reading it. */
.jd {
  margin-top: var(--space-5);
  background: var(--bg-1);
  border: 1px solid var(--border); border-radius: var(--radius-m);
}
.jd-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
}
.jd-head-name { font-size: var(--fs-0); color: var(--ink-faint); }
.jd-toggle {
  font: inherit; font-size: var(--fs-0); cursor: pointer;
  padding: 2px 10px; color: var(--ink-faint);
  background: none; border: 1px solid var(--border); border-radius: var(--radius-m);
}
.jd-toggle:hover { color: var(--ink); border-color: var(--border-bright); }
.jd-toggle[hidden] { display: none; }

.jd-stage { padding: var(--space-4) var(--space-4) var(--space-2); overflow-x: auto; }
/* The min-width is what stops the wide map being squeezed until its labels
   are unreadable; the stage scrolls instead. Below the breakpoint the script
   has swapped in the upright map, which is drawn to fit a phone column, so
   the floor comes off and the scroller has nothing to scroll. */
.jd-map { display: block; width: 100%; min-width: 520px; height: auto; }
[data-jd-fit="narrow"] { overflow-x: visible; }
[data-jd-fit="narrow"] .jd-map { min-width: 0; max-width: 340px; margin: 0 auto; }

/* The map itself. Geometry is in the template; only colour and weight here. */
.jd-edge { stroke: var(--border-bright); stroke-width: 1; stroke-linecap: round; }
.jd-edge-exit { stroke: var(--ink-faint); stroke-dasharray: 3 4; opacity: 0.75; }

.jd-node rect { fill: var(--bg-0); stroke: var(--border-bright); stroke-width: 1; }
/* Anchoring is left to the `text-anchor` attribute the layout writes, and is
   deliberately not set here: a CSS declaration beats a presentation attribute,
   so `text-anchor: middle` in this file silently centred the upright map's
   labels on the x the layout had chosen for their left edge, and every step
   name hung off the side of its box. */
.jd-node .jd-name {
  fill: var(--ink); font-family: var(--font-mono); font-size: 11px;
}
.jd-node .jd-num {
  fill: var(--ink-faint); font-family: var(--font-mono); font-size: 9.5px;
  font-variant-numeric: tabular-nums;
}
.jd-tag {
  fill: var(--ink-faint); font-family: var(--font-mono); font-size: 8.5px;
  letter-spacing: 0.14em; text-anchor: middle;
}
.jd-node.is-entry rect, .jd-node.is-done rect { stroke: var(--accent); }
.jd-node.is-entry .jd-tag { fill: var(--accent); }
.jd-node.is-exit rect { fill: none; stroke: var(--ink-faint); stroke-dasharray: 3 4; }
.jd-node.is-exit .jd-name { fill: var(--ink-faint); }

/* The blocker is named only once the numbers are in. Before that it is just
   another step, which is the honest order. */
.jd-tag-blocker { opacity: 0; transition: opacity 0.4s ease; }
.jd-node.is-blocking .jd-tag-blocker { opacity: 1; fill: var(--level-warning); }
.jd-node.is-blocking rect { stroke: var(--level-warning); }

.jd-err { fill: var(--level-error); opacity: 0; transition: opacity 0.4s ease; }
.jd-node.is-erring .jd-err { opacity: 1; }
.jd-node.is-erring rect { stroke: var(--level-error); }

.jd-dot { fill: var(--accent); }
.jd-dot.is-lost { fill: var(--level-warning); }

/* ---------- what the map worked out ---------- */
.jd-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4);
  margin: 0; padding: var(--space-4);
  border-top: 1px solid var(--border);
  opacity: 0.28; transition: opacity 0.5s ease;
}
.jd[data-phase="2"] .jd-stats, .jd[data-phase="3"] .jd-stats { opacity: 1; }
.jd-stat dt {
  font-size: var(--fs-0); font-weight: 700; letter-spacing: 0.16em; color: var(--ink-faint);
}
.jd-stat dd {
  margin: 6px 0 0; font-size: var(--fs-3); font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}
.jd-stat p { margin: 4px 0 0; font-size: var(--fs-0); line-height: 1.55; color: var(--ink-faint); }
.jd-stat-blocker dd { color: var(--level-warning); }

/* ---------- the session that did not finish ---------- */
.jd-replay {
  padding: var(--space-4);
  border-top: 1px solid var(--border);
  opacity: 0.28; transition: opacity 0.5s ease;
}
.jd[data-phase="3"] .jd-replay { opacity: 1; }
.jd-replay-head { margin: 0 0 var(--space-3); font-size: var(--fs-0); color: var(--ink-faint); }
.jd-replay-head b { color: var(--ink-muted); font-weight: 400; }
.jd-steps { margin: 0; padding: 0; list-style: none; font-size: var(--fs-0); line-height: 1.9; }
/* A line waiting to be replayed is drawn, faintly, rather than absent: the
   strip holds its height either way, and an empty rectangle for the first ten
   seconds reads as something failing to load. */
.jd-steps li {
  display: grid; grid-template-columns: 5.5ch 6.5ch 1fr; gap: var(--space-3);
  color: var(--ink-muted);
  opacity: 0.1; transform: translateY(4px);
  transition: opacity 0.3s ease, transform 0.3s ease;
}
.jd-steps li.is-in { opacity: 1; transform: none; }
.jd-t { color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.jd-kind { color: var(--ink-faint); }
.jd-steps li.is-error .jd-kind, .jd-steps li.is-error .jd-what { color: var(--level-error); }
.jd-steps li.is-gone .jd-what { color: var(--ink-faint); }

/* ---------- the three questions ----------
   These double as the demo's captions: the act playing is the question being
   answered, so the marker is a playhead rather than a number. */
.jd-acts {
  margin: 0; padding: var(--space-4);
  border-top: 1px solid var(--border);
  list-style: none;
}
.jd-act {
  position: relative;
  padding-left: var(--space-5);
  margin-bottom: var(--space-3);
  font-size: var(--fs-0); line-height: 1.65; color: var(--ink-faint);
  transition: color 0.4s ease;
}
.jd-act:last-child { margin-bottom: 0; }
.jd-act b { font-weight: 700; color: inherit; }
.jd-act::before {
  content: "▸"; position: absolute; left: 0; top: 0;
  opacity: 0.35; transition: opacity 0.4s ease, transform 0.4s ease;
  transform: translateX(-3px);
}
.jd-act.is-on { color: var(--ink-muted); }
.jd-act.is-on b { color: var(--ink); }
.jd-act.is-on::before { opacity: 1; transform: none; color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .jd-stats, .jd-replay, .jd-steps li, .jd-act, .jd-act::before,
  .jd-tag-blocker, .jd-err { transition: none; }
  .jd-steps li { opacity: 1; transform: none; }
}

@media (max-width: 620px) {
  .jd-stats { grid-template-columns: 1fr; gap: var(--space-4); }
  .jd-steps li { grid-template-columns: 5.5ch 1fr; }
  .jd-steps .jd-kind { display: none; }
}

/* ── the demo's scenario tabs ─────────────────────────────────────────────── */
/* A checkout funnel reads as "this is for online shops". The same failure in a
   bank app, a signup and a delivery app is the same shape, and a visitor will
   not make that leap on your behalf, so the tabs are the point, not chrome. */
.jd-tabs { display: flex; flex-wrap: wrap; gap: 2px; }
.jd-tab {
  font: inherit; font-size: var(--fs-0); cursor: pointer;
  padding: 2px 10px; color: var(--ink-faint);
  background: none; border: 1px solid transparent; border-radius: var(--radius-m);
}
.jd-tab:hover { color: var(--ink-muted); }
.jd-tab.is-on {
  color: var(--ink);
  border-color: var(--border-bright);
  background: var(--bg-2, transparent);
}
.jd-tab:focus-visible { outline: 1px solid var(--border-bright); outline-offset: 1px; }

.jd-scene[hidden] { display: none; }

.jd-caption {
  margin: 0; padding: var(--space-3) var(--space-4) 0;
  font-size: var(--fs-0); color: var(--ink-faint);
}

/* The line that turns a percentage back into money. The stats say 62%; this
   says what the other 38% was. */
.jd-verdict {
  margin: var(--space-3) 0 0;
  font-size: var(--fs-0); color: var(--ink-muted);
  opacity: 0; transition: opacity 0.6s ease;
}
.jd[data-phase="3"] .jd-verdict { opacity: 1; }

@media (max-width: 640px) {
  .jd-head { flex-wrap: wrap; }
  .jd-tabs { order: 2; width: 100%; }
}
