/* Scene figures.
 *
 * The 3D scenes on /, /systems, /revenue-leak-audit and /fluxlead. Hand-authored, like the rest of
 * this site, and kept in its own file so the three reviewed stylesheets are not touched to add a
 * decoration.
 *
 * THE TOKEN BRIDGE, AND WHY IT IS SCOPED
 *
 * The static fallback diagrams are drawn by the generator, which speaks its own colour vocabulary:
 * --color-primary-text, --color-accent, --color-elevated-surface, --color-border,
 * --color-secondary-text. This site speaks a different one: --color-ivory, --color-cyan,
 * --color-charcoal, --color-rule-dark, --color-mist.
 *
 * Rather than fork the drawings or rename the site's tokens, the five names are redefined INSIDE
 * .scene-figure. Scoped, so nothing leaks into the site's own cascade, and one place to look when a
 * diagram is the wrong colour. The alternative -- a global mapping block -- would have put a second
 * naming layer over a design system that already has one.
 *
 * THREE RULES THIS FILE ENCODES
 *
 * 1. The poster holds the space. The canvas is layered on top of it, absolutely positioned, so the
 *    section has its full height before any script runs and nothing moves when a scene starts.
 * 2. The poster is never removed and never display:none. When a scene is live it fades out of sight
 *    but stays in the flow, ready for a context loss two minutes later.
 * 3. The stage list is always visible. It is the accessible copy of the scene's argument, and hiding
 *    it once the 3D runs would give the story to the visitors who can see the scene and a bare list
 *    to the ones who cannot.
 */

.scene-figure {
  /* The bridge. The generator's names, this site's colours. */
  --color-primary-text: var(--color-ivory);
  --color-secondary-text: var(--color-mist);
  --color-accent: var(--color-cyan);
  --color-elevated-surface: var(--color-charcoal);
  --color-border: var(--color-rule-dark);

  margin: var(--space-32) 0 0;
}

/* The cream sections invert the ground, so the bridge inverts with them. Without this the diagram
   would draw ivory strokes on cream and disappear. */
.section-cream .scene-figure,
.section-cream-alt .scene-figure {
  --color-primary-text: var(--color-cream-text);
  --color-secondary-text: var(--color-cream-body);
  --color-accent: var(--color-brass);
  --color-elevated-surface: #FFFFFF;
  --color-border: var(--color-rule-light);
}

.scene-stage-area {
  position: relative;
  width: 100%;
  /* A ratio rather than a height, so the box is reserved at every width and the reservation is
     correct before the stylesheet knows anything about the viewport. */
  aspect-ratio: 16 / 10;
  background: var(--color-charcoal);
  border: 1px solid var(--color-rule-dark);
  border-radius: 4px;
  overflow: hidden;
}

.section-cream .scene-stage-area,
.section-cream-alt .scene-stage-area {
  background: #FFFFFF;
  border-color: var(--color-rule-light);
}

.scene-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  font: var(--text-caption);
  transition: opacity 240ms linear;
}

.scene-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

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

/* Only once the runtime actually has a live scene in it. Until then the attribute says idle, and a
   poster hidden ahead of a scene that never starts is a blank rectangle where the argument was. */
[data-wcs-canvas="live"] .scene-poster { opacity: 0; }

.scene-caption { margin-top: var(--space-16); }

.scene-stages {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-16);
  counter-reset: scene-stage;
}

.scene-stage {
  counter-increment: scene-stage;
  border-top: 1px solid var(--color-rule-dark);
  padding-top: var(--space-12);
}

.section-cream .scene-stage,
.section-cream-alt .scene-stage { border-top-color: var(--color-rule-light); }

.scene-stage-label {
  display: block;
  font: var(--text-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-cyan);
  margin-bottom: var(--space-8);
}

.section-cream .scene-stage-label,
.section-cream-alt .scene-stage-label { color: var(--color-brass); }

.scene-stage-label::before { content: counter(scene-stage, decimal-leading-zero) "  "; }

.scene-stage-copy {
  display: block;
  font: var(--text-caption);
  color: var(--color-mist);
}

.section-cream .scene-stage-copy,
.section-cream-alt .scene-stage-copy { color: var(--color-cream-body); }

/* The stage the scroll has reached. A rule that changes colour, not a highlight: this marks position
   in a sequence and must not read as the one stage that matters. */
[data-wcs-stage="0"] .scene-stage[data-wcs-stage-index="0"],
[data-wcs-stage="1"] .scene-stage[data-wcs-stage-index="1"],
[data-wcs-stage="2"] .scene-stage[data-wcs-stage-index="2"],
[data-wcs-stage="3"] .scene-stage[data-wcs-stage-index="3"],
[data-wcs-stage="4"] .scene-stage[data-wcs-stage-index="4"] {
  border-top-color: var(--color-cyan);
}

@media (max-width: 720px) {
  .scene-stage-area { aspect-ratio: 4 / 3; }
  .scene-stages { grid-template-columns: 1fr; }
}


/* ═══════════════════════════════════════════════════════════
   PER-RECIPE STAGE TREATMENTS
   ═══════════════════════════════════════════════════════════

   The owner review said the scenes read as a technical demonstration in a box.
   Measured against this file, that was fair: every scene got an identical
   bordered 16:10 rectangle followed by an identical four-column row of
   captions, whatever it was arguing. Four routes, one presentation.

   It also became load-bearing at this gate. The duplicated card grids are gone,
   so the stage list is no longer a caption under a diagram - it is the only
   place the reader meets the sequence, and it has to hold that weight.

   The hook is `data-wcs-recipe`, already on the figure and already carrying
   exactly the right information: what this scene is arguing. No new markup, no
   generator change, and a new recipe simply falls back to the shared default
   rather than inheriting a treatment designed for a different argument.

   One vocabulary, four dialects. Deliberately NOT a per-route stylesheet: the
   shared rules above still decide type, colour, rhythm and the reduced-motion
   and cream inversions, so the routes stay one site. */

/* ── /systems: layers, so the list stacks ───────────────────
   The scene argues that credibility accumulates: foundation first, current work
   last. A four-across row flattens that into four peers, which is the one
   reading the section is trying to correct. So it becomes a single column of
   bands with a rule down the side, each stage stepping in from the last. */
[data-wcs-recipe="layered-credibility-architecture"] .scene-stages {
  grid-template-columns: 1fr;
  gap: 0;
  border-left: 1px solid var(--color-rule-dark);
  margin-left: var(--space-4);
}

[data-wcs-recipe="layered-credibility-architecture"] .scene-stage {
  border-top: none;
  padding: var(--space-16) 0 var(--space-16) var(--space-24);
  position: relative;
}

/* The step. Small, and it compounds down the stack rather than announcing
   itself - the diagram is doing the illustrating, this is just refusing to
   contradict it. */
[data-wcs-recipe="layered-credibility-architecture"] .scene-stage:nth-child(2) { padding-left: var(--space-32); }
[data-wcs-recipe="layered-credibility-architecture"] .scene-stage:nth-child(3) { padding-left: var(--space-40); }
[data-wcs-recipe="layered-credibility-architecture"] .scene-stage:nth-child(4) { padding-left: var(--space-48); }

/* The tick onto the spine, in place of the border-top the shared rule removed.
   It is what the scroll position colours, so it has to be a real mark rather
   than a gap. */
[data-wcs-recipe="layered-credibility-architecture"] .scene-stage::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(var(--space-16) + 0.55em);
  width: var(--space-16);
  height: 1px;
  background: var(--color-rule-dark);
  transition: background-color var(--motion-base) var(--motion-ease);
}

.section-cream [data-wcs-recipe="layered-credibility-architecture"] .scene-stages,
.section-cream-alt [data-wcs-recipe="layered-credibility-architecture"] .scene-stages { border-left-color: var(--color-rule-light); }
.section-cream [data-wcs-recipe="layered-credibility-architecture"] .scene-stage::before,
.section-cream-alt [data-wcs-recipe="layered-credibility-architecture"] .scene-stage::before { background: var(--color-rule-light); }

/* Scroll position, expressed in the same grammar as the shared rule: the mark
   changes colour, it does not light up. This marks position in a sequence and
   must not read as the one stage that matters. */
[data-wcs-recipe="layered-credibility-architecture"][data-wcs-stage="0"] .scene-stage[data-wcs-stage-index="0"]::before,
[data-wcs-recipe="layered-credibility-architecture"][data-wcs-stage="1"] .scene-stage[data-wcs-stage-index="1"]::before,
[data-wcs-recipe="layered-credibility-architecture"][data-wcs-stage="2"] .scene-stage[data-wcs-stage-index="2"]::before,
[data-wcs-recipe="layered-credibility-architecture"][data-wcs-stage="3"] .scene-stage[data-wcs-stage-index="3"]::before {
  background: var(--color-cyan);
  width: var(--space-24);
}

.section-cream [data-wcs-recipe="layered-credibility-architecture"][data-wcs-stage="0"] .scene-stage[data-wcs-stage-index="0"]::before,
.section-cream [data-wcs-recipe="layered-credibility-architecture"][data-wcs-stage="1"] .scene-stage[data-wcs-stage-index="1"]::before,
.section-cream [data-wcs-recipe="layered-credibility-architecture"][data-wcs-stage="2"] .scene-stage[data-wcs-stage-index="2"]::before,
.section-cream [data-wcs-recipe="layered-credibility-architecture"][data-wcs-stage="3"] .scene-stage[data-wcs-stage-index="3"]::before {
  background: var(--color-brass);
}

/* Below the breakpoint the indent stops earning its space: at 390px a 48px
   inset is a quarter of the line. The spine stays, the stepping goes. */
@media (max-width: 720px) {
  [data-wcs-recipe="layered-credibility-architecture"] .scene-stage,
  [data-wcs-recipe="layered-credibility-architecture"] .scene-stage:nth-child(2),
  [data-wcs-recipe="layered-credibility-architecture"] .scene-stage:nth-child(3),
  [data-wcs-recipe="layered-credibility-architecture"] .scene-stage:nth-child(4) {
    padding-left: var(--space-20);
  }
  [data-wcs-recipe="layered-credibility-architecture"] .scene-stage::before { width: var(--space-12); }
}

@media (prefers-reduced-motion: reduce) {
  [data-wcs-recipe="layered-credibility-architecture"] .scene-stage::before { transition: none; }
}

/* ── /revenue-leak-audit: a path, so the list travels ───────
   The scene argues that one enquiry moves through four places and can stall at
   any of them. A stack would be wrong here in the way a row is wrong on
   /systems: it would draw four separate checks instead of one journey.

   So the stages sit on a track, each with a node on a continuous rule, reading
   left to right.

   The stage area was widened to 21:9 here as well, on the reasoning that a
   sectional view is a cutaway along a length. Reverted after looking at it: the
   geometry is sized to its own frame and does not grow into a wider one, so a
   21:9 box put a single centred slab in the middle of six hundred pixels of
   empty ground - a worse version of exactly the complaint being fixed. The
   shared 16:10 stays, and the identity of this route lives in the track. */
[data-wcs-recipe="product-or-service-sectional-view"] .scene-stages {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
  margin-top: var(--space-24);
}

[data-wcs-recipe="product-or-service-sectional-view"] .scene-stage {
  border-top: none;
  padding: var(--space-20) var(--space-20) 0 0;
  position: relative;
}

/* The rule the nodes sit on. Drawn per stage rather than as one background line
   so it wraps correctly when the track collapses to a column on a phone. */
[data-wcs-recipe="product-or-service-sectional-view"] .scene-stage::before {
  content: "";
  position: absolute;
  inset-inline: 0 0;
  top: 0;
  height: 1px;
  background: var(--color-rule-dark);
}

/* The node. The stage the scroll has reached fills it; the others stay open, so
   the track reads as a position along a path rather than a highlight. */
[data-wcs-recipe="product-or-service-sectional-view"] .scene-stage::after {
  content: "";
  position: absolute;
  left: 0;
  top: -3.5px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  border: 1px solid var(--color-rule-dark);
  background: var(--color-navy);
  transition: background-color var(--motion-base) var(--motion-ease),
              border-color var(--motion-base) var(--motion-ease);
}

[data-wcs-recipe="product-or-service-sectional-view"][data-wcs-stage="0"] .scene-stage[data-wcs-stage-index="0"]::after,
[data-wcs-recipe="product-or-service-sectional-view"][data-wcs-stage="1"] .scene-stage[data-wcs-stage-index="1"]::after,
[data-wcs-recipe="product-or-service-sectional-view"][data-wcs-stage="2"] .scene-stage[data-wcs-stage-index="2"]::after,
[data-wcs-recipe="product-or-service-sectional-view"][data-wcs-stage="3"] .scene-stage[data-wcs-stage-index="3"]::after {
  background: var(--color-cyan);
  border-color: var(--color-cyan);
}

.section-cream [data-wcs-recipe="product-or-service-sectional-view"] .scene-stage::before,
.section-cream-alt [data-wcs-recipe="product-or-service-sectional-view"] .scene-stage::before { background: var(--color-rule-light); }
.section-cream [data-wcs-recipe="product-or-service-sectional-view"] .scene-stage::after,
.section-cream-alt [data-wcs-recipe="product-or-service-sectional-view"] .scene-stage::after {
  border-color: var(--color-rule-light);
  background: var(--color-cream);
}

/* On a phone the track turns and runs down the side, which is the same journey
   read in the direction a phone reads. The 21:9 strip also goes: at 390px it
   would be 167px tall and there would be nothing to see in it. */
@media (max-width: 720px) {
  [data-wcs-recipe="product-or-service-sectional-view"] .scene-stages { grid-template-columns: 1fr; }
  [data-wcs-recipe="product-or-service-sectional-view"] .scene-stage {
    padding: var(--space-16) 0 var(--space-16) var(--space-20);
  }
  [data-wcs-recipe="product-or-service-sectional-view"] .scene-stage::before {
    inset-inline: 0 auto;
    top: 0;
    bottom: 0;
    width: 1px;
    height: auto;
  }
  [data-wcs-recipe="product-or-service-sectional-view"] .scene-stage::after {
    left: -3.5px;
    top: var(--space-16);
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-wcs-recipe="product-or-service-sectional-view"] .scene-stage::after { transition: none; }
}

/* ── /fluxlead: a gate, so the flow breaks ──────────────────
   This scene is not arguing a sequence. It is arguing a STOP: preparation runs,
   preparation halts, a person decides, and only then does anything happen. A
   list of four evenly spaced captions says the opposite of that - it says four
   equal steps, which is the reading the whole page exists to prevent.

   So the third stage, the decision, is set apart. Gold, because gold is this
   site's judgement colour and cyan is its signal colour, and the difference is
   the point: the machine signals, the person judges.

   The gap before it is real space rather than a divider. A workflow that pauses
   for a human should look like it pauses. */
[data-wcs-recipe="controlled-workflow-map"] .scene-stages {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-16);
  align-items: start;
}

[data-wcs-recipe="controlled-workflow-map"] .scene-stage:nth-child(3) {
  border-top-color: var(--color-brass);
  padding-left: var(--space-16);
  margin-left: var(--space-8);
}

[data-wcs-recipe="controlled-workflow-map"] .scene-stage:nth-child(3) .scene-stage-label {
  color: var(--color-brass);
}

/* The gate itself: a full-height rule on the decision stage, so the eye reads a
   barrier rather than a wider gap. */
[data-wcs-recipe="controlled-workflow-map"] .scene-stage:nth-child(3)::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: var(--space-4);
  width: 1px;
  background: var(--color-brass);
  opacity: 0.55;
}

[data-wcs-recipe="controlled-workflow-map"] .scene-stage { position: relative; }

/* Everything after the gate is downstream of a human decision, which the
   stage copy states and the rule should not contradict. */
[data-wcs-recipe="controlled-workflow-map"] .scene-stage:nth-child(4) { border-top-color: var(--color-rule-dark); }

/* The scroll marker stays cyan on the machine stages and gold on the gate,
   rather than overwriting the distinction the section is built on. */
[data-wcs-recipe="controlled-workflow-map"][data-wcs-stage="2"] .scene-stage[data-wcs-stage-index="2"] {
  border-top-color: var(--color-brass);
}

@media (max-width: 720px) {
  /* Stacked, the gate reads down the left edge instead of across. The rule
     moves with it; a barrier drawn on the wrong axis is just a stray line. */
  [data-wcs-recipe="controlled-workflow-map"] .scene-stages { grid-template-columns: 1fr; }
  [data-wcs-recipe="controlled-workflow-map"] .scene-stage:nth-child(3) {
    margin-left: 0;
    padding-left: var(--space-16);
  }
}

@media (prefers-reduced-motion: reduce) {
  /* The runtime already lowers the mode. This is the brace to that belt: somebody who asked for less
     motion must not get a poster cross-fading at them either. */
  .scene-poster { transition: none; }
}
