/* ── What it's cost you: the camouflage beat ───────────────────────
   The one place the camouflaged state lives on the site. One pinned
   scroll, driven by a single progress value, --camo-p, 0 → 1:

     0.00–0.26  the pattern lands over ink, shape by shape; the ground cuts
                to orange
     0.30–0.50  full camouflage; the line surfaces, orange on orange → white
     0.55–0.75  the shapes return in ink, one by one, until the ground is
                ink again; the dots turn low contrast
     0.60–0.68  "Most brands are camouflaged." lets go; "Yours probably is."
                stays and settles to the centre
     0.80–0.95  the pattern thins out; the line holds in the clear

   CSS scroll-driven animation owns --camo-p where the browser has view
   timelines. scripts/camo.js feeds the same property everywhere else, so
   a reader who stops halfway sees the page half camouflaged either way.

   Shapes are Olly's solid artwork (reference_assets/camo). Colour and the
   dot matrix are applied here, from tokens. The darker orange in the
   pattern is --color-orange-hover: no new colour. */

@property --camo-p {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

@keyframes camo-progress {
  from { --camo-p: 0; }
  to   { --camo-p: 1; }
}

.camo-track {
  position: relative;
  height: 400vh;
  height: 400svh;
  background-color: var(--color-black);
  view-timeline-name: --camo;
  view-timeline-axis: block;
}

.camo-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  display: grid;
  place-items: center;

  animation: camo-progress linear both;
  animation-timeline: --camo;
  animation-range: contain 0% contain 100%;

  /* Phase factors, resolved here so every child reads the same values */
  --drain: clamp(0, (var(--camo-p) - 0.55) / 0.2, 1);
  --thin: clamp(0, (var(--camo-p) - 0.8) / 0.15, 1);
}

.camo-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Every change in the pattern is a cut, not a fade. Orange faded over ink,
   or ink over orange, passes through brown; a shape that lands whole never
   does. Each shape enters at its own offset, --s, set by a step class. */
.camo-ground {
  fill: var(--color-orange);
  opacity: clamp(0, (var(--camo-p) - 0.26) / 0.004, 1);
}

.camo-shape {
  --in: clamp(0, (var(--camo-p) - var(--s)) / 0.004, 1);
  opacity: var(--in);
}

.camo-shape--dark   { fill: var(--color-orange-hover); }
.camo-shape--bright { fill: var(--color-orange); }

/* The drain: the same shapes return in ink, in reverse order of the build,
   and the ink ground closes the gaps */
.camo-shape--ink {
  fill: var(--color-ink);
}

.camo-cover {
  fill: var(--color-ink);
  opacity: clamp(0, (var(--camo-p) - 0.74) / 0.004, 1);
}

/* Dotted shapes live in a mask, white, so the dots sit on one grid across
   the frame; .camo-dotfield carries the dots themselves */
.camo-shape--dots {
  fill: var(--color-white);
  opacity: calc(var(--in) * (1 - var(--thin)));
}

.camo-dotfield {
  fill: url(#camo-dots);
}

/* Ink dots on orange, draining to a low-contrast grey on ink. Square, on
   the 0/90 axes, snapped to whole pixels by scripts/dot-grid.js. */
.camo-dot {
  shape-rendering: crispEdges;
  fill: color-mix(in srgb, var(--color-white) calc(var(--drain) * 12%), var(--color-ink));
}

.camo-s0  { --s: 0; }
.camo-s1  { --s: 0.022; }
.camo-s2  { --s: 0.044; }
.camo-s3  { --s: 0.066; }
.camo-s4  { --s: 0.088; }
.camo-s5  { --s: 0.11; }
.camo-s6  { --s: 0.132; }
.camo-s7  { --s: 0.154; }
.camo-s8  { --s: 0.176; }
.camo-s9  { --s: 0.198; }
.camo-s10 { --s: 0.22; }
.camo-s11 { --s: 0.242; }

.camo-d0  { --s: 0.56; }
.camo-d1  { --s: 0.5735; }
.camo-d2  { --s: 0.587; }
.camo-d3  { --s: 0.6005; }
.camo-d4  { --s: 0.614; }
.camo-d5  { --s: 0.6275; }
.camo-d6  { --s: 0.641; }
.camo-d7  { --s: 0.6545; }
.camo-d8  { --s: 0.668; }
.camo-d9  { --s: 0.6815; }
.camo-d10 { --s: 0.695; }
.camo-d11 { --s: 0.7085; }
.camo-d12 { --s: 0.722; }

/* The line. Live text from the start: the hidden state is colour only,
   never opacity on the text node. Transparent over ink, then the darker
   orange of the pattern, then white. */
.camo-line {
  position: relative;
  z-index: 1;
  padding-inline: var(--pad-h);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(20px, 5.6vw, 100px);
  line-height: 0.95;
  letter-spacing: -0.03em;
  text-align: center;
  text-wrap: balance;

  --hide: clamp(0, (var(--camo-p) - 0.27) / 0.004, 1);
  --show: clamp(0, (var(--camo-p) - 0.34) / 0.14, 1);
  --line: color-mix(in srgb,
      var(--color-white) calc(var(--show) * 100%),
      color-mix(in srgb, var(--color-orange-hover) calc(var(--hide) * 100%), transparent));
  --let-go: clamp(0, (var(--camo-p) - 0.6) / 0.08, 1);
  --settle: calc(var(--let-go) * var(--let-go) * (3 - 2 * var(--let-go)));
  color: var(--line);
}

.camo-line span {
  display: block;
}

/* On the way out the first sentence lets go and "Yours probably is." stays,
   sliding up half a line to sit alone at the centre */
.camo-line-a {
  color: color-mix(in srgb, var(--line) calc((1 - var(--let-go)) * 100%), transparent);
}

.camo-line-b {
  transform: translateY(calc(var(--settle) * -0.475em));
}

/* ── In the clear ─────────────────────────────────────────────── */
.camo-clear {
  background-color: var(--color-black);
  color: var(--color-white);
  padding: var(--space-lg) var(--pad-h) 0;
  text-align: center;
}

.camo-body {
  max-width: 34em;
  margin: 0 auto;
  font-family: var(--font-body);
  font-weight: 300;
  font-size: clamp(18px, 2vw, 26px);
  line-height: 1.5;
}

/* Reduced motion: no scroll. The full camouflage as a static panel with the
   line already resolved to white, then the clear copy, then Stand Back. */
@media (prefers-reduced-motion: reduce) {
  .camo-track {
    height: auto;
  }

  .camo-stage {
    position: relative;
    animation: none;
    --camo-p: 0.5;
  }
}
