/* site/app/flow.css — the user-flow map. A working document, not the app.
 * Uses the same tokens so the two read as one project, but it is a document: denser,
 * quieter, and built to be scanned and argued with rather than operated.
 */

/* ⚠ The attention role: "this needs a human decision". It is deliberately NOT --action.
 * Orange is the thing you are meant to press, and there is nothing to press on an unanswered
 * question — using orange for it made the questions compete with buttons everywhere else in
 * the app, and orange text on cream is unreadable in daylight besides.
 * ⚠ THIS FILE USED TO REDEFINE --attn HERE, guessing tokens.css would name it --attention.
 * It shipped as --attn itself, so the guess became a :root rule that SHADOWED the real token
 * — flow.css loads after tokens.css, so every --attn on this page silently collapsed back to
 * --warn, and "needs your call" became the same amber as "partly built" in the legend, which
 * is the one place the two sit side by side. The line is gone; --attn / --attn-bg / --attn-ink
 * now come straight from tokens.css and flip with the theme. */

body { background: var(--bg); color: var(--ink); }

/* ── Header ───────────────────────────────────────────────────────────────── */
.top {
  position: sticky; top: 0; z-index: 30;
  background: var(--chrome);
  backdrop-filter: var(--chrome-blur); -webkit-backdrop-filter: var(--chrome-blur);
  border-bottom: 1px solid var(--rule);
  padding-top: var(--safe-top);
}
.top-in {
  max-width: 940px; margin: 0 auto; padding: 18px 20px 12px;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
}
.top h1 {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.6rem, 4vw, 2.1rem); line-height: 1.05; letter-spacing: -.02em; margin: 0;
}
.sub { margin: 6px 0 0; font-size: .9375rem; line-height: 1.5; color: var(--ink-secondary); max-width: 54ch; }
.applink {
  flex: none; text-decoration: none; white-space: nowrap;
  font: 600 13px/1 var(--font-ui); letter-spacing: -.006em;
  color: var(--ink); background: var(--bg-sunken);
  padding: 10px 14px; border-radius: var(--r-full);
  transition: transform var(--t-press) var(--ease-out), background-color var(--t-press) var(--ease-out);
}
.applink:active { transform: scale(.97); }
@media (hover: hover) and (pointer: fine) { .applink:hover { background: var(--rule); } }

/* Journey tabs — horizontally scrollable on a phone, which is where this gets read.
 * ⚠ On desktop that scroll was a trap: the row overflowed at 940px, the scrollbar was
 *   hidden on purpose, and there is no swipe on a mouse — so the last tab read as
 *   "Food & dri" and looked like a rendering fault rather than something scrollable.
 *   Wide screens wrap instead (see the min-width: 860px block); only touch gets the swipe. */
.journeys {
  max-width: 940px; margin: 0 auto; padding: 0 20px 14px;
  display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none;
}
.journeys::-webkit-scrollbar { display: none; }
.jtab {
  flex: none; text-align: left; cursor: pointer;
  border: 1px solid var(--rule); background: var(--bg-raised);
  border-radius: var(--r-md); padding: 9px 14px;
  display: flex; flex-direction: column; gap: 2px;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: transform var(--t-press) var(--ease-out), background-color var(--t-press) var(--ease-out),
              border-color var(--t-press) var(--ease-out);
}
.jtab b { font: 600 14px/1.2 var(--font-ui); letter-spacing: -.008em; color: var(--ink); }
.jtab span { font: 400 12px/1.2 var(--font-ui); color: var(--ink-tertiary); }
.jtab:active { transform: scale(.97); }
/* ⚠ The selected tab was painted raw --navy. In dark mode the page ground is also navy, so
   the tab you were on vanished into the background and the four you were not on were the
   only ones you could see. Inverting against --ink/--bg flips with the theme and survives
   greyscale, which hue alone does not. */
.jtab[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); }
.jtab[aria-pressed="true"] b { color: var(--bg); }
.jtab[aria-pressed="true"] span { color: color-mix(in srgb, var(--bg) 72%, var(--ink)); }

/* ── Body ─────────────────────────────────────────────────────────────────── */
.wrap { max-width: 940px; margin: 0 auto; padding: 22px 20px calc(60px + var(--safe-bottom)); }

.blurb {
  margin: 0 0 22px; font-size: 1rem; line-height: 1.55; color: var(--ink-secondary);
  max-width: 62ch;
}

/* Lane headers. Hidden on narrow screens where the flow stacks into one column and the
   per-step lane tag carries the information instead. */
.lanes {
  display: none; gap: 12px; margin-bottom: 10px;
  font: 600 11px/1 var(--font-ui); letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-tertiary);
}
.lanes span { flex: 1; }

/* ── Steps ────────────────────────────────────────────────────────────────── */
.step-row { display: flex; align-items: center; gap: 10px; }

.step {
  flex: 1; min-width: 0; cursor: pointer; text-align: left;
  display: flex; align-items: center; gap: 13px;
  background: var(--bg-raised); border: 1px solid var(--rule);
  border-left: 3px solid var(--steel);
  border-radius: var(--r-md); padding: 14px 16px;
  box-shadow: var(--shadow-1);
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: transform var(--t-press) var(--ease-out), box-shadow var(--t-press) var(--ease-out);
}
.step:active { transform: scale(.985); }
@media (hover: hover) and (pointer: fine) { .step:hover { box-shadow: var(--shadow-2); } }

/* The left edge encodes WHO acts — colour plus the written lane tag, never colour alone.
 * ⚠ Staff used to be --navy-70 and the system --steel: both are brand constants, not theme
 *   roles, so in dark mode they sat on a navy card and disappeared. The phone layout is
 *   exactly where these stripes are load-bearing, and courtside at night is exactly when the
 *   phone layout gets used. --ink and --ink-tertiary flip with the theme. */
.step.lane-0 { border-left-color: var(--action); }
.step.lane-1 { border-left-color: var(--ink-tertiary); }
.step.lane-2 { border-left-color: var(--ink); }

.step-n {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--bg-sunken); color: var(--ink-tertiary);
  font: 600 12px/1 var(--font-ui); font-variant-numeric: tabular-nums;
}
.step-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.step-title { font: 600 15px/1.3 var(--font-ui); letter-spacing: -.008em; color: var(--ink); }
.step-sub { font: 400 13px/1.35 var(--font-ui); color: var(--ink-tertiary); }
.step-status {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  font: 500 11px/1 var(--font-ui); letter-spacing: .02em; color: var(--ink-tertiary);
  white-space: nowrap;
}
@media (max-width: 520px) {
  .step { align-items: flex-start; }
  .step-status { align-self: flex-start; margin-top: 2px; }
}

/* ⚠ The lane lives INSIDE the card. As a sibling it was a fixed 96px column, which on a
   375px phone left the card 229px and wrapped every title onto two lines. Inside, it costs
   nothing horizontally. On wide screens the column position already says who acts, so it
   is hidden there rather than repeated. */
.step-lane {
  font: 600 10px/1 var(--font-ui); letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-tertiary); margin-bottom: 3px;
}

/* ── Connectors ───────────────────────────────────────────────────────────────
 * ⚠ The arrow used to be a sibling of .step-row and positioned itself from var(--lane) —
 *   which is set ON the row, not on the arrow. It always fell back to 0, so on the desktop
 *   swimlane every arrow stacked in the same column, up to ~300px away from the card it
 *   claimed to come from. An arrow that names the wrong handoff is worse than no arrow:
 *   a swimlane IS the handoff, and this one was asserting a flow that does not exist.
 *   The two lanes a connector joins are now written onto the connector itself by flow.js.
 *
 * The elbow is three absolutely-positioned pieces — down out of the source lane, across,
 * down into the destination lane — placed off --half, which is half a grid column measured
 * in the connector's own width. On a phone --n is 1, so --half is 50% and the elbow
 * collapses to the plain vertical arrow the stacked layout wants.
 */
.arrow { display: flex; justify-content: flex-start; padding-left: 26px; }
.arrow-line {
  position: relative; width: 12px; height: 24px; color: var(--ink-tertiary);
  --n: 1;
  --half: calc((100% - (var(--n) - 1) * 12px) / var(--n) / 2); /* 12px = the .step-row gap */
}
.arrow-line i { position: absolute; background: currentColor; }
.a-from  { top: 0;   height: 50%; width: 2px;  left: var(--half);  margin-left: -1px; }
.a-to    { top: 50%; height: 50%; width: 2px;  right: var(--half); margin-right: -1px; }
.a-cross { top: 50%; height: 2px; margin-top: -1px; left: var(--half); right: var(--half); }
.arrow-line[data-dir="left"] .a-from { left: auto; margin-left: 0; right: var(--half); margin-right: -1px; }
.arrow-line[data-dir="left"] .a-to   { right: auto; margin-right: 0; left: var(--half); margin-left: -1px; }
.a-head {
  position: absolute; bottom: 0; width: 12px; height: 8px; right: calc(var(--half) - 6px);
  fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.arrow-line[data-dir="left"] .a-head { right: auto; left: calc(var(--half) - 6px); }

/* ── Status dots. Colour AND a word, everywhere. ──────────────────────────── */
.dot { width: 8px; height: 8px; border-radius: 50%; flex: none; display: inline-block; }
.dot.built   { background: var(--ok); }
.dot.partial { background: var(--warn); }
.dot.none    { background: var(--ink-tertiary); }
/* ⚠ A ring, not a disc — a glyph as well as a colour. Four statuses drawn as four identical
   circles put the whole distinction on hue, and "needs your call" landing anywhere near the
   amber of "partly built" makes the two unreadable side by side in the legend. Hollow also
   says the right thing: this one is not filled in yet. */
.dot.ask     { width: 9px; height: 9px; background: transparent;
               box-shadow: inset 0 0 0 2.5px var(--attn); }

/* ⚠ A "needs your call" step is the entire reason this page gets sent to anyone, and it was
   marked by an 8px dot you had to hunt for down a column of near-identical cards. It now
   carries a tint, a border and a filled worded pill, so it is findable in a scroll-past and
   still findable in greyscale. Deliberately not orange — nothing here is pressable, and the
   old orange-on-cream heading in the panel could not be read in daylight anyway. */
.step[data-ask] {
  background: color-mix(in srgb, var(--attn) 9%, var(--bg-raised));
  border-top-color: color-mix(in srgb, var(--attn) 45%, var(--rule));
  border-right-color: color-mix(in srgb, var(--attn) 45%, var(--rule));
  border-bottom-color: color-mix(in srgb, var(--attn) 45%, var(--rule));
}
/* The badge a question-bearing step wears when its status already says something else. */
.step-ask {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 6px;
  margin-top: 6px; padding: 4px 9px; border-radius: var(--r-full);
  background: color-mix(in srgb, var(--attn) 20%, transparent);
  font: 600 11px/1 var(--font-ui); letter-spacing: .02em; color: var(--ink);
}
/* When the status IS "ask", the status pill carries the same words — fill it instead of
   printing them twice. */
.step[data-status="ask"] .step-status {
  background: color-mix(in srgb, var(--attn) 20%, transparent);
  color: var(--ink); font-weight: 600;
  padding: 5px 9px; border-radius: var(--r-full);
}

/* ── Legend ───────────────────────────────────────────────────────────────── */
.legend {
  margin-top: 34px; padding: 18px 20px;
  background: var(--bg-sunken); border-radius: var(--r-lg);
}
.legend h3 {
  margin: 0 0 12px; font: 600 11px/1 var(--font-ui);
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-tertiary);
}
.legend ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.legend li { display: flex; align-items: center; gap: 10px; font-size: .875rem; color: var(--ink-secondary); }
.legend b { color: var(--ink); font-weight: 600; }

/* ── Detail panel ─────────────────────────────────────────────────────────── */
/* Built from --navy rather than a literal: a scrim wants to be dark in both themes, but it
   should still be the brand's dark and not an arbitrary one. */
.panel-scrim { position: fixed; inset: 0; z-index: 40;
               background: color-mix(in srgb, var(--navy) 55%, transparent); }
.panel {
  position: fixed; z-index: 41; right: 0; top: 0; bottom: 0; width: min(460px, 92vw);
  background: var(--bg-raised); box-shadow: -8px 0 40px rgba(0,0,0,.24);
  overflow-y: auto; padding: 26px 26px calc(40px + var(--safe-bottom));
  transform: translateX(100%);
  /* Exit is faster than enter: the .open rule supplies the enter duration, so removing the
     class leaves the shorter one behind. flow.js waits this long before setting hidden. */
  transition: transform var(--t-exit) var(--ease-drawer);
}
/* The focus ring on the panel itself is kept, not suppressed: when it opens from a keypress
   it is the only thing telling a keyboard user their focus moved. It does not appear on a
   mouse click, because :focus-visible reads the last input method. */
.panel.open { transform: translateX(0); transition-duration: var(--t-sheet); }

/* ⚠ Enters from the right, leaves to the right. A panel that arrives one way and departs
   another reads as two unrelated things happening. */
@media (max-width: 640px) {
  .panel {
    right: 0; left: 0; top: auto; width: auto; max-height: 86dvh;
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    transform: translateY(100%);
    box-shadow: 0 -8px 40px rgba(0,0,0,.28);
  }
  .panel.open { transform: translateY(0); }
}

/* ⚠ 34px, and it is the only way out of the panel on a phone. --tap-min is the floor, not a
   target: below it a thumb on a one-handed phone misses. */
.panel-x {
  position: absolute; top: 14px; right: 14px;
  width: var(--tap-min); height: var(--tap-min);
  display: grid; place-items: center;
  border-radius: 50%; border: 0; cursor: pointer;
  background: var(--bg-sunken); color: var(--ink-secondary); font-size: 15px;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: transform var(--t-press) var(--ease-out);
}
.panel-x:active { transform: scale(.92); }

.p-eyebrow {
  font: 600 11px/1 var(--font-ui); letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-tertiary); margin-bottom: 10px;
}
.panel h2 {
  font-family: var(--font-display); font-weight: 600; font-size: 1.6rem;
  line-height: 1.15; letter-spacing: -.018em; margin: 0 0 4px; padding-right: 54px;
}
.p-sub { margin: 0 0 12px; color: var(--ink-tertiary); font-size: .9375rem; }
.p-status {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--bg-sunken); border-radius: var(--r-full); padding: 6px 12px;
  font: 500 12px/1 var(--font-ui); color: var(--ink-secondary); margin-bottom: 20px;
}
.panel h3 {
  font: 600 11px/1 var(--font-ui); letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-tertiary); margin: 18px 0 7px;
}
.panel p { margin: 0; font-size: .9375rem; line-height: 1.6; color: var(--ink-secondary); max-width: 52ch; }

/* The questions are the reason this page exists — they get the attention colour.
 * ⚠ They used to get --action. "I NEED YOUR CALL" was orange type on a pale orange wash,
 *   which is the lowest-contrast text in the app, on the one line that has to be read. */
.p-ask {
  margin-top: 22px; padding: 16px 18px;
  background: color-mix(in srgb, var(--attn) 12%, transparent);
  border-left: 3px solid var(--attn); border-radius: 0 var(--r-md) var(--r-md) 0;
}
.p-ask h3 { color: var(--ink); margin-top: 0; }
.p-ask p { color: var(--ink); }

/* ── Wide screens: real swimlanes ─────────────────────────────────────────── */
@media (min-width: 860px) {
  /* No swipe on a mouse, so the tab row wraps here instead of hiding its overflow. */
  .journeys { flex-wrap: wrap; overflow-x: visible; }

  .lanes { display: flex; }
  .step-row { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }
  /* The step sits in its actor's column, so the eye reads handoffs as sideways movement. */
  .step { grid-column: calc(var(--lane) + 1); }
  .step-lane { display: none; }
  /* The connector is the same three-column grid, so the elbow lands on real column centres
     rather than on a percentage guess. flow.js sets grid-column and --nw per connector. */
  .arrow { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; padding-left: 0; }
  .arrow-line { width: auto; --n: var(--nw, 1); }
}

@media (prefers-reduced-motion: reduce) {
  .panel { transition-duration: 1ms; }
  .step:active, .jtab:active, .applink:active, .panel-x:active { transform: none; }
}
@media (prefers-reduced-transparency: reduce) {
  .top { background: var(--bg); backdrop-filter: none; -webkit-backdrop-filter: none; }
}
