/* APEX site · the idea, where everything lives, the journey flow */

.shead .eyebrow { display: flex; align-items: center; gap: 9px; }
.eyebrow__av { width: 24px; height: 24px; border-radius: 50%; }

/* 01 · the frontend (Telegram) */
/* The phone is a real DOM chat, not a recording. It has to jump to whichever job
   is under the pointer - a clip has no seek - and it has to stay crisp, weigh
   nothing, and carry none of the personal detail the real crops do (this repo is
   public). Words and sources: js/content.js. */
.front__grid { display: grid; grid-template-columns: minmax(270px, .82fr) minmax(0, 1.18fr); gap: clamp(30px, 5vw, 88px); align-items: center; }
.front__stage { display: grid; justify-items: center; gap: 16px; }
.front .phone { height: min(76vh, 700px); }
.front__hint { font-family: var(--mono); font-size: .6rem; line-height: 1.7; color: var(--dim); text-align: center; max-width: 32ch; margin: 0; }

/* the Telegram chrome */
.phone--tg .phone__screen { background: #0e1621; }
.tgbar { position: absolute; inset: 0 0 auto; z-index: 3; height: 56px; display: flex; align-items: center; gap: 8px; padding: 16px 12px 0; background: #17212b; }
.tgbar__back { width: 15px; height: 15px; flex: none; fill: none; stroke: #6ab3f3; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.tgbar__av { width: 26px; height: 26px; border-radius: 50%; flex: none; }
.tgbar__id { display: grid; line-height: 1.25; margin-right: auto; }
.tgbar__id b { font-size: .7rem; color: #fff; }
.tgbar__status { font-family: var(--display); font-style: normal; font-size: .55rem; color: #7d8b99; transition: color .3s; }
.tgbar__status.is-typing { color: #6ab3f3; }
.tgbar__tg { width: 15px; height: 15px; flex: none; }
.tgview { position: absolute; inset: 56px 0 46px; overflow: hidden; }
.tgthread { position: relative; padding: 10px 9px 0; will-change: transform; }
.tgcompose { position: absolute; inset: auto 0 0; z-index: 3; height: 46px; display: flex; align-items: center; gap: 10px; padding: 0 14px 10px; background: #17212b; }
.tgcompose span { flex: 1; font-size: .62rem; color: #6d7a87; }
.tgcompose .ic { width: 16px; height: 16px; color: #6ab3f3; }

/* one chapter per job; the active one is lit, the ones already played stay dim */
.tgchapter { padding-bottom: 14px; }
/* the pill fades with its chapter: left always-on it hangs over an empty screen
   with no messages under it, because the bubbles below are still idle */
.tgday { display: block; width: fit-content; margin: 0 auto 10px; padding: 2px 9px; border-radius: 999px; background: rgba(0, 0, 0, .3); font-family: var(--mono); font-size: .46rem; letter-spacing: .1em; text-transform: uppercase; color: #a8b6c3; opacity: 0; transition: opacity .55s var(--ease); }
.tgchapter[data-state="on"] .tgday { opacity: 1; transition-delay: .12s; }
.tgchapter[data-state="past"] .tgday { opacity: .26; }
.tgmsg {
  max-width: 88%; width: fit-content; margin-bottom: 6px; padding: 6px 9px 4px;
  border-radius: 12px 12px 12px 4px; background: #1e2c3a; font-size: .66rem; line-height: 1.45; color: #e9eef3;
  opacity: 0; transform: translateY(9px); transition: opacity .55s var(--ease), transform .55s var(--ease);
}
.tgmsg--me { margin-left: auto; border-radius: 12px 12px 4px 12px; background: #2b5278; }
.tgchapter[data-state="on"] .tgmsg { opacity: 1; transform: none; transition-delay: calc(var(--i) * .14s + .12s); }
.tgchapter[data-state="past"] .tgmsg { opacity: .26; transform: none; transition-delay: 0s; }
.tgtext { display: block; white-space: pre-wrap; }
.tgtext b { color: #fff; font-weight: 600; }
.tgtext i { color: #a8b6c3; }
.tgwho { display: flex; align-items: center; gap: 5px; margin-bottom: 3px; }
.tgav { width: 14px; height: 14px; border-radius: 50%; }
.tgwho b { font-family: var(--mono); font-size: .48rem; letter-spacing: .1em; color: var(--c); }
.tgtime { display: block; text-align: right; font-family: var(--mono); font-size: .44rem; color: rgba(233, 238, 243, .45); margin-top: 2px; }
.tgvoice { display: flex; align-items: center; gap: 7px; }
.tgvoice .ic { width: 14px; height: 14px; color: #6ab3f3; flex: none; }
.tgwave {
  flex: none; width: 52px; height: 13px; color: #6ab3f3; opacity: .6;
  background: repeating-linear-gradient(90deg, currentColor 0 2px, transparent 2px 5px);
  -webkit-mask-image: radial-gradient(ellipse 52% 100% at 50% 50%, #000 45%, transparent 100%);
  mask-image: radial-gradient(ellipse 52% 100% at 50% 50%, #000 45%, transparent 100%);
}
.tgbtn { display: block; text-align: center; padding: 6px 10px; border-radius: 9px; background: rgba(106, 179, 243, .16); border: 1px solid rgba(106, 179, 243, .4); color: #6ab3f3; font-size: .64rem; }
/* the ratio is declared so the chapter heights don't shift when the shot loads */
.tgphoto { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 9px; margin-bottom: 5px; }

/* the six jobs */
.cases { list-style: none; padding: 0; margin: 0; border-top: 1px solid var(--line); }
.case {
  position: relative; display: grid; grid-template-columns: 46px minmax(0, 1fr) auto; gap: 3px 16px;
  padding: 16px 0; border-bottom: 1px solid var(--line); isolation: isolate; cursor: pointer; transition: padding .55s var(--ease);
}
.case::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: color-mix(in oklab, var(--c) 15%, transparent);
  transform: scaleY(0); transform-origin: bottom; transition: transform .55s var(--ease);
}
.case.is-on { padding-inline: 18px; }
.case.is-on::before { transform: scaleY(1); transform-origin: top; }
.case:focus-visible { outline: 1px solid var(--c); outline-offset: 3px; }
.case__num { grid-row: 1 / 3; font-family: var(--mono); font-size: .72rem; color: var(--dim); padding-top: .3em; transition: color .4s; }
.case.is-on .case__num { color: var(--c); }
.case__title { font-size: clamp(1.05rem, 1.85vw, 1.6rem); font-weight: 700; letter-spacing: -.03em; line-height: 1.1; }
.case__sub { grid-column: 2; font-family: var(--display); font-size: .88rem; color: var(--cream-2); }
.case__when { grid-column: 3; grid-row: 1; font-family: var(--mono); font-size: .58rem; color: var(--dim); white-space: nowrap; padding-top: .45em; }
.case__agents { grid-column: 3; grid-row: 2; display: flex; gap: 12px; justify-content: flex-end; align-items: center; }
.case__agents i { display: inline-flex; align-items: center; gap: 5px; font-style: normal; }
.case__av { width: 20px; height: 20px; border-radius: 50%; }
.case__agents b { font-family: var(--mono); font-size: .53rem; letter-spacing: .1em; color: var(--c); }
.case__bar { position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; overflow: hidden; }
.case__bar i { display: block; height: 100%; background: var(--c); transform: scaleX(0); transform-origin: left; }

/* 02 · the setup — five steps from a bare machine to a working assistant.
   The frames are markup, not screen grabs, for the same reasons as the phone
   above: the official Hermes docs ship no screenshots of the wizard, a borrowed
   one is someone else's machine, and a bitmap carries neither a highlight that
   holds its place at every width nor a hotspot you can hover. Real commands and
   real prompt text (Hermes 0.21.2, hermes_cli/setup.py). Step 04 quotes the real
   SOUL.md, and step 05 is a real capture, which is ours.
   The progress bar is the spine down the step-number gutter: the numbers already
   occupied that column, so the bar costs no layout. Below 900px the gutter is
   gone, so it becomes a 3px five-segment rail that sticks under the nav. */
.setup__lede { max-width: 56ch; color: var(--cream-2); font-size: clamp(1rem, 1.2vw, 1.15rem); margin: -.5em 0 clamp(48px, 7vh, 88px); }
.setup__bar { display: none; }

/* the assembly rig: APEX builds himself as each step passes — body, brain, face,
   a soul, then the ascent. Each layer is a complete stage of the figure, so
   exactly one stage is ever lit; tools/build-rig.py cut them out and put them on
   one shared 900x1125 canvas, feet on a common floor line, and they superimpose
   to the pixel below the neck. That is what the convergence below is built on:
   the stages don't cross-fade like slides, they collapse INTO each other, and
   only the part that actually changed — the head, the armour — reads as moving.
   Transparent art — never re-introduce an opaque backing, a flat field that close
   to the page ink shows up as a rectangle the moment it drifts.
   Sticky, so he stays in view through the steps. */
.setup__grid { display: grid; gap: clamp(28px, 4.5vw, 76px); align-items: start; }
/* the second column exists only once a layer has actually loaded — until the art
   is generated the steps keep the full width instead of facing a dead gap */
.setup__grid.has-rig { grid-template-columns: minmax(0, 1fr) clamp(240px, 27vw, 400px); }
.rig { display: none; }
/* 4:5, matching the exported art — the figures are tall (mane plus full body),
   so a square box would letterbox them and waste the column's width.
   The negative top margin only ever shows on step 01. Everywhere below that the
   rig is stuck at `top`, so the margin just pulls its UNSTUCK position up, and
   step 01 is the one step where that is where it sits — it was starting level with
   the step number, and the art carries 17% headroom above the mane, so the lion
   read as hanging low beside his own heading. */
.setup__grid.has-rig .rig {
  display: block; position: sticky; top: 108px; aspect-ratio: 4 / 5;
  margin-top: clamp(-52px, -3.2vw, -30px);
}

/* Every layer is the same box: a stage, or an effect drawn in percentages of it.
   Three depths, and the stage sits in the middle of them — an effect that has to
   wrap round the figure (the soul, the flames) is two layers, not one, because a
   single layer can't be both behind him and in front. */
.rig__part { position: absolute; inset: 0; z-index: 1; opacity: 0; }
.rig__part > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.rig__fx--back { z-index: 0; }
.rig__fx--front { z-index: 2; }
/* the fallback, and the whole of it when motion is reduced: a plain cross-fade on
   the step's own latch. When the rig converges, motion.js takes opacity over. */
.rig__part { transform: translateY(16px) scale(.97); transition: opacity .8s var(--ease), transform .8s var(--ease); }
.rig__part.is-on { opacity: 1; transform: none; }
/* …and then it owns opacity, transform and filter outright, frame by frame, so
   the transition has to go: it would smear each frame into the next and the
   figure would arrive a beat after the step it belongs to. */
.rig.is-converging .rig__part { transition: none; will-change: opacity, transform, filter; }

/* 02 · the brain lights up. Every number here is the brain's own box on the
   shared canvas — centre 46.9% across, 29.1% down, about 18% wide — so the glow
   sits in the skull's opening and not somewhere near it. Screened rather than
   drawn over: it lights the gold art underneath instead of laying a grey disc on
   top of it. */
.rig__brain { mix-blend-mode: screen; }
.rig__brain i { position: absolute; left: 46.9%; top: 29.1%; transform: translate(-50%, -50%); border-radius: 50%; }
.rig__core { width: 23%; height: 11%; background: radial-gradient(closest-side, rgba(255, 244, 208, .95), rgba(246, 196, 92, .55) 55%, transparent); }
.rig__bloom { width: 52%; height: 32%; background: radial-gradient(closest-side, rgba(233, 173, 79, .45), rgba(233, 173, 79, .12) 55%, transparent); }
/* the shine: a specular band travelling across the core, clipped to the core's own
   ellipse so it never runs out onto the skull. It's the pulse's partner — this
   step's transition has no zoom, so the brain has to be the thing that moves. */
.rig__shine { width: 26%; height: 12.5%; overflow: hidden; }
.rig__shine::before {
  content: ""; position: absolute; inset: -70% -150%;
  background: linear-gradient(104deg, transparent 33%, rgba(255, 255, 255, .95) 50%, transparent 67%);
}

/* 04 · the soul. Still no new art: the armoured stage holds while gold copies of
   HIM light up behind — one blurred wide into a bloom, one tight enough to stay a
   rim on his outline — under turning rays, rings travelling outwards and motes
   drifting up in front. The filter chain turns every opaque pixel gold (black,
   then white, then sepia pushed round to gold) and the blur spreads it past his
   edge. Motion only runs while the step is on. */
.rig__soul::before {
  content: ""; position: absolute; left: 50%; top: 46%; width: 104%; aspect-ratio: 1; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(233, 173, 79, .5), rgba(233, 173, 79, .17) 54%, transparent 80%);
}
.rig__bloomed, .rig__rim { filter: brightness(0) invert(1) sepia(1) saturate(6) hue-rotate(-12deg); }
.rig__bloomed { filter: brightness(0) invert(1) sepia(1) saturate(6) hue-rotate(-12deg) blur(26px); opacity: .95; }
.rig__rim { filter: brightness(0) invert(1) sepia(1) saturate(6) hue-rotate(-12deg) blur(5px); opacity: .8; }
/* a thin repeating fan, masked to a ring so it never reaches his face or the
   frame's corners — at full width it would read as a striped background */
.rig__rays {
  position: absolute; left: 50%; top: 44%; width: 124%; aspect-ratio: 1; transform: translate(-50%, -50%);
  background: repeating-conic-gradient(from 0deg, rgba(255, 214, 130, .32) 0deg 2.4deg, transparent 2.4deg 12deg);
  -webkit-mask-image: radial-gradient(closest-side, transparent 26%, #000 45%, transparent 76%);
          mask-image: radial-gradient(closest-side, transparent 26%, #000 45%, transparent 76%);
}
.rig__ring {
  position: absolute; left: 50%; top: 46%; width: 44%; aspect-ratio: 1; border-radius: 50%;
  border: 1px solid rgba(255, 206, 122, .6); transform: translate(-50%, -50%) scale(.35); opacity: 0;
}
.rig__ring:nth-of-type(2) { animation-delay: 1.9s; }
.rig__motes i {
  position: absolute; left: var(--x); bottom: var(--y); width: 7px; height: 7px; border-radius: 50%;
  background: #fff2cf; box-shadow: 0 0 14px 5px rgba(255, 196, 102, .85); opacity: .75;
}

/* The soul and the ascent in WebGL (js/rigfx.js): one canvas behind him, one in
   front, both reaching well past the column so the rays and the fire have room.
   When it runs, the CSS versions below step aside; they stay as what reduced
   motion and a browser without WebGL get. The brain (step 02) is still CSS. */
.rig__gl { position: absolute; inset: -16% -40% -8% -22%; width: 162%; height: 124%; pointer-events: none; transition: opacity .5s var(--ease); }
/* the body and the armour, built out of points of light (js/rigmorph.js): in
   front of him, the same overhang as the WebGL above so the dust can come from
   beyond the figure. It owns the skeleton's image, not its layer (--build). */
.rig__morph { position: absolute; inset: -16% -40% -8% -22%; width: 162%; height: 124%; z-index: 3; pointer-events: none; }
.rig__part[data-at="0"] > img { opacity: var(--build, 1); }
.rig__gl--back { z-index: 0; }
.rig__gl--front { z-index: 3; }
.rig.has-gl .rig__soul, .rig.has-gl .rig__motes, .rig.has-gl .rig__fire, .rig.has-gl .rig__sparks { display: none; }

/* 05 · the ascent. He has evolved, so the stage itself shakes — on the IMAGE, not
   the layer, because motion.js owns the layer's transform while it converges.
   What makes it read as a power-up rather than a bonfire is the blaze: the same
   trick as the soul's rim, but burnt hot and flickering, so the fire takes HIS
   OUTLINE instead of standing off him in columns. The plume climbs behind that,
   the tongues sit round his feet, and the sparks come off the top in front. */
.rig__blaze {
  filter: brightness(0) invert(1) sepia(1) saturate(9) hue-rotate(-22deg) blur(15px);
  opacity: .92; transform: scale(1.04);
}
/* two gradients, one element: the body's own heat at 62% down, and a crest above
   the mane (the figure's head tops out at 14.7%) so the power reads as going UP
   and not as a lamp behind him. Both are frame percentages, like every other
   position in the rig. */
.rig__plume {
  position: absolute; inset: 0;
  background: radial-gradient(26% 15% at 46% 8%, rgba(255, 240, 190, .45), transparent 72%),
              radial-gradient(40% 33% at 46% 62%, rgba(255, 206, 110, .5), rgba(240, 150, 40, .18) 58%, transparent 82%);
  filter: blur(20px);
}
/* the floor line is 90.7% down the canvas, so the tongues start just under the
   feet; x runs across the figure's own width, never wider */
.rig__flames b {
  position: absolute; left: var(--x); bottom: calc(6% + var(--y)); transform: translate(-50%, 0);
  width: calc(var(--s) * 10%); height: calc(var(--s) * 27%); transform-origin: 50% 100%;
  border-radius: 50% 50% 46% 46% / 74% 74% 26% 26%; filter: blur(3px); opacity: .72;
  background: linear-gradient(to top, rgba(255, 120, 30, 0), rgba(255, 140, 40, .85) 16%,
              rgba(255, 196, 86, .9) 50%, rgba(255, 244, 210, .9) 78%, rgba(255, 255, 255, 0));
}
.rig__sparks i {
  position: absolute; left: var(--x); bottom: var(--y); width: 5px; height: 5px; border-radius: 50%;
  background: #fff6de; box-shadow: 0 0 12px 4px rgba(255, 186, 74, .9); opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .rig__brain.is-on .rig__core { animation: brain-fire 1.5s ease-in-out infinite; }
  .rig__brain.is-on .rig__bloom { animation: brain-fire 3.1s ease-in-out infinite .4s; }
  .rig__brain.is-on .rig__shine::before { animation: brain-shine 3.2s ease-in-out infinite; }
  .rig__soul.is-on .rig__bloomed, .rig__soul.is-on .rig__rim, .rig__soul.is-on::before { animation: soul-breathe 3.6s ease-in-out infinite; }
  .rig__soul.is-on .rig__rays { animation: soul-turn 26s linear infinite; }
  .rig__soul.is-on .rig__ring { animation: soul-wave 3.8s ease-out infinite; }
  .rig__motes i { opacity: 0; }
  .rig__motes.is-on i { animation: soul-rise var(--d) linear var(--w) infinite; }
  .rig__ascend.is-on > img { animation: rig-shake .16s linear infinite; }
  .rig__fire.is-on .rig__blaze { animation: blaze-flicker .5s ease-in-out infinite alternate; }
  .rig__fire.is-on .rig__plume { animation: aura-flare 1.7s ease-in-out infinite; }
  .rig__fire.is-on .rig__flames b { animation: flame-lick 1s ease-in-out infinite var(--w); }
  .rig__sparks.is-on i { animation: spark-fly var(--d) linear var(--w) infinite; }
}
@keyframes soul-breathe { 50% { opacity: .4; } }
@keyframes soul-turn { to { transform: translate(-50%, -50%) rotate(360deg); } }
@keyframes soul-wave {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(.35); }
  18% { opacity: .8; }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.55); }
}
@keyframes soul-rise {
  0% { opacity: 0; transform: translateY(0) scale(.5); }
  20% { opacity: 1; }
  100% { opacity: 0; transform: translateY(var(--rise, -110px)) scale(1.1); }
}
@keyframes brain-fire { 50% { opacity: .42; transform: translate(-50%, -50%) scale(1.14); } }
/* across, hold, and back again — the return pass is what makes it read, since one
   sweep every few seconds is easy to scroll straight past. It still rests at each
   end rather than oscillating without pause, which would read as a scanner. */
@keyframes brain-shine {
  0%, 6% { transform: translateX(-150%); }
  40%, 56% { transform: translateX(150%); }
  90%, 100% { transform: translateX(-150%); }
}
/* small, fast and never square-on: a power hum, not a wobble */
@keyframes rig-shake {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-1.6px, 1px) rotate(-.25deg); }
  40% { transform: translate(1.4px, -1.2px) rotate(.2deg); }
  60% { transform: translate(-1.1px, -.8px) rotate(.18deg); }
  80% { transform: translate(1.5px, .9px) rotate(-.15deg); }
}
@keyframes aura-flare { 50% { opacity: .66; transform: scale(1.06, 1.1); } }
@keyframes blaze-flicker { to { opacity: .68; transform: scale(1.075, 1.045); } }
@keyframes flame-lick {
  0%, 100% { transform: translate(-50%, 0) scale(1, 1); opacity: .8; }
  35% { transform: translate(-50%, -5%) scale(.86, 1.3); opacity: 1; }
  70% { transform: translate(-50%, -2%) scale(1.14, .88); opacity: .66; }
}
@keyframes spark-fly {
  0% { opacity: 0; transform: translateY(0) scale(.4); }
  15% { opacity: 1; }
  100% { opacity: 0; transform: translateY(var(--fly, -190px)) scale(1.15); }
}

.steps { position: relative; display: grid; gap: clamp(62px, 10vh, 124px); }
.spine { position: absolute; left: 21px; top: 10px; bottom: 10px; width: 2px; background: var(--line); }
.spine__fill { display: block; width: 100%; height: 100%; background: var(--gold); transform: scaleY(0); transform-origin: top; }

/* .step's dimming is a CSS opacity transition — never point a GSAP autoAlpha at it */
.step { position: relative; display: grid; grid-template-columns: 76px minmax(0, 1fr); gap: 0 clamp(18px, 2.6vw, 40px); opacity: .42; transition: opacity .6s var(--ease); }
.step.is-on, .step.is-past { opacity: 1; }
.step__n { position: relative; z-index: 1; }
.step__dot {
  display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%;
  background: var(--ink); border: 1px solid var(--line-2); font-family: var(--mono); font-size: .7rem; color: var(--dim);
  transition: background .5s var(--ease), border-color .5s var(--ease), color .5s var(--ease);
}
.step.is-past .step__dot { border-color: var(--gold); color: var(--gold); }
.step.is-on .step__dot { border-color: var(--gold); background: var(--gold); color: var(--ink); }
.step__tag { font-family: var(--mono); font-size: .66rem; letter-spacing: .18em; text-transform: uppercase; color: var(--mint); margin: .55em 0 .6em; }
.step__title { font-size: clamp(1.45rem, 2.7vw, 2.5rem); line-height: 1.06; letter-spacing: -.035em; font-weight: 700; margin: 0 0 .5em; max-width: 21ch; }
.step__lede { color: var(--cream-2); font-size: clamp(.95rem, 1.05vw, 1.08rem); max-width: 58ch; margin: 0 0 30px; }
.step__frames { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; }
.step__frames--two { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }

/* the terminal frame */
.term { border: 1px solid var(--line-2); border-radius: 14px; background: #080e0d; box-shadow: 0 30px 80px rgba(0, 0, 0, .45); }
.term__bar { display: flex; align-items: center; gap: 7px; padding: 11px 15px; border-bottom: 1px solid var(--line); }
.term__bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--line-2); flex: none; }
.term__name { margin-left: 8px; font-family: var(--mono); font-size: .58rem; letter-spacing: .12em; text-transform: uppercase; color: var(--dim); }
.term__logo { width: 22px; height: 22px; flex: none; }
/* sized up on the user's note: the old setting was too small to read at a glance */
.term__body { padding: 20px 22px 22px; font-family: var(--mono); font-size: clamp(.78rem, .92vw, .95rem); line-height: 1.95; }
/* break-word, not anywhere: `anywhere` splits mid-token and chopped commands in half */
.ln { margin: 0; color: var(--cream-2); white-space: pre-wrap; overflow-wrap: break-word; }
.ps { color: var(--mint); margin-right: 9px; }
.ln--out { color: var(--dim); }
.ln--ok { color: var(--mint); }
.ln--warn { color: var(--gold); }
.ln--menu { color: var(--cream); }
.ln--sel { color: var(--gold); }
/* the one line that carries the step's point — meant to read from across a room */
.ln--big { font-size: 1.24em; line-height: 1.55; padding: 3px 0; }
.ln b { color: var(--cream); font-weight: 600; }
.ln mark, .bmsg mark, .term--soul mark { background: rgba(233, 173, 79, .15); color: var(--gold); padding: 1px 5px; border-radius: 4px; -webkit-box-decoration-break: clone; box-decoration-break: clone; }

/* the bot-creation chat: the same frame, wearing Telegram */
.term--tg { background: #0e1621; }
.term--tg .term__bar { background: #17212b; border-radius: 13px 13px 0 0; border-bottom-color: rgba(0, 0, 0, .3); }
.term--tg .term__body { font-family: var(--display); font-size: clamp(.72rem, .85vw, .84rem); line-height: 1.5; display: grid; gap: 7px; justify-items: start; }
.bmsg { max-width: 92%; margin: 0; padding: 7px 10px 6px; border-radius: 12px 12px 12px 4px; background: #1e2c3a; color: #e9eef3; white-space: pre-wrap; overflow-wrap: anywhere; }
.bmsg--me { justify-self: end; border-radius: 12px 12px 4px 12px; background: #2b5278; }
.bmsg b { color: #fff; font-weight: 600; }

/* step 03: the chat, squeezed 10% from its old half-width, with where it keeps
   things beside it. The column is 90% of what a two-up column used to get. */
.step__frames--store { grid-template-columns: calc((100% - 20px) / 2 * .9) auto; justify-content: start; align-items: center; gap: 20px clamp(28px, 4vw, 60px); }
.store { display: grid; gap: 14px; }
.store__label { margin: 0 0 2px; font-family: var(--mono); font-size: .62rem; letter-spacing: .16em; text-transform: uppercase; color: var(--dim); }
.store__item {
  display: flex; align-items: center; gap: 14px; padding: 14px 22px 14px 16px;
  border: 1px solid var(--line-2); border-radius: 14px; background: #080e0d;
}
.store__logo { width: 38px; height: 38px; flex: none; color: var(--cream); }
.store__item b { font-size: clamp(1rem, 1.15vw, 1.15rem); font-weight: 600; color: var(--cream); letter-spacing: -.01em; }

/* step 04: SOUL.md. Prose in the display face, markdown marks in mono, and a warm
   ring round the frame, the page's one nod to glow outside the rig. */
.term--soul { border-color: rgba(233, 173, 79, .34); box-shadow: 0 0 0 1px rgba(233, 173, 79, .06), 0 0 60px rgba(233, 173, 79, .1), 0 30px 80px rgba(0, 0, 0, .45); }
.term--soul .term__body { font-family: var(--display); font-size: clamp(.84rem, .95vw, .98rem); line-height: 1.55; }
.term--soul p { margin: 0; color: var(--cream-2); }
.term--soul b { color: var(--cream); font-weight: 600; }
.term--soul .ps { display: inline-block; min-width: 2em; margin: 0; text-indent: 0; font-family: var(--mono); color: var(--gold); }
.term--soul .soul__lead { font-size: 1.12em; color: var(--cream); margin-bottom: 4px; }
.term--soul .soul__h { margin: 16px 0 6px; font-family: var(--mono); font-size: .8em; letter-spacing: .14em; text-transform: uppercase; color: var(--mint); }
.term--soul .soul__h .ps { min-width: 0; margin-right: 8px; color: var(--mint); }
/* hanging indent, so a wrapped rule lines up under its own text, not the marker */
.term--soul .soul__li { padding: 2px 0 2px 2em; text-indent: -2em; }

/* The hover "?" hotspots and their readout panels were removed on the user's
   note: they made the section verbose, and this audience skims rather than
   hunts. The reasoning now lives in the step's single line — and in what he
   says out loud over the slide. Don't reintroduce them. */

/* the one real capture in this section: just the skills list, cropped from the
   Skills tab. The numbered boxes and legend went with the rest of the tab.
   The header is typeset, not captured, to pass as part of the shot: the panel's
   own ink (#031c1d) and divider (#152e2c) sampled off the capture, its box icon,
   and wide-tracked capitals like its "PERSONAL" title. It sizes in cqw so it
   scales with the image instead of the page. */
.shot2 { margin: 0; }
.shot2__box { position: relative; border-radius: 14px; overflow: hidden; border: 1px solid var(--line-2); box-shadow: 0 30px 80px rgba(0, 0, 0, .5); container-type: inline-size; background: #031c1d; }
/* height: auto, or the height ATTRIBUTE wins and the shot is 469px tall at every
   width; with it, the attributes only supply the ratio, reserved before the file
   arrives (see the note on `w`/`h` in content.js) */
.shot2__box img { width: 100%; height: auto; }
.shot2__head {
  display: flex; align-items: center; gap: 1.3cqw; margin: 0; padding: 2.6cqw 1.5cqw 2.4cqw;
  border-bottom: 1px solid #152e2c; color: #fafbe6;
  font-family: var(--display); font-weight: 600; font-size: 2.3cqw; line-height: 1; letter-spacing: .14em; text-transform: uppercase;
}
.shot2__head .ic { width: 1.05em; height: 1.05em; stroke-width: 1.7; }

@media (max-width: 900px) {
  /* no number gutter left, so the progress bar becomes a rail under the nav */
  .setup__bar { display: flex; gap: 4px; position: sticky; top: 58px; z-index: 5; height: 3px; margin: 0 0 34px; }
  .setup__bar i { flex: 1; background: var(--line); transition: background .45s var(--ease); }
  .setup__bar i.is-on { background: var(--gold); }
  .spine { display: none; }
  .steps { gap: 58px; }
  .step { grid-template-columns: minmax(0, 1fr); opacity: 1; }
  .step__n { margin-bottom: 15px; }
  .step__dot { width: 38px; height: 38px; }
  .step__frames--two, .step__frames--store { grid-template-columns: minmax(0, 1fr); }
  .store { grid-template-columns: repeat(2, minmax(0, max-content)); }
  .store__label { grid-column: 1 / -1; }
  .store__logo { width: 30px; height: 30px; }
  /* the rig is a 30vh band up here, so anything that travels has to travel less
     or it leaves the box before it fades */
  .rig__gl, .rig__morph { inset: 0; width: 100%; height: 100%; }
  .rig__motes i { --rise: -60px; }
  .rig__sparks i { --fly: -95px; }
  /* no room for a column beside the steps: APEX rides along at the top instead,
     sticky under the segment rail, and still gains a part per step. He needs an
     opaque backing or the step text scrolls through him. */
  /* minmax(0, …), not 1fr, here, on .step and on .step__frames: a bare 1fr (or
     an implicit auto track) floors at min-content,
     and the unbreakable install command in step 01 pushed every frame 31px past
     the screen edge */
  .setup__grid.has-rig { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .setup__grid.has-rig .rig {
    order: -1; position: sticky; top: 64px; z-index: 4; height: 30vh; aspect-ratio: auto;
    margin-bottom: 20px; background: var(--ink); box-shadow: 0 14px 22px -10px var(--ink);
  }
}
@media (prefers-reduced-motion: reduce) {
  .spine__fill { transform: scaleY(1); }
}

/* 04 · the journey flow */
.flow { position: relative; margin: clamp(30px, 5vh, 60px) 0 clamp(80px, 13vh, 150px); }
.flow__line { position: absolute; left: 32px; right: 0; top: 15px; width: calc(100% - 32px); height: 34px; overflow: visible; }
.flow__line path { fill: none; stroke: var(--gold); stroke-width: 2; vector-effect: non-scaling-stroke; }
.flow__nodes { position: relative; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(20px, 3vw, 48px); }
.fnode__icon { width: 62px; height: 62px; border-radius: 50%; display: grid; place-items: center; background: var(--ink); border: 1px solid var(--line-2); color: var(--gold); margin-bottom: 24px; }
.fnode__icon .ic { width: 25px; height: 25px; }
.fnode__n { font-family: var(--mono); font-size: .68rem; color: var(--dim); }
.fnode h3 { font-size: clamp(1.3rem, 2vw, 1.9rem); letter-spacing: -.03em; margin: .2em 0 .45em; line-height: 1.05; }
.fnode p { color: var(--cream-2); font-size: .95rem; max-width: 30ch; margin: 0; }
.skillx { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(34px, 5vw, 86px); align-items: center; }
.skillx__shot { position: relative; border-radius: 18px; overflow: hidden; border: 1px solid var(--line-2); box-shadow: 0 40px 110px rgba(0, 0, 0, .55); }
.skillx__shot img { width: 100%; }
.hl { position: absolute; left: .8%; width: 96.5%; border: 2px solid var(--gold); border-radius: 8px; opacity: .25; transition: opacity .45s, box-shadow .6s; }
.hl b { position: absolute; right: 10px; top: -14px; width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; background: var(--gold); color: var(--ink); font-family: var(--mono); font-size: .72rem; }
.hl--1 { top: 23.6%; height: 15.8%; }
.hl--2 { top: 68.8%; height: 23%; }
.skillx__shot[data-hl="1"] .hl--1, .skillx__shot[data-hl="2"] .hl--2 { opacity: 1; box-shadow: 0 0 0 9999px rgba(11, 19, 18, .5); }
.skillx__notes { display: grid; gap: 14px; }
.skillnote {
  display: flex; gap: 16px; text-align: left; background: transparent; border: 1px solid var(--line); border-radius: 18px; padding: 20px 22px;
  color: var(--cream-2); cursor: pointer; transition: border-color .35s, background .35s;
}
.skillnote b { width: 28px; height: 28px; flex: none; border-radius: 50%; display: grid; place-items: center; border: 1px solid var(--line-2); font-family: var(--mono); font-size: .72rem; transition: .35s; }
.skillnote strong { display: block; font-size: 1.1rem; margin-bottom: 5px; letter-spacing: -.02em; }
.skillnote.is-on { border-color: var(--gold); background: rgba(233, 173, 79, .06); }
.skillnote.is-on b { background: var(--gold); border-color: var(--gold); color: var(--ink); }
.selfimprove { display: flex; gap: 16px; padding: 22px; border-radius: 18px; background: var(--ink-3); margin-top: 6px; }
.selfimprove .ic { width: 26px; height: 26px; color: var(--mint); }
.selfimprove p { margin: 0; color: var(--cream-2); font-size: .95rem; }

@media (max-width: 900px) {
  /* The phone stays put while the six jobs scroll past it. Sticky means the rest
     of the grid slides up behind it, so the stage needs its own opaque band -
     full-bleed past the section padding - or the job rows read straight through
     the gaps around the phone. The top padding is the fixed nav's clearance. */
  .front__grid { grid-template-columns: 1fr; gap: 26px; align-items: start; }
  .front__stage {
    position: sticky; top: 0; z-index: 2; background: var(--ink);
    margin-inline: calc(var(--pad) * -1); padding: 58px var(--pad) 16px;
    box-shadow: 0 16px 26px -10px var(--ink);
  }
  .front .phone { height: min(44vh, 360px); }
  .front__hint { display: none; }
  .case { grid-template-columns: 34px 1fr; gap: 4px 14px; padding: 20px 0; }
  .case__when { grid-column: 2; grid-row: 3; padding-top: 7px; }
  .case__agents { grid-column: 2; grid-row: 4; justify-content: flex-start; padding-top: 8px; }
  .skillx { grid-template-columns: 1fr; }
  .flow__line { display: none; }
  .flow__nodes { grid-template-columns: 1fr 1fr; row-gap: 40px; }
}
@media (max-width: 560px) { .flow__nodes { grid-template-columns: 1fr; } }

/* No transform-driven thread here: the chat scrolls like a chat, all of it visible.
   Both !importants are load-bearing. A media query carries no specificity of its
   own, so a plain `.tgchapter .tgmsg` loses to the `[data-state="past"]` rule above
   and the messages stay dimmed to .26; and the transform is written inline by
   GSAP, which no selector can outrank. */
@media (prefers-reduced-motion: reduce) {
  .tgview { overflow-y: auto; }
  .tgthread { transform: none !important; }
  .tgchapter[data-state] .tgmsg { opacity: 1 !important; transform: none !important; }
  .tgchapter[data-state] .tgday { opacity: 1 !important; }
}
