/* ---------------------------------------------------------------------------
   The pieces the new copy needs, drawn once for all three directions
   ---------------------------------------------------------------------------
   The argument changed shape: it is no longer "two numbers differ" but "a
   record left one system and did not arrive, and here is where it stopped".
   Three things carry that, and all three directions want them, so they live
   here rather than being drawn three times and drifting apart:

     .flowline   SOURCE → LOGIC → DESTINATION, the model being described
     .tally      Expected / Received / Missing, the moment a gap appears
     .trace      the chain that narrows 7 → 5 → 2 → a reason

   Each takes its colour from whatever it is dropped into, so the same markup
   reads on the dark stage and on the light page.
   --------------------------------------------------------------------------- */

/* --- SOURCE → LOGIC → DESTINATION ---------------------------------------- */

.flowline {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto 1fr;
  align-items: center;
  gap: clamp(8px, 1.6vw, 18px);
}

.flow-node {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 20px 14px;
  border: 1px solid var(--flow-line, var(--line));
  border-radius: var(--r-lg);
  background: var(--flow-fill, var(--bg-panel));
  text-align: center;
}

.flow-node .mark {
  border-color: var(--flow-line, var(--line));
  background: var(--flow-tile, var(--bg-raised));
  color: inherit;
  box-shadow: none;
}

.flow-node b {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--flow-dim, var(--text-dim));
}

.flow-node span {
  font-size: 14.5px;
  color: var(--flow-soft, var(--text-soft));
  max-width: 22ch;
}

/* The arrow between two nodes. A glyph rather than a border, so it keeps its
   weight when the row wraps to a column on a phone. */
.flow-arrow {
  display: grid;
  place-items: center;
  font-size: 20px;
  line-height: 1;
  color: var(--accent-brand);
}

@media (max-width: 760px) {
  .flowline {
    grid-template-columns: 1fr;
  }

  .flow-arrow {
    transform: rotate(90deg);
  }
}

/* --- Expected / Received / Missing ---------------------------------------- */

.tally {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  overflow: hidden;
  border: 1px solid var(--flow-line, var(--line));
  border-radius: var(--r-lg);
  background: var(--flow-line, var(--line));
}

.tally div {
  padding: 18px 20px;
  background: var(--flow-fill, var(--bg-panel));
}

.tally b {
  display: block;
  margin-bottom: 4px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--flow-dim, var(--text-dim));
}

.tally span {
  font-size: clamp(24px, 3.2vw, 34px);
  font-weight: 600;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}

.tally .is-missing span {
  color: var(--err);
}

/* --- the trace: a difference, followed back to its cause ------------------ */

.trace {
  display: grid;
  gap: 0;
  max-width: 560px;
}

.trace-step {
  position: relative;
  display: grid;
  grid-template-columns: 62px 1fr;
  align-items: center;
  gap: 16px;
  padding: 15px 18px;
  border: 1px solid var(--flow-line, var(--line));
  border-radius: var(--r);
  background: var(--flow-fill, var(--bg-panel));
}

/* The count, which is the whole point: it narrows down the chain. */
.trace-step i {
  font-size: 23px;
  font-weight: 600;
  font-style: normal;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.trace-step p {
  font-size: 15.5px;
  color: var(--flow-soft, var(--text-soft));
}

/* The drop between steps, drawn rather than spaced, so the chain reads as one
   thing falling through stages instead of five cards in a list. */
.trace-link {
  justify-self: start;
  width: 62px;
  height: 22px;
  display: grid;
  place-items: center;
  color: var(--flow-dim, var(--text-dim));
}

.trace-link::before {
  content: '';
  width: 1px;
  height: 100%;
  background: currentColor;
  opacity: 0.45;
}

/* Where it stops: the reason, which is the answer the page promises. */
.trace-step.is-cause {
  border-color: var(--accent-brand);
  background: var(--flow-cause, var(--accent-wash));
}

.trace-step.is-cause i,
.trace-step.is-cause p {
  color: var(--accent);
}

.trace-step.is-cause p b {
  display: block;
  font-weight: 600;
}

/*
 * The records themselves, under the reason.
 *
 * The funnel narrows 7, 7, 5, 2 and then used to stop at a category — which is
 * the same failure the reason blocks on the home page had before they named
 * their rows. If the last number is two, the last line should be able to say
 * which two.
 */
.trace-step.is-cause p small {
  display: block;
  margin-top: 4px;
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 12.5px;
  letter-spacing: -0.01em;
  color: var(--flow-soft, var(--text-soft));
}

@media (max-width: 520px) {
  .trace-step {
    grid-template-columns: 46px 1fr;
    gap: 12px;
  }

  .trace-link {
    width: 46px;
  }
}

/* ---------------------------------------------------------------------
   The mechanism, built rather than photographed
   ---------------------------------------------------------------------
   These two were screenshots. A screenshot of a canvas has to be shown at
   something near the size it was taken at or its 12px labels turn to
   mush, so the flow took a third of the page to say a thing that is four
   boxes and three lines.

   Rebuilt in the page, they are as small as they need to be and no
   smaller, they stay sharp at any density, and the chain can arrive one
   step at a time — which is the one thing a picture of a chain cannot do.

   The values are the application's own, read off `SourcesCanvas.css` and
   `Drilldown.css` rather than eyeballed off the old screenshots: the
   cards are the sizes they are in the product, the dotted fields are the
   same two grids, and the flow canvas keeps its warm ground while the
   investigation keeps its neutral one. They differ in the product and
   they should differ here.
   --------------------------------------------------------------------- */

/* --- the flow, as the sources canvas draws it --- */
.appflow {
  --fl-card: #26231f;
  --fl-border: #3d3831;
  --fl-tile: #302c26;
  --fl-ink: #f3efe8;
  --fl-muted: #b1aa9e;
  --fl-edge: #4d473e;
  --fl-ok: #4cc88a;
  --fl-violet: #9187ff;
  --fl-canvas: #1c1a17;
  --fl-dot: #34302a;

  margin: 30px 0 0;
  padding: 26px 22px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background-color: var(--fl-canvas);
  background-image: radial-gradient(circle, var(--fl-dot) 1px, transparent 1px);
  background-size: 24px 24px;
}

.appflow-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.appflow-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 14px;
  border: 1px solid var(--fl-border);
  border-radius: 6px;
  background: var(--fl-card);
  box-shadow: 0 1px 0 var(--fl-border);
  color: var(--fl-ink);
}

.appflow-tile {
  flex: none;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border: 1px solid var(--fl-border);
  border-radius: 6px;
  background: var(--fl-tile);
  color: var(--fl-muted);
}

.appflow-tile svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The one brand mark in the flow keeps its own colour, as it does in the
   product: a connected system is recognised by its logo, not recoloured
   into the canvas. */
/*
   A connected system's own mark, in its own colours.

   `shopify-colour.svg` rather than `shopify.svg`: the file in the logo
   strip is the monochrome one, which that row inverts to white so the
   marks read as a single band. Inverted here it was a white blob in a
   white circle — the shape of a bag is carried entirely by its two
   greens and the counter of the S, and a one-colour fill throws all
   three away. So the strip keeps the flat mark and the tile, where this
   is a system somebody actually connected, gets the real one.
*/
.appflow-tile img {
  width: 21px;
  height: 21px;
}

.appflow-text {
  flex: 1;
  min-width: 0;
}

.appflow-step {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  line-height: 18px;
  color: var(--fl-muted);
}

.appflow-badge {
  flex: none;
  padding: 0 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--fl-violet) 16%, transparent);
  color: var(--fl-violet);
  font-size: 12px;
  font-weight: 600;
  line-height: 18px;
}

.appflow-name {
  overflow: hidden;
  font-size: 16px;
  line-height: 20px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.appflow-ok {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--fl-ok);
}

.appflow-ok svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Three ports at a sixth, a half and five sixths of the width, all
   arriving at the half. Percentages of the viewBox rather than pixels,
   so the curves follow the columns at any width. */
.appflow-wires {
  display: block;
  width: 100%;
  height: 42px;
}

.appflow-wires path {
  fill: none;
  stroke: var(--fl-edge);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

.appflow-mid {
  max-width: 260px;
  margin-inline: auto;
}

.appflow-stem {
  width: 2px;
  height: 30px;
  margin-inline: auto;
  background: var(--fl-edge);
}

@media (max-width: 620px) {
  .appflow-row {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Three curves converging make sense beside three columns and nonsense
     under a stack, so the fan becomes the stem it already is. */
  .appflow-wires {
    height: 26px;
  }

  .appflow-wires path:not(.is-stem) {
    display: none;
  }
}

/* --- the investigation chain, as the drilldown canvas draws it --- */
.appchain {
  --dr-card: #2a2a2a;
  --dr-border: #3d3d3d;
  --dr-ink: #ededed;
  --dr-dim: #8a8a8a;
  --dr-ok: #3ecf8e;
  --dr-orange: #ff6c37;
  --dr-canvas: #212121;
  --dr-dot: #3d3d3d;

  margin: 26px 0 0;
  padding: 30px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background-color: var(--dr-canvas);
  background-image: radial-gradient(circle, var(--dr-dot) 1px, transparent 1px);
  background-size: 20px 20px;
  overflow-x: auto;
}

.appchain-track {
  display: flex;
  align-items: flex-start;
  min-width: max-content;
  margin-inline: auto;
  /* Room for the branch labels, which sit above the cards rather than on
     the wire. In the product they lie along a 62px fan curve with a pill
     of canvas behind them; a 72px straight wire is not long enough to
     hold `REJECTED`, so on the wire they covered the wire and overhung
     the cards either side. Above it, the overhang lands on empty field. */
  padding: 24px 0 4px;
}

.appchain-node {
  flex: none;
  width: 156px;
}

.appchain-card {
  position: relative;
  box-sizing: border-box;
  height: 60px;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 10px;
  border: 1px solid var(--dr-ok);
  border-radius: 4px;
  background: var(--dr-card);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--dr-ok) 16%, transparent);
  color: var(--dr-ink);
}

.appchain-card svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: var(--dr-dim);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.appchain-copy {
  min-width: 0;
}

.appchain-copy b {
  display: block;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.25;
}

.appchain-copy small {
  display: block;
  margin-top: 1px;
  overflow: hidden;
  font-size: 11px;
  color: var(--dr-dim);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.appchain-num {
  position: absolute;
  top: 3px;
  right: 5px;
  font-size: 11px;
  color: var(--dr-dim);
}

/* The figure the step came back with, in the token's colours. */
.appchain-chip {
  display: inline-block;
  margin-top: 6px;
  padding: 2px 8px;
  border: 1px solid var(--dr-orange);
  border-radius: 10px;
  background: color-mix(in srgb, var(--dr-orange) 10%, transparent);
  color: var(--dr-orange);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 11px;
}

.appchain-wire {
  position: relative;
  flex: none;
  width: 72px;
  height: 2px;
  margin-top: 29px;
  border-radius: 1px;
  background: var(--dr-dim);
}

/* The answer that sent the run down this branch, on the wire it took. */
.appchain-wire b {
  position: absolute;
  bottom: 34px;
  left: 50%;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--dr-canvas);
  color: var(--dr-ok);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  transform: translateX(-50%);
}

/*
   Built one step at a time, once it is on screen.

   The chain is an argument that runs left to right — each step asks the
   next system in the path what it saw — and arriving all at once is the
   one thing that does not say. Nodes come in from the left, wires draw
   themselves outward from the node that feeds them.

   The delay is per item rather than per type, so a node and the wire
   after it never land together: `--i` is just its place in the line.
*/
.appchain-node,
.appchain-wire {
  opacity: 0;
  transition:
    opacity 0.42s ease,
    transform 0.42s cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: calc(var(--i) * 130ms);
}

.appchain-node {
  transform: translateX(-14px);
}

.appchain-wire {
  transform: scaleX(0);
  transform-origin: left center;
}

.appchain.is-built .appchain-node,
.appchain.is-built .appchain-wire {
  opacity: 1;
  transform: none;
}

/*
   Narrow: the chain turns the corner and runs down the page.

   Sideways it was a scrolling strip that showed one and a half cards and
   no sign there were more — a chain cut off at the edge reads as a
   rendering fault, not as something to swipe. Down the page every step
   is on screen, and the sequence it builds in becomes top to bottom,
   which is the direction a phone is read in anyway.
*/
@media (max-width: 620px) {
  .appchain {
    overflow-x: visible;
    padding: 22px 20px 24px;
  }

  .appchain-track {
    flex-direction: column;
    align-items: stretch;
    min-width: 0;
    padding: 0;
  }

  .appchain-node {
    width: 100%;
  }

  .appchain-card {
    height: auto;
    min-height: 60px;
    padding: 10px;
  }

  .appchain-wire {
    width: 2px;
    height: 26px;
    margin: 0 0 0 29px;
    transform-origin: center top;
  }

  /* Beside the wire now, not above it: there is room either side down
     here and none above, which is the opposite of the wide case. */
  .appchain-wire b {
    bottom: auto;
    top: 50%;
    left: 10px;
    transform: translateY(-50%);
  }

  .appchain-wire {
    transform: scaleY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .appchain-node,
  .appchain-wire {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ---------------------------------------------------------------------------
   A question, as the canvas draws one
   ---------------------------------------------------------------------------
   Two bordered boxes reading "if this happens, expect this" is a description of
   a branch. This is the branch — one question card, its two ports, the fan that
   comes out of them, and what each answer leads to.

   The geometry is the application's, from `canvas.tsx`: a 156x60 card whose
   port line is half its height, lanes 92 tall with 34 between them, ports split
   9 either side of the centre, and a 56px fan. Half of `LANE_H + LANE_GAP` is
   how far each lane sits from the question's own line, which is what makes the
   two curves symmetric without moving the node they leave.
   --------------------------------------------------------------------------- */

.appask {
  --dr-card: #2a2a2a;
  --dr-border: #3d3d3d;
  --dr-ink: #ededed;
  --dr-dim: #8a8a8a;
  --dr-ok: #3ecf8e;
  --dr-canvas: #212121;
  --dr-dot: #3d3d3d;

  margin: 26px 0 0;
  padding: 26px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background-color: var(--dr-canvas);
  background-image: radial-gradient(circle, var(--dr-dot) 1px, transparent 1px);
  background-size: 20px 20px;
  overflow-x: auto;
}

.appask-track {
  display: flex;
  align-items: flex-start;
  /* Centred when there is room, scrolled when there is not. */
  width: max-content;
  min-width: max-content;
  margin-inline: auto;
  /* The stack is 218 tall — two 92px lanes and the 34 between them — and the
     question sits on its centre line. */
  height: 218px;
}

.appask-card {
  position: relative;
  box-sizing: border-box;
  width: 156px;
  height: 60px;
  margin-top: 79px;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 10px;
  border: 1px solid var(--dr-ok);
  border-radius: 4px;
  background: var(--dr-card);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--dr-ok) 16%, transparent);
  color: var(--dr-ink);
}

/* The two ways out, on the edge of the card rather than beside it — a question
   gives up its single output port for these. */
.appask-card::after,
.appask-card::before {
  content: '';
  position: absolute;
  right: -6px;
  width: 10px;
  height: 10px;
  border: 2px solid var(--dr-canvas);
  border-radius: 50%;
  background: var(--dr-dim);
}

.appask-card::before {
  top: 16px;
}

.appask-card::after {
  top: 34px;
}

.appask-fan {
  flex: none;
  width: 56px;
  height: 218px;
}

.appask-fan path {
  fill: none;
  stroke: var(--dr-dim);
  stroke-width: 2;
}

.appask-lanes {
  display: flex;
  flex-direction: column;
  gap: 34px;
}

.appask-lane {
  position: relative;
  height: 92px;
}

.appask-lane .appask-out {
  box-sizing: border-box;
  width: 168px;
  height: 60px;
  display: flex;
  align-items: center;
  padding: 0 12px;
  border: 1px solid var(--dr-border);
  border-radius: 4px;
  background: var(--dr-card);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--dr-ink);
}

.appask-lane.is-yes .appask-out {
  border-color: var(--dr-ok);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--dr-ok) 16%, transparent);
}

/* The answer that sent the run this way, on the wire it took — a pill of
   canvas colour over the curve, exactly as the product draws it. */
.appask-label {
  position: absolute;
  top: 30px;
  right: calc(100% + 4px);
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--dr-canvas);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  transform: translateY(-50%);
}

.appask-lane.is-yes .appask-label {
  color: var(--dr-ok);
}

.appask-lane.is-no .appask-label {
  color: var(--dr-dim);
}

@media (max-width: 560px) {
  .appask {
    padding: 20px 16px;
  }
}

/* ---------------------------------------------------------------------------
   Light
   ---------------------------------------------------------------------------
   The same diagrams as the application draws them in its light theme: the flow
   canvas's warm ground from `SourcesCanvas.css`, the investigation's neutral
   one from Geist. Everything above takes its colours from these names, so this
   is the whole of it.
   --------------------------------------------------------------------------- */

:root[data-theme='light'] .appflow {
  --fl-canvas: var(--bg);
  --fl-dot: #d7d2c6;
  --fl-card: #ffffff;
  --fl-border: #d7d2c6;
  --fl-tile: #ffffff;
  --fl-ink: #201515;
  --fl-muted: #5e5a52;
  --fl-edge: #c5c0b1;
  --fl-ok: #1f7a4d;
  --fl-violet: #695be8;
}

:root[data-theme='light'] :is(.appchain, .appask) {
  --dr-canvas: #fafafa;
  --dr-dot: #d4d4d4;
  --dr-card: #ffffff;
  --dr-border: #d4d4d4;
  --dr-ink: #171717;
  --dr-dim: #666666;
  --dr-ok: #1f7a4d;
  /* The brand orange is a fill; as text on white it needs the deeper one. */
  --dr-orange: #c7491c;
}
