@charset "utf-8";
/* ============================================================================
   ARXEON DESIGN SYSTEM — "PRISM"
   05 · GRAPHICS — mass, depth and artwork
   Requires: arxeon.tokens.css, arxeon.base.css
   Load AFTER arxeon.components.css.
   ----------------------------------------------------------------------------
   WHY THIS FILE EXISTS

   The first four files build an instrument: hairlines, 1px edges, near-black,
   nothing wasted. That reads elegant at the scale of a control and THIN at the
   scale of a page — a 28px logo and a lot of empty dark is not the same thing
   as expensive. Restraint with nothing to be restrained about is just absence.

   So this file gives the system the vocabulary it was missing: real artwork at
   page scale, surfaces with mass, and depth you can move through. The three
   laws do not change — the ground stays colourless, one angle, light not
   paint. There is simply far more of it, and it is much bigger.

   FOUR LAYERS, BACK TO FRONT
     1  .ax-fx-bloom     enormous soft light. hundreds of pixels, not tens.
     2  .ax-fx-field     the mark's own blades at page scale, in three planes.
     2b .ax-fx-scrim     readability. REQUIRED wherever text crosses a field.
     3  .ax-fx-lattice   a 30deg optical lattice — the bench the light sits on.
     4  .ax-fx-beam      a hard 30deg shaft crossing the composition.
   Each is independent, each parallaxes at its own rate, and each is inert
   under prefers-reduced-motion.
   ========================================================================= */

/* ── THE STAGE ────────────────────────────────────────────────────────────
   Any section can become a stage. Layers are absolutely positioned inside
   it and clipped by it, so a bleeding graphic never widens the document. */

.ax-stage {
  position: relative;
  isolation: isolate;
  overflow: clip;              /* clip, not hidden: no scroll container */
}
@supports not (overflow: clip) { .ax-stage { overflow: hidden; } }

.ax-fx {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  will-change: transform;
}
.ax-stage > *:not(.ax-fx) { position: relative; z-index: 1; }


/* ── 1 · BLOOM ────────────────────────────────────────────────────────────
   The caustic field in arxeon.base.css is ambient — 17% alpha spread over
   the whole viewport, felt rather than seen. This is the opposite: a small
   number of very large, very deliberate pools of light, placed. */

/* ROUND 18. This was three pools of coloured light — cyan, violet, indigo —
   blurred 40px and saturated 125%, spanning the whole viewport. Site.Master
   puts one on every page, which made it the single largest coloured object
   on the site and the reason the top-left of every screenshot had a teal
   cast and the bottom had an aubergine one. The token sweep could not reach
   it because it lives in the graphics sheet rather than the component one —
   worth remembering: a system's colour is only as centralised as its least
   central file.

   It is now one pool, no hue at all: white at a few percent, high and left,
   so the page has a top-lit whisper instead of weather. The three-pool
   structure is left readable above in case a future SECTION wants its own
   lighting — which is where a bloom belongs, not behind the entire site. */

.ax-fx-bloom {
  --bloom-a: .055;
  inset: -30% -20%;
  background:
    radial-gradient(46% 52% at 72% 8%, rgb(var(--ax-white-rgb) / var(--bloom-a)), transparent 66%);
  filter: blur(60px);
  transform: translate3d(var(--field-x, 0px), var(--field-y, 0px), 0);
}
.ax-fx-bloom--left {
  background:
    radial-gradient(46% 52% at 20% 10%, rgb(var(--ax-white-rgb) / var(--bloom-a)), transparent 66%);
  filter: blur(60px);
}
.ax-fx-bloom--quiet { --bloom-a: .035; }


/* ── 2 · THE FIELD ────────────────────────────────────────────────────────
   Images/Arxeon-field.svg: seventy-seven blades — the mark's own eleven,
   repeated across seven fans at three depths, every path verbatim from the
   purchased artwork. It bleeds off the top and right on purpose. Artwork
   that is fully contained and centred reads as a logo on a slide; artwork
   that is confidently cropped reads as artwork.

   The DISPERSION copy is the same image again, offset along the 30deg axis,
   blurred and screened — the chromatic fringe a real prism leaves. It is
   what stops the field looking like a flat decal.                        */

.ax-fx-field {
  --field-a: .62;
  --field-x: 0px;
  --field-y: 0px;
  inset: -12% -8%;
  background: url("../Images/Arxeon-field.svg") right top / cover no-repeat;
  opacity: var(--field-a);
  transform: translate3d(var(--field-x), var(--field-y), 0);
  /* THE MASK IS THE COMPOSITION. Without it the field tiles edge to edge and
     reads as wallpaper — heavy, but cheap, and it fights the headline for the
     same pixels. Masked, the artwork occupies the right of the frame and the
     left stays clean for type. Artwork needs a subject and a ground; a
     texture has neither. */
  mask-image:
    linear-gradient(100deg, transparent 4%, rgb(0 0 0 / .35) 34%, #000 72%),
    linear-gradient(#000 0%, #000 62%, transparent 97%);
  -webkit-mask-image:
    linear-gradient(100deg, transparent 4%, rgb(0 0 0 / .35) 34%, #000 72%),
    linear-gradient(#000 0%, #000 62%, transparent 97%);
  /* TWO masks, intersected. The horizontal one composes left-to-right; the
     vertical one stops the artwork ending in a hard horizontal cut at the
     stage's bottom edge, which reads as a clipping bug rather than a fade. */
  mask-composite: intersect;
  -webkit-mask-composite: source-in;
}
.ax-fx-field::after {
  content: "";
  position: absolute;
  inset: 0;
  background: inherit;
  transform: translate3d(14px, -24px, 0);     /* ~30deg from vertical */
  filter: blur(11px) saturate(180%);
  mix-blend-mode: screen;
  opacity: .5;
}
.ax-fx-field--quiet { --field-a: .26; }
.ax-fx-field--loud  { --field-a: .85; }
.ax-fx-field--left  { background-position: left top; transform: scaleX(-1) translate3d(var(--field-x), var(--field-y), 0); }


/* ── 2b · THE SCRIM ───────────────────────────────────────────────────────
   THE LAYER THAT MAKES HEAVY ARTWORK LEGAL.

   Artwork this large lands underneath running text, and measured on the real
   render the hero lead came in at 1.44:1 on a phone and 3.93:1 on a desktop —
   over a bright blade, near-white-on-cyan. "Expensive" and "unreadable" are
   one careless layer apart, so the scrim is not optional dressing: any stage
   whose text overlaps a field MUST carry one.

   It sits above the artwork and below the content — source order decides,
   because every .ax-fx shares z-index -1 — and it darkens only the side the
   type is on, so the composition keeps its subject.                       */

.ax-fx-scrim {
  --scrim-a: .84;
  inset: 0;
  background: linear-gradient(100deg,
      rgb(var(--ax-black-rgb) / var(--scrim-a)) 0%,
      rgb(var(--ax-black-rgb) / calc(var(--scrim-a) * .86)) 30%,
      rgb(var(--ax-black-rgb) / calc(var(--scrim-a) * .40)) 58%,
      transparent 82%);
}
/* Narrow screens have no clean side to hand the artwork, so the scrim turns
   vertical: solid through the text band at the top, releasing underneath. */
@media (max-width: 1023px) {
  .ax-fx-scrim {
    --scrim-a: .90;
    background: linear-gradient(176deg,
        rgb(var(--ax-black-rgb) / var(--scrim-a)) 0%,
        rgb(var(--ax-black-rgb) / calc(var(--scrim-a) * .94)) 58%,
        rgb(var(--ax-black-rgb) / calc(var(--scrim-a) * .40)) 84%,
        transparent 100%);
  }
}
.ax-fx-scrim--soft { --scrim-a: .62; }
.ax-fx-scrim--hard { --scrim-a: .94; }


/* ── 3 · THE LATTICE ──────────────────────────────────────────────────────
   A 30deg optical lattice, two gauges deep. This is the layer that makes the
   page read as an instrument rather than a poster: it is the bench the light
   is sitting on. Barely visible by design — if you can see it without
   looking for it, turn it down.                                          */

.ax-fx-lattice {
  --lat-a: .038;
  inset: -40%;
  transform: skewX(var(--ax-axis)) translate3d(var(--field-x, 0px), var(--field-y, 0px), 0);
  background:
    repeating-linear-gradient(90deg,
      transparent 0 127px,
      rgb(var(--ax-white-rgb) / var(--lat-a)) 127px 128px,
      transparent 128px 254px),
    repeating-linear-gradient(90deg,
      transparent 0 31px,
      rgb(var(--ax-white-rgb) / calc(var(--lat-a) * .34)) 31px 32px,
      transparent 32px 63px);
  mask-image: radial-gradient(64% 58% at 50% 42%, #000 6%, transparent 76%);
  -webkit-mask-image: radial-gradient(64% 58% at 50% 42%, #000 6%, transparent 76%);
}
.ax-fx-lattice--loud { --lat-a: .075; }


/* ── 4 · THE BEAM ─────────────────────────────────────────────────────────
   One hard shaft of light on the brand axis. Use at most once per view — a
   beam is an event, and two events in one composition is a pattern.      */

.ax-fx-beam {
  --beam-x: 62%;
  --beam-w: 210px;
  --beam-a: .12;
  inset: -30% 0;
  overflow: hidden;
}
.ax-fx-beam::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: var(--beam-x);
  inline-size: var(--beam-w);
  transform: skewX(var(--ax-axis));
  background: linear-gradient(90deg,
      transparent,
      rgb(var(--ax-cyan-rgb) / var(--beam-a)) 34%,
      rgb(var(--ax-white-rgb) / calc(var(--beam-a) * .55)) 50%,
      rgb(var(--ax-violet-rgb) / var(--beam-a)) 66%,
      transparent);
  filter: blur(26px);
}


/* ── THE HERO PRISM ───────────────────────────────────────────────────────
   The centrepiece. The mark at poster scale, cropped by the viewport, with
   the dispersion fringe and a bloom behind it. This is the single graphic a
   visitor remembers, so it gets its own component rather than being three
   utility classes stacked by hand on every page.                         */

.ax-prism {
  position: absolute;
  inset-block: -18% -6%;
  inset-inline-end: -14%;
  inline-size: min(66vw, 1180px);
  z-index: -1;
  pointer-events: none;
  background: url("../Images/Arxeon-mark.svg") right center / contain no-repeat;
  opacity: .5;
  filter: drop-shadow(0 0 120px rgb(var(--ax-violet-rgb) / .34));
  transform: translate3d(var(--field-x, 0px), var(--field-y, 0px), 0);
}
.ax-prism::after {
  content: "";
  position: absolute;
  inset: 0;
  background: inherit;
  transform: translate3d(18px, -31px, 0);
  filter: blur(16px) saturate(200%);
  mix-blend-mode: screen;
  opacity: .55;
}
@media (max-width: 1023px) {
  .ax-prism { inline-size: 104vw; inset-inline-end: -34%; inset-block: auto -4%; block-size: 62%; opacity: .34; }
}


/* ── MASS ─────────────────────────────────────────────────────────────────
   .ax-card is a thin surface: one step of lightness, a hairline edge. That
   is correct for a list of eight. It is wrong for a block that has to carry
   a page. .ax-slab is the heavy counterpart — a deeper ground, a real inner
   lip, a much larger radius, and an occlusion shadow with actual spread.  */

.ax-slab {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding: var(--ax-sp-12);
  border-radius: var(--ax-r-3xl);
  border: 1px solid transparent;
  background:
    linear-gradient(168deg, var(--ax-ink-150) 0%, var(--ax-ink-100) 46%, var(--ax-ink-050) 100%) padding-box,
    var(--ax-edge) border-box;
  box-shadow:
    inset 0 1px 0 rgb(var(--ax-white-rgb) / .055),
    inset 0 0 90px -40px rgb(var(--ax-cyan-rgb) / .22),
    var(--ax-el-4);
}
@media (max-width: 767px) { .ax-slab { padding: var(--ax-sp-9); border-radius: var(--ax-r-2xl); } }

.ax-slab::before {            /* the lit top lip, wider than a card's */
  content: "";
  position: absolute;
  inset-inline: 8%;
  inset-block-start: 0;
  block-size: 1px;
  background: var(--ax-grad-hair);
  opacity: .8;
  pointer-events: none;
}
.ax-slab--sunken {
  background:
    linear-gradient(168deg, var(--ax-ink-025), var(--ax-ink-050)) padding-box,
    var(--ax-edge-quiet) border-box;
  box-shadow: inset 0 2px 24px -8px rgb(var(--ax-black-rgb) / .9);
}
.ax-slab--lit {
  background:
    linear-gradient(168deg, var(--ax-ink-200) 0%, var(--ax-ink-100) 55%, var(--ax-ink-050) 100%) padding-box,
    var(--ax-edge-hi) border-box;
  box-shadow:
    inset 0 1px 0 rgb(var(--ax-white-rgb) / .10),
    inset 0 0 120px -30px rgb(var(--ax-cyan-rgb) / .30),
    var(--ax-el-5);
}


/* ── POSTER TYPE ──────────────────────────────────────────────────────────
   The scale ladder tops out at 82px, which is a headline. A hero on a page
   this dark needs a MASS of type — something that behaves like a printed
   sheet rather than a line of text. Two steps above the ladder, both fluid,
   both on the same 1.200 ratio.                                          */

.ax-display-0 {
  font-size: var(--ax-fs-d0);
  line-height: .92;
  letter-spacing: -.038em;
  font-weight: var(--ax-fw-heavy);
  color: var(--ax-text-strong);
  text-wrap: balance;
  margin: 0;
}
.ax-display-00 {
  font-size: var(--ax-fs-d00);
  line-height: .88;
  letter-spacing: -.045em;
  font-weight: var(--ax-fw-heavy);
  color: var(--ax-text-strong);
  text-wrap: balance;
  margin: 0;
}
/* Poster type wants an outline, not a fill, when it is a background element.
   The stroke is the mark's own light rather than a grey. */
.ax-display-hollow {
  color: transparent;
  -webkit-text-stroke: 1px rgb(var(--ax-white-rgb) / .16);
  text-stroke: 1px rgb(var(--ax-white-rgb) / .16);
}


/* ── THE RULE OF EIGHT ────────────────────────────────────────────────────
   A row of eight hairline blades, on the axis, as a section mark. Cheap,
   quiet, and it puts the mark's geometry on a page without putting the logo
   on it eight times.                                                     */

.ax-marks {
  display: flex;
  align-items: flex-end;
  gap: 5px;
  block-size: 26px;
  inline-size: fit-content;
}
.ax-marks i {
  display: block;
  inline-size: 2px;
  border-radius: 2px;
  transform: skewX(var(--ax-axis));
  background: linear-gradient(var(--ax-axis-fill), var(--ax-spec-0), var(--ax-spec-8));
}
.ax-marks i:nth-child(1) { block-size: 100%; }
.ax-marks i:nth-child(2) { block-size: 86%; }
.ax-marks i:nth-child(3) { block-size: 72%; }
.ax-marks i:nth-child(4) { block-size: 59%; }
.ax-marks i:nth-child(5) { block-size: 47%; }
.ax-marks i:nth-child(6) { block-size: 36%; }
.ax-marks i:nth-child(7) { block-size: 26%; }
.ax-marks i:nth-child(8) { block-size: 17%; }


/* ── PARALLAX ─────────────────────────────────────────────────────────────
   arxeon.graphics.js writes --field-y (and --field-x) from scroll position.
   Movement is along the 30deg axis, because everything in this system is.
   The whole mechanism is one rAF-throttled write of two custom properties;
   nothing is measured per frame.                                         */

[data-ax-parallax] { will-change: transform; }
@media (prefers-reduced-motion: reduce) {
  [data-ax-parallax] { transform: none !important; }
  .ax-fx-field, .ax-prism { --field-x: 0px !important; --field-y: 0px !important; }
}


/* ── PRINT / FORCED COLORS ────────────────────────────────────────────── */
@media print { .ax-fx, .ax-prism { display: none !important; } }
@media (forced-colors: active) { .ax-fx, .ax-prism { display: none !important; } }


/* ═══════════════════════════════════════════════════════════════════════════
 *  09 · THE CORRIDOR
 *  ---------------------------------------------------------------------------
 *  THE IDEA. The mark is eleven blades at 30 degrees whose heights decay along
 *  a ramp. A room in one-point perspective is a series of receding planes whose
 *  heights decay along a ramp. They are the same geometry. So the racks ARE the
 *  blades — stood upright and walked through — and each rank carries the next
 *  stop of the mark's own spectrum. Walking the corridor is walking through the
 *  logo. That is why this belongs to Arxeon and to nobody else.
 *
 *  THE ROOM IS NOT SYMMETRICAL. Rounds 7 and 8 built a hallway with a wall on
 *  each side, and the reference is not that: the racks are a single row down
 *  the RIGHT, and the left is open floor and ceiling with nothing on it. That
 *  is also the better page, because the copy owns the left and there is now no
 *  rack light behind it at all.
 *
 *  ── THE FLATTENING, AND WHY EVERY EARLIER ROUND FUDGED THE GEOMETRY ────────
 *  Round 7 measured a wall turned to exactly rotateY(90deg) rendering at ZERO
 *  width and concluded that CSS could not draw a true side wall here, so every
 *  round since tilted the racks to 72 degrees to get a face out of them. That
 *  conclusion was wrong, and the real cause is worth writing down because it is
 *  invisible and it cost three rounds.
 *
 *  Measured again, in this exact nesting, a 190px face at several angles:
 *
 *      rank opacity      72deg     89deg     90deg     100deg    108deg
 *      ----------------------------------------------------------------
 *      1  (true 3D)      2.9px    44.4px    46.8px    69.7px    87.1px
 *      .6 (flattened)   53.2px     3.0px     0.0px    29.9px    53.2px
 *
 *  The second row is |cos(angle)| — an ORTHOGRAPHIC projection, which is what
 *  you get when the 3D context collapses. The rank was animating OPACITY, and
 *  an element with opacity other than 1 is forced to `transform-style: flat`,
 *  which flattens every descendant's rotation into the rank's own plane. The
 *  fade was quietly destroying the room's third dimension for the whole of its
 *  life, and 90deg read as zero because a flattened plane at 90deg really is.
 *
 *  The fix is structural: the rank animates TRANSFORM ONLY and stays at
 *  opacity 1 forever, and the fade moves onto its children, which are leaves
 *  and have no 3D of their own to lose. With that, rotateY(90deg) projects
 *  exactly as perspective says it should — 46.8px at this depth and growing as
 *  the cabinet approaches — so the racks are now TRUE boxes with no fudge in
 *  them anywhere.
 *
 *  ── THE CABINET ───────────────────────────────────────────────────────────
 *  Two real faces meeting at a real corner:
 *
 *      u   the door, at x = half - depth, rotateY(90deg), running the
 *          cabinet's 600mm width straight down the corridor
 *      i   the near end, at z = 0, spanning the cabinet's 1m depth
 *
 *  They share the vertical edge at the corner, which is the brightest line on
 *  the cabinet because it is the one the aisle light catches. Cabinets stand
 *  one metre apart with 600mm bodies, so there is a real gap between them and
 *  you can see down it — a row of boxes, not a wall.
 *
 *  COST. Fourteen ranks x (a frame, a door, an end) plus twelve wires and three
 *  flat washes: 58 elements. Only transform and opacity animate.
 * ═════════════════════════════════════════════════════════════════════════ */

.ax-corridor {
  --cor-persp:   540px;
  --cor-half:    560px;   /* half the ROOM width                            */
  --cor-h:       700px;   /* room height, floor to ceiling                  */
  --cor-far:    5480px;   /* where a rank fades in                          */
  /* THE NEAR PLANE IS THE COMPOSITION. At 420 the scale reaches 4.5x and the
     nearest cabinet alone fills the right half of the frame — you are not
     looking down a row any more, you are standing against one box. At 260 it
     reaches 1.9x: the nearest cabinet runs off the right edge the way it does
     in the photograph and eight more are legible behind it. */
  --cor-near:    260px;   /* where it has finished fading out               */

  /* The cabinet, in the same units the room is in: 1060px reads as about
     3.5m across, so 0.3px per mm. A 600mm rack is 190px wide and a metre deep
     is 290px. --cor-far and --cor-n together put the pitch at 293px, which is
     the one metre centre-to-centre Farhad asked for, so the gap between two
     cabinets is 103px of real daylight. */
  /* THE PROPORTIONS ARE A COMPOSITION DECISION, and they were wrong twice.
     What the eye reads as "a row of racks" is the DOOR — the face that runs
     down the corridor — repeated with gaps. On screen that face is
     x_door * (s_near - s_far) wide while the cabinet's end is depth * s, so at
     a 220px door line and 340px of depth the ends came out six times wider
     than the doors and fourteen of them merged into one dotted panel with
     hairlines in it. Pushing the door line out to 410 and cutting the depth to
     150 makes the two faces about equal: dark side, lit corner, lit door, dark
     side — which is what makes the row countable. */
  --rk-dp:       110px;   /* depth into the right wall                       */
  --rk-w:        280px;   /* width along the corridor — 410px pitch, a gap  */
  --rk-ht:       600px;   /* height (≈ 2 m) in a 700px room                 */
  --u:            16px;   /* ONE RACK UNIT. Every horizontal rhythm on the
                             cabinet is a multiple of this, which is what keeps
                             the indicators on the blades and off the gaps.   */
  --rk-gap:      130px;   /* the daylight between two cabinets               */

  --cor-dur:      34s;
  --cor-n:        14;
  /* Well left of centre, as the reference is: everything right of this ray is
     the rack row, everything left is open floor and ceiling under the copy.
     At 48% the row sat in a band around three-quarters across with dead black
     beyond it; at 40% the nearest cabinets run off the right edge of the frame
     the way they do in the photograph.

     But 40% only clears the copy on a WIDE screen. The copy column is 52% of
     the container at every desktop width, so between 1024 and 1365 a vanishing
     point at 40% puts the ceiling fitting — the brightest thing in the room —
     directly under the lead, measured at rgb(168,189,200) and 1.05:1. So 52%
     is the base and the 40% composition is bought back at 1366 and up. */
  --cor-ox:       52%;
  --cor-oy:       50%;

  position: absolute;
  inset: 0;
  overflow: hidden;
  perspective: var(--cor-persp);
  perspective-origin: var(--cor-ox) var(--cor-oy);
  /* THIS IS FLAT, AND IT MATTERS. It used to preserve 3D, which put the
     scrim, the haze, the deck and the wires into the SAME 3D rendering
     context as the racks — and in a 3D context siblings sort by depth, not by
     document order. The ranks run out to --cor-near, +260px, which is NEARER
     THAN THE SCRIM AT ZERO, so the last stretch of every rank's travel was
     painting in FRONT of the thing that protects the headline. Measured at
     1600 with the index strip hidden: the same seek returned a ground of
     rgb(4,12,18) on some runs and rgb(9,107,160) on others — 6.47:1 or
     1.91:1, decided by how the compositor happened to split the planes that
     frame. Flat here, preserve-3d on __world only: the racks keep their
     depth among themselves, and everything after them in the markup paints
     after them on screen, every frame. */
  transform-style: flat;
  pointer-events: none;
  /* Safari flattens a 3D subtree under some compositing; isolate it. */
  isolation: isolate;
  /* MEASURED against the reference photograph rather than judged. Sampling
     its rack side gives mean luminance 37.7, p90 66, p99 173, max 255 and a
     mean RGB of (6, 41, 102) — a deep BLUE room with blown highlights in it.
     Round 9's first cut measured 6.1 / 16 / 35 / 80 and (4, 6, 11): six times
     too dark, and neutral. This ground is the first of the corrections. */
  background: radial-gradient(72% 64% at var(--cor-ox) var(--cor-oy),
      #1B4A8C 0%, #113265 30%, #091D4E 56%, #04102C 80%, #010512 100%);
}

.ax-corridor__world {
  position: absolute;
  inset-block-start: var(--cor-oy);
  inset-inline-start: var(--cor-ox);
  inline-size: 0;
  block-size: 0;
  transform-style: preserve-3d;
}

/* ── the ranks ───────────────────────────────────────────────────────────── */
/* TRANSFORM ONLY. See the flattening note above: the moment this element's
   opacity leaves 1, every rotation inside it collapses to orthographic and the
   room loses its depth. Nothing may be added here that forces a flat context —
   no opacity, no filter, no mix-blend-mode, no mask. */
.ax-corridor__rank {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  animation: ax-corridor-run var(--cor-dur) linear infinite;
  animation-delay: calc(var(--i) * var(--cor-dur) / var(--cor-n) * -1);
  will-change: transform;
}
@keyframes ax-corridor-run {
  from { transform: translateZ(calc(var(--cor-far) * -1)); }
  to   { transform: translateZ(var(--cor-near)); }
}

/* The fade the rank is no longer allowed to carry. Same clock, same stagger,
   on the leaves — which have no 3D of their own to lose. */
.ax-corridor__rank > * {
  animation: ax-corridor-fade var(--cor-dur) linear infinite;
  animation-delay: calc(var(--i) * var(--cor-dur) / var(--cor-n) * -1);
}
/* The ramps are SHORT on purpose. At 9%–84% roughly a third of the ranks were
   part-transparent at any instant, and because the biggest, nearest cabinet is
   always the one on its way out, the brightest thing in the frame was always
   the thing being faded: measured, it capped the rack side at luminance 82
   against the reference's 255. */
@keyframes ax-corridor-fade {
  0%   { opacity: 0; }
  6%   { opacity: 1; }
  93%  { opacity: 1; }
  100% { opacity: 0; }
}

/* ── THE FRAME ─────────────────────────────────────────────────────────────
   The box the room is made of, at this rank's depth: a rectangle the size of
   the room's cross section, carried by the rank, so perspective scales it,
   moves it and thickens its borders for free. Fourteen of them nested is the
   receding tunnel of glowing frames the reference has overhead.

   No box-shadow on the frame itself. A shadow spreads around all four sides
   and draws a solid rectangle across the room; only the edges are meant to
   exist. */
.ax-corridor__rank b {
  position: absolute;
  inset-inline-start: calc(var(--cor-half) * -1);
  /* THE AISLE, not the whole room. Spanning the full width put the frame's
     right-hand border and its top and bottom rails straight through the rack
     faces, and depth sorting across fourteen separate rank subtrees does not
     reliably put a far frame behind a near cabinet. Ending the frame at the
     rack line removes the question instead of arguing with it: a frame's right
     edge is at 250 * its own scale, a nearer cabinet's door edge at 250 * a
     LARGER scale, so the two can never overlap at any depth. The frame's right
     border now reads as the line where the rack row begins. */
  inline-size: calc(var(--cor-half) * 2 - var(--rk-dp));
  inset-block-start: calc(var(--cor-h) / -2);
  block-size: var(--cor-h);
  box-sizing: border-box;
  border: 2px solid rgb(var(--rk-rgb) / .82);
  border-block-start: 4px solid rgb(var(--ax-white-rgb) / .95);
  border-block-end: 3px solid rgb(var(--rk-rgb) / 1);
  /* A box-shadow IS allowed here, and only here. Round 7's ties were
     scaffolding whose side edges were not meant to exist, so a shadow around
     them drew a solid rectangle across the room. This frame is a rectangle on
     purpose — Farhad asked for "box box design with border glow on ceiling" —
     so a glow spreading off all four edges is the effect, not an artefact. */
  box-shadow: 0 0 26px rgb(var(--rk-rgb) / .40),
              inset 0 0 34px rgb(var(--rk-rgb) / .22);
  /* No right border. There is no post at the rack line in the reference, and
     a nearer frame's right edge correctly occludes the rack faces behind it —
     correct, and it read as a sheet of glass laid over the row. The top and
     bottom rails still cross in front of the far cabinets, which is a ceiling
     beam passing in front of them and is exactly right. */
  border-inline-end: 0;
}

/* The ceiling light, and the only place in this room a box-shadow belongs:
   a fixture glows in every direction, which is exactly what a spread shadow
   does. Inset from the walls so it reads as a fitting rather than a seam. */
.ax-corridor__rank b::before {
  content: "";
  position: absolute;
  inset-inline: 21%;
  inset-block-start: 34px;
  block-size: 11px;
  border-radius: 4px;
  background: linear-gradient(180deg,
      rgb(var(--ax-white-rgb) / 1) 0%,
      rgb(var(--ax-white-rgb) / .78) 52%,
      rgb(var(--rk-rgb) / .66) 100%);
  box-shadow: 0 0 26px 7px rgb(var(--ax-white-rgb) / .40),
              0 0 60px 18px rgb(var(--rk-rgb) / .62),
              0 0 130px 40px rgb(var(--rk-rgb) / .26),
              /* and the wash it throws down the aisle beneath it */
              0 90px 120px -20px rgb(var(--rk-rgb) / .34);
}

/* What it throws back off the floor. */
.ax-corridor__rank b::after {
  content: "";
  position: absolute;
  inset-inline: 21%;
  inset-block-end: 24px;
  block-size: 4px;
  background: linear-gradient(180deg,
      rgb(var(--rk-rgb) / .72) 0%, rgb(var(--rk-rgb) / .18) 70%, transparent 100%);
  box-shadow: 0 0 26px 8px rgb(var(--rk-rgb) / .30);
}

/* ── THE CABINET ───────────────────────────────────────────────────────────
   Both faces share the corner at (half - depth, ·, 0), and in both of them
   local x = 0 IS that corner: on the end face because it is the left edge, on
   the door because the door is hinged there and rotates away from it. One set
   of gradients therefore lights both faces from the same place, which is the
   aisle. */
/* ── THE CABINET ───────────────────────────────────────────────────────────
   Three planes to a rack, and one shared variable behind all of them: the
   cabinet's --u, the height of one rack unit. Every horizontal rhythm in here
   — slot mouths, blade faces, indicator rows, the blink — is a multiple of it,
   which is why the lights always land ON a blade and never in the gap between
   two, without a single hand-placed dot. */
.ax-corridor__rank i,
.ax-corridor__rank u,
.ax-corridor__rank s {
  position: absolute;
  inset-block-start: calc(var(--rk-ht) / -2);
  block-size: var(--rk-ht);
  box-sizing: border-box;
  transform-style: flat;
  backface-visibility: visible;
}

/* THE FLANK — the cabinet's steel side, seen end-on across the aisle.
   No indicators on it at all, and that is the whole point: lights on every
   face gave one unbroken dotted field fourteen ranks deep, which is a wall.
   Dark flank, lit corner, lit door, dark flank is what makes the eye count
   boxes. It carries the cap and the plinth so the cabinet has a top and a
   bottom, and the dark seam the door's bright edge sits against. */
.ax-corridor__rank i {
  inset-inline-start: calc(var(--rk-dp) / -2);
  inline-size: var(--rk-dp);
  transform: translateX(calc(var(--cor-half) - var(--rk-dp) / 2));
  border: 2px solid rgb(var(--ax-white-rgb) / .16);
  border-block-start-color: rgb(var(--ax-white-rgb) / .62);   /* the cap    */
  border-block-end-color:   rgb(var(--ax-black-rgb) / .94);   /* the plinth */
  border-inline-start: 2px solid rgb(var(--ax-black-rgb) / .92);
  background:
    /* a hard specular running down the brushed panel */
    linear-gradient(97deg,
        rgb(var(--ax-white-rgb) / .26) 0 2px,
        rgb(var(--ax-white-rgb) / .10) 2px 7%,
        rgb(var(--ax-white-rgb) / .03) 26%,
        transparent 58%,
        rgb(var(--ax-black-rgb) / .44) 100%),
    /* the brushing itself */
    repeating-linear-gradient(90deg,
        rgb(var(--ax-white-rgb) / .06) 0 1px, transparent 1px 13px),
    /* the perforated ventilation panel — a real hex-ish mesh at this scale,
       and the thing that stops the nearest cabinet presenting a blank sheet
       of card to the camera */
    radial-gradient(circle at 50% 50%,
        rgb(var(--ax-black-rgb) / .80) 0 1.2px, transparent 1.9px),
    radial-gradient(circle at 50% 50%,
        rgb(var(--ax-white-rgb) / .12) 0 .8px, transparent 1.5px),
    /* the pressed vent bands, on the same rack-unit rhythm as the door */
    repeating-linear-gradient(180deg,
        transparent 0 calc(var(--u) * 2),
        rgb(var(--ax-black-rgb) / .50) calc(var(--u) * 2) calc(var(--u) * 2 + 3px),
        rgb(var(--ax-white-rgb) / .13) calc(var(--u) * 2 + 3px) calc(var(--u) * 2 + 5px),
        transparent calc(var(--u) * 2 + 5px) calc(var(--u) * 6)),
    /* the cabinet's own lamps, glowing through from inside the mesh */
    linear-gradient(90deg,
        rgb(var(--rk-rgb) / .22) 0%, rgb(var(--rk-rgb) / .06) 24%, transparent 58%),
    linear-gradient(180deg, #253A69 0%, #17264A 46%, #0D1628 80%, #060B18 100%);
  background-size: auto, auto, 5px 5.6px, 5px 5.6px, auto, auto, auto;
  background-position: 0 0, 0 0, 0 0, 2.5px 2.8px, 0 0, 0 0, 0 0;
}

/* THE DOOR — the glass front, and the face that makes the row.
   Hinged on the corner and running the cabinet's width straight down the
   corridor at rotateY(90deg): a true side plane, no tilt anywhere in it.

   Ten background layers, front of the glass to back of the bay:
     1  the specular streak ON the glass
     2  the bezel's inner lip
     3  amber, 4 white, 5 the rank's own stop — three indicator grids at
        coprime HORIZONTAL periods and rack-unit VERTICAL ones, so the lamps
        scatter without ever falling off a blade
     6  the blade faces, lifted out of the dark
     7  the slot mouths — the recess each blade sits in
     8  THE CABLE BUNDLE, glimpsed through the mouths. It is an SVG because
        cables CURVE and no stack of gradients makes a curve.
     9  the interior falling away from the glass
    10  the body

   Local x = 0 is the near edge, at the corner; local x grows AWAY from the
   camera, which on screen runs right to left, so the gradients read near
   first. */
.ax-corridor__rank u {
  inset-inline-start: 0;
  inline-size: var(--rk-w);
  transform-origin: 0 50%;
  transform: translateX(calc(var(--cor-half) - var(--rk-dp))) rotateY(90deg);
  border-block-start: 3px solid rgb(var(--ax-white-rgb) / .78);
  border-block-end: 3px solid rgb(var(--ax-black-rgb) / .94);
  border-inline-start: 4px solid rgb(var(--ax-white-rgb) / .98);  /* THE CORNER */
  /* The bloom the rack throws into the aisle. A box-shadow on a plane this
     thin spreads in the plane's own space, so it reads as glow around the
     cabinet rather than as a box — the one place in this section where that
     is the effect and not the artefact. */
  box-shadow: 0 0 22px rgb(var(--ax-white-rgb) / .14),
              0 0 46px rgb(var(--rk-rgb) / .52),
              0 0 120px rgb(var(--rk-rgb) / .30),
              0 0 260px rgb(var(--rk-rgb) / .13);
  background:
    /* THE REFLECTION. A sheet of glass in a lit room does not have a soft
       sheen, it has a hard-edged band with the room in it — this one is the
       ceiling run, seen in the door. It is the layer that stops the front
       reading as matte board. */
    linear-gradient(99deg,
        transparent 0 21%,
        rgb(var(--ax-white-rgb) / .30) 23%,
        rgb(var(--ax-white-rgb) / .12) 25%,
        rgb(var(--ax-white-rgb) / .015) 27%,
        transparent 30% 66%,
        rgb(var(--ax-white-rgb) / .16) 68%,
        rgb(var(--ax-white-rgb) / .03) 71%,
        transparent 74% 100%),
    linear-gradient(102deg,
        transparent 0 4%,
        rgb(var(--ax-white-rgb) / .46) 7%,
        rgb(var(--ax-white-rgb) / .16) 10%,
        rgb(var(--ax-white-rgb) / .04) 14%,
        transparent 19% 47%,
        rgb(var(--ax-white-rgb) / .24) 52%,
        rgb(var(--ax-white-rgb) / .05) 57%,
        transparent 62% 100%),
    linear-gradient(180deg,
        rgb(var(--ax-white-rgb) / .30) 0 2px,
        rgb(var(--ax-white-rgb) / .08) 2px 7px,
        transparent 7px calc(100% - 6px),
        rgb(var(--ax-black-rgb) / .40) calc(100% - 6px) 100%),
    linear-gradient(90deg,
        rgb(var(--ax-white-rgb) / .38) 0 2px,
        transparent 2px calc(100% - 4px),
        rgb(var(--ax-white-rgb) / .14) calc(100% - 4px) 100%),
    radial-gradient(circle at 50% 50%,
        rgb(255 176 92 / .95) 0 1.7px, transparent 2.6px),
    radial-gradient(circle at 50% 50%,
        rgb(var(--ax-white-rgb) / 1) 0 1.9px, transparent 2.9px),
    radial-gradient(circle at 50% 50%,
        rgb(var(--rk-rgb) / 1) 0 2.2px, transparent 3.2px),
    repeating-linear-gradient(180deg,
        transparent 0 4px,
        rgb(var(--ax-white-rgb) / .26) 4px 5px,
        rgb(var(--ax-white-rgb) / .13) 5px 9px,
        rgb(var(--ax-white-rgb) / .05) 9px calc(var(--u) - 3px),
        transparent calc(var(--u) - 3px) var(--u)),
    repeating-linear-gradient(180deg,
        rgb(var(--ax-white-rgb) / .34) 0 1px,
        rgb(var(--ax-black-rgb) / .80) 1px 4px,
        transparent 4px calc(var(--u) - 3px),
        rgb(var(--ax-black-rgb) / .60) calc(var(--u) - 3px) var(--u)),
    url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27150%27%20height%3D%27192%27%3E%3Cg%20fill%3D%27none%27%20stroke-linecap%3D%27round%27%3E%3Cpath%20d%3D%27M12%20-8C40%2042%204%2092%2028%20200%27%20stroke%3D%27%230E8FC4%27%20stroke-width%3D%274.5%27%20opacity%3D%270.62%27%2F%3E%3Cpath%20d%3D%27M28%20-8C58%2048%2020%2098%2044%20200%27%20stroke%3D%27%237A3CDC%27%20stroke-width%3D%273.0%27%20opacity%3D%270.5%27%2F%3E%3Cpath%20d%3D%27M46%20-8C18%2052%2062%20102%2036%20200%27%20stroke%3D%27%2316C2E6%27%20stroke-width%3D%272.5%27%20opacity%3D%270.55%27%2F%3E%3Cpath%20d%3D%27M68%20-8C96%2046%2066%2098%2088%20200%27%20stroke%3D%27%230C74B4%27%20stroke-width%3D%274.0%27%20opacity%3D%270.46%27%2F%3E%3Cpath%20d%3D%27M90%20-8C64%2052%20104%20102%2082%20200%27%20stroke%3D%27%239450F0%27%20stroke-width%3D%272.5%27%20opacity%3D%270.5%27%2F%3E%3Cpath%20d%3D%27M112%20-8C138%2048%20108%2098%20130%20200%27%20stroke%3D%27%2314AADC%27%20stroke-width%3D%273.5%27%20opacity%3D%270.52%27%2F%3E%3Cpath%20d%3D%27M134%20-8C110%2050%20144%20100%20124%20200%27%20stroke%3D%27%230E8FC4%27%20stroke-width%3D%272.0%27%20opacity%3D%270.58%27%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
    radial-gradient(130% 96% at 14% 50%,
        transparent 30%, rgb(var(--ax-black-rgb) / .24) 72%, rgb(var(--ax-black-rgb) / .48) 100%),
    linear-gradient(180deg, #33507F 0%, #1F3357 46%, #101A31 100%);
  background-size:
    auto, auto, auto, auto,
    53px var(--u), 37px calc(var(--u) * 3), 23px var(--u),
    auto, auto,
    150px calc(var(--u) * 12),
    auto, auto;
  background-position:
    0 0, 0 0, 0 0, 0 0,
    calc(var(--i) * 13px) calc(var(--u) / 2), calc(var(--i) * 7px) calc(var(--u) / 2),
    calc(var(--i) * -11px) calc(var(--u) / 2),
    0 0, 0 0,
    calc(var(--i) * 29px) calc(var(--i) * 17px),
    0 0, 0 0;
}

/* THE BAY BEHIND — what you see through the metre of daylight between two
   cabinets. Round 9 left it empty and the gaps read as holes cut in the
   picture; it is the back of the aisle, so it carries the same cable bundle
   on a dark wall with a conduit run across it. Hinged where the door ends,
   spanning exactly the gap. */
.ax-corridor__rank s {
  inset-inline-start: 0;
  inline-size: var(--rk-gap);
  transform-origin: 0 50%;
  transform: translateX(calc(var(--cor-half) - var(--rk-dp)))
             translateZ(calc(var(--rk-w) * -1))
             rotateY(90deg);
  background:
    linear-gradient(180deg,
        rgb(var(--rk-rgb) / .34) 0 3px,
        transparent 3px 12%,
        transparent 88%,
        rgb(var(--rk-rgb) / .20) 97% 100%),
    url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27150%27%20height%3D%27192%27%3E%3Cg%20fill%3D%27none%27%20stroke-linecap%3D%27round%27%3E%3Cpath%20d%3D%27M12%20-8C40%2042%204%2092%2028%20200%27%20stroke%3D%27%230E8FC4%27%20stroke-width%3D%274.5%27%20opacity%3D%270.62%27%2F%3E%3Cpath%20d%3D%27M28%20-8C58%2048%2020%2098%2044%20200%27%20stroke%3D%27%237A3CDC%27%20stroke-width%3D%273.0%27%20opacity%3D%270.5%27%2F%3E%3Cpath%20d%3D%27M46%20-8C18%2052%2062%20102%2036%20200%27%20stroke%3D%27%2316C2E6%27%20stroke-width%3D%272.5%27%20opacity%3D%270.55%27%2F%3E%3Cpath%20d%3D%27M68%20-8C96%2046%2066%2098%2088%20200%27%20stroke%3D%27%230C74B4%27%20stroke-width%3D%274.0%27%20opacity%3D%270.46%27%2F%3E%3Cpath%20d%3D%27M90%20-8C64%2052%20104%20102%2082%20200%27%20stroke%3D%27%239450F0%27%20stroke-width%3D%272.5%27%20opacity%3D%270.5%27%2F%3E%3Cpath%20d%3D%27M112%20-8C138%2048%20108%2098%20130%20200%27%20stroke%3D%27%2314AADC%27%20stroke-width%3D%273.5%27%20opacity%3D%270.52%27%2F%3E%3Cpath%20d%3D%27M134%20-8C110%2050%20144%20100%20124%20200%27%20stroke%3D%27%230E8FC4%27%20stroke-width%3D%272.0%27%20opacity%3D%270.58%27%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"),
    linear-gradient(90deg,
        transparent 0%,
        rgb(var(--ax-black-rgb) / .26) 52%,
        rgb(var(--ax-black-rgb) / .56) 100%),
    /* the conduit tray the bundle is dressed into */
    linear-gradient(180deg,
        transparent 0 17%,
        rgb(var(--ax-white-rgb) / .16) 17% 18%,
        rgb(var(--ax-black-rgb) / .50) 18% 22%,
        rgb(var(--ax-white-rgb) / .08) 22% 23%,
        transparent 23% 100%),
    linear-gradient(180deg, #1B3260 0%, #0F1D3C 54%, #060C1C 100%);
  background-size: auto, 118px calc(var(--u) * 9), auto, auto, auto;
  background-position: 0 0, calc(var(--i) * -23px) calc(var(--i) * 31px), 0 0, 0 0, 0 0;
}

/* ── THE BLINK ─────────────────────────────────────────────────────────────
   Round 8 removed blinking altogether because round 7's version ran on
   `steps(7)`, which is a strobe. This is the other way to do it: a second,
   sparser grid of indicators breathing on a slow ease, at a period that is
   different on every rank so fourteen cabinets never pulse together. Opacity
   on a pseudo-element is composited, and nothing here steps. */
.ax-corridor__rank u::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 50% 50%,
        rgb(var(--ax-white-rgb) / 1) 0 2.1px, transparent 3.2px),
    radial-gradient(circle at 50% 50%,
        rgb(var(--rk-rgb) / 1) 0 1.6px, transparent 2.5px);
  background-size: 67px calc(var(--u) * 2), 31px var(--u);
  background-position:
    calc(var(--i) * 11px) calc(var(--u) / 2),
    calc(var(--i) * -7px) calc(var(--u) / 2);
  mask-image: linear-gradient(180deg,
      transparent 6%, #000 24%, #000 72%, transparent 88%);
  -webkit-mask-image: linear-gradient(180deg,
      transparent 6%, #000 24%, #000 72%, transparent 88%);
  mix-blend-mode: screen;
  animation: ax-corridor-blink calc(2.6s + var(--i) * 0.31s) ease-in-out infinite alternate;
  animation-delay: calc(var(--i) * -0.7s);
}
@keyframes ax-corridor-blink {
  from { opacity: .22; }
  to   { opacity: 1; }
}

/* The light the cabinet throws into the aisle. Screen-blended so it adds
   rather than covers — a rack throws light, it does not paint over the room. */
/* ── THE FLOOR REFLECTION ──────────────────────────────────────────────────
   A polished floor is most of why a room like this reads as expensive, and
   there is no floor plane to reflect in — the floor is drawn in 2D. So the
   door simply CONTINUES below its own plinth, flipped, fading, at a fraction
   of the brightness. It sits below the floor line in the door's own vertical
   plane, which from a camera above the floor lands exactly where a reflection
   would: the trick every real-time renderer uses before it can afford rays. */
.ax-corridor__rank u::before {
  content: "";
  position: absolute;
  inset-block-start: 100%;
  inset-inline: 0;
  block-size: 52%;
  transform: scaleY(-1);
  background:
    radial-gradient(circle at 50% 50%,
        rgb(255 176 92 / .70) 0 1.7px, transparent 2.6px),
    radial-gradient(circle at 50% 50%,
        rgb(var(--ax-white-rgb) / .70) 0 1.9px, transparent 2.9px),
    radial-gradient(circle at 50% 50%,
        rgb(var(--rk-rgb) / .90) 0 2.2px, transparent 3.2px),
    repeating-linear-gradient(180deg,
        rgb(var(--rk-rgb) / .16) 0 1px, transparent 1px var(--u)),
    linear-gradient(180deg,
        rgb(var(--rk-rgb) / .30) 0%, rgb(var(--rk-rgb) / .06) 46%, transparent 86%);
  background-size:
    53px var(--u), 37px calc(var(--u) * 3), 23px var(--u), auto, auto;
  background-position:
    calc(var(--i) * 13px) calc(var(--u) / 2), calc(var(--i) * 7px) calc(var(--u) / 2),
    calc(var(--i) * -11px) calc(var(--u) / 2), 0 0, 0 0;
  /* Wet, not mirrored: a reflection loses contrast with distance from the
     object, and none of it survives more than half a cabinet down. */
  mask-image: linear-gradient(180deg, #000 0%, rgb(0 0 0 / .46) 38%, transparent 88%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, rgb(0 0 0 / .46) 38%, transparent 88%);
  mix-blend-mode: screen;
  opacity: .72;
}

/* ── FLOOR AND CEILING, drawn in 2D ─────────────────────────────────────
   Every line that runs away from you passes through the vanishing point, and
   every line across you stays horizontal. A conic gradient centred on the
   vanishing point IS that pencil, exactly. This layer is the fine panel
   jointing; the bright runs are the wires below, and the cross-lines are the
   frames above — together they make the floor read as panels rather than as
   a fan, which is what Farhad asked for. */
.ax-corridor__deck {
  position: absolute;
  inset: 0;
  background: repeating-conic-gradient(from 0deg at var(--cor-ox) var(--cor-oy),
      rgb(var(--ax-cyan-rgb) / .46) 0deg 0.20deg,
      transparent 0.22deg 3.6deg);
  /* THE RACK WEDGE. Both of these layers are drawn in 2D on top of the 3D
     world, so until now the ceiling hatch and the floor runs painted straight
     across the cabinets — the racks looked like glass. In one-point
     perspective a rack's silhouette is bounded by RAYS from the vanishing
     point, and those rays are the same at every depth, so one conic gradient
     centred on the vanishing point removes exactly the region the row of
     cabinets occupies and nothing else. x in [450,560], y in [-300,300] gives
     a half-angle of atan(300/450) = 33.7deg, hence 56.3deg to 123.7deg in
     conic terms, feathered by two degrees on each side. */
  mask-image:
    linear-gradient(180deg,
        transparent 0%,
        #000 calc(var(--cor-oy) - 36%), #000 calc(var(--cor-oy) - 23%),
        transparent calc(var(--cor-oy) - 9%), transparent calc(var(--cor-oy) + 9%),
        #000 calc(var(--cor-oy) + 23%), #000 calc(var(--cor-oy) + 38%),
        transparent 100%),
    radial-gradient(64% 60% at var(--cor-ox) var(--cor-oy),
        transparent 0%, #000 24%, #000 66%, transparent 94%),
    conic-gradient(from 0deg at var(--cor-ox) var(--cor-oy),
        #000 0deg 54deg, transparent 58deg 122deg, #000 126deg 360deg);
  -webkit-mask-image:
    linear-gradient(180deg,
        transparent 0%,
        #000 calc(var(--cor-oy) - 36%), #000 calc(var(--cor-oy) - 23%),
        transparent calc(var(--cor-oy) - 9%), transparent calc(var(--cor-oy) + 9%),
        #000 calc(var(--cor-oy) + 23%), #000 calc(var(--cor-oy) + 38%),
        transparent 100%),
    radial-gradient(64% 60% at var(--cor-ox) var(--cor-oy),
        transparent 0%, #000 24%, #000 66%, transparent 94%),
    conic-gradient(from 0deg at var(--cor-ox) var(--cor-oy),
        #000 0deg 54deg, transparent 58deg 122deg, #000 126deg 360deg);
  mask-composite: intersect;
  -webkit-mask-composite: source-in;
  opacity: .86;
}

/* ── THE WIRE LIGHTS ───────────────────────────────────────────────────────
   The geometry is free. A line that runs the length of a corridor at a fixed
   (x, y) projects to a ray FROM THE VANISHING POINT whose angle is atan2(y, x)
   — the world offset itself, with the depth divided out. So a wire is a div
   rotated about the vanishing point and nothing more, and because the camera
   travels straight down the corridor these lines do not move on screen at all.
   That is not a shortcut; it is what actually happens.

   Eight in the floor and four in the ceiling, because the ceiling now has the
   frames and their fixtures and the floor is where the long runs read.

   Each wire is clipped to a TRIANGLE: a point at the vanishing point widening
   to full thickness at the edge of the frame, which is the one thing a rotated
   rectangle gets wrong. The element is the halo; ::after is the hot core. */
.ax-corridor__wires {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* THE RACK WEDGE. Both of these layers are drawn in 2D on top of the 3D
     world, so until now the ceiling hatch and the floor runs painted straight
     across the cabinets — the racks looked like glass. In one-point
     perspective a rack's silhouette is bounded by RAYS from the vanishing
     point, and those rays are the same at every depth, so one conic gradient
     centred on the vanishing point removes exactly the region the row of
     cabinets occupies and nothing else. x in [450,560], y in [-300,300] gives
     a half-angle of atan(300/450) = 33.7deg, hence 56.3deg to 123.7deg in
     conic terms, feathered by two degrees on each side. */
  mask-image:
    linear-gradient(180deg,
        #000 0%, #000 calc(var(--cor-oy) - 17%),
        rgb(0 0 0 / .22) calc(var(--cor-oy) - 3%),
        rgb(0 0 0 / .22) calc(var(--cor-oy) + 3%),
        #000 calc(var(--cor-oy) + 17%), #000 100%),
    radial-gradient(40% 36% at var(--cor-ox) var(--cor-oy),
        transparent 0%, transparent 12%, #000 52%),
    conic-gradient(from 0deg at var(--cor-ox) var(--cor-oy),
        #000 0deg 54deg, transparent 58deg 122deg, #000 126deg 360deg);
  -webkit-mask-image:
    linear-gradient(180deg,
        #000 0%, #000 calc(var(--cor-oy) - 17%),
        rgb(0 0 0 / .22) calc(var(--cor-oy) - 3%),
        rgb(0 0 0 / .22) calc(var(--cor-oy) + 3%),
        #000 calc(var(--cor-oy) + 17%), #000 100%),
    radial-gradient(40% 36% at var(--cor-ox) var(--cor-oy),
        transparent 0%, transparent 12%, #000 52%),
    conic-gradient(from 0deg at var(--cor-ox) var(--cor-oy),
        #000 0deg 54deg, transparent 58deg 122deg, #000 126deg 360deg);
  mask-composite: intersect;
  -webkit-mask-composite: source-in;
}

.ax-corridor__wires i {
  position: absolute;
  inset-inline-start: var(--cor-ox);
  inset-block-start: var(--cor-oy);
  inline-size: 2600px;
  block-size: 44px;
  margin-block-start: -22px;
  transform-origin: 0 50%;
  transform: rotate(var(--a));
  clip-path: polygon(0 50%, 100% 0, 100% 100%);
  /* The halo. Wide and weak: thin bright lines read as lasers fired across
     the room. A lighting run is a soft field with a hot filament in it. */
  background: linear-gradient(90deg,
      transparent 0%,
      rgb(var(--w-rgb) / 0) 5%,
      rgb(var(--w-rgb) / .30) 26%,
      rgb(var(--w-rgb) / .20) 64%,
      rgb(var(--w-rgb) / .09) 100%);
  mix-blend-mode: screen;
}
.ax-corridor__wires i::after {
  content: "";
  position: absolute;
  inset-block: 43%;
  inset-inline: 0;
  clip-path: polygon(0 50%, 100% 0, 100% 100%);
  background:
    linear-gradient(90deg,
        transparent 0%, rgb(var(--ax-white-rgb) / 0) 4%,
        rgb(var(--ax-white-rgb) / .74) 22%,
        rgb(var(--ax-white-rgb) / .46) 66%,
        rgb(var(--ax-white-rgb) / .24) 100%),
    linear-gradient(90deg,
        transparent 0%, rgb(var(--w-rgb) / 0) 4%,
        rgb(var(--w-rgb) / .90) 21%,
        rgb(var(--w-rgb) / .68) 68%,
        rgb(var(--w-rgb) / .42) 100%);
}

/* A pulse travelling out along the wire, away from the vanishing point, which
   is the direction the room is travelling. It is a transform on a child, so
   it costs one composited layer and cannot tick. */
.ax-corridor__wires i::before {
  content: "";
  position: absolute;
  inset-block: 34%;
  inline-size: 20%;
  inset-inline-start: 0;
  background: linear-gradient(90deg,
      transparent 0%,
      rgb(var(--w-rgb) / .30) 28%,
      rgb(var(--ax-white-rgb) / .44) 52%,
      rgb(var(--w-rgb) / .26) 74%,
      transparent 100%);
  animation: ax-corridor-pulse var(--w-dur, 11s) linear infinite;
  animation-delay: calc(var(--p) * -1s);
  will-change: transform, opacity;
}
@keyframes ax-corridor-pulse {
  0%   { transform: translateX(10%);  opacity: 0; }
  14%  { opacity: .85; }
  64%  { opacity: .50; }
  100% { transform: translateX(440%); opacity: 0; }
}

/* ── depth haze ──────────────────────────────────────────────────────────
   Real distance eats contrast. Without this the far ranks stay as crisp as
   the near ones and the whole thing reads as wallpaper rather than space. The
   second stop is the pool of bounced light on the floor — in the reference the
   floor is the brightest surface in the frame. */
.ax-corridor__haze {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(40% 44% at var(--cor-ox) var(--cor-oy),
        rgb(var(--ax-cyan-rgb) / .34) 0%,
        rgb(var(--ax-azure-rgb) / .14) 42%,
        transparent 76%),
    radial-gradient(54% 26% at var(--cor-ox) 84%,
        rgb(var(--ax-azure-rgb) / .20) 0%,
        rgb(var(--ax-violet-rgb) / .07) 46%,
        transparent 80%),
    radial-gradient(96% 92% at var(--cor-ox) var(--cor-oy),
        transparent 0%, transparent 48%,
        rgb(var(--ax-black-rgb) / .26) 80%,
        rgb(var(--ax-black-rgb) / .60) 100%);
}

/* ── the scrim ───────────────────────────────────────────────────────────
   The system's law: wherever type crosses artwork, this is REQUIRED, and it
   is measured rather than judged. With the racks moved to a single row on the
   right, the ground under the copy is floor and ceiling line-work rather than
   rack light, so this can be far lighter than it was in round 8 — the picture
   is legible under the headline instead of blacked out.

   IT IS NO LONGER PART OF THE CORRIDOR. It used to be the corridor's last
   child, which made it the law over the room and nothing else — and round 11
   put a second piece of artwork, the world map, ABOVE it. Two things went
   wrong with that. The map's own mask became the only thing keeping a white
   dot field off the lead paragraph, which is protection by arrangement rather
   than by rule; and inside the corridor's isolated, three-dimensional layer
   the scrim turned out to be droppable — measured at 1600, three runs in
   seven rasterised the frame with no scrim at all and the floor grid blazing
   straight through the index strip at 1.91:1.

   So it sits at the top of the SECTION now, after every piece of artwork and
   before the copy. Everything the type crosses is underneath it, whatever
   gets added next. */
.ax-hero1__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* This base now governs 1024-1279 only, where the vanishing point is at 52%
     and the copy column reaches 52% as well — the two want the same pixels, so
     the scrim has to be dense right through the column and release hard after
     it. Wider than 1280 it is replaced below, and narrower than 1024 it turns
     vertical. */
  /* RETUNED IN ROUND 12, and most of it went away. These numbers were set
     against a lit server room whose racks reached rgb(28,166,243) right
     through the copy column — they had to be near opaque to hold AA, and the
     price was that the left half of the section was a black rectangle. The
     room is parked; what is under the copy now is a dot field at half opacity
     over a dark sky. At .96 the scrim was burying North America and hiding
     Calgary, which is the one site on the map that is our own address. */
  background: linear-gradient(97deg,
      rgb(var(--ax-black-rgb) / .72) 0%,
      rgb(var(--ax-black-rgb) / .66) 32%,
      rgb(var(--ax-black-rgb) / .56) 50%,
      rgb(var(--ax-black-rgb) / .14) 66%,
      transparent 80%);
}

/* ── the section ─────────────────────────────────────────────────────────── */
/* THE ONE NUMBER THE TWO SECTIONS SHARE. The fall leaves the hero at this
   offset from the container's left edge and the spine picks it up at the same
   offset in the section below, so the two halves meet on the pixel without
   either of them measuring the other. It sits in the page margin, clear of
   the copy, which starts at the container edge. */
/* ── THE SPINE ────────────────────────────────────────────────────────────
   The thread that falls out of the hero does not belong to any one section.
   It runs down the left margin of the whole page and each section taps it:
   section 2 peels a spur off it into the prism, section 3 lets it run past.
   Every section from here gets one of these and the seam problem is solved by
   a class rather than by a negotiation between two neighbours.

   IT IS NOT CALLED ax-rail. That name is already the header's progress bar,
   in arxeon.components.css and in Site.Master — taking it silently restyled
   the header's own rail and left this one looking like it had simply failed
   to render.

   It overshoots a viewport in both directions and the section clips it, so it
   spans the section's padding as well as its content without knowing what
   that padding is. */
.ax-spine {
  position: absolute;
  inset-block: -100vh -100vh;
  /* THE GUTTER IS IN HERE FOR A REASON. An absolutely positioned child is laid
     out against its container's PADDING box, and .ax-container carries the
     page gutter as padding — so a bare -18px here is 18px left of the page,
     not 18px left of the copy, and the section clips it away entirely. The
     hero's half of the thread sits inside the copy, where -18px means what it
     looks like it means; this one has to add the gutter back. */
  inset-inline-start: calc(var(--ax-gutter) - var(--ax-fall-x));
  inline-size: 2px;
  background: rgb(var(--ax-white-rgb) / .8);
  box-shadow: 0 0 10px rgb(var(--ax-white-rgb) / .16);
  pointer-events: none;
  z-index: 0;
}

:root {
  /* A POSITIVE MAGNITUDE, negated at every use site. Held as -18px it read
     fine in inset-inline-start and then silently destroyed
     calc(5% - var(--ax-fall-x)), which expands to "5% - -18px" — not valid
     calc, so the declaration was dropped, the width fell back to auto, and
     the spine rendered at zero pixels wide. It looked exactly like a z-index
     problem for half an hour. */
  --ax-fall-x: 18px;
}

.ax-hero1 {
  position: relative;
  display: grid;
  align-items: center;
  /* dvh, not vh: on iOS Safari the URL bar collapses on first scroll and a vh
     hero grows by ~60px under your finger. That jump is the "dancing". */
  min-block-size: calc(100dvh - 84px);
  padding-block: clamp(4rem, 2rem + 8vw, 8rem);
  overflow: clip;
  isolation: isolate;
}
.ax-hero1 > .ax-container { position: relative; z-index: 2; }

/* NOT a ch measure. `ch` resolves against THIS element's font size, which is
   the 16px body — so 30ch was a 285px column, and the display headline inside
   it wrapped to nine lines and made the hero 1861px tall. The copy column is
   a fraction of the container; the measure is set on the text itself. */
.ax-hero1__copy { max-inline-size: min(46rem, 52%); }
@media (max-width: 1023px) { .ax-hero1__copy { max-inline-size: none; } }

.ax-hero1__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ax-div-1);
}
.ax-hero1__eyebrow::before {
  content: "";
  inline-size: 26px;
  block-size: 2px;
  background: var(--ax-grad-sweep);
}

.ax-hero1__title {
  margin-block: var(--ax-sp-7) 0;
  /* --ax-fs-d0 tops out at 119px, which is a full-bleed poster size. This
     headline lives in a half-width column beside artwork, so it gets its own
     ramp: three lines at 1440, two on a phone. */
  font-size: clamp(2.3rem, 1.1rem + 3.4vw, 4.25rem);
  font-weight: var(--ax-fw-heavy);
  line-height: 1.06;
  letter-spacing: var(--ax-tr-display);
  color: var(--ax-text-strong);
  text-wrap: balance;
}

.ax-hero1__lead {
  margin-block-start: var(--ax-sp-8);
  max-inline-size: 46ch;
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-lead);
  letter-spacing: var(--ax-tr-lead);
  color: var(--ax-text-body);
}

.ax-hero1__row { display: flex; flex-wrap: wrap; gap: var(--ax-sp-5); margin-block-start: var(--ax-sp-10); }

/* The four disciplines as a ticker along the floor of the section — the same
   ramp the corridor is running, stated in words. */
.ax-hero1__index {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ax-sp-4) var(--ax-sp-8);
  margin-block-start: var(--ax-sp-12);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}
.ax-hero1__fall {
  position: relative;
  display: block;
  block-size: 0;
}
/* It starts as a point of light and becomes a line. --ax-fall-x is the one
   number this and section 2's spine have to agree on: both are laid out from
   the container's left edge, so the same offset puts them on the same pixel
   at every width without either measuring anything. */
.ax-hero1__fall::before {
  content: "";
  position: absolute;
  inset-block-start: var(--ax-sp-8);
  inset-inline-start: calc(var(--ax-fall-x) * -1);
  inline-size: 2px;
  block-size: 70vh;
  background: linear-gradient(180deg,
      transparent 0%,
      rgb(var(--ax-white-rgb) / .34) 14%,
      rgb(var(--ax-white-rgb) / .82) 46%,
      rgb(var(--ax-white-rgb) / .9) 100%);
  box-shadow: 0 0 16px rgb(var(--ax-white-rgb) / .22);
}
/* The source. Four disciplines are named on the line directly above this. */
.ax-hero1__fall::after {
  content: "";
  position: absolute;
  inset-block-start: calc(var(--ax-sp-8) - 13px);
  inset-inline-start: calc(var(--ax-fall-x) * -1 - 13px);
  inline-size: 28px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(closest-side,
      rgb(var(--ax-white-rgb) / .5) 0%,
      rgb(var(--ax-spec-2-rgb) / .22) 46%,
      transparent 74%);
}

.ax-hero1__index span { display: inline-flex; align-items: center; gap: var(--ax-sp-4); }
.ax-hero1__index span::before {
  content: "";
  inline-size: 6px; block-size: 6px;
  border-radius: 1px;
  transform: skewX(var(--ax-axis));
  background: var(--div-stop, var(--ax-cyan));
}

/* Wider than 1280 the corridor's rails reach further into the copy column,
   because the aisle is a fixed pixel width and the column is not. Measured at
   1440 the lead sat at 4.37:1 and at 1600 the index strip at 3.95:1 — both
   clean AA failures. The scrim carries further right at those widths. */
@media (min-width: 1280px) {
  .ax-hero1__scrim {
    /* 1280 is the tightest desktop width: the copy column still reaches 52%
       but the vanishing point has not yet moved out to 40%, so the index strip
       at the foot of the column sat over a floor run at rgb(5,52,71) and
       4.34:1. Dense a little further, released a little later. */
    background: linear-gradient(97deg,
        rgb(var(--ax-black-rgb) / .70) 0%,
        rgb(var(--ax-black-rgb) / .64) 34%,
        rgb(var(--ax-black-rgb) / .52) 52%,
        rgb(var(--ax-black-rgb) / .12) 66%,
        transparent 80%);
  }
}

/* ── responsive ──────────────────────────────────────────────────────────── */
/* Wide enough for the copy column and the room not to want the same pixels. */
@media (min-width: 1366px) {
  .ax-corridor { --cor-ox: 40%; }
}
@media (max-width: 1023px) {
  .ax-corridor {
    --cor-ox: 46%; --cor-half: 440px; --cor-h: 580px;
    --cor-persp: 530px; --rk-dp: 240px; --rk-w: 160px; --rk-ht: 500px;
    /* THE PHONE COMPOSITION. Below 1024 the copy moves to the bottom of the
       hero and the scrim turns with it, so a room centred at 50% is a room
       painted entirely behind the headline — measured safe, and invisible.
       Lifting the vanishing point to 36% puts the racks, the ceiling bars and
       the wires in the clear band ABOVE the type instead of under it. Every
       mask in this section is written against --cor-oy, so they all follow. */
    --cor-oy: 36%;
  }
  /* The copy no longer owns the left at these widths — it sits at the bottom —
     so the masks must stop excluding a column that is not there, or half the
     ceiling simply goes missing. The scrim below is what protects the type
     here, and it is measured. */
  .ax-corridor__wires {
    mask-image:
      linear-gradient(180deg,
          #000 0%, #000 calc(var(--cor-oy) - 17%),
          rgb(0 0 0 / .22) calc(var(--cor-oy) - 3%),
          rgb(0 0 0 / .22) calc(var(--cor-oy) + 3%),
          #000 calc(var(--cor-oy) + 17%), #000 100%),
      radial-gradient(40% 36% at var(--cor-ox) var(--cor-oy),
          transparent 0%, transparent 12%, #000 52%);
    -webkit-mask-image:
      linear-gradient(180deg,
          #000 0%, #000 calc(var(--cor-oy) - 17%),
          rgb(0 0 0 / .22) calc(var(--cor-oy) - 3%),
          rgb(0 0 0 / .22) calc(var(--cor-oy) + 3%),
          #000 calc(var(--cor-oy) + 17%), #000 100%),
      radial-gradient(40% 36% at var(--cor-ox) var(--cor-oy),
          transparent 0%, transparent 12%, #000 52%);
  }
  .ax-corridor__deck {
    mask-image:
      linear-gradient(180deg,
          transparent 0%,
          #000 calc(var(--cor-oy) - 30%), #000 calc(var(--cor-oy) - 20%),
          transparent calc(var(--cor-oy) - 8%), transparent calc(var(--cor-oy) + 8%),
          #000 calc(var(--cor-oy) + 20%), #000 calc(var(--cor-oy) + 34%),
          transparent 100%),
      radial-gradient(64% 60% at var(--cor-ox) var(--cor-oy),
          transparent 0%, #000 24%, #000 66%, transparent 94%);
    -webkit-mask-image:
      linear-gradient(180deg,
          transparent 0%,
          #000 calc(var(--cor-oy) - 30%), #000 calc(var(--cor-oy) - 20%),
          transparent calc(var(--cor-oy) - 8%), transparent calc(var(--cor-oy) + 8%),
          #000 calc(var(--cor-oy) + 20%), #000 calc(var(--cor-oy) + 34%),
          transparent 100%),
      radial-gradient(64% 60% at var(--cor-ox) var(--cor-oy),
          transparent 0%, #000 24%, #000 66%, transparent 94%);
  }
  .ax-hero1__scrim {
    /* Measured: a ceiling tie sweeping past put the eyebrow's ground at
       rgb(82,83,85) and the run at 3.61:1 on a 360px screen. The copy sits low
       on a phone, so the scrim has to be dense by the time it reaches it — but
       it now starts far lighter, because the room it is protecting the type
       from has moved up out of the way. */
    background: linear-gradient(180deg,
        rgb(var(--ax-black-rgb) / .06) 0%,
        rgb(var(--ax-black-rgb) / .16) 30%,
        rgb(var(--ax-black-rgb) / .64) 48%,
        rgb(var(--ax-black-rgb) / .86) 64%,
        rgb(var(--ax-black-rgb) / .92) 100%);
  }
  .ax-hero1 { align-items: end; min-block-size: calc(100dvh - 68px); }
  .ax-hero1__copy { max-inline-size: none; }
}
@media (max-width: 639px) {
  /* --cor-n stays 14 at every width. It is the divisor for the stagger, and
     the markup ships fourteen ranks; changing one without the other bunches
     them into a clump with a hole behind it. */
  .ax-corridor {
    --cor-ox: 44%; --cor-half: 350px; --cor-h: 470px; --cor-persp: 430px;
    --rk-dp: 195px; --rk-w: 135px; --rk-ht: 400px;
    /* MEASURED, not chosen. On a 390x844 phone the hero is 776 tall and the
       copy begins 169px down — 21.7% — so the only clear ground is a strip
       across the top. The vanishing point goes INTO that strip at 19% and the
       room is composed as a letterboxed plate above the type, which is the one
       arrangement where a phone gets the picture AND the headline gets 4.5:1.
       Everything below the strip is black on purpose. */
    --cor-oy: 19%;
  }
  .ax-hero1__scrim {
    background: linear-gradient(180deg,
        rgb(var(--ax-black-rgb) / .03) 0%,
        rgb(var(--ax-black-rgb) / .08) 13%,
        rgb(var(--ax-black-rgb) / .56) 20%,
        rgb(var(--ax-black-rgb) / .86) 26%,
        rgb(var(--ax-black-rgb) / .93) 35%,
        rgb(var(--ax-black-rgb) / .93) 100%);
  }
  /* Reclaimed from the gaps, so the plate above has somewhere to be: the
     phone layout had about 90px of dead air between the buttons and the
     index strip that the desktop rhythm does not need down here. */
  .ax-hero1__row { margin-block-start: var(--ax-sp-8); }
  .ax-hero1__index { margin-block-start: var(--ax-sp-8); }
  .ax-hero1__lead { font-size: var(--ax-fs-md); }
}

/* ── motion and capability guards ────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .ax-corridor__rank,
  .ax-corridor__rank > *,
  .ax-corridor__rank i::after,
  .ax-corridor__rank u::after,
  .ax-corridor__wires i::before { animation: none !important; }
  /* The pulses are the one thing with nowhere sensible to stop, so they leave
     rather than freeze mid-wire. */
  .ax-corridor__wires i::before { opacity: 0; }
  /* The fade lives on the leaves now, so frozen they would all sit at zero.
     Give them back their opacity and fan the ranks out in depth, so the still
     is a composed picture rather than a blank corridor. Note the rank itself
     stays at opacity 1 even here — see the flattening note. */
  .ax-corridor__rank > * { opacity: 1; }
  .ax-corridor__rank { transform: translateZ(calc(var(--i) * -290px)); }
  .ax-corridor__rank u::after { opacity: .62; }
}
/* A 3D subtree is the one thing a weak GPU cannot fake. */
@supports not (transform-style: preserve-3d) {
  .ax-corridor__world { display: none; }
}
@media print, (forced-colors: active) { .ax-corridor, .ax-hero1__scrim { display: none; } }


/* Paused while off screen. A 3D subtree animating behind three sections of
   page is pure battery for nothing. */
.ax-corridor.is-paused * { animation-play-state: paused !important; }


/* ═══════════════════════════════════════════════════════════════════════════
   10 · THE WORLD — a component, not a hero
   ───────────────────────────────────────────────────────────────────────────
   Four sites, three continents. Drop it into any section:

     <div class="ax-worldmap" aria-hidden="true">
       <span class="ax-worldmap__field"></span>
       <span class="ax-worldmap__lit">
         <i class="ax-worldmap__sheen"></i>
         <i class="ax-worldmap__wave" style="--x: 18.31%; --y: 20.52%; --d: 0s"></i>
         ... one per site ...
       </span>
       <svg class="ax-worldmap__routes" viewBox="0 0 2400 996"> ... </svg>
       <span class="ax-worldmap__site" style="--x: ...; --y: ...; --c: ...; --d: ..."></span>
     </div>

   It carries its own aspect ratio and positions everything in percentages of
   itself, so a section only has to say how wide it is and where. Section 1's
   placement is at the foot of this block; anything later gets its own.

   ── WHY NOTHING MOVES INSIDE THE SVG ───────────────────────────────────────
   An SVG loaded as a background-image is re-rasterised IN FULL on every frame
   in which anything inside it animates, and these files hold 3,955 vector
   circles. Round 11 ran the sheen and the four waves inside the file and it
   ticked on a fast machine. Measured at 1440, headless:

     animation inside the svg          median frame 100.0ms   ~10fps
     static svg + composited layers    median frame  16.7ms   60fps, locked

   So the artwork is two static files — one to look at, one to mask with — and
   every moving thing is a plain element in the page carrying nothing but a
   transform or an opacity. The compositor moves those without repainting.

   The corollary is a rule: NOTHING may be animated inside Images/arxeon-world*.svg,
   and nothing in this block may animate a property that forces layout or
   paint. transform and opacity only. A width, a background-position or a
   filter here would put the whole dot field back on the paint path.
   ═══════════════════════════════════════════════════════════════════════════ */
.ax-worldmap {
  position: relative;
  /* The reference artwork's own box. It was 2400/996, which squashed every
     continent vertically by 21% — Africa read short and Siberia read like a
     slab. Changing the art without changing this would have stretched it
     instead, so the two belong together. */
  aspect-ratio: 1755 / 925;
  pointer-events: none;
  /* The lit layer screens over the field. Isolating keeps that blend INSIDE
     the component, so the brightest thing the map can do cannot reach the
     page behind it — which is what makes the copy's margins safe. */
  isolation: isolate;
}
.ax-worldmap > * { position: absolute; inset: 0; }

/* Rasterised once and never again. */
.ax-worldmap__field {
  background: url("../Images/arxeon-world.svg") center / contain no-repeat;
}

/* The silhouette of the world, used as a stencil. Everything inside this
   layer is a plain gradient; the mask is what makes it land on continents.
   The mask file carries no graticule on purpose — with it, a moving light
   would run along the latitude lines as well as through the land. */
.ax-worldmap__lit {
  -webkit-mask: url("../Images/arxeon-world-field.svg") center / contain no-repeat;
          mask: url("../Images/arxeon-world-field.svg") center / contain no-repeat;
  overflow: hidden;
  mix-blend-mode: screen;
}
.ax-worldmap__lit > i { position: absolute; display: block; }

/* THE SHEEN. A long band of light crossing west to east once every 17
   seconds. It is a rectangle with a gradient in it — the stencil above turns
   it into the continents lighting up in sequence. */
.ax-worldmap__sheen {
  inset-block: 0;
  inset-inline-start: -34%;
  inline-size: 34%;
  background: linear-gradient(90deg,
      transparent 0%,
      rgb(var(--ax-white-rgb) / .10) 46%,
      rgb(var(--ax-white-rgb) / .78) 78%,
      rgb(var(--ax-white-rgb) / .16) 92%,
      transparent 100%);
  animation: ax-world-sheen 17s linear infinite;
}
@keyframes ax-world-sheen { to { transform: translateX(400%); } }

/* THE WAVE. Each site pushes a ring outward through the dot field — a single
   div with an annular gradient, scaled up and faded out. Because the stencil
   only lets the continents through, what you see is the FIELD lighting up in
   a widening circle rather than a ring drawn over it, and the ring dies the
   moment it runs off the coast. They fire west to east in the order the
   packets arrive, so the map reads as one signal crossing the world rather
   than four lamps blinking. */
.ax-worldmap__wave {
  inset-inline-start: var(--x);
  inset-block-start: var(--y);
  inline-size: 13%;
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(closest-side,
      transparent 58%,
      rgb(var(--ax-white-rgb) / .92) 82%,
      rgb(var(--ax-white-rgb) / .18) 94%,
      transparent 100%);
  animation: ax-world-wave 6.6s cubic-bezier(.16, .72, .3, 1) infinite;
  animation-delay: var(--d);
}
@keyframes ax-world-wave {
  0%   { transform: scale(.06); opacity: 0; }
  7%   { opacity: 1; }
  72%  { opacity: .45; }
  100% { transform: scale(3.4); opacity: 0; }
}

/* THE ROUTES. Four quadratics in the map's own coordinate space. This is the
   one thing here that repaints rather than composites — stroke-dashoffset is
   not a compositor property — but it is four thin paths, not four thousand
   circles, and it measured free. */
.ax-worldmap__routes { inline-size: 100%; block-size: 100%; overflow: visible; }
/* STROKE WIDTHS ARE IN THE MAP'S COORDINATE SPACE, NOT IN PIXELS. The box is
   2400 units wide and lands on about 835 on a 1440 screen, so everything here
   is drawn at roughly 0.35 scale: a 2.2 stroke arrives as three quarters of a
   pixel and all but disappears. These are the numbers that render at the
   weight they look like. */
.ax-worldmap__rt path {
  fill: none;
  stroke: url(#ax-route);
  stroke-width: 5.5;
  opacity: .38;
}
.ax-worldmap__pk path {
  fill: none;
  stroke: #DFF6FF;
  stroke-width: 9;
  stroke-linecap: round;
  stroke-dasharray: 20 980;
  animation: ax-world-flow var(--fd) linear infinite;
  animation-delay: var(--fdl);
}
@keyframes ax-world-flow {
  from { stroke-dashoffset: 1000; }
  to   { stroke-dashoffset: 0; }
}

/* THE SITES. A breathing glow, a white pip and a ring of the division's own
   colour. The glow is the ::before so that it can breathe without taking the
   pip's brightness with it. */
.ax-worldmap__site {
  /* inset:auto first — the blanket rule above stretches every direct child to
     the box, and a site is a point, not a sheet. */
  inset: auto;
  inset-inline-start: var(--x);
  inset-block-start: var(--y);
  inline-size: 12%;
  aspect-ratio: 1;
  translate: -50% -50%;
}
.ax-worldmap__site::before,
.ax-worldmap__site::after { content: ""; position: absolute; border-radius: 50%; }
.ax-worldmap__site::before {
  inset: 0;
  background: radial-gradient(closest-side, var(--c) 0%, transparent 68%);
  opacity: .42;
  animation: ax-world-breathe 6.6s ease-in-out infinite;
  animation-delay: var(--d);
}
@keyframes ax-world-breathe { 0%, 100% { opacity: .34; } 46% { opacity: .8; } }
.ax-worldmap__site::after {
  inset: 46.4%;
  background: rgb(var(--ax-white-rgb));
  box-shadow: 0 0 0 2px var(--c), 0 0 12px 2px var(--c);
}

/* Reduced motion is ONE RULE now, and that is the real prize of moving the
   animation out of the file. It used to need a second copy of the whole map,
   because prefers-reduced-motion does not reach an SVG loaded as a
   background-image — measured, both states, no effect. Now the motion lives
   in the page, where the query works. The waves are left parked at four
   different radii so what a reader who asked for stillness gets is a composed
   picture rather than a blank one. */
@media (prefers-reduced-motion: reduce) {
  .ax-worldmap__sheen,
  .ax-worldmap__wave,
  .ax-worldmap__pk path,
  .ax-worldmap__site::before { animation: none; }
  .ax-worldmap__sheen { opacity: 0; }
  .ax-worldmap__site::before { opacity: .6; }
  .ax-worldmap__wave { opacity: .5; }
  .ax-worldmap__wave:nth-of-type(2) { transform: scale(1.9); }
  .ax-worldmap__wave:nth-of-type(3) { transform: scale(1.1); }
  .ax-worldmap__wave:nth-of-type(4) { transform: scale(2.6); }
  .ax-worldmap__wave:nth-of-type(5) { transform: scale(1.5); }
}
@media print, (forced-colors: active) { .ax-worldmap { display: none; } }


/* ── SECTION 1's placement of it ─────────────────────────────────────────── */

/* The room used to light this section. With the room parked, the ground has
   to carry it: a deep field with the light source sitting BEHIND the Gulf
   cluster, so the brightest part of the picture is the part the map is
   busiest in and the copy sits in the dark half. The second layer is a cool
   bloom off the bottom left, which stops the copy column reading as a flat
   black rectangle. */
.ax-hero1__sky {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(62% 66% at 74% 44%,
        #17417E 0%, #0E2C5E 30%, #071B45 56%, #030C24 80%, #010410 100%),
    radial-gradient(74% 56% at 12% 92%,
        rgb(var(--ax-spec-6-rgb) / .16) 0%, transparent 62%);
}

/* CALGARY IS AT 18.31% OF THE MAP and the copy column reaches 52% of the
   section, so the map's width is not a taste decision: it is whatever keeps
   the head office — the one site on here that is the company's own address —
   clear of the type. Solve it and the answer is about 59% of the viewport,
   which is where these numbers come from. */
.ax-hero1__map {
  /* The COMPONENT is position:relative, so that it can be dropped into normal
     flow in a later section. A hero lays it over the section instead, and has
     to say so — without this it takes a row in the grid and pushes the copy
     off the bottom of the screen, which is exactly what it did. */
  position: absolute;
  z-index: 1;
  inset-block-start: 50%;
  /* RE-SOLVED after the map's box changed from 2400x996 to 1755x925. Same
     width, a fifth TALLER — so at the old 62% it reached further up and down
     into the copy column and took the headline at 1280 and the lead at 1024
     below AA. This is not a taste decision: it is whatever puts Calgary, now
     at 15.32% of the box rather than 18.31%, clear of a copy column that
     reaches 52% of the section. */
  inset-inline-end: -2%;
  inline-size: 56%;
  /* A drift, not a move. Forty-six seconds end to end and about one percent
     of travel — below the threshold where you would call it an animation, and
     above the one where the picture feels dead. It is a transform on a single
     element, so it costs the compositor one matrix and the painter nothing. */
  animation: ax-world-drift 46s ease-in-out infinite alternate;
  /* THE MAP IS KEPT OFF THE COPY BY THIS, NOT BY THE SCRIM. The scrim is a
     blunt instrument — dense enough to protect the headline's whole box, it
     also blacks out the half of the section the reader is looking at, which
     is what round 11 was doing. This is the precise one: the map is simply
     absent across the copy column and arrives at full strength just past it.
     The numbers are solved, not chosen. At 1280 the copy box reaches 52% of
     the section and the map runs 46% to 102%, so the box ends 11% into the
     map — the ramp has to still be dark there and finished before Calgary at
     15.32%. That is the whole of the space this gradient has to work in. */
  -webkit-mask-image: linear-gradient(90deg,
      transparent 0%, rgb(var(--ax-black-rgb) / .08) 7%,
      rgb(var(--ax-black-rgb) / .30) 12%,
      #000 19%, #000 93%, rgb(var(--ax-black-rgb) / .55) 100%);
          mask-image: linear-gradient(90deg,
      transparent 0%, rgb(var(--ax-black-rgb) / .08) 7%,
      rgb(var(--ax-black-rgb) / .30) 12%,
      #000 19%, #000 93%, rgb(var(--ax-black-rgb) / .55) 100%);
}
@keyframes ax-world-drift {
  from { transform: translate3d(0, -50%, 0) scale(1); }
  to   { transform: translate3d(-1.4%, -49%, 0) scale(1.04); }
}

/* The world needs something to stand on or it floats. One soft ellipse under
   it, no edges. */
.ax-hero1__map::after {
  content: "";
  position: absolute;
  inset-block-start: 88%;
  inset-inline: 6% 6%;
  block-size: 26%;
  background: radial-gradient(50% 50% at 50% 0%,
      rgb(var(--ax-spec-4-rgb) / .14) 0%, transparent 72%);
  z-index: -1;
}

@media (min-width: 1366px) {
  .ax-hero1__map { inline-size: 58%; inset-inline-end: -3%; }
}

/* Below 1024 the copy moves to the FLOOR of the section and the map takes the
   top, letterboxed — the arrangement the corridor used, and the strongest
   version of this section. It can run full width here because there is no
   copy beside it to keep clear of. */
@media (max-width: 1023px) {
  .ax-hero1__map {
    inset-block-start: 4%;
    inset-inline: -8% -8%;
    inline-size: auto;
    animation: none;
    transform: none;
    opacity: .9;
    /* The copy is at the FLOOR here, so the map is kept off it vertically
       rather than horizontally. */
    -webkit-mask-image: linear-gradient(180deg,
        transparent 0%, #000 12%, #000 66%, transparent 92%);
            mask-image: linear-gradient(180deg,
        transparent 0%, #000 12%, #000 66%, transparent 92%);
  }
  .ax-hero1__sky {
    background:
      radial-gradient(86% 44% at 56% 18%,
          #17417E 0%, #0E2C5E 32%, #071B45 58%, #030C24 82%, #010410 100%),
      radial-gradient(90% 40% at 50% 100%,
          rgb(var(--ax-spec-6-rgb) / .14) 0%, transparent 64%);
  }
}

/* THE MAP IS ON PHONES NOW. It could not be before: the corridor already owned
   the only clear band, the top quarter above where the eyebrow starts at
   21.7%. With the room parked, that band is the map's, and a phone finally
   gets the picture the desktop gets. */
@media (max-width: 639px) {
  .ax-hero1__map {
    inset-block-start: 1%;
    inset-inline: -26% -26%;
    opacity: .82;
  }
}

/* The hero's own stillness, and it has to live HERE rather than with the
   component's: both rules name .ax-hero1__map, so they carry the same
   specificity and the later one wins — a reduced-motion override written
   above the rule it overrides simply loses, which is what it did. Stopping a
   transform animation also means restoring the transform it was holding: the
   drift keyframes carry the map's vertical centring, so without this the map
   springs to the top of the section the moment the motion stops. */
@media (prefers-reduced-motion: reduce) {
  .ax-hero1__map {
    animation: none;
    transform: translate3d(0, -50%, 0);
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   11 · THE SPLIT — section 2, and the mark doing the work
   ───────────────────────────────────────────────────────────────────────────
   The mark is a spectrum, and a spectrum is what you get when one beam is
   split. So the mark is not printed on this section, it IS this section's
   mechanism: white light arrives from the left edge of the page, passes
   through the eleven blades, and leaves as four coloured rays — one per
   discipline. Each ray then flattens out and becomes the rule that carries
   its row.

   There is not a border anywhere in here. The light is the structure. If a
   row ever needs separating from the one below it, the answer is its ray,
   not a 1px line.

   MOTION. Nothing is scroll-linked and nothing is measured per frame. One
   IntersectionObserver puts .is-in on the stage when it arrives; every reveal
   below is a CSS transition on transform and opacity, which the compositor
   runs without repainting. Afterwards the section is still except for one
   packet of light per ray — four stroke-dashoffset loops, the same technique
   the map uses, and the same caveat: it is the one property in here that
   repaints, and it is affordable because it is four thin paths.
   ═══════════════════════════════════════════════════════════════════════════ */
.ax-split {
  /* THERE IS NO JOIN, BECAUSE THE TWO SECTIONS OVERLAP AND THIS ONE FADES IN.
     Matching a colour to the hero's last row of pixels cannot work: the hero
     ends on a radial, so its bottom edge is a different colour at every x —
     measured at 1440 it runs from near black on the left to rgb(3,9,27) under
     the map. Any single colour here steps against most of that width, which is
     what the line across the page was.

     So this section is pulled UP under the hero by --ax-seam, its top padding
     gives that height back, and its ground starts fully TRANSPARENT and only
     reaches its own ink well below the overlap. For that whole distance you
     are looking at the hero's ground through this one, at every x, with no
     edge anywhere. The hero's bottom is empty below the index strip, so the
     overlap costs no content. */
  --ax-seam: 180px;

  position: relative;
  margin-block-start: calc(var(--ax-seam) * -1);
  padding-block: calc(clamp(6rem, 3rem + 10vw, 11rem) + var(--ax-seam))
                 clamp(6rem, 3rem + 10vw, 11rem);
  overflow: clip;
  isolation: isolate;
  /* NO STEP AT THE TOP EDGE. This section used to start on --ax-ink-050,
     which is a NEUTRAL near-black, while the hero above it ends on #010410,
     which is a BLUE one. Two blacks a few points apart in luminance but a
     long way apart in hue read as a hard line across the page — that was the
     seam. It starts on the hero's exact terminal colour now and takes half
     the section to settle into its own ink, and the hero's bottom-left bloom
     is picked up and carried on at the top-left so the light does not stop
     either. */
  background:
    radial-gradient(52% 58% at 18% 44%, rgb(var(--ax-spec-2-rgb) / .09) 0%, transparent 72%),
    radial-gradient(62% 70% at 88% 84%, rgb(var(--ax-spec-7-rgb) / .08) 0%, transparent 74%),
    radial-gradient(70% 22% at 11% 0%, rgb(var(--ax-spec-6-rgb) / .05) 0%, transparent 76%),
    /* IT MUST REACH FULL OPACITY BEFORE THE HERO'S LAST ROW, and that is the
       whole trick. While this is translucent you are seeing the hero through
       it; the moment the hero ends, whatever it was still contributing
       disappears in a single row — which is a line, however small. Measured:
       opaque only by 1.6x the overlap, that left a step of 7 sitting exactly
       at the hero's edge at every width. Opaque at .96 of it, the hero is
       already contributing nothing by the time it stops. */
    linear-gradient(180deg,
        rgb(0 0 0 / 0) 0px,
        rgb(3 5 11 / .42) calc(var(--ax-seam) * .48),
        rgb(5 7 13 / .9) calc(var(--ax-seam) * .82),
        #05070D calc(var(--ax-seam) * .96),
        var(--ax-ink-050) calc(var(--ax-seam) * 3));
}

/* The container has to be a positioning context for the rail to hang off. */
.ax-split > .ax-container { position: relative; }

.ax-split__head { max-inline-size: min(52rem, 64%); }

.ax-split__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ax-div-2);
}
.ax-split__eyebrow::before {
  content: "";
  inline-size: 26px; block-size: 2px;
  background: var(--ax-grad-sweep);
}

.ax-split__title {
  margin-block: var(--ax-sp-7) 0;
  font-size: clamp(2rem, 1rem + 2.8vw, 3.4rem);
  font-weight: var(--ax-fw-heavy);
  line-height: 1.08;
  letter-spacing: var(--ax-tr-display);
  color: var(--ax-text-strong);
  text-wrap: balance;
}

.ax-split__lead {
  margin-block-start: var(--ax-sp-7);
  max-inline-size: 52ch;
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-lead);
  letter-spacing: var(--ax-tr-lead);
  color: var(--ax-text-body);
}

/* ── the stage ───────────────────────────────────────────────────────────
   Two columns: the optics on the left, the four rows on the right. The rays
   are laid over BOTH, because a ray starts in the first column and ends in
   the second — that is the whole point of them. */
.ax-split__stage {
  position: relative;
  margin-block-start: clamp(3.5rem, 2rem + 5vw, 6rem);
  display: grid;
  /* The gutter is as wide as the fan needs, not as narrow as it can get.
     At 15% the four rays had 40 units of the 1000-unit box to separate in and
     they came out of the prism as a knot; at 22% they leave as four lines you
     can count. */
  grid-template-columns: minmax(150px, 22%) 1fr;
  gap: 0;
}

/* THE OPTICS SPAN THE WHOLE STAGE, not the first column. A ray starts at the
   prism and ends at a row in the other column — penned into the left column
   it has nowhere to go, and the first build drew four near-vertical hairpins
   squeezed into 300px because of exactly that. Absolute, so it is out of the
   grid's flow and the rows keep the grid to themselves. */
.ax-split__optics { position: absolute; inset: 0; z-index: 0; }
.ax-split__rows   { grid-column: 2; position: relative; z-index: 1; }

/* THE BEAM. It starts outside the container, at the left edge of the page,
   so the light is arriving from somewhere rather than starting politely at a
   margin. -50vw is well past the gutter at every width. */
/* THE SPINE — section 2's half of the fall, and the beam in one element.
   It is an L: a left border running up out of the top of the section to catch
   the thread falling out of the hero, and a bottom border running right into
   the prism, with a rounded elbow between them. One element rather than three,
   because a border can turn a corner and a background cannot.

   The vertical reach is 1400px of overshoot — far more than the distance from
   the section's top to here at any width — and the section clips its own
   overflow, so it is cut exactly at the boundary where the hero's half stops.
   The height is 1400px PLUS 12% of the stage, and that 12% is the same figure
   the prism's entry uses, which is what lands the elbow on the beam's line.

   THE BEAM ENDS INSIDE THE MARK. It used to run to 8% of the stage, which on a
   wide screen is past the blades — white went in one side and came out the
   other, and a prism that passes white through is not a prism. */
/* THE SPUR. The rail runs past this section on its way down the page; what
   feeds the prism is a tap off it. That is the physically sensible version —
   a beam splitter takes part of the light and lets the rest through — and it
   is what lets the rail carry on into section 3 instead of stopping halfway
   down section 2 and leaving a gap in the middle of the page.

   The left border is transparent: the rail is already drawing that line. Only
   the bottom border and its share of the rounded corner are painted, so the
   spur reads as peeling away. */
.ax-split__beam {
  position: absolute;
  inset-block-start: calc(12% - 58px);
  inset-inline-start: calc(var(--ax-fall-x) * -1);
  /* to the prism's entry, about a third of the way into the blades */
  inline-size: calc(5% + var(--ax-fall-x));
  block-size: 58px;
  border-inline-start: 2px solid transparent;
  border-block-end: 2px solid rgb(var(--ax-white-rgb) / .86);
  border-end-start-radius: 18px;
  filter: drop-shadow(0 0 7px rgb(var(--ax-white-rgb) / .3));
  /* NOT PART OF THE REVEAL, and that is deliberate. The reveal fires when the
     stage reaches the viewport; the boundary this thing crosses is most of a
     screen further up, so armed it was invisible at the one moment it exists
     for — the reader watched the line fall out of the hero and stop dead. It
     is simply always there. */
}

/* One packet, always in transit, so the sections are tied together even when
   nothing else is moving. It belongs to the RAIL now rather than to the spur,
   because the rail is the thing that runs the length of the page. */
.ax-spine::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inline-size: 2px;
  block-size: 96px;
  background: linear-gradient(180deg,
      transparent 0%, rgb(var(--ax-white-rgb) / .95) 60%, transparent 100%);
  animation: ax-split-fall 7.4s cubic-bezier(.45, 0, .55, 1) infinite;
  animation-delay: var(--spine-d, 0s);
}
@keyframes ax-split-fall {
  0%   { transform: translateY(0); opacity: 0; }
  6%   { opacity: 1; }
  90%  { opacity: 1; }
  100% { transform: translateY(210vh); opacity: 0; }
}
/* The strike. Light hitting glass does not simply stop, it blooms — and the
   bloom is what tells you WHERE in the picture the event happens. */
.ax-split__beam::after {
  content: "";
  position: absolute;
  inset-block-start: 100%;
  inset-inline-end: -48px;
  inline-size: 96px;
  aspect-ratio: 1;
  translate: 0 -50%;
  border-radius: 50%;
  background: radial-gradient(closest-side,
      rgb(var(--ax-white-rgb) / .34) 0%,
      rgb(var(--ax-spec-2-rgb) / .16) 42%,
      transparent 72%);
}
/* NOTHING ARMS THE SPINE. There used to be a scaleX(0) here, left over from
   when this element was a short horizontal beam that drew itself in with the
   rest of the reveal. It survived the rewrite, and since the reveal only fires
   when the STAGE reaches the viewport, the one thing whose whole job is to
   cross a boundary most of a screen higher up was scaled to zero width for
   exactly as long as anyone was looking at that boundary. */

/* THE PRISM. The mark at the size of a machine rather than a logo. */
/* THE PRISM SITS AT THE TOP, not the middle. Four rays leaving a centred
   prism have to climb or fall half the height of the section before they can
   run, and at this aspect that is a hairpin. From the top they descend a
   narrow trunk down the gutter and peel off one at a time — which is both
   easier to draw and the truer picture: a bundle of light with a discipline
   leaving it at each floor. */
.ax-split__prism {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  /* AN INSTRUMENT, NOT A DECAL. At 168px against a 1360px stage the mark was
     a sticker in the corner — too small to be the thing that split anything.
     It fills its own column now, and it is TALL enough that the four rays can
     leave it at four different heights, which is what puts each one in its own
     colour. */
  inline-size: 17%;
  min-inline-size: 118px;
  max-inline-size: 246px;
  aspect-ratio: 1377.4 / 1220.9;
  overflow: visible;
}
.ax-split__blade {
  fill: url(#ax-blade);
  transform-origin: 50% 50%;
  transition:
    opacity .5s var(--ax-ease-out),
    transform .7s var(--ax-ease-out);
  /* The blades light in sequence, left to right, as the beam reaches them.
     --b is the blade's index in the stack. */
  transition-delay: calc(700ms + var(--b) * 46ms);
}
.ax-split__stage.is-armed .ax-split__blade { opacity: 0; transform: translateY(14px); }
.ax-split__stage.is-in    .ax-split__blade { opacity: 1; transform: translateY(0); }

/* ── the rays ────────────────────────────────────────────────────────────
   One box laid over the whole stage. preserveAspectRatio is none so the four
   ends stay pinned to the four rows however tall the rows turn out to be;
   non-scaling-stroke is what keeps that stretch from making the horizontal
   runs fat and the curves thin. */
.ax-split__rays {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  overflow: visible;
  pointer-events: none;
}
.ax-split__rt path {
  fill: none;
  stroke: var(--c);
  stroke-width: 1.6;
  opacity: .55;
  /* LONGER THAN ANY RAY CAN POSSIBLY BE, and deliberately not normalised.
     pathLength does not help here: these paths carry non-scaling-stroke, and
     with that set Chromium measures dash lengths in SCREEN space while
     pathLength normalises USER space, so the two disagree and the long rays
     came up two thirds short. A dash nobody can outgrow has no such argument
     with anything. The cost is that a longer ray draws in at the same rate
     rather than in the same time, which is the right way round anyway. */
  stroke-dasharray: 3000;
  transition: stroke-dashoffset 2.2s var(--ax-ease-out);
}
.ax-split__rt path:nth-child(1) { transition-delay: 1180ms; }
.ax-split__rt path:nth-child(2) { transition-delay: 1300ms; }
.ax-split__rt path:nth-child(3) { transition-delay: 1420ms; }
.ax-split__rt path:nth-child(4) { transition-delay: 1540ms; }
.ax-split__stage.is-armed .ax-split__rt path { stroke-dashoffset: 3000; }
.ax-split__stage.is-in    .ax-split__rt path { stroke-dashoffset: 0; }

/* One packet per ray, and they are the only thing still moving once the
   section has settled. */
.ax-split__pk path {
  fill: none;
  stroke: rgb(var(--ax-white-rgb) / .92);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-dasharray: 14 986;
  transition: opacity .8s linear 2.3s;
  animation: ax-split-flow var(--fd) linear infinite;
  animation-delay: var(--fdl);
}
.ax-split__stage.is-armed .ax-split__pk path { opacity: 0; animation-play-state: paused; }
.ax-split__stage.is-in    .ax-split__pk path { opacity: 1; animation-play-state: running; }
@keyframes ax-split-flow {
  from { stroke-dashoffset: 1000; }
  to   { stroke-dashoffset: 0; }
}

/* ── the four rows ───────────────────────────────────────────────────────
   Equal rows, so the rays have four known heights to land on: 1fr rows all
   take the height of the tallest, which is what pins the ray ends at 12, 112,
   212 and 312 of the 400-unit box. Change this to auto and the rays miss. */
.ax-split__rows {
  display: grid;
  grid-template-rows: repeat(4, 1fr);
  margin: 0;
  padding: 0;
  list-style: none;
}

.ax-split__row {
  position: relative;
  padding-block: clamp(1.3rem, .9rem + 1.2vw, 2rem) clamp(1.5rem, 1rem + 1.6vw, 2.4rem);
  padding-inline-start: clamp(1.5rem, .6rem + 2vw, 3rem);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "no   name   tags"
    "no   kicker tags"
    "body body   body"
    "more more   more";
  column-gap: clamp(1rem, .4rem + 1.2vw, 1.8rem);
  transition:
    opacity .7s var(--ax-ease-out),
    transform .7s var(--ax-ease-out);
  transition-delay: calc(1500ms + var(--r) * 140ms);
}
.ax-split__stage.is-armed .ax-split__row { opacity: 0; transform: translateX(-18px); }
.ax-split__stage.is-in    .ax-split__row { opacity: 1; transform: translateX(0); }

.ax-split__no {
  grid-area: no;
  align-self: start;
  font-family: var(--ax-font-mono);
  font-size: clamp(1.5rem, 1rem + 1.4vw, 2.4rem);
  font-weight: var(--ax-fw-heavy);
  line-height: 1;
  color: var(--c);
  /* The number is the one thing in the row lit by its own ray. */
  text-shadow: 0 0 22px color-mix(in oklab, var(--c) 55%, transparent);
}

.ax-split__name {
  grid-area: name;
  margin: 0;
  font-size: clamp(1.15rem, .85rem + .8vw, 1.6rem);
  font-weight: var(--ax-fw-bold);
  line-height: 1.12;
  letter-spacing: var(--ax-tr-display);
  color: var(--ax-text-strong);
}

.ax-split__kicker {
  grid-area: kicker;
  margin-block: var(--ax-sp-3) 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}

.ax-split__body {
  grid-area: body;
  margin-block: var(--ax-sp-6) 0;
  max-inline-size: 58ch;
  font-size: var(--ax-fs-md);
  line-height: var(--ax-lh-lead);
  color: var(--ax-text-body);
}

/* The manifest, as a column. It was one line of middots, which at 1920 left
   two thirds of every row empty — the body ended at 45% and this sat at 90%
   with a field of nothing between them. Stacked, it balances the body across
   the rule and the row reads as a spec sheet. */
.ax-split__tags {
  grid-area: tags;
  justify-self: end;
  align-self: start;
  padding-inline-start: var(--ax-sp-8);
  margin: 0;
  display: grid;
  gap: var(--ax-sp-4);
  list-style: none;
  text-align: end;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}
/* Each one gets the discipline's own colour as a tick, so the right-hand
   column is still carrying the spectrum rather than going grey. */
.ax-split__tags li { display: flex; align-items: center; justify-content: flex-end; gap: var(--ax-sp-4); }
.ax-split__tags li::after {
  content: "";
  inline-size: 5px; block-size: 5px;
  border-radius: 1px;
  transform: skewX(var(--ax-axis));
  background: var(--c);
  opacity: .8;
}

.ax-split__more {
  grid-area: more;
  justify-self: start;
  margin-block-start: var(--ax-sp-6);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c);
  text-decoration: none;
  border-block-end: 1px solid color-mix(in oklab, var(--c) 45%, transparent);
  padding-block-end: 3px;
  transition: border-color var(--ax-d-base) var(--ax-ease);
}
.ax-split__more:hover,
.ax-split__more:focus-visible { border-block-end-color: var(--c); }

/* ── smaller screens ─────────────────────────────────────────────────────
   Below 1024 the optics column would squeeze the rows to nothing, so the
   prism moves up beside the heading and the rays go. What replaces them is
   the honest version of the same idea: each row keeps its own ray as a short
   lead-in rule, in its own colour. */
@media (max-width: 1023px) {
  /* The copy sits at the FLOOR of the hero here, so there is far less empty
     hero to hide under — the overlap has to come down or it starts eating the
     index strip. */
  .ax-split { --ax-seam: 112px; }
  .ax-split__head { max-inline-size: none; }
  .ax-split__stage { grid-template-columns: 1fr; }
  .ax-split__optics { display: none; }
  /* The optics go, but the thread does not: it is the thing that stops the
     two sections reading as two. It runs down the margin and stops at the
     first row, with no elbow to turn, because there is no prism to turn into. */
  .ax-split__stage { position: relative; }
  .ax-split__stage::before {
    content: "";
    position: absolute;
    inset-block-start: -1400px;
    inset-inline-start: calc(var(--ax-fall-x) * -1);
    inline-size: 2px;
    block-size: 1400px;
    background: linear-gradient(180deg,
        rgb(var(--ax-white-rgb) / .8) 0%,
        rgb(var(--ax-white-rgb) / .8) 82%,
        transparent 100%);
  }
  .ax-split__rows { grid-template-rows: none; }
  .ax-split__row {
    padding-inline-start: 0;
    padding-block: clamp(1.8rem, 1.2rem + 2vw, 2.6rem);
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "no   name"
      "no   kicker"
      "body body"
      "tags tags"
      "more more";
  }
  .ax-split__tags {
    justify-self: start;
    padding-inline-start: 0;
    margin-block-start: var(--ax-sp-5);
    /* A column on a wide screen, a wrapping row on a narrow one — stacked
       here it would be four lines of nothing down the left. */
    display: flex;
    flex-wrap: wrap;
    gap: var(--ax-sp-4) var(--ax-sp-7);
    text-align: start;
  }
  .ax-split__tags li { justify-content: flex-start; }
  .ax-split__row::before {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    inline-size: clamp(64px, 22vw, 150px);
    block-size: 2px;
    background: linear-gradient(90deg, var(--c), transparent);
    opacity: .85;
  }
}

@media (max-width: 639px) {
  .ax-split { --ax-seam: 76px; }
  .ax-split__row {
    grid-template-columns: 1fr;
    grid-template-areas: "no" "name" "kicker" "body" "tags" "more";
    /* Stacked, the number and the name were touching — on a wide screen the
       number sits BESIDE them and the gap comes from the column. */
    row-gap: var(--ax-sp-3);
  }
  .ax-split__kicker { margin-block-start: 0; }
}

/* Reduced motion: everything arrives, nothing travels. The rays are drawn,
   the blades are lit, the rows are in place — the section just does not
   perform getting there, and the packets do not run. */
@media (prefers-reduced-motion: reduce) {
  .ax-split__blade,
  .ax-split__rt path,
  .ax-split__pk path,
  .ax-split__row { transition: none; }
  .ax-split__blade { opacity: 1; transform: none; }
  /* The spine is not motion, it is structure — it stays. Only the packet
     running down it stops. */
  .ax-spine::before { animation: none; opacity: 0; }
  .ax-split__rt path { stroke-dashoffset: 0; }
  .ax-split__row { opacity: 1; transform: none; }
  .ax-split__pk path { animation: none; opacity: 0; }
}

/* NO SCRIPT, NO REVEAL, AND THE SECTION IS STILL THERE. Every rule above is
   written with the FINISHED state as the default; the hidden state only
   applies once the script has added .is-armed, which it does a frame before
   it starts watching. So a reader with no JavaScript, or one whose script
   fails, gets the whole section drawn and still — they simply do not get to
   watch it arrive. A reveal is a finish, never a gate on the content. */
@media print, (forced-colors: active) { .ax-split__optics { display: none; } }


/* ═══════════════════════════════════════════════════════════════════════════
   12 · THE REGISTER — section 3, the work with the names lifted out
   ───────────────────────────────────────────────────────────────────────────
   Section 1 makes the claim, section 2 names the four disciplines, and this is
   the proof — told the only honest way it can be told. A wall of entries with
   the client names removed, and one entry in it that is not removed.

   THE BAR IS THE IDEA. It is not a black rectangle: it is three or two blocks
   of different widths with gaps between them, so it reads as a NAME that has
   been taken out rather than as a graphic device. Each bar breathes on its own
   clock, which is what makes the wall feel like something still being kept
   rather than a picture of a filing cabinet.

   The spectrum runs BACKWARDS across the wall, violet to cyan, so the last
   entry — the one we are allowed to sign — arrives in the same cyan as the
   Calgary beacon in section 1 and row 01 in section 2. The colour comes home.

   SEAM. Same technique as section 2 and it is now a two-line job: --ax-seam
   for the overlap and a ground that starts transparent. The spine runs down
   the margin through all of it. See section 11's note for why the fade has to
   finish before the previous section's last row.
   ═══════════════════════════════════════════════════════════════════════════ */
.ax-reg {
  --ax-seam: 180px;

  position: relative;
  margin-block-start: calc(var(--ax-seam) * -1);
  padding-block: calc(clamp(6rem, 3rem + 10vw, 11rem) + var(--ax-seam))
                 clamp(6rem, 3rem + 10vw, 11rem);
  overflow: clip;
  isolation: isolate;
  background:
    radial-gradient(56% 50% at 84% 22%, rgb(var(--ax-spec-7-rgb) / .07) 0%, transparent 74%),
    radial-gradient(60% 56% at 6% 78%, rgb(var(--ax-spec-2-rgb) / .06) 0%, transparent 76%),
    linear-gradient(180deg,
        rgb(0 0 0 / 0) 0px,
        rgb(6 6 9 / .42) calc(var(--ax-seam) * .48),
        rgb(8 8 10 / .9) calc(var(--ax-seam) * .82),
        #08080A calc(var(--ax-seam) * .96),
        var(--ax-ink-050) calc(var(--ax-seam) * 3));
}
.ax-reg > .ax-container { position: relative; }

.ax-reg__head { max-inline-size: min(54rem, 66%); }

.ax-reg__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ax-div-4);
}
.ax-reg__eyebrow::before {
  content: "";
  inline-size: 26px; block-size: 2px;
  background: var(--ax-grad-sweep);
}

.ax-reg__title {
  margin-block: var(--ax-sp-7) 0;
  font-size: clamp(2rem, 1rem + 2.8vw, 3.4rem);
  font-weight: var(--ax-fw-heavy);
  line-height: 1.08;
  letter-spacing: var(--ax-tr-display);
  color: var(--ax-text-strong);
  text-wrap: balance;
}

.ax-reg__lead {
  margin-block-start: var(--ax-sp-7);
  max-inline-size: 54ch;
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-lead);
  letter-spacing: var(--ax-tr-lead);
  color: var(--ax-text-body);
}

/* A count of what is actually on this page, not a claim about the company. */
.ax-reg__count {
  margin-block-start: var(--ax-sp-7);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}

/* ── the wall ────────────────────────────────────────────────────────────
   Deliberately NOT four full-width rows. Section 2 is already that shape, and
   a second section built the same way would read as the same section twice. */
.ax-reg__wall {
  margin: clamp(3.5rem, 2rem + 5vw, 6rem) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(2rem, 1.2rem + 2.4vw, 3.4rem) clamp(1.6rem, 1rem + 2vw, 3rem);
}

.ax-reg__item { min-inline-size: 0; }

/* THE REDACTION. Blocks the width of the words that were there, with real
   gaps between them — a name taken out, not a bar drawn on. */
.ax-reg__bar {
  display: flex;
  align-items: stretch;
  gap: 6px;
  block-size: 19px;
  margin-block-end: var(--ax-sp-6);
  animation: ax-reg-breathe 9.4s ease-in-out infinite;
  animation-delay: calc(var(--d) * -1);
}
.ax-reg__bar i {
  display: block;
  inline-size: var(--w);
  border-radius: 2px;
  background: linear-gradient(180deg,
      color-mix(in oklab, var(--c) 92%, white) 0%,
      var(--c) 46%,
      color-mix(in oklab, var(--c) 72%, black) 100%);
}
@keyframes ax-reg-breathe { 0%, 100% { opacity: .5; } 50% { opacity: .95; } }

/* The region, where it has not been made public either. */
.ax-reg__hide {
  display: inline-block;
  inline-size: 3.4em;
  block-size: .62em;
  border-radius: 1px;
  vertical-align: -1px;
  background: currentColor;
  opacity: .42;
}

/* TWO LINES' WORTH WHETHER IT USES THEM OR NOT. Four regions is a long line
   and it wraps; one region is not. Without a floor here the description under
   a wrapping entry sits eighteen pixels lower than the one beside it and the
   wall stops reading as a grid. */
.ax-reg__meta {
  margin: 0;
  min-block-size: 2.9em;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  line-height: 1.45;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}
.ax-reg__sep { color: var(--c); opacity: .8; padding-inline: 2px; }

.ax-reg__what {
  margin-block: var(--ax-sp-4) 0;
  font-size: var(--ax-fs-md);
  line-height: 1.42;
  color: var(--ax-text-body);
}

/* ── the one we can name ─────────────────────────────────────────────────
   No bar. The word itself, set in the display face, is the whole point of the
   section — the wall exists so that this one entry means something. */
.ax-reg__name {
  margin: 0 0 var(--ax-sp-5);
  font-size: clamp(1.4rem, 1rem + 1.1vw, 2rem);
  font-weight: var(--ax-fw-heavy);
  line-height: 19px;
  letter-spacing: var(--ax-tr-display);
  color: var(--ax-text-strong);
  text-shadow: 0 0 26px color-mix(in oklab, var(--c) 52%, transparent);
}
.ax-reg__item--named .ax-reg__what { color: var(--ax-text-body); }
.ax-reg__more {
  display: inline-block;
  margin-block-start: var(--ax-sp-5);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c);
  text-decoration: none;
  border-block-end: 1px solid color-mix(in oklab, var(--c) 45%, transparent);
  padding-block-end: 3px;
  transition: border-color var(--ax-d-base) var(--ax-ease);
}
.ax-reg__more:hover,
.ax-reg__more:focus-visible { border-block-end-color: var(--c); }

@media (max-width: 1279px) { .ax-reg__wall { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 1023px) {
  .ax-reg { --ax-seam: 112px; }
  .ax-reg__head { max-inline-size: none; }
  .ax-reg__wall { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 639px) {
  .ax-reg { --ax-seam: 76px; }
  .ax-reg__wall { grid-template-columns: 1fr; }
  /* One column, nothing to line up with — the floor only leaves a hole. */
  .ax-reg__meta { min-block-size: 0; }
}

/* Reduced motion: the wall stops breathing and sits at a legible strength. */
@media (prefers-reduced-motion: reduce) {
  .ax-reg__bar { animation: none; opacity: .8; }
}
@media print, (forced-colors: active) { .ax-spine { display: none; } }


/* ═══════════════════════════════════════════════════════════════════════════
 *  13 · THE RELIEF — section 1
 *  ---------------------------------------------------------------------------
 *  THE IDEA, and it comes straight out of the headline. "Most of what we build
 *  never carries our name" is a sentence about work you cannot see the author
 *  of — so the mark is not printed on this page, it is CUT INTO it. At rest it
 *  is one step of grey above the canvas: you sense a shape on the right of the
 *  screen before you can name it. Then, every thirteen seconds, a band of light
 *  rakes across the surface at the blades' own 30deg and the eleven of them
 *  come up in sequence, the way light crosses something machined. Then it is
 *  gone again.
 *
 *  Nobody has to notice. That is the point of it — the graphic behaves the way
 *  the company does.
 *
 *  WHY IT IS BUILT THIS WAY, which is the part worth keeping:
 *
 *  · TWO LAYERS, ONE MASK. Both .ax-relief__cut and .ax-relief__rake carry the
 *    identical mask image at the identical size and position, so they register
 *    to the pixel. The cut paints the resting shape; the rake paints the light.
 *
 *  · THE LIGHT MOVES, THE MASK DOES NOT. The band is a CHILD of the masked
 *    element. Animating the masked element itself would drag the mask along
 *    with it and the whole mark would slide across the page. The parent holds
 *    the shape still and clips; only the child moves.
 *
 *  · ONE TRANSFORM ON ONE COMPOSITED LAYER. Round 12 measured what happens when
 *    artwork animates the other way — motion inside an SVG used as a background
 *    re-rasterises the whole image every frame, and that cost 100ms/frame
 *    against 16.7ms for the same result driven from the page. So nothing here
 *    animates inside the file. The file is static; the page moves one element.
 *
 *  · THE BAND IS PARALLEL TO THE BLADES, not across them. Skewed to the mark's
 *    own axis and travelling horizontally, it meets the eleven blades one after
 *    another instead of all at once — which is why it reads as a sweep down a
 *    surface rather than a flash.
 *
 *  Images/arxeon-mark-solid.svg is the eleven paths verbatim from the purchased
 *  artwork, filled white, no gradient and no <style> element. Built by
 *  _verify/build-mark-solid.py, which asserts the blade count and XML-parses
 *  the result before it writes.
 * ═════════════════════════════════════════════════════════════════════════ */

/* THE CONTINUUM — and this is the whole answer to "no section change".
   .ax-relief used to clip its own artwork, which is what made it a section:
   a box with an edge, and artwork that stopped at the edge. The clip moved
   up here instead, to a wrapper that holds section 1 AND section 2. Nothing
   else changed about the hero — the mark is still positioned against
   .ax-relief, at the same percentages, so its composition is untouched —
   but its lower bleed is no longer cut off at the hero's floor. The blade
   tips simply keep going into what comes next.
   Two sections, one clipped surface. There is no seam to hide because there
   is no longer a boundary for a seam to form on. */
.ax-continuum {
  /* 84px is the header. max() so a short laptop window does not crush it.
     It lives here rather than on .ax-relief because the page-level spine
     below needs to know where the hero ends. */
  --hero-h: max(620px, calc(100svh - 84px));
  position: relative;
  overflow: clip;
}

/* ── THE SPINE, promoted to the whole page ───────────────────────────────
   Round 20 gave section 2 a spine that started above its own top edge so it
   looked continuous with the hero. Two aligned lines pretending to be one.
   This is the real thing: ONE line, drawn once, starting inside the hero and
   running to the end of the last section — so sections 2 and 3 do not have
   a join for it to cross, they are simply different stretches of the same
   line. Adding a fourth section extends it; it never has to be re-aligned.

   It is placed by a real .ax-container rather than by absolute insets. The
   container carries the page gutter as PADDING, so an absolutely positioned
   child measures against the padding box and lands at the page edge instead
   of the content edge — a trap this codebase has hit more than once. A
   normal-flow 1px child of the container simply sits where the content
   starts, at every width, with no arithmetic to keep in step. */
.ax-continuum__rail {
  position: absolute;
  inset-inline: 0;
  inset-block-start: calc(var(--hero-h) - 150px);
  /* The seal hangs at the bottom of this rail, so its clearance from section
     4's last element is (that section's bottom padding) minus (this inset plus
     the seal's own height). Both numbers have to be the SAME at every width or
     the seal drifts into the content — which is exactly what happened on a
     phone, where the section's floor was shorter and the seal landed on top of
     a full-width button. One floor, one inset, all widths. */
  inset-block-end: var(--ax-sp-12);
  pointer-events: none;
  z-index: 0;
}
/* The rail is a flex column so the line can GROW and the seal can sit at its
   end. That is the whole reason the seal lives in here rather than in section
   4's markup: a line and a terminator declared in two different places have to
   be kept in step by hand at every width, and they never are. Owned by one
   element, they meet exactly, always. */
.ax-continuum__rail > .ax-container {
  block-size: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.ax-continuum__spine {
  position: relative;
  flex: 1 1 auto;
  inline-size: 1px;
  background: var(--ax-line);
  overflow: hidden;
}

/* THE SEAL. The light has been draining down this line since the hero; here
   it arrives, and the mark is finally lit. It is the only place on the page
   besides the header rail where the brand's spectrum appears at all — which
   is exactly why it means something when it does. Small on purpose: a
   hallmark stamped on silver, not a logo on a slide. */
.ax-continuum__seal {
  flex: none;
  display: block;
  inline-size: 40px;
  block-size: auto;
  /* centred on the 1px line it terminates */
  margin-inline-start: -19.5px;
  margin-block-start: var(--ax-sp-4);
  opacity: .92;
}
/* On a phone the page gutter is 20px, so a 40px seal centred on the line ends
   up 1px from the screen edge and reads as falling off rather than as a
   terminator. Below 768px it hangs BESIDE the line instead of across it —
   left edge on the spine, like a flag on a pole. */
@media (max-width: 767px) {
  .ax-continuum__seal { inline-size: 34px; margin-inline-start: 0; }
}
/* the packet: the rake's light, arriving from the mark above and draining
   the length of the page */
.ax-continuum__spine i {
  position: absolute;
  inset-inline: 0;
  block-size: 9%;
  display: block;
  background: linear-gradient(180deg,
      rgb(var(--ax-white-rgb) / 0),
      rgb(var(--ax-accent-text-rgb) / .55) 50%,
      rgb(var(--ax-white-rgb) / 0));
  transform: translate3d(0, -140%, 0);
  will-change: transform;
  animation: ax-drain 17s var(--ax-ease-in-out) infinite;
}
@keyframes ax-drain {
  0%        { transform: translate3d(0, -140%, 0); }
  62%, 100% { transform: translate3d(0, 1200%, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .ax-continuum__spine i { animation: none; transform: translate3d(0, 300%, 0); }
}
@media print, (forced-colors: active) { .ax-continuum__rail { display: none; } }

.ax-relief {
  position: relative;
  display: grid;
  grid-template-rows: 1fr auto;
  min-block-size: var(--hero-h);
  padding-block: var(--ax-sp-14) var(--ax-sp-9);
}

/* ── the artwork ─────────────────────────────────────────────────────────── */

.ax-relief__art {
  position: absolute;
  inset-block: -6% -12%;
  inset-inline-end: -8%;
  inline-size: min(72%, 1120px);
  pointer-events: none;
  z-index: 0;
}
.ax-relief__cut,
.ax-relief__rake {
  position: absolute;
  inset: 0;
  /* identical in both, or the light does not sit inside the shape */
  mask-image: url("../Images/arxeon-mark-solid.svg");
  mask-repeat: no-repeat;
  mask-position: center;
  mask-size: contain;
  -webkit-mask-image: url("../Images/arxeon-mark-solid.svg");
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
}

/* The resting state: one step of grey above the page. Deliberately close to
   invisible — measured separation from the canvas is nine 8-bit steps, which
   is enough to read as a shape and not enough to read as a picture. */
.ax-relief__cut { background: var(--ax-ink-100); }

/* The rake clips the light; the light is its child. */
.ax-relief__rake { overflow: hidden; }
.ax-relief__rake i {
  position: absolute;
  inset-block: -30%;
  inset-inline-start: 0;
  inline-size: 26%;
  display: block;
  background: linear-gradient(90deg,
      rgb(var(--ax-white-rgb) / 0),
      rgb(var(--ax-white-rgb) / .14) 42%,
      rgb(var(--ax-white-rgb) / .16) 58%,
      rgb(var(--ax-white-rgb) / 0));
  transform: translate3d(-80%, 0, 0) skewX(var(--ax-axis));
  will-change: transform;
  animation: ax-rake 13s var(--ax-ease-in-out) infinite;
}
/* Sweeps for the first 46%, then holds off-screen for the rest. A light that
   runs continuously is a loading bar; one that passes and leaves is an event. */
@keyframes ax-rake {
  0%        { transform: translate3d(-80%, 0, 0) skewX(var(--ax-axis)); }
  46%, 100% { transform: translate3d(440%, 0, 0) skewX(var(--ax-axis)); }
}

/* THE SCRIM. System law: wherever type crosses artwork, the ground under the
   type is guaranteed, never hoped for. The copy sits left and the mark sits
   right, so this only has to hold the overlap — it runs from the leading edge
   and is fully transparent well before the mark's dense end. */
.ax-relief__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(100deg,
      var(--ax-bg) 0%,
      rgb(var(--ax-black-rgb) / .72) 34%,
      rgb(var(--ax-black-rgb) / 0) 66%);
  /* ROUND 20: the scrim used to stop dead at the hero's floor, and since it
     darkens the left of the page that stop was a real step — measured 1.65
     mean channel difference across the join row. Below the ~6 steps the eye
     resolves, but it was the ONLY thing left changing at the boundary, and
     the brief was that nothing changes there. Faded out vertically before it
     reaches the floor, it now ends inside the hero rather than at its edge. */
  mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 94%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 94%);
}

.ax-relief > .ax-container { position: relative; z-index: 2; }

/* ── the copy ────────────────────────────────────────────────────────────── */

.ax-relief__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--ax-sp-7);
  max-inline-size: min(58%, 840px);
  padding-block-start: var(--ax-sp-9);
}
.ax-relief__eyebrow {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  font-weight: var(--ax-fw-medium);
  letter-spacing: var(--ax-tr-micro);
  text-transform: uppercase;
  color: var(--ax-text-muted);
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-5);
}
/* One short accent dash, the only colour in the copy column. */
.ax-relief__eyebrow::before {
  content: "";
  inline-size: 26px;
  block-size: 1px;
  background: var(--ax-accent-text);
  flex: none;
}
.ax-relief__title {
  font-size: var(--ax-fs-d1);
  line-height: var(--ax-lh-display);
  letter-spacing: var(--ax-tr-hero);
  font-weight: var(--ax-fw-bold);
  color: var(--ax-text-strong);
  text-wrap: balance;
  margin: 0;
}
.ax-relief__lead {
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-lead);
  letter-spacing: var(--ax-tr-lead);
  color: var(--ax-text-muted);
  text-wrap: pretty;
  max-inline-size: 54ch;
  margin: 0;
}
.ax-relief__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ax-sp-5);
  margin-block-start: var(--ax-sp-3);
}

/* ── the four disciplines ────────────────────────────────────────────────── */

.ax-relief__disciplines {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-block-start: var(--ax-sp-12);
  border-block-start: 1px solid var(--ax-line);
  list-style: none;
  padding: 0;
}
.ax-relief__disc {
  display: flex;
  align-items: center;
  gap: var(--ax-sp-5);
  padding: var(--ax-sp-7) var(--ax-sp-6) 0 0;
  min-inline-size: 0;
}
/* A hairline between, never around — four boxes would be a table. */
.ax-relief__disc + .ax-relief__disc {
  border-inline-start: 1px solid var(--ax-line);
  padding-inline-start: var(--ax-sp-7);
}
.ax-relief__ico {
  flex: none;
  inline-size: 22px;
  block-size: 22px;
  color: var(--ax-text-subtle);
}
.ax-relief__ico svg { inline-size: 100%; block-size: 100%; display: block; }
.ax-relief__no {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: var(--ax-tr-micro);
  color: var(--ax-text-subtle);
  flex: none;
}
.ax-relief__name {
  font-size: var(--ax-fs-sm);
  font-weight: var(--ax-fw-medium);
  color: var(--ax-text-body);
  letter-spacing: var(--ax-tr-body);
  min-inline-size: 0;
}

/* ── responsive ──────────────────────────────────────────────────────────── */

@media (max-width: 1023px) {
  .ax-relief__copy { max-inline-size: 100%; }
  .ax-relief__art { inline-size: 104%; inset-inline-end: -26%; inset-block: 2% -6%; opacity: .55; }
  .ax-relief__scrim {
    background: linear-gradient(160deg,
        var(--ax-bg) 0%, rgb(var(--ax-black-rgb) / .78) 42%, rgb(var(--ax-black-rgb) / .30) 100%);
  }
  .ax-relief__disciplines { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ax-relief__disc:nth-child(3) { border-inline-start: 0; padding-inline-start: 0; }
  .ax-relief__disc:nth-child(n+3) { border-block-start: 1px solid var(--ax-line); margin-block-start: var(--ax-sp-2); }
}
@media (max-width: 639px) {
  .ax-relief { min-block-size: auto; padding-block: var(--ax-sp-11) var(--ax-sp-9); }
  /* Two capsules of different widths stacked on top of each other read as a
     mistake rather than a pair. Full width, matched, is the phone answer. */
  .ax-relief__row { inline-size: 100%; }
  .ax-relief__row .ax-btn { inline-size: 100%; }
  .ax-relief__disciplines { grid-template-columns: minmax(0, 1fr); }
  .ax-relief__disc { padding-inline-start: 0 !important; border-inline-start: 0 !important; }
  .ax-relief__disc + .ax-relief__disc { border-block-start: 1px solid var(--ax-line); }
}

/* Reduced motion: the light does not travel, it RESTS across the mark. The
   section still has a lit shape in it; it simply stops being an event. */
@media (prefers-reduced-motion: reduce) {
  .ax-relief__rake i {
    animation: none;
    transform: translate3d(150%, 0, 0) skewX(var(--ax-axis));
    inline-size: 46%;
  }
}
@media print, (forced-colors: active) {
  .ax-relief__art, .ax-relief__scrim { display: none; }
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  14 · THE FOLD — section 2, and the join that is supposed to disappear
 *  ---------------------------------------------------------------------------
 *  THE BRIEF was that a reader should not feel a section change. Every previous
 *  attempt on this site treated that as a seam problem — match the colour at
 *  the boundary, overlap the two grounds, fade one into the other. All of that
 *  is work you only have to do because the two sections are different surfaces
 *  in the first place.
 *
 *  So this one removes the boundary instead of hiding it, four ways:
 *
 *  1 · ONE GROUND. Section 1 and section 2 are the same flat --ax-bg. No
 *      gradient ends, no panel, no band. Measured row-to-row at the join, the
 *      pixel discontinuity is zero, because nothing changes there.
 *
 *  2 · THE ARTWORK CROSSES IT. The clip lives on .ax-continuum now, so the
 *      mark's lower blades run out of the hero and into these rows. The tips
 *      are the thin end of the blades — the elegant part — and they are what
 *      the first entry sits against.
 *
 *  3 · THE SPINE CROSSES IT. One hairline starts inside the hero, above this
 *      section's first pixel, and runs unbroken down past all four entries.
 *      A single line crossing a boundary is the strongest possible statement
 *      that there is no boundary. It also carries a slow packet of light —
 *      the same light that rakes the mark above, now draining down the page.
 *      Light enters at the top of the site, crosses the mark, and walks down
 *      into the work. That is one continuous idea, not two sections.
 *
 *  4 · THE CONTENT CROSSES IT. The hero's four-discipline strip is already
 *      this section's table of contents — same numbers, same names, same
 *      icons. So this section never introduces itself. Its heading exists for
 *      crawlers and screen readers and is visually hidden, because a heading
 *      that says "What we build" directly under a strip that already said it
 *      is the announcement of a new section, and announcing is the one thing
 *      we are trying not to do.
 *
 *  Nothing here is scroll-linked. One IntersectionObserver per row, and the
 *  CSS is written with the FINISHED state as its default — the hidden state
 *  lives behind .is-armed, which the script adds one frame before it starts
 *  watching. A reader with no JavaScript gets four finished entries rather
 *  than four empty spaces.
 * ═════════════════════════════════════════════════════════════════════════ */

.ax-fold {
  position: relative;
  /* The floor under this section was sized for it being the last thing on the
     page. Section 3 follows it now, and 200px of nothing between the two reads
     as a gap rather than as breathing. */
  padding-block: var(--ax-sp-13) var(--ax-sp-11);
}

/* ── the spine ───────────────────────────────────────────────────────────── */

/* The fold's own spine was retired when the spine was promoted to the page
   (see .ax-continuum__rail above). .ax-fold__inner stays: it is the
   positioning context the rows are laid out against. */
.ax-fold__inner { position: relative; }

/* ── the entries ─────────────────────────────────────────────────────────── */

.ax-fold__list {
  position: relative;
  z-index: 1;
  list-style: none;
  margin: 0;
  padding: 0;
}
.ax-fold__row {
  display: grid;
  grid-template-columns: 110px minmax(0, 1fr);
  gap: var(--ax-sp-8);
  padding-block: var(--ax-sp-12);
  transition: opacity var(--ax-d-slower) var(--ax-ease-out),
              transform var(--ax-d-slower) var(--ax-ease-out);
}
/* Hairlines BETWEEN entries only. A line above the first one would draw the
   top edge of a box, which is the section boundary we just removed. */
.ax-fold__row + .ax-fold__row { border-block-start: 1px solid var(--ax-line); }

.ax-fold__no {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-lg);
  font-weight: var(--ax-fw-medium);
  line-height: 1;
  color: var(--ax-text-subtle);
  /* sits ON the spine: the line runs through the column, the number rides it */
  padding-inline-start: var(--ax-sp-7);
}
.ax-fold__body { min-inline-size: 0; max-inline-size: 62ch; }

.ax-fold__kicker {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: var(--ax-tr-micro);
  text-transform: uppercase;
  color: var(--ax-text-muted);
  margin: 0 0 var(--ax-sp-5);
}
.ax-fold__kicker svg { inline-size: 18px; block-size: 18px; display: block; flex: none; }

.ax-fold__name {
  font-size: var(--ax-fs-d3);
  line-height: 1.1;
  letter-spacing: var(--ax-tr-display);
  font-weight: var(--ax-fw-bold);
  color: var(--ax-text-strong);
  margin: 0 0 var(--ax-sp-6);
  text-wrap: balance;
}
.ax-fold__text {
  font-size: var(--ax-fs-md);
  line-height: var(--ax-lh-body);
  color: var(--ax-text-body);
  text-wrap: pretty;
  margin: 0;
}
.ax-fold__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ax-sp-3) var(--ax-sp-6);
  list-style: none;
  margin: var(--ax-sp-7) 0 0;
  padding: 0;
}
.ax-fold__tags li {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-2xs);
  letter-spacing: var(--ax-tr-tiny);
  color: var(--ax-text-subtle);
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
}
.ax-fold__tags li::before {
  content: "";
  inline-size: 4px;
  block-size: 4px;
  border-radius: 50%;
  background: var(--ax-ink-500);
  flex: none;
}
.ax-fold__more {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  margin-block-start: var(--ax-sp-7);
  font-size: var(--ax-fs-sm);
  font-weight: var(--ax-fw-medium);
  color: var(--ax-accent-text);
  text-decoration: none;
}
.ax-fold__more::after { content: "\2192"; transition: transform var(--ax-d-base) var(--ax-ease-out); }
.ax-fold__more:hover::after { transform: translateX(4px); }

/* ── arrival ─────────────────────────────────────────────────────────────── */
/* Finished state is the default. .is-armed is what hides it, and only the
   script adds that — so no script means no hiding. */
.ax-fold.is-armed .ax-fold__row { opacity: 0; transform: translate3d(0, 16px, 0); }
.ax-fold .ax-fold__row.is-in { opacity: 1; transform: none; }

@media (max-width: 767px) {
  .ax-fold { padding-block: var(--ax-sp-11) var(--ax-sp-13); }
  .ax-fold__row { grid-template-columns: minmax(0, 1fr); gap: var(--ax-sp-5); padding-block: var(--ax-sp-10); }
  .ax-fold__no { padding-inline-start: var(--ax-sp-7); }
}

@media (prefers-reduced-motion: reduce) {
  .ax-fold.is-armed .ax-fold__row { opacity: 1; transform: none; }
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  15 · THE GRAIN — section 3, the proof
 *  ---------------------------------------------------------------------------
 *  Section 1 makes the claim, section 2 names the four disciplines, and the
 *  next thing any reader wants is evidence that the first two are real. The
 *  build before this one had the right instinct and the wrong execution: a
 *  wall of eleven redaction bars, which Farhad called the worst thing on the
 *  page and was right to. A blacked-out table does not read as discretion, it
 *  reads as ABSENCE — you are looking at the shape of what is missing, eleven
 *  times, in the spot where the proof was supposed to be.
 *
 *  So this is the same honesty expressed as PRESENCE. Every line names what
 *  was built and where; not one of them names who paid for it. Nothing is
 *  hidden on screen because nothing confidential is on screen — the client
 *  was never the interesting part. "Field platforms for oil and gas, in four
 *  countries" is a bigger claim than any logo would have been, and it costs
 *  nobody their confidentiality.
 *
 *  THE RHYTHM IS THE TRANSITION. Section 2 is four large entries with a lot
 *  of air. This is eleven short ones, dense, two to a row. Same spine, same
 *  language, finer ticks — the page reads as zooming in from the four
 *  disciplines to the grain underneath them, which is why there is no heading
 *  here either, only a lower-case bridge line that finishes section 2's
 *  sentence. A reader scrolls from one to the other without being told that
 *  anything happened.
 * ═════════════════════════════════════════════════════════════════════════ */

.ax-grain-sec {
  position: relative;
  padding-block: 0 var(--ax-sp-15);
}
.ax-grain-sec__inner { position: relative; }

/* The bridge. Lower case, mono, muted — deliberately not a heading. It is the
   second half of a sentence the previous section started. */
.ax-grain-sec__bridge {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-2xs);
  letter-spacing: var(--ax-tr-tiny);
  color: var(--ax-text-subtle);
  margin: 0 0 var(--ax-sp-11);
  padding-inline-start: var(--ax-sp-7);
}

.ax-grain-sec__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 var(--ax-sp-12);
  list-style: none;
  margin: 0;
  padding: 0;
}

.ax-grain-sec__rec {
  position: relative;
  display: grid;
  /* 92px, not a ch value: ch measures the "0" glyph and ignores letter-spacing,
     so an 8.5ch column sized for a tracked uppercase GOVERNMENT came up ~17px
     short and the sector ran straight into the line of work. */
  grid-template-columns: 92px minmax(0, 1fr);
  gap: var(--ax-sp-6);
  align-items: baseline;
  padding: var(--ax-sp-7) 0 var(--ax-sp-7) var(--ax-sp-7);
  border-block-start: 1px solid var(--ax-line-soft);
}
/* The tick: a short stub reaching in from the spine's side. At rest it is the
   same hairline as everything else; colour arrives on hover, never before —
   the rule this design system settled on in round 18. */
.ax-grain-sec__rec::before {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline-start: 0;
  inline-size: 14px;
  block-size: 1px;
  background: var(--ax-ink-400);
  transition: inline-size var(--ax-d-base) var(--ax-ease-out),
              background-color var(--ax-d-base) var(--ax-ease);
}
.ax-grain-sec__rec:hover::before { inline-size: 34px; background: var(--ax-accent-text); }

.ax-grain-sec__sector {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: var(--ax-tr-micro);
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
.ax-grain-sec__what {
  font-size: var(--ax-fs-md);
  line-height: 1.45;
  color: var(--ax-text-body);
  margin: 0;
  min-inline-size: 0;
}
.ax-grain-sec__where {
  display: block;
  margin-block-start: var(--ax-sp-3);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-2xs);
  letter-spacing: var(--ax-tr-tiny);
  color: var(--ax-text-subtle);
}

/* The close. One line, sitting apart from the list, doing the job the wall of
   black bars was trying to do. */
.ax-grain-sec__close {
  margin-block-start: var(--ax-sp-12);
  padding-inline-start: var(--ax-sp-7);
  max-inline-size: 54ch;
}
.ax-grain-sec__close p {
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-lead);
  letter-spacing: var(--ax-tr-lead);
  color: var(--ax-text-muted);
  text-wrap: pretty;
  margin: 0;
}
.ax-grain-sec__close .ax-fold__more { margin-block-start: var(--ax-sp-7); }

@media (max-width: 1023px) {
  .ax-grain-sec__list { grid-template-columns: minmax(0, 1fr); gap: 0; }
}
@media (max-width: 639px) {
  .ax-grain-sec { padding-block-end: var(--ax-sp-13); }
  .ax-grain-sec__rec { grid-template-columns: minmax(0, 1fr); gap: var(--ax-sp-3); }
  .ax-grain-sec__sector { inline-size: auto; }
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  16 · THE EXCEPTION — section 4, and the end of the argument
 *  ---------------------------------------------------------------------------
 *  Three sections have now said, in three different ways, that Arxeon's work
 *  is anonymous: a mark cut into the page rather than printed on it, four
 *  disciplines described without a client between them, and eleven records
 *  that name what was built and never who for. Section 3 closes on "the names
 *  it does carry are not ours to print."
 *
 *  This section is the other half of that sentence. There is exactly one
 *  exception on the whole site and it is worth arriving at rather than
 *  announcing: Qlynic is the thing Arxeon owns, which is the only reason its
 *  name can be read here. That is the payoff of the anonymity, not a
 *  contradiction of it.
 *
 *  THE RHYTHM CLOSES THE SET. Hero: one sentence, enormous. Fold: four large
 *  entries. Grain: eleven fine ones. This: one thing again, and short — a coda
 *  rather than a section. Long, larger, finer, then single. A reader feels the
 *  page resolve without being told it has.
 *
 *  AND THE COLOUR ARRIVES. The page has been monochrome for four screens. The
 *  spectrum shows up once, at 40px, on the seal that terminates the spine —
 *  the light that has been walking down the page since the hero finally lands
 *  on something. Colour as an event, earned, at the exact moment the company
 *  signs its name. That was the whole thesis of round 18 and this is the only
 *  place on the page that gets to spend it.
 * ═════════════════════════════════════════════════════════════════════════ */

.ax-sign {
  position: relative;
  padding-block: 0 var(--ax-sp-16);
}
.ax-sign__inner {
  position: relative;
  max-inline-size: 60ch;
  padding-inline-start: var(--ax-sp-7);
}

/* Same lower-case mono bridge as section 3 — this page does not use headings
   to change subject, it finishes sentences. */
.ax-sign__bridge {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-2xs);
  letter-spacing: var(--ax-tr-tiny);
  color: var(--ax-text-subtle);
  margin: 0 0 var(--ax-sp-7);
}

.ax-sign__name {
  font-size: var(--ax-fs-d2);
  line-height: var(--ax-lh-display);
  letter-spacing: var(--ax-tr-display);
  font-weight: var(--ax-fw-bold);
  color: var(--ax-text-strong);
  margin: 0 0 var(--ax-sp-8);
}

.ax-sign__lead {
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-lead);
  letter-spacing: var(--ax-tr-lead);
  color: var(--ax-text-muted);
  text-wrap: pretty;
  margin: 0 0 var(--ax-sp-9);
}
.ax-sign__lead strong {
  color: var(--ax-text-body);
  font-weight: var(--ax-fw-medium);
}

@media (max-width: 639px) {
  .ax-sign__inner { max-inline-size: 100%; }
  .ax-sign .ax-btn { inline-size: 100%; }
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  17 · THE SIGNAL — section 1 (rebuilt in round 38)
 *  ---------------------------------------------------------------------------
 *  A Calgary software company whose work runs across North America, said with
 *  the map rather than about it.
 *
 *  WHAT CHANGED, AND WHY. The first version made the map a BACKGROUND: the
 *  copy sat on top of it, so the continent had to be cropped on three sides
 *  and scrimmed behind the headline, and at 84px the headline and a 900px map
 *  were two giants shouting over each other. Farhad's verdict — too big, too
 *  empty, zoomed, and the animated route lines looked broken — was a verdict
 *  on the layout as much as on any one part of it.
 *
 *  So the section is now two columns that never overlap: the statement on the
 *  left at the size a statement needs, the continent on the right fitted WHOLE
 *  inside its frame, softened only at its extremes. The frame's fades are
 *  computed in the WebGL fragment shader (arxeon.continent.js), not with a CSS
 *  mask, because a mask over a canvas that repaints every frame is re-applied
 *  every frame.
 *
 *  TWO TONES, ONE LINE OF THOUGHT. "Built in Calgary." is the claim and gets
 *  the white; "Running across North America." is the reach and steps down to
 *  the secondary text colour. It reads as one sentence with a weight shift,
 *  which is how the best product pages set a headline now, and it lets the
 *  size come down a long way without the line losing its authority.
 *
 *  NOTHING HERE ANIMATES EXCEPT THE CANVAS and one small on-air dot. The
 *  section's motion is the continent; everything around it holds still so the
 *  eye has somewhere to rest.
 * ═════════════════════════════════════════════════════════════════════════ */

.ax-signal {
  position: relative;
  isolation: isolate;
  overflow: clip;
  background: var(--ax-bg);
  /* the bottom is deliberately deeper than the top: section 2 opens on a
     full-bleed photograph, and it needs a clear breath of ground before it */
  padding-block: clamp(40px, 7svh, 88px) clamp(64px, 10svh, 120px);
}

/* the light the continent sits in — behind the map, never behind the type */
.ax-signal::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(38% 48% at 71% 44%, rgb(var(--ax-accent-rgb) / .085), transparent 72%),
    radial-gradient(46% 30% at 70% 88%, rgb(var(--ax-spec-8-rgb) / .045), transparent 74%);
}

.ax-signal__stage {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  grid-template-areas: "copy map" "disc disc";
  column-gap: clamp(24px, 3.2vw, 56px);
  row-gap: clamp(28px, 5svh, 56px);
  align-items: center;
}

/* ── the statement ───────────────────────────────────────────────────────── */

.ax-signal__copy {
  grid-area: copy;
  display: grid;
  row-gap: var(--ax-sp-8);
  align-content: center;
  max-inline-size: 34rem;
}

.ax-signal__station { display: grid; row-gap: var(--ax-sp-2); }
.ax-signal__sname {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  margin: 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ax-text-body);
}
/* on air: a slow breath, never a blink */
.ax-signal__live {
  inline-size: 6px;
  block-size: 6px;
  border-radius: 50%;
  background: rgb(var(--ax-accent-text-rgb));
  box-shadow: 0 0 0 3px rgb(var(--ax-accent-text-rgb) / .16);
  animation: ax-signal-air 4.2s var(--ax-ease-in-out) infinite;
}
@keyframes ax-signal-air { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
.ax-signal__sdata {
  margin: 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
.ax-signal__sdata b {
  font-weight: 500;
  color: var(--ax-text-muted);
  font-variant-numeric: tabular-nums;
}

.ax-signal__title {
  margin: 0;
  font-size: clamp(2.125rem, 1rem + 2.6vw, 3.25rem);
  line-height: 1.03;
  font-weight: 700;
  letter-spacing: -.035em;
  text-wrap: balance;
}
.ax-signal__claim { display: block; color: var(--ax-text-strong); }
.ax-signal__reach { display: block; color: var(--ax-text-muted); }

.ax-signal__lead {
  margin: 0;
  max-inline-size: 44ch;
  font-size: var(--ax-fs-md);
  line-height: var(--ax-lh-lead);
  color: var(--ax-text-muted);
}
.ax-signal__lead strong { font-weight: 600; color: var(--ax-text-body); }

.ax-signal__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ax-sp-5);
  margin-block-start: var(--ax-sp-2);
}

/* ── the continent ───────────────────────────────────────────────────────── */

.ax-signal__mapwrap {
  grid-area: map;
  position: relative;
  min-inline-size: 0;
}
.ax-signal__map {
  position: relative;
  margin: 0;
  inline-size: 100%;
  aspect-ratio: 16 / 11;
}
.ax-signal__gl,
.ax-signal__still {
  position: absolute;
  inset: 0;
  display: block;
  inline-size: 100%;
  block-size: 100%;
}
.ax-signal__still { object-fit: contain; }

/* CALGARY, labelled on top of its own beacon. With the renderer running the
   label is placed by transform every frame; the percentages are where the
   beacon stands in the still, for the no-script picture. */
.ax-signal__pin {
  position: absolute;
  left: var(--pin-x, 45.88%);
  top: var(--pin-y, 41.74%);
  z-index: 1;
  margin: -28px 0 0 12px;
  padding: 4px 8px;
  border-radius: var(--ax-r-xs);
  /* NEARLY OPAQUE, and measured into it: at .62 the lit land and the beacon
     shone through the plate and the label fell to 1.35:1 on a phone. The
     label has to be readable whatever the transmission is lighting under it. */
  background: rgb(var(--ax-black-rgb) / .9);
  box-shadow: inset 0 0 0 1px rgb(var(--ax-white-rgb) / .14);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  line-height: 1.2;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ax-text-body);
  pointer-events: none;
}
.ax-signal__pin::before {
  /* the leader from the top of the beacon to the label, on the thirty-degree
     axis every diagonal in this system uses */
  content: "";
  position: absolute;
  left: -12px;
  top: 28px;
  inline-size: 14px;
  block-size: 1px;
  background: rgb(var(--ax-white-rgb) / .38);
  transform: rotate(-30deg);
  transform-origin: 0 50%;
}
.ax-signal__map.is-live-gl .ax-signal__pin { left: 0; top: 0; will-change: transform; }

/* top right of the frame: land never reaches that corner, and it keeps the
   control well away from the two calls to action so it cannot be read as a
   third one */
.ax-signal__listen {
  position: absolute;
  right: 1%;
  top: 3%;
  z-index: 2;
}
.ax-signal__listen.is-on { color: rgb(var(--ax-accent-text-rgb)); border-color: rgb(var(--ax-accent-text-rgb) / .45); }

/* ── the two disciplines, as the section's floor ─────────────────────────── */

/* doubled selector on purpose: base.css resets ul[class] padding at a higher
   specificity than a single class, and that reset ate this padding once */
.ax-signal__stage > .ax-signal__disciplines {
  grid-area: disc;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--ax-sp-8) var(--ax-sp-12);
  margin: 0;
  padding: var(--ax-sp-9) 0 0;
  list-style: none;
  border-block-start: 1px solid var(--ax-line);
}
.ax-signal__disc {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr);
  column-gap: var(--ax-sp-5);
  align-items: start;
}
.ax-signal__ico {
  display: block;
  inline-size: 20px;
  block-size: 20px;
  margin-block-start: 1px;
  color: var(--ax-text-muted);
}
.ax-signal__ico svg { display: block; inline-size: 100%; block-size: 100%; }
.ax-signal__dname {
  margin: 0;
  font-size: var(--ax-fs-sm);
  font-weight: 600;
  line-height: var(--ax-lh-head);
  color: var(--ax-text-strong);
}
.ax-signal__dbody {
  margin: var(--ax-sp-2) 0 0;
  max-inline-size: 48ch;
  font-size: var(--ax-fs-sm);
  line-height: var(--ax-lh-body);
  color: var(--ax-text-muted);
}
/* round 102: under each discipline, what it is built with, in the station
   plate's voice so it reads as data rather than copy. Names keep their own
   spelling (no capitals forced); no-break spaces in the markup keep each dot
   with the name before it. */
.ax-signal__dstack {
  margin: var(--ax-sp-3) 0 0;
  max-inline-size: 30rem;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-2xs);
  line-height: 1.7;
  letter-spacing: .02em;
  color: var(--ax-text-subtle);
}

/* ── narrow ──────────────────────────────────────────────────────────────── */

@media (max-width: 1023px) {
  /* one column: the statement, then the continent under it, then the floor */
  .ax-signal__stage {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "copy" "map" "disc";
  }
  .ax-signal__copy { max-inline-size: 40rem; }
}

@media (max-width: 639px) {
  /* round 102: with the stage's own weight, so it wins over the two-column
     rule above (a bare .ax-signal__disciplines never did) */
  .ax-signal__stage > .ax-signal__disciplines { grid-template-columns: minmax(0, 1fr); }
  .ax-signal__listen { right: 0; top: 0; }
}

/* ── the continent arriving ──────────────────────────────────────────────
   ROUND 92. Until the renderer's first frame the frame was black. The map
   cannot draw before every script on the page has arrived, which on a slow
   line is seconds and on a fast one still half of one, so the first thing
   a visitor saw of the section's one moving part was a dark rectangle with
   a label floating in it.

   Now Calgary is on air from the first paint. A beacon stands where the
   city will stand, under its own label, transmissions leave it across the
   empty plane the continent will lie on, and it is all CSS, so it is there
   before any script is. When the first frame is drawn (.is-drawn, set by
   arxeon.continent.js on the frame and its wrap) the continent spreads out
   of Calgary in the shader (THE ARRIVAL, in the script), all of this fades
   out under it, and when the fade has run it is removed (.is-arrived), so
   nothing keeps moving behind the canvas.

   Without script there is nothing to wait for, so none of it shows. */
.ax-signal__map::before,
.ax-signal__map::after,
.ax-signal__mapwrap::before,
.ax-signal__mapwrap::after {
  content: "";
  position: absolute;
  pointer-events: none;
  /* the fade-out is a filter, because the pulses below already animate
     opacity, and a running animation outranks any value it is given. No
     filter until then: a filter costs every frame it is on screen. */
  transition: filter .9s var(--ax-ease-out);
}

/* the plane: points in a hex field, tilted like the table the continent
   lies on, and only around the city */
.ax-signal__map::before {
  inset: 8% -6% -2%;
  background-image:
    radial-gradient(circle, rgb(var(--ax-white-rgb) / .42) 0 .9px, transparent 1.5px),
    radial-gradient(circle, rgb(var(--ax-white-rgb) / .42) 0 .9px, transparent 1.5px);
  background-size: 15px 13px;
  background-position: 0 0, 7.5px 6.5px;
  -webkit-mask-image: radial-gradient(54% 46% at 46% 42%, #000 0%, rgb(0 0 0 / .55) 50%, transparent 100%);
          mask-image: radial-gradient(54% 46% at 46% 42%, #000 0%, rgb(0 0 0 / .55) 50%, transparent 100%);
  transform: perspective(1200px) rotateX(48deg);
  transform-origin: 46% 42%;
  opacity: .5;
  animation: ax-arrive-plane 2.8s var(--ax-ease-in-out) infinite;
}

/* the beacon: Calgary, already on air. A point of light on the ground with
   its column standing up to the label, exactly where the continent's own
   beacon will stand: the ground is at --cal-y (measured from the renderer:
   48.4% of the frame at every size, the frame being 16:11), the top of the
   column where the label points (--pin-y). */
.ax-signal__map::after {
  z-index: 2;
  left: var(--pin-x, 45.88%);
  top: var(--pin-y, 41.74%);
  inline-size: 16px;
  block-size: calc(var(--cal-y, 48.42%) - var(--pin-y, 41.74%) + 8px);
  margin-inline-start: -8px;
  background:
    radial-gradient(circle at 50% calc(100% - 8px), #fff 0 2.6px, rgb(var(--ax-accent-text-rgb)) 4.6px, rgb(var(--ax-accent-text-rgb) / 0) 8px),
    linear-gradient(to top, rgb(var(--ax-accent-text-rgb) / .95), rgb(var(--ax-accent-text-rgb) / .12)) 50% 0 / 2px calc(100% - 8px) no-repeat;
  filter: drop-shadow(0 0 7px rgb(var(--ax-accent-text-rgb) / .75));
  transform-origin: 50% calc(100% - 8px);
  animation: ax-arrive-beacon 2.8s var(--ax-ease-in-out) infinite;
}

/* the transmissions: two rings leaving the city across the plane, the way
   the continent's own do once it is there */
.ax-signal__mapwrap::before,
.ax-signal__mapwrap::after {
  z-index: 1;
  left: var(--cal-x, 45.95%);
  top: var(--cal-y, 48.42%);
  inline-size: 84%;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 1.5px solid rgb(var(--ax-accent-text-rgb) / .85);
  background: radial-gradient(closest-side, rgb(var(--ax-accent-text-rgb) / 0) 72%, rgb(var(--ax-accent-text-rgb) / .14) 94%, rgb(var(--ax-accent-text-rgb) / 0) 100%);
  box-shadow: 0 0 30px rgb(var(--ax-accent-text-rgb) / .26), inset 0 0 30px rgb(var(--ax-accent-text-rgb) / .18);
  opacity: 0;
  transform: translate(-50%, -50%) perspective(1200px) rotateX(60deg) scale(.03);
  animation: ax-arrive-ring 2.8s cubic-bezier(.22, .61, .36, 1) infinite;
}
.ax-signal__mapwrap::after { animation-delay: 1.4s; }

@keyframes ax-arrive-plane {
  0%, 100% { opacity: .38; }
  50%      { opacity: .62; }
}
@keyframes ax-arrive-beacon {
  0%, 100% { transform: scale(.9); opacity: .78; }
  12%      { transform: scale(1.12); opacity: 1; }
  40%      { transform: scale(1); opacity: .92; }
}
@keyframes ax-arrive-ring {
  0%   { opacity: 0;   transform: translate(-50%, -50%) perspective(1200px) rotateX(60deg) scale(.03); }
  10%  { opacity: .95; }
  100% { opacity: 0;   transform: translate(-50%, -50%) perspective(1200px) rotateX(60deg) scale(1); }
}

/* The first frame is drawn: the waiting fades out under the continent, and
   when the fade has run it is gone (content: none takes the animations with
   it). With the still instead of the renderer, the same, once the still has
   loaded. */
.ax-signal__map.is-drawn::before,
.ax-signal__mapwrap.is-drawn::before,
.ax-signal__mapwrap.is-drawn::after { filter: opacity(0); }
.ax-signal__map.is-drawn::after { filter: drop-shadow(0 0 7px rgb(var(--ax-accent-text-rgb) / .75)) opacity(0); }
.ax-signal__map.is-arrived::before,
.ax-signal__map.is-arrived::after,
.ax-signal__mapwrap.is-arrived::before,
.ax-signal__mapwrap.is-arrived::after { content: none; }

/* Until the first frame the label keeps the still's place. The renderer
   takes it over (left and top to 0, then a transform every frame) from the
   moment it starts, and between that and its first frame the label sat in
   the frame's top left corner. */
.ax-signal__map.is-live-gl:not(.is-drawn) .ax-signal__pin { left: var(--pin-x, 45.88%); top: var(--pin-y, 41.74%); }

/* Asked for less motion: the beacon and one transmission, standing still. */
@media (prefers-reduced-motion: reduce) {
  .ax-signal__map::before,
  .ax-signal__map::after,
  .ax-signal__mapwrap::before { animation: none; }
  .ax-signal__mapwrap::before { opacity: .45; transform: translate(-50%, -50%) perspective(1200px) rotateX(60deg) scale(.42); }
  .ax-signal__mapwrap::after { content: none; }
}
/* No script, nothing to wait for: the still is already there. */
@media (scripting: none) {
  .ax-signal__map::before,
  .ax-signal__map::after,
  .ax-signal__mapwrap::before,
  .ax-signal__mapwrap::after { content: none; }
}

/* ── the world ─────────────────────────────────────────────────────────────
   ROUND 93. On a large screen the section was a narrow column of words and
   a map floating in black, shorter than the window, so the top of the next
   section showed under it and the first view read as two halves of
   nothing. Now the section owns the first screen, and the black around the
   continent is the world it lies on:

   THE PLANE goes on past the frame to the edges of the screen, drawn in the
   continent's own camera on one more canvas behind everything
   (arxeon.continent.js, THE WORLD): the lines of latitude and longitude,
   marks where they cross, the names of the lines where land does not
   reach, and a sweep of light turning over Calgary that lights the land and
   the lines as it passes. The signal leaves Calgary for the visitor's own
   city (from the browser's time zone: nothing is asked for and nothing is
   sent), and for anywhere the map is clicked. A pointer finds characters in
   the dark around it, and over the map a sight with a line back to
   Calgary, its coordinates read out in the corner.

   THE INSTRUMENTS sit on the frame: corner marks, the link's state, the
   readout, and a scale bar that is the true distance at Calgary.

   THE STATION PLATE types itself in as the page paints (no script needed)
   and gains a clock; the headline locks in out of noise as the script
   arrives, and a light runs along its second line. */

/* THE FIRST SCREEN IS THIS SECTION'S: the window below the bar (84 + 2, or
   68 + 2 on a phone), with the statement and the continent standing in the
   middle and the two disciplines on its floor. */
.ax-signal {
  display: flex;
  flex-direction: column;
  min-block-size: calc(100svh - 86px);
}
.ax-signal > .ax-signal__stage { flex: 1 0 auto; }
@media (min-width: 1024px) {
  .ax-signal__stage { grid-template-rows: minmax(0, 1fr) auto; }
}
@media (max-width: 767px) {
  .ax-signal { min-block-size: calc(100svh - 70px); }
}

/* the plane, as far as the screen goes, behind everything in the section */
.ax-signal__world {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  inline-size: 100%;
  block-size: 100%;
  pointer-events: none;
}

/* over the map, its own size: the signal's trips and the sight */
.ax-signal__over {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: block;
  inline-size: 100%;
  block-size: 100%;
  pointer-events: none;
}

/* the instruments: corner marks like the edges of a sight, and three lines
   of readout, in the plate's own small capitals */
.ax-signal__hud {
  --ax-hud-c: rgb(var(--ax-white-rgb) / .30);
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(var(--ax-hud-c), var(--ax-hud-c)) left top / 16px 1px no-repeat,
    linear-gradient(var(--ax-hud-c), var(--ax-hud-c)) left top / 1px 16px no-repeat,
    linear-gradient(var(--ax-hud-c), var(--ax-hud-c)) right top / 16px 1px no-repeat,
    linear-gradient(var(--ax-hud-c), var(--ax-hud-c)) right top / 1px 16px no-repeat,
    linear-gradient(var(--ax-hud-c), var(--ax-hud-c)) left bottom / 16px 1px no-repeat,
    linear-gradient(var(--ax-hud-c), var(--ax-hud-c)) left bottom / 1px 16px no-repeat,
    linear-gradient(var(--ax-hud-c), var(--ax-hud-c)) right bottom / 16px 1px no-repeat,
    linear-gradient(var(--ax-hud-c), var(--ax-hud-c)) right bottom / 1px 16px no-repeat;
  opacity: 0;
  transition: opacity .9s var(--ax-ease-out) .3s;
}
.ax-signal__map.is-drawn .ax-signal__hud { opacity: 1; }
/* each on its own small plate, like Calgary's label: wherever the land is
   lit under it, it reads */
.ax-signal__hud p {
  position: absolute;
  margin: 0;
  padding: 3px 7px;
  border-radius: var(--ax-r-xs);
  background: rgb(var(--ax-black-rgb) / .9);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  line-height: 1.55;
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ax-text-subtle);
}
.ax-signal__hud b { font-weight: 500; color: var(--ax-text-muted); font-variant-numeric: tabular-nums; }
.ax-signal__hud-link {
  left: 18px;
  top: 10px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.ax-signal__hud-link svg { inline-size: 12px; block-size: 12px; color: rgb(var(--ax-accent-text-rgb)); }
.ax-signal__hud-read { left: 18px; bottom: 10px; display: grid; }
.ax-signal__hud-scale { right: 18px; bottom: 10px; display: grid; justify-items: end; row-gap: 3px; }
/* a phone's frame is narrow: the projection's name goes, the readout's
   second line shortens to the city */
@media (max-width: 639px) {
  .ax-signal__hud-scale > span:last-child { display: none; }
  .ax-signal__hud-link { left: 12px; top: 8px; }
  .ax-signal__hud-read { left: 12px; bottom: 8px; }
  .ax-signal__hud-scale { right: 12px; bottom: 8px; }
}
.ax-signal__hud-bar {
  display: block;
  inline-size: 80px;
  block-size: 5px;
  border: 1px solid rgb(var(--ax-white-rgb) / .38);
  border-block-start: 0;
}

/* the visitor's city, labelled where the signal lands, in the pin's own
   voice; the script puts it on whichever side of the point it fits and
   draws its leader */
.ax-signal__you {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
  display: grid;
  row-gap: 2px;
  padding: 5px 9px;
  border-radius: var(--ax-r-xs);
  background: rgb(var(--ax-black-rgb) / .9);
  box-shadow: inset 0 0 0 1px rgb(var(--ax-accent-text-rgb) / .38);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  line-height: 1.35;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ax-text-muted);
  pointer-events: none;
  opacity: 0;
  transition: opacity .6s var(--ax-ease-out);
}
.ax-signal__you.is-on { opacity: 1; }
.ax-signal__you b { font-weight: 500; color: var(--ax-text-strong); }

/* the clock on the station plate; a visitor's own time difference in the accent */
.ax-signal__clock b {
  font-weight: 500;
  color: var(--ax-text-muted);
  font-variant-numeric: tabular-nums;
}
.ax-signal__clock span { color: rgb(var(--ax-accent-text-rgb)); }

/* the headline locking in: each character in a box the width of its real
   letter, a word never broken; the noise in the accent, glowing */
.ax-signal__title.is-locking .ax-lw { display: inline-block; white-space: nowrap; }
.ax-signal__title.is-locking .ax-lc { display: inline-block; text-align: center; }
.ax-signal__title .ax-lc.is-n {
  color: rgb(var(--ax-accent-text-rgb));
  text-shadow: 0 0 14px rgb(var(--ax-accent-text-rgb) / .45);
}
/* and the light along "Running across North America.", once */
.ax-signal__reach.is-lit {
  background: linear-gradient(100deg, var(--ax-text-muted) 0 40%, #fff 48%, rgb(var(--ax-accent-text-rgb)) 53%, var(--ax-text-muted) 62% 100%) 100% 0 / 250% 100% no-repeat;
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: ax-reach-light 1.7s var(--ax-ease-in-out) both;
}
@keyframes ax-reach-light {
  from { background-position: 100% 0; }
  to   { background-position: 0% 0; }
}

/* the station plate types itself in as the page paints, a line at a time */
@media (prefers-reduced-motion: no-preference) {
  .ax-signal__station > * { animation: ax-station-type .8s steps(26, end) both; }
  .ax-signal__station > :nth-child(2) { animation-delay: .22s; }
  .ax-signal__station > :nth-child(3) { animation-delay: .44s; }
  .ax-signal__station > :nth-child(4) { animation-delay: .12s; }
}
@keyframes ax-station-type {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0); }
}

@media print, (forced-colors: active) {
  .ax-signal__world, .ax-signal__over, .ax-signal__hud, .ax-signal__you { display: none; }
  .ax-signal__station > * { animation: none; }
}

/* ── still ───────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  /* the renderer draws one frame and stops; this is everything else */
  .ax-signal__live { animation: none; }
}

@media print, (forced-colors: active) {
  .ax-signal::before, .ax-signal__mapwrap { display: none; }
  .ax-signal__stage { grid-template-columns: minmax(0, 1fr); grid-template-areas: "copy" "disc"; }
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  18 · THE BROADCAST — the page reacts to the track
 *  ---------------------------------------------------------------------------
 *  Scripts/arxeon.signal.js turns the audio into eleven numbers on each
 *  section and draws nothing. Everything below is CSS reading those numbers.
 *  That split is the point: any section built later reacts by reading the
 *  same bus, and the whole system degrades to the static page if the script
 *  never runs. Since round 38 the bus runs ONLY WHILE THE TRACK PLAYS — with
 *  the sound off nothing on the page keeps time to a beat nobody can hear.
 *
 *      --ax-sig-low / -mid / -high    0..1, the three bands
 *      --ax-sig-hit                   0..1, decaying from a transient
 *      --ax-sig-b0 … --ax-sig-b7      0..1, eight bands, low to high
 *
 *  THE SPECTRUM IS THE GEOGRAPHY. b0..b7 are laid WEST TO EAST across the
 *  continent — bass on the Pacific coast where the transmission starts, hats
 *  on the Atlantic. It is eight columns inside the same dot mask, so light can
 *  only land on land, and the visitor sees the continent moving exactly with
 *  what they hear without a single bar-graph anywhere on the page.
 *
 *  EVERY REACTIVE DECLARATION IS opacity OR transform, and nothing else. A
 *  custom property used inside a gradient re-rasterises that gradient on every
 *  frame; used in an opacity it does not. So the grounds stay static and the
 *  layers above them fade — which is why sixty frames a second of this costs
 *  about a millisecond.
 *
 *  DEFAULTS EVERYWHERE. Every var() carries a fallback, so with the script
 *  absent — or blocked, or still loading — the section is exactly the page it
 *  was before this file: nothing collapses to zero and disappears.
 * ═════════════════════════════════════════════════════════════════════════ */

/* ── section 1 ───────────────────────────────────────────────────────────── */

/* SECTION 1 NO LONGER READS THESE PROPERTIES. Its continent is a WebGL canvas
   (Scripts/arxeon.continent.js), and a canvas has no style to read a custom
   property from, so it takes the same eight bands through Arxeon.signal.read()
   instead. The spectrum strips, the rings, the arcs and the headline glitch
   that used to live here went with the old map in round 38. */

/* ── the control ─────────────────────────────────────────────────────────── */

/* Hidden in the markup and revealed by the script, because a button that does
   nothing is worse than no button. WCAG 1.4.2 wants a way to stop audio that
   runs past three seconds; this is it, and it is also the only way to start
   it, so it can never be missed. */
.ax-sound {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  padding: 7px var(--ax-sp-5);
  border: 0;
  border-radius: var(--ax-r-pill, 999px);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--ax-line);
  color: var(--ax-text-muted);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: var(--ax-tr-micro);
  text-transform: uppercase;
  cursor: pointer;
  transition: color .18s var(--ax-ease-out), box-shadow .18s var(--ax-ease-out);
}
.ax-sound[hidden] { display: none; }
.ax-sound:hover { color: var(--ax-text); box-shadow: inset 0 0 0 1px var(--ax-line-hi, var(--ax-line)); }
.ax-sound.is-on { color: var(--ax-accent-text); box-shadow: inset 0 0 0 1px rgb(var(--ax-accent-text-rgb) / .38); }
.ax-sound__eq {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  inline-size: 16px;
  block-size: 12px;
}
.ax-sound__eq i {
  flex: 1;
  display: block;
  block-size: 100%;
  border-radius: 1px;
  background: currentColor;
  opacity: .45;
  transform: scaleY(.22);
  transform-origin: 50% 100%;
  transition: transform .12s linear;
}
/* At rest a flat little grille; live, the five bars ARE five of the eight
   bands, so the control is a readout of the same bus the map is on. The
   values are written onto the button itself rather than inherited, because
   the bus is scoped to the section and this lives in the header. */
.ax-sound.is-on .ax-sound__eq i { opacity: 1; transition: none; }
.ax-sound.is-on .ax-sound__eq i:nth-child(1) { transform: scaleY(calc(.22 + var(--ax-sig-b0, 0) * .78)); }
.ax-sound.is-on .ax-sound__eq i:nth-child(2) { transform: scaleY(calc(.22 + var(--ax-sig-b2, 0) * .78)); }
.ax-sound.is-on .ax-sound__eq i:nth-child(3) { transform: scaleY(calc(.22 + var(--ax-sig-b4, 0) * .78)); }
.ax-sound.is-on .ax-sound__eq i:nth-child(4) { transform: scaleY(calc(.22 + var(--ax-sig-b5, 0) * .78)); }
.ax-sound.is-on .ax-sound__eq i:nth-child(5) { transform: scaleY(calc(.22 + var(--ax-sig-b7, 0) * .78)); }
.ax-sound__label { line-height: 1; }
@media (max-width: 899px) { .ax-sound__label { display: none; } .ax-sound { padding: 7px 10px; } }

/* ── stillness ───────────────────────────────────────────────────────────── */

/* The script never adds .is-live when the visitor has asked for less motion,
   so none of the above can engage. These rules are the belt to that braces:
   if the class ever arrives anyway, nothing here moves. Sound stays available
   — wanting less motion is not the same as wanting no music. */
@media (prefers-reduced-motion: reduce) {
  .ax-sound.is-on .ax-sound__eq i { transform: scaleY(.6); }
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  19 · THE CHANNEL — section 2, the work as stations
 *  ---------------------------------------------------------------------------
 *  Section 1 is a transmission from Calgary. This is what is on the wire, so
 *  it is not a slider: one station fills the screen, the rail carries on down
 *  the left edge as the tuner scale, and a change lands as a TEAR rather than
 *  a slide. Scripts/arxeon.channel.js drives it; this draws it.
 *
 *  EACH STATION OWNS A BAND. --ax-sig-st is "the band the station on air cares
 *  about", resolved in JS because CSS cannot index a custom property by a
 *  variable. With two projects the first sits on the bass and the second on
 *  the air; with eight they get one each. Nothing here counts.
 *
 *  --st IS THE STATION'S OWN ACCENT, an rgb triplet set inline per <li>, so a
 *  project brings its real brand colour with it and the tuner reads as
 *  genuinely different channels rather than one colour repeated.
 *
 *  THE PLATE IS A PHOTOGRAPH AND THE TYPE IS TYPE. Nothing is baked into the
 *  image: the name, the status, the line, the stack and the link are all real
 *  markup over the top. That is what keeps it sharp on a phone, selectable,
 *  and readable by a crawler.
 *
 *  EVERY REACTIVE DECLARATION IS opacity OR transform. Round 25 measured what
 *  happens when that rule is broken — a reactive opacity on a masked element
 *  ran at 47ms a frame — so it is not a preference here, it is the budget.
 *
 *  ROUND 39 — THE STAGE. The plates stopped being one photograph each. Every
 *  project is its ROOM plus its OBJECT on a transparent background, and
 *  Scripts/arxeon.stage.js composes them live in WebGL: the room covers the
 *  section, the object stands on the room's floor and is fitted between the
 *  card and the edge, so it is never cropped (the old plate cut the tower's
 *  head off on every wide screen) and never under the text. While it runs
 *  the section carries .is-live-gl and the markup's pictures below are
 *  hidden; they are what a visitor without WebGL or without script sees,
 *  and they are laid out here as the same two layers, registered exactly as
 *  Farhad drew them.
 * ═════════════════════════════════════════════════════════════════════════ */

.ax-channel {
  --ch-h: clamp(660px, calc(100svh - 84px), 1080px);
  --ch-pad: calc(var(--ax-sp-12) + var(--ax-sp-9));

  position: relative;
  display: grid;
  min-block-size: var(--ch-h);
  overflow: clip;
  isolation: isolate;
  background: var(--ax-bg);
}

/* ── the plates ──────────────────────────────────────────────────────────── */

.ax-channel__stations {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  z-index: 0;
}
.ax-channel__station {
  position: absolute;
  inset: 0;
  /* the container, rebuilt as a grid: gutter | column | gutter. The plate
     spans the whole thing and bleeds; the card is locked to the middle
     column, so it lines up with section 1's copy to the pixel. */
  display: grid;
  grid-template-columns:
      minmax(var(--ax-gutter), 1fr)
      minmax(0, var(--ax-container-wide))
      minmax(var(--ax-gutter), 1fr);
  /* stretch, so the single row fills the section and align-self on the card
     has somewhere to centre inside */
  align-content: stretch;
  opacity: 0;
  visibility: hidden;
  transition: opacity .55s var(--ax-ease-out), visibility 0s .55s;
}
.ax-channel__station.is-current {
  opacity: 1;
  visibility: visible;
  transition: opacity .55s var(--ax-ease-out), visibility 0s 0s;
}

/* NO GRID PLACEMENT HERE, and this cost an hour. An absolutely positioned
   child of a grid container is normally laid out against the container's
   PADDING BOX — but the moment you give it grid-row/grid-column, its
   containing block becomes that GRID AREA instead. With align-content:end the
   row was only as tall as the card, so inset:0 resolved to a 1920x294 strip
   at the very bottom and the artwork looked shrunk into a corner. It had:
   the box was the corner. */
.ax-channel__plate {
  position: absolute;
  inset: 0;
  overflow: clip;
  z-index: 0;
}
/* THE PICTURE WITHOUT WEBGL: the room and the object as the two layers they
   are, on one box with the room's own proportions. The box COVERS the plate
   (min-size 100% in both axes, and aspect-ratio carries the larger one
   across), hangs from the TOP so the object's head is the last thing to be
   cropped, and sits at 72% across so a narrow screen keeps the object rather
   than the empty half of the room. The object's four percentages are its
   rectangle in the 1672x941 room, written by the stage builder. */
.ax-channel__art {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 72%;
  translate: -72% 0;
  aspect-ratio: 1672 / 941;
  min-inline-size: 100%;
  min-block-size: 100%;
}
.ax-channel__room,
.ax-channel__object {
  position: absolute;
  display: block;
  margin: 0;
}
.ax-channel__room { inset: 0; }
.ax-channel__object {
  left: var(--ox, 60%);
  top: var(--oy, 3%);
  inline-size: var(--ow, 22%);
  block-size: var(--oh, 82%);
}
.ax-channel__room img,
.ax-channel__object img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

/* THE STAGE — one canvas under every station. It is drawn only once the
   renderer has its layers, and only then are the pictures above hidden, so
   there is no frame with neither. */
.ax-channel__scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.ax-channel__gl {
  position: absolute;
  inset: 0;
  display: block;
  inline-size: 100%;
  block-size: 100%;
}
.ax-channel.is-live-gl .ax-channel__plate { visibility: hidden; }
/* the morph is the retune now; the scan-line tear is the fallback's */
.ax-channel.is-live-gl .ax-channel__tear { display: none; }

/* THE VEIL — the station's own colour, lit by the station's own band. This is
   where section 2 breathes with the track: the plate stays a static bitmap and
   a flat colour layer above it changes opacity, which composites. */
.ax-channel__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(ellipse 70% 80% at 72% 48%,
      rgb(var(--st, var(--ax-accent-text-rgb)) / .55) 0%,
      rgb(var(--st, var(--ax-accent-text-rgb)) / .16) 45%,
      rgb(var(--st, var(--ax-accent-text-rgb)) / 0) 78%);
  opacity: .12;
  will-change: opacity;
}
.ax-channel.is-live.is-in .ax-channel__veil {
  opacity: calc(.10 + var(--ax-sig-st, 0) * .34);
}

/* the guarantee that type never sits on unprotected artwork */
.ax-channel__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* Measured by looking: the first pass ran to .86 black across the left
     half and a solid --ax-bg along the whole bottom, which between them
     deleted the plate. A scrim's job is to make type legible, not to hide the
     photograph the section is built around. Pulled back until the artwork
     reads and the contrast harness still passes at 4.5:1. */
  /* ROUND 38: the first layer is new. Section 1 now ends on its own ground,
     and a full-bleed photograph starting on a hard edge right under it read
     as the page cutting to the next slide. The plate rises out of the ground
     instead. */
  background:
    linear-gradient(to bottom, var(--ax-bg) 0%, rgb(var(--ax-black-rgb) / .55) 7%, rgb(var(--ax-black-rgb) / 0) 22%),
    linear-gradient(74deg, rgb(var(--ax-black-rgb) / .92) 0%, rgb(var(--ax-black-rgb) / .74) 18%,
        rgb(var(--ax-black-rgb) / .30) 44%, rgb(var(--ax-black-rgb) / 0) 68%),
    linear-gradient(to top, rgb(var(--ax-black-rgb) / .74) 0%, rgb(var(--ax-black-rgb) / 0) 34%);
}

/* ── the card ────────────────────────────────────────────────────────────── */

.ax-channel__card {
  grid-column: 2;
  grid-row: 1;
  /* CENTRED, not floored. Pinned to the bottom of a 1080px section the card
     was a small island with four hundred pixels of nothing above it — the
     same mistake section 1 made before the station plate went in. Centred, it
     sits opposite the plate's subject and the composition reads as one frame
     rather than two unrelated corners. */
  align-self: center;
  justify-self: start;
  position: relative;
  z-index: 2;
  max-inline-size: min(46%, 620px);
  /* CLEARS THE TUNER. Measured, not guessed: at 1440 the container runs
     edge to edge, so the card's left edge and the tuner's ticks both wanted
     x=40..61 — and the contrast harness found grey tick text sitting on the
     teal segment of the Qlynic logo at 1.04:1. At 1920 the container is
     centred and the collision vanishes, which is exactly why it passed there
     and failed in the middle. Both now hang off the same container edge with a
     constant gap, so the relationship holds at every width instead of only
     the ones that happened to be tested. */
  padding-inline-start: var(--ch-indent, 52px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--ax-sp-6);
}

/* THE WHOLE MARK TAKES THE STATION'S COLOUR, not part of it. Round 26 tinted
   only .ec-mark — the cross — and left the rest white. But that cross is not an
   ornament beside the word: its vertical stroke and crossbar ARE the spine and
   middle bar of the "e" in "eau", with two separate rects completing the
   letter. Colouring half a letterform one colour and half another stops it
   being a letter, and at 22px the wordmark read as "+au". A logo is one object.
   Marks that carry their own gradients (Qlynic) set fill per path and ignore
   `color` entirely, so this is safe for every station. */
.ax-channel__mark {
  block-size: 30px;
  display: block;
  color: rgb(var(--st, var(--ax-accent-text-rgb)));
}
.ax-channel__mark svg { block-size: 100%; inline-size: auto; display: block; }
.ax-channel__mark .ec-mark { fill: currentColor; }

.ax-channel__name {
  font-size: var(--ax-fs-d3, var(--ax-fs-2xl));
  line-height: var(--ax-lh-display);
  letter-spacing: var(--ax-tr-hero);
  font-weight: var(--ax-fw-bold);
  color: var(--ax-text-strong);
  margin: 0;
}
/* the rule under the name is the station's meter */
.ax-channel__name::after {
  content: "";
  display: block;
  inline-size: 110px;
  block-size: 2px;
  margin-block-start: var(--ax-sp-4);
  border-radius: 2px;
  background: rgb(var(--st, var(--ax-accent-text-rgb)));
  transform: scaleX(.28);
  transform-origin: 0 50%;
  will-change: transform;
}
.ax-channel.is-live.is-in .ax-channel__name::after {
  transform: scaleX(calc(.28 + var(--ax-sig-st, 0) * .72));
}

.ax-channel__meta { display: flex; align-items: center; gap: var(--ax-sp-5); flex-wrap: wrap; }
.ax-channel__status {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  padding: 5px var(--ax-sp-5);
  border-radius: var(--ax-r-pill, 999px);
  box-shadow: inset 0 0 0 1px rgb(var(--st, var(--ax-accent-text-rgb)) / .42);
  background: rgb(var(--st, var(--ax-accent-text-rgb)) / .10);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: var(--ax-tr-micro);
  text-transform: uppercase;
  color: var(--ax-text-950, #F5F5F7);
}
.ax-channel__status::before {
  content: "";
  inline-size: 6px;
  block-size: 6px;
  border-radius: 50%;
  background: rgb(var(--st, var(--ax-accent-text-rgb)));
  flex: none;
}
.ax-channel__status[data-status="building"] { box-shadow: inset 0 0 0 1px var(--ax-line); background: none; }
.ax-channel__status[data-status="building"]::before { background: var(--ax-text-subtle); }

.ax-channel__owner {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: var(--ax-tr-micro);
  text-transform: uppercase;
  color: var(--ax-text-muted);
}

.ax-channel__line {
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-lead);
  letter-spacing: var(--ax-tr-lead);
  color: var(--ax-text-body);
  text-wrap: pretty;
  margin: 0;
}

.ax-channel__stack {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ax-sp-4);
  margin: 0;
  padding: 0;
  list-style: none;
}
.ax-channel__stack li {
  padding: 4px var(--ax-sp-5);
  border-radius: var(--ax-r-xs);
  box-shadow: inset 0 0 0 1px var(--ax-line);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: var(--ax-tr-micro);
  color: var(--ax-text-muted);
}

.ax-channel__link {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-2xs);
  letter-spacing: var(--ax-tr-micro);
  color: var(--ax-accent-text);
  text-decoration: none;
  border-block-end: 1px solid rgb(var(--ax-accent-text-rgb) / .35);
  padding-block-end: 2px;
}
.ax-channel__link:hover { border-block-end-color: var(--ax-accent-text); }
.ax-channel__link svg { inline-size: 14px; block-size: 14px; }

/* the card's contents arrive one after another when a station lands */
.ax-channel__card > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .5s var(--ax-ease-out), transform .5s var(--ax-ease-out);
}
.ax-channel__station.is-current .ax-channel__card > * { opacity: 1; transform: none; }
.ax-channel__station.is-current .ax-channel__card > :nth-child(1) { transition-delay: .06s; }
.ax-channel__station.is-current .ax-channel__card > :nth-child(2) { transition-delay: .12s; }
.ax-channel__station.is-current .ax-channel__card > :nth-child(3) { transition-delay: .18s; }
.ax-channel__station.is-current .ax-channel__card > :nth-child(4) { transition-delay: .24s; }
.ax-channel__station.is-current .ax-channel__card > :nth-child(5) { transition-delay: .30s; }
.ax-channel__station.is-current .ax-channel__card > :nth-child(6) { transition-delay: .36s; }

/* ── the section's own furniture ─────────────────────────────────────────── */

.ax-channel__stage {
  position: relative;
  z-index: 3;
  display: grid;
  grid-template-rows: auto 1fr;
  pointer-events: none;      /* the plates own the space; only controls click */
}
.ax-channel__stage a,
.ax-channel__stage button { pointer-events: auto; }

.ax-channel__label {
  align-self: start;
  justify-self: start;
  margin-block-start: var(--ax-sp-12);
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-5);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-2xs);
  font-weight: var(--ax-fw-medium);
  letter-spacing: var(--ax-tr-micro);
  text-transform: uppercase;
  color: var(--ax-text-muted);
  margin-block-end: 0;
}
.ax-channel__label::before {
  content: "";
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  background: var(--ax-accent-text);
  flex: none;
  box-shadow: 0 0 0 0 rgb(var(--ax-accent-text-rgb) / .6);
  animation: ax-channel-onair 2.6s var(--ax-ease-out) infinite;
}
@keyframes ax-channel-onair {
  0%        { box-shadow: 0 0 0 0 rgb(var(--ax-accent-text-rgb) / .55); }
  70%, 100% { box-shadow: 0 0 0 10px rgb(var(--ax-accent-text-rgb) / 0); }
}

/* THE TUNER — the rail from section 1, carried on and made usable. */
.ax-channel__tuner {
  position: absolute;
  inset-block: 18%;
  /* the container's own border box, so the tuner and the card are hung off
     one edge rather than two that drift apart as the viewport changes */
  inset-inline-start: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--ax-sp-7);
  margin: 0;
  padding: 0;
  list-style: none;
}
.ax-channel__tuner::before {
  content: "";
  position: absolute;
  inset-block: -12%;
  inset-inline-start: 0;
  inline-size: 1px;
  background: linear-gradient(to bottom,
      rgb(var(--ax-white-rgb) / 0) 0%,
      rgb(var(--ax-white-rgb) / .09) 14%,
      rgb(var(--ax-white-rgb) / .09) 86%,
      rgb(var(--ax-white-rgb) / 0) 100%);
}
.ax-channel__tick {
  position: relative;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: var(--ax-tr-micro);
  color: var(--ax-text-subtle);
  /* a hairline that grows into a mark when the station is on air */
  padding-inline-start: 26px;
  line-height: 1;
  transition: color .3s var(--ax-ease-out);
}
.ax-channel__tick::before {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 0;
  inline-size: 9px;
  block-size: 1px;
  background: currentColor;
  opacity: .5;
  transform-origin: 0 50%;
  transition: inline-size .3s var(--ax-ease-out), opacity .3s var(--ax-ease-out);
}
.ax-channel__tick:hover { color: var(--ax-text); }
.ax-channel__tick.is-current { color: var(--ax-accent-text); }
.ax-channel__tick.is-current::before { inline-size: 17px; opacity: 1; }
/* the live tick pulses with the low end */
.ax-channel.is-live.is-in .ax-channel__tick.is-current::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 0;
  inline-size: 17px;
  block-size: 1px;
  background: var(--ax-accent-text);
  filter: none;
  opacity: var(--ax-sig-low, 0);
  transform: scaleX(calc(1 + var(--ax-sig-low, 0) * 1.4));
  transform-origin: 0 50%;
}

/* THE TEAR — the retune. Horizontal bands sweeping once, 460ms, and then it
   is gone. It is one element and it only ever changes opacity and transform,
   which is why a change can land on a beat without costing a frame. */
.ax-channel__tear {
  position: absolute;
  inset: -10% 0;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  background: repeating-linear-gradient(to bottom,
      rgb(var(--ax-white-rgb) / .055) 0 2px,
      rgb(var(--ax-white-rgb) / 0) 2px 7px);
  will-change: opacity, transform;
}
.ax-channel.is-retuning .ax-channel__tear { animation: ax-channel-tear .46s steps(6, end) 1; }
@keyframes ax-channel-tear {
  0%   { opacity: 0;   transform: translateY(-4%) scaleY(1); }
  18%  { opacity: 1;   transform: translateY(2%)  scaleY(1.06); }
  46%  { opacity: .72; transform: translateY(-3%) scaleY(.96); }
  74%  { opacity: .9;  transform: translateY(4%)  scaleY(1.04); }
  100% { opacity: 0;   transform: translateY(0)   scaleY(1); }
}
/* a drop tears it too, briefly, without changing station */
.ax-channel.is-glitch .ax-channel__tear { animation: ax-channel-tear .4s steps(5, end) 1; }

/* ── responsive ──────────────────────────────────────────────────────────── */

@media (max-width: 1023px) {
  /* one column: the stage above, the card on the floor of the section. The
     scrim is dark only where the card is, so the object keeps its light. */
  .ax-channel__card {
    align-self: end;
    max-inline-size: 100%;
    padding-inline-end: var(--ax-sp-7);
    padding-block-end: var(--ch-pad);
  }
  .ax-channel__scrim {
    background:
      linear-gradient(to top, var(--ax-bg) 4%, rgb(var(--ax-black-rgb) / .90) 36%,
          rgb(var(--ax-black-rgb) / .55) 50%, rgb(var(--ax-black-rgb) / 0) 66%);
  }
  /* the picture without WebGL, the same idea: it takes the upper part of the
     section and fades out before the card, with the object centred (78% is
     where a tall, narrow crop of the room puts the object in the middle) */
  .ax-channel__plate {
    inset-block-end: 38%;
    -webkit-mask-image: linear-gradient(to bottom, #000 78%, transparent);
            mask-image: linear-gradient(to bottom, #000 78%, transparent);
  }
  .ax-channel__art { inset-inline-start: 78%; translate: -78% 0; }
}
@media (max-width: 639px) {
  /* the tuner lies down along the bottom here, so the card takes the width back */
  /* taller than the screen on purpose: the object gets the screen first and
     the card follows it, instead of the two sharing one phone-sized frame */
  .ax-channel { --ch-pad: var(--ax-sp-11); --ch-indent: 0px; min-block-size: clamp(740px, 112svh, 1000px); }
  .ax-channel__tuner {
    inset-block: auto;
    inset-block-end: var(--ax-sp-7);
    inset-inline-start: var(--ax-gutter);
    inset-inline-end: var(--ax-gutter);
    /* stop it painting over the plate's subject on a narrow screen */
    padding: 0;
    flex-direction: row;
    justify-content: flex-start;
    gap: var(--ax-sp-6);
  }
  .ax-channel__tuner::before { display: none; }
  .ax-channel__tick { padding-inline-start: 0; padding-block-start: 12px; }
  .ax-channel__tick::before { inset-block-start: 0; inset-inline-start: 0; inline-size: 14px; }
  .ax-channel__tick.is-current::before { inline-size: 26px; }
  .ax-channel.is-live .ax-channel__tick.is-current::after { inset-block-start: 0; inline-size: 26px; }
  .ax-channel__card { align-self: end; padding-block-end: calc(var(--ch-pad) + var(--ax-sp-10)); }
  .ax-channel__name { font-size: var(--ax-fs-2xl); }
  .ax-channel__line { font-size: var(--ax-fs-md); }
}

/* ── stillness ───────────────────────────────────────────────────────────── */

/* The module never auto-advances, never scrambles and never adds .is-retuning
   under reduced motion; these rules make sure nothing moves even if a class
   arrives anyway. Tuning by hand still works — wanting less motion is not
   wanting less content. */
@media (prefers-reduced-motion: reduce) {
  .ax-channel__station,
  .ax-channel__station.is-current,
  .ax-channel__card > * { transition: none; }
  .ax-channel__card > * { opacity: 1; transform: none; }
  .ax-channel__label::before { animation: none; }
  .ax-channel.is-retuning .ax-channel__tear,
  .ax-channel.is-glitch .ax-channel__tear { animation: none; opacity: 0; }
  .ax-channel.is-live.is-in .ax-channel__veil { opacity: .16; }
  .ax-channel.is-live.is-in .ax-channel__name::after { transform: scaleX(.6); }
  .ax-channel.is-live.is-in .ax-channel__tick.is-current::after { display: none; }
}
@media print, (forced-colors: active) {
  .ax-channel__scene, .ax-channel__plate, .ax-channel__veil, .ax-channel__scrim, .ax-channel__tear { display: none; }
  .ax-channel__station { position: static; opacity: 1; visibility: visible; }
}

/* ── the instruments ───────────────────────────────────────────────────────
   ROUND 94. Section 2 was a caption beside a photograph: after section 1's
   world it read as a product slide. It keeps the stage and gains what an
   instrument would have (arxeon.channel.js and arxeon.stage.js, ROUND 94):

   THE DIAL. The tuner's two numbers became a scale with a station on each
   major mark, a needle in the station's colour that glides to the one on
   air (it can be dragged), and a line growing toward the next station while
   it waits to advance.

   THE READOUT, top right: what the channel is doing (standby, tuning,
   scanning, locked). THE LOG, under "On air": what is on the wire when a
   station lands, typed, every word of it read off the page or measured live.

   THE LOCK. Corner marks close in on the object, its number and name over
   the corner, a sweep passes down it, and on a wide screen the station's
   stack leaves the card and is pinned to the object.

   THE CLASSIFIED. Three stations for work that cannot carry its client's
   name: the name and the stack are bars, the status is hatched, and the
   object is a hologram (the stage draws it).

   THE WIRE, from Calgary on the map to the dial, drawn by the scroll.

   --nc is the colour of the station on air, set on the section by the
   channel; --lk is the locked station's, set on the lock by the stage. */

/* ── the dial ── */
.ax-channel__tuner.is-dial {
  justify-content: space-between;
  gap: 0;
}
@media (min-width: 640px) {
  /* the rail comes in off the page's edge, so the station numbers stand in
     one column with "On air" and the log above them; on the very edge of
     the screen a scale read as cut off */
  .ax-channel__tuner.is-dial { inset-inline-start: max(0px, calc(var(--ax-gutter) - 26px)); }
}
@media (min-width: 1024px) {
  /* the log sits under "On air"; the dial starts below it */
  .ax-channel__tuner.is-dial { inset-block: max(30%, calc(var(--ax-sp-12) + 182px)) 14%; }
}
/* the fine scale between the stations */
.ax-channel__tuner.is-dial::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 6px;
  background: repeating-linear-gradient(to bottom,
      rgb(var(--ax-white-rgb) / .16) 0 1px,
      rgb(var(--ax-white-rgb) / 0) 1px 9px);
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 6%, #000 94%, transparent);
  pointer-events: none;
}
/* the needle, in the colour of the station on air; its grip is wider than it looks */
.ax-channel__needle {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: 19px;      /* stops short of the station's number */
  block-size: 2px;
  margin-block-start: -1px;
  list-style: none;
  border-radius: 1px;
  background: rgb(var(--nc, var(--ax-accent-text-rgb)));
  box-shadow: 0 0 10px 1px rgb(var(--nc, var(--ax-accent-text-rgb)) / .6);
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
  transition: transform .62s cubic-bezier(.2, .9, .25, 1.12), background-color .4s var(--ax-ease-out), box-shadow .4s var(--ax-ease-out);
}
.ax-channel__needle::before {
  content: "";
  position: absolute;
  inset: -9px -6px;
}
.ax-channel__needle::after {
  content: "";
  position: absolute;
  inset-block-start: -2px;
  inset-inline-end: -3px;
  inline-size: 6px;
  block-size: 6px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 8px 2px rgb(var(--nc, var(--ax-accent-text-rgb)) / .9);
}
.ax-channel__tuner.is-dragging .ax-channel__needle { transition: none; cursor: grabbing; }
.ax-channel__needle.is-plug { animation: ax-needle-plug .8s var(--ax-ease-out) 1; }
@keyframes ax-needle-plug {
  0%   { box-shadow: 0 0 10px 1px rgb(var(--nc, var(--ax-accent-text-rgb)) / .6); }
  18%  { box-shadow: 0 0 26px 8px rgb(var(--nc, var(--ax-accent-text-rgb)) / .95); }
  100% { box-shadow: 0 0 10px 1px rgb(var(--nc, var(--ax-accent-text-rgb)) / .6); }
}
/* the line toward the next station, grown over the dwell */
.ax-channel__next {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: 1px;
  list-style: none;
  background: linear-gradient(to bottom, rgb(var(--nc, var(--ax-accent-text-rgb)) / .7), rgb(var(--nc, var(--ax-accent-text-rgb)) / .25));
  transform-origin: 50% 0;
  scale: 1 0;
  opacity: 0;
  pointer-events: none;
}
.ax-channel__next.is-up { transform-origin: 50% 100%; background: linear-gradient(to top, rgb(var(--nc, var(--ax-accent-text-rgb)) / .7), rgb(var(--nc, var(--ax-accent-text-rgb)) / .25)); }
.ax-channel__next.is-on { opacity: 1; animation: ax-next-grow var(--dwell, 8200ms) linear forwards; }
@keyframes ax-next-grow {
  from { scale: 1 0; }
  to   { scale: 1 1; }
}

/* ── the readout ── */
.ax-channel__readout {
  position: absolute;
  inset-block-start: var(--ax-sp-12);
  inset-inline-end: var(--ax-gutter);
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  block-size: 1.8em;     /* "On air"'s own height, so the two share a middle */
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: var(--ax-tr-micro);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ax-text-subtle);
  pointer-events: none;
}
.ax-channel__readout b { font-weight: 500; color: var(--ax-text-muted); font-variant-numeric: tabular-nums; }
/* an object reaching up into the top right: the readout stands beside "On air" */
.ax-channel.is-crowded .ax-channel__readout {
  inset-inline-end: auto;
  inset-inline-start: calc(var(--ax-gutter) + var(--ax-onair, 66px) + var(--ax-sp-8));
}
.ax-channel__readout span::before { content: "\00B7"; margin-inline-end: 9px; color: var(--ax-text-subtle); }
.ax-channel__readout[data-state="tuning"] span,
.ax-channel__readout[data-state="scanning"] span { color: rgb(var(--nc, var(--ax-accent-text-rgb))); }

/* ── the log ── */
.ax-channel__log {
  position: absolute;
  inset-block-start: calc(var(--ax-sp-12) + 36px);
  inset-inline-start: var(--ax-gutter);
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  row-gap: 2px;
  max-inline-size: 52%;      /* wider than its longest line will ever be */
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  line-height: 1.75;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
  pointer-events: none;
}
.ax-channel__log li { min-block-size: 1.75em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ax-channel__log li:not(:empty)::before {
  /* the prompt stands where "On air"'s dot does, the line where its word does */
  content: "\203A";
  display: inline-block;
  inline-size: 7px;
  margin-inline-end: var(--ax-sp-5);
  text-align: center;
  color: rgb(var(--nc, var(--ax-accent-text-rgb)));
}
.ax-channel__log li:not(:empty):not(.is-done)::after {
  content: "";
  display: inline-block;
  inline-size: .6em;
  block-size: 1.05em;
  margin-inline-start: 3px;
  vertical-align: -2px;
  background: rgb(var(--nc, var(--ax-accent-text-rgb)) / .8);
}
.ax-channel__log.is-tight { display: none; }

/* ── the lock ── */
.ax-channel__lock {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.ax-channel__frame {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  opacity: 0;
  transition: opacity .2s var(--ax-ease-out);
}
.ax-channel__lock.is-on .ax-channel__frame { opacity: 1; transition: opacity .35s var(--ax-ease-out); }
.ax-channel__corner {
  position: absolute;
  inline-size: 18px;
  block-size: 18px;
  border: 0 solid rgb(var(--lk, var(--ax-accent-text-rgb)) / .85);
  transition: translate .6s cubic-bezier(.2, .9, .2, 1);
}
.ax-channel__corner.is-tl { inset-inline-start: -18px; inset-block-start: -18px; border-inline-start-width: 1px; border-block-start-width: 1px; translate: -26px -26px; }
.ax-channel__corner.is-tr { inset-inline-end: -18px;   inset-block-start: -18px; border-inline-end-width: 1px;   border-block-start-width: 1px; translate: 26px -26px; }
.ax-channel__corner.is-bl { inset-inline-start: -18px; inset-block-end: -18px;   border-inline-start-width: 1px; border-block-end-width: 1px;   translate: -26px 26px; }
.ax-channel__corner.is-br { inset-inline-end: -18px;   inset-block-end: -18px;   border-inline-end-width: 1px;   border-block-end-width: 1px;   translate: 26px 26px; }
.ax-channel__lock.is-on .ax-channel__corner { translate: 0 0; }
.ax-channel__tag {
  position: absolute;
  inset-inline-start: -18px;
  inset-block-end: calc(100% + 26px);
  padding: 2px 7px;
  border-radius: var(--ax-r-xs);
  background: rgb(var(--ax-black-rgb) / .72);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgb(var(--lk, var(--ax-accent-text-rgb)));
}
.ax-channel__sweep {
  position: absolute;
  inset-inline: -18px;
  inset-block-start: 0;
  block-size: 1px;
  opacity: 0;
  background: linear-gradient(90deg, rgb(var(--lk, var(--ax-accent-text-rgb)) / 0), rgb(var(--lk, var(--ax-accent-text-rgb)) / .9) 14%,
      rgb(var(--ax-white-rgb) / .95) 50%, rgb(var(--lk, var(--ax-accent-text-rgb)) / .9) 86%, rgb(var(--lk, var(--ax-accent-text-rgb)) / 0));
  box-shadow: 0 0 12px rgb(var(--lk, var(--ax-accent-text-rgb)) / .8);
}
.ax-channel__lock.is-on:not(.is-quiet) .ax-channel__sweep { animation: ax-lock-sweep 1.25s linear .05s 1 both; }
@keyframes ax-lock-sweep {
  0%   { inset-block-start: -3%;  opacity: 0; }
  6%   { opacity: 1; }
  90%  { opacity: 1; }
  100% { inset-block-start: 103%; opacity: 0; }
}
/* the stack, pinned to the object: a dot on its edge, a leader, the name */
.ax-channel__calls { position: absolute; inset-block-start: 0; inset-inline-start: 0; }
.ax-channel__call {
  position: absolute;
  display: block;
  translate: 0 -50%;
  opacity: 0;
  transition: opacity .35s var(--ax-ease-out);
}
.ax-channel__lock.is-on .ax-channel__call { opacity: 1; }
.ax-channel__lock:not(.is-on) .ax-channel__call,
.ax-channel__lock:not(.is-on) .ax-channel__call i { transition-delay: 0s !important; transition-duration: .15s; }
.ax-channel__call b {
  display: block;
  padding: 3px 7px;
  border-radius: var(--ax-r-xs);
  background: rgb(var(--ax-black-rgb) / .78);
  box-shadow: inset 0 0 0 1px rgb(var(--lk, var(--ax-accent-text-rgb)) / .30);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ax-text-muted);
}
.ax-channel__call i {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: 100%;
  inline-size: var(--lead, 30px);
  block-size: 1px;
  background: linear-gradient(to left, rgb(var(--lk, var(--ax-accent-text-rgb)) / .75), rgb(var(--lk, var(--ax-accent-text-rgb)) / .35));
  transform-origin: 100% 50%;
  scale: 0 1;
  transition: scale .4s var(--ax-ease-out);
  transition-delay: inherit;
}
.ax-channel__call i::before {
  content: "";
  position: absolute;
  inset-inline-start: -3px;
  inset-block-start: -2.5px;
  inline-size: 6px;
  block-size: 6px;
  border-radius: 50%;
  background: rgb(var(--lk, var(--ax-accent-text-rgb)));
  box-shadow: 0 0 8px rgb(var(--lk, var(--ax-accent-text-rgb)) / .9);
}
.ax-channel__lock.is-on .ax-channel__call i { scale: 1 1; }
.ax-channel__call.is-left { translate: -100% -50%; }
.ax-channel__call.is-left i { inset-inline-end: auto; inset-inline-start: 100%; transform-origin: 0 50%;
  background: linear-gradient(to right, rgb(var(--lk, var(--ax-accent-text-rgb)) / .75), rgb(var(--lk, var(--ax-accent-text-rgb)) / .35)); }
.ax-channel__call.is-left i::before { inset-inline-start: auto; inset-inline-end: -3px; }
/* while the callouts carry the stack, the card's chips are for screen readers only */
@media (min-width: 1024px) {
  .ax-channel.is-live-gl.has-callouts .ax-channel__stack {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* ── the classified ── */
.ax-channel__redact {
  position: relative;
  display: inline-block;
  inline-size: calc(var(--n, 6) * .62em);
  block-size: .78em;
  margin-inline-end: .32em;
  vertical-align: -.06em;
  border-radius: 2px;
  background: linear-gradient(90deg, rgb(var(--st, var(--nc, 168 182 204)) / .82), rgb(var(--st, var(--nc, 168 182 204)) / .52));
}
.ax-channel__redact:last-child { margin-inline-end: 0; }
.ax-channel__name .ax-channel__redact { inline-size: calc(var(--n, 6) * .56em); block-size: .66em; vertical-align: .02em; }
.ax-channel__name.is-trying .ax-channel__redact { background: rgb(var(--st, 168 182 204) / .14); box-shadow: inset 0 0 0 1px rgb(var(--st, 168 182 204) / .45); }
.ax-channel__name.is-trying .ax-channel__redact::after {
  content: attr(data-noise);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: space-around;
  overflow: hidden;
  font-family: var(--ax-font-mono);
  font-size: .62em;
  font-weight: 500;
  letter-spacing: 0;
  color: rgb(var(--st, 168 182 204));
}
.ax-channel__status[data-status="classified"] {
  background: repeating-linear-gradient(135deg, rgb(var(--st, 168 182 204) / .16) 0 4px, rgb(var(--st, 168 182 204) / 0) 4px 8px);
}
.ax-channel__stack li.is-redacted { padding-block: 6px; line-height: 0; }
.ax-channel__stack li.is-redacted .ax-channel__redact { block-size: 8px; vertical-align: 0; }

/* without WebGL a classified station's hologram is drawn once on this
   canvas, placed in the borrowed room by the same box the stage gives it */
.ax-channel__holo-still {
  position: absolute;
  display: block;
  margin: 0;
  pointer-events: none;
}

/* the name locking in: each character in a box the width of its real letter */
.ax-channel__name.is-locking .ax-lw { display: inline-block; white-space: nowrap; }
.ax-channel__name.is-locking .ax-lc { display: inline-block; text-align: center; }
.ax-channel__name .ax-lc.is-n {
  color: rgb(var(--st, var(--ax-accent-text-rgb)));
  text-shadow: 0 0 14px rgb(var(--st, var(--ax-accent-text-rgb)) / .45);
}

/* ── the wire ── */
.ax-wire {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  overflow: visible;
  pointer-events: none;
  visibility: hidden;
  z-index: 4;
}
.ax-signal > .ax-wire { z-index: 1; }
.ax-wire__run { fill: none; stroke: rgb(var(--ax-accent-text-rgb) / .07); stroke-width: 1; }
.ax-wire__lit {
  fill: none;
  stroke: rgb(var(--ax-accent-text-rgb) / .62);
  stroke-width: 1.2;
  stroke-linecap: round;
  stroke-dasharray: 0 99999;
}
.ax-wire__head { fill: #fff; opacity: 0; filter: drop-shadow(0 0 5px rgb(var(--ax-accent-text-rgb))) drop-shadow(0 0 2px #fff); }

/* ── smaller screens ── */
@media (max-width: 1023px) {
  .ax-channel__log { display: none; }
}
@media (max-width: 639px) {
  /* a phone keeps the lock's corners and its scan; the name is in the card
     right under the object, and the label row is left to "On air" */
  .ax-channel__needle,
  .ax-channel__next,
  .ax-channel__readout,
  .ax-channel__tag,
  .ax-channel__tuner.is-dial::after { display: none; }
  .ax-channel__tuner.is-dial { justify-content: flex-start; gap: var(--ax-sp-6); }
  .ax-channel__readout { inset-block-start: var(--ax-sp-12); }
  .ax-channel__corner { inline-size: 12px; block-size: 12px; }
  .ax-channel__corner.is-tl { inset-inline-start: -12px; inset-block-start: -12px; }
  .ax-channel__corner.is-tr { inset-inline-end: -12px; inset-block-start: -12px; }
  .ax-channel__corner.is-bl { inset-inline-start: -12px; inset-block-end: -12px; }
  .ax-channel__corner.is-br { inset-inline-end: -12px; inset-block-end: -12px; }
  .ax-channel__tag { inset-inline-start: -12px; inset-block-end: calc(100% + 18px); }
}

/* ── stillness ── */
@media (prefers-reduced-motion: reduce) {
  .ax-channel__needle { transition: none; }
  .ax-channel__next { display: none; }
  .ax-channel__corner { transition: none; translate: 0 0; }
  .ax-channel__call, .ax-channel__call i { transition: none; }
  /* round 95: as specific as the rule that starts the sweep, or it loses to it */
  .ax-channel__lock.is-on:not(.is-quiet) .ax-channel__sweep { animation: none; }
  .ax-wire { display: none; }
}
@media print, (forced-colors: active) {
  .ax-channel__log, .ax-channel__readout, .ax-channel__lock, .ax-channel__needle, .ax-channel__next, .ax-wire { display: none; }
}

/* ===========================================================================
   20 · THE OPEN CHANNEL — section 3
   ---------------------------------------------------------------------------
   Round 28 built this as a column that grew downward, which is what every AI
   chat on the internet is. Two things were wrong with it and they were the
   same thing: the page stretched further the longer you talked, so nobody
   could tell how much was left, and there was nothing to look at but your own
   typing. Round 30 replaces both.

   THE FRAME IS FIXED. The section is exactly one screen, like sections 1 and
   2, and it never grows. The conversation is a STACK, not a scroll: the newest
   exchange sits at the bottom against the entry, older ones recede upward,
   shrink and dim, and the third one back is gone. `justify-content: flex-end`
   plus `overflow: clip` is the whole mechanism — new messages push old ones
   out of the top and the page height never moves.

   THE BRIEF ASSEMBLES WHILE YOU TALK. The right half is not empty and it is
   not waiting: it is there from the first click, holding the whole ladder —
   3,000 to 50,000 — and labelled estimating. Every answer adds scope lines and
   moves the band, and the SCALE BAR under the figures makes that geometric
   rather than numeric: you watch the span contract. The bar is logarithmic,
   because 3k to 50k on a linear axis leaves everything below 10k in a smear at
   the left edge.

   It can widen, and a widening is MARKED. A visitor who adds payments on turn
   four has genuinely made the job bigger; a one-way ratchet would have to lie
   about that. Narrowing is quiet, widening pulses.

   THE RAIL IS THE THROUGH-LINE. Section 1 puts a hairline down the left edge,
   section 2 turns it into the tuner scale, and here it becomes the progress
   of the conversation — one tick per exchange, filling as you go, ending at
   the eye. Three sections, one line. The rail lives INSIDE the stage as its
   own grid column, the same fix round 26 applied to the tuner, so it and the
   content hang off the same edge at every width instead of drifting apart.
   ======================================================================== */

/* ROUND 40 · THE PRESENCE, AND THE TWO EDGES.
   Section 2 ends in true black (its stage fades the room to #000), and this
   section used to start on --ax-bg: a five-level step, which on a good screen
   in a dark room is a visible line under the tower. Now the top of this
   section IS that black -- the void the head sits in -- and it only lifts back
   to --ax-bg at the bottom, where section 4 begins on it. Where section 2 has
   no WebGL it ends on --ax-bg instead, and the void fades in from that.

   THREE COLUMNS from 1100px: you on the left, it in the middle, what it
   works out on the right -- the four ways in before you pick, the brief
   after. The face column is sized here and the canvas fits the head to
   whatever the grid made of it (arxeon.presence.js, layout()). */
.ax-open {
  --op-h: clamp(660px, calc(100svh - 84px), 1080px);
  --op-pad: var(--ax-sp-11);
  --op-face: clamp(300px, 30vw, 560px);
  position: relative;
  display: grid;
  min-block-size: var(--op-h);
  padding-block: var(--op-pad);
  background: var(--ax-bg);
  overflow: clip;
  isolation: isolate;
}

/* ── the dark ────────────────────────────────────────────────────────── */

.ax-open__dark {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(34% 46% at 50% 40%, rgb(var(--ax-white-rgb) / .022), transparent 72%),
    linear-gradient(to bottom, var(--ax-ink-000) 0%, var(--ax-ink-000) 64%, rgb(var(--ax-black-rgb) / 0) 100%);
}
.ax-channel:not(.is-live-gl) + .ax-open .ax-open__dark {
  background:
    radial-gradient(34% 46% at 50% 40%, rgb(var(--ax-white-rgb) / .022), transparent 72%),
    linear-gradient(to bottom, rgb(var(--ax-black-rgb) / 0) 0%, var(--ax-ink-000) 16%, var(--ax-ink-000) 64%, rgb(var(--ax-black-rgb) / 0) 100%);
}

/* the canvas the presence is drawn on: the whole section, under the text */
.ax-open__scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.ax-open__gl {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

/* ── the stage: rail · conversation · face · what it works out ───────── */

/* .ax-open__talk is a wrapper in the markup and nothing in the layout: its
   four children are placed on the stage's own rows, by hand, the same four
   rows round 30 placed them on -- so hiding the voice row still costs an
   empty row and nothing else, and the face and the right-hand column can
   span all four. */
.ax-open__stage {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) var(--op-face) minmax(0, .92fr);
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  column-gap: var(--ax-sp-8);
  row-gap: var(--ax-sp-5);
  align-content: stretch;
  block-size: 100%;
  min-block-size: 0;
}

/* ── the rail ────────────────────────────────────────────────────────── */

.ax-open__rail {
  position: relative;
  grid-column: 1;
  grid-row: 1 / -1;
  display: grid;
  grid-template-rows: auto 1fr;
  justify-items: start;
  min-block-size: 0;
}

.ax-open__eye {
  position: relative;
  inline-size: 7px;
  block-size: 7px;
  margin-inline-start: 1px;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-accent-text-rgb));
}
/* THE MOVING PART IS A CHILD. Round 25 measured 47ms a frame when opacity was
   animated on an element that also carried a mask or a filter. The halo is its
   own element so the compositor can fade it on its own layer. */
.ax-open__eye > i {
  position: absolute;
  inset: -8px;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-accent-text-rgb) / .34);
  opacity: .30;
  will-change: opacity;
}
.ax-open.is-live.is-in .ax-open__eye > i {
  opacity: calc(.18 + var(--ax-sig-low, 0) * .74);
  transition: opacity .09s linear;
}
.ax-open.is-armed:not(.is-live) .ax-open__eye > i { animation: ax-open-breathe 3.6s var(--ax-ease-in-out) infinite; }
@keyframes ax-open-breathe { 0%, 100% { opacity: .20; } 50% { opacity: .58; } }
.ax-open.is-thinking .ax-open__eye > i { animation: ax-open-work .9s var(--ax-ease-in-out) infinite; }
@keyframes ax-open-work { 0%, 100% { opacity: .28; transform: scale(1); } 50% { opacity: .95; transform: scale(1.6); } }

/* one tick per exchange, filling downward */
.ax-open__ticks {
  margin: var(--ax-sp-4) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-auto-rows: 1fr;
  row-gap: var(--ax-sp-2);
  justify-items: start;
  align-content: start;
  inline-size: 9px;
  block-size: min(46%, 340px);
}
.ax-open__ticks li {
  inline-size: 1px;
  block-size: 100%;
  background: var(--ax-line-soft);
  transition: background-color .4s var(--ax-ease-out), inline-size .4s var(--ax-ease-out);
}
.ax-open__ticks li.is-done { inline-size: 3px; background: rgb(var(--ax-accent-text-rgb)); }
.ax-open__ticks li.is-now  { inline-size: 3px; background: rgb(var(--ax-accent-text-rgb) / .55); }

/* ── the conversation column ─────────────────────────────────────────── */

/* FOUR ROWS, PLACED BY HAND. The orb sits between the head and the stack, and
   it is hidden until a track is picked. With implicit placement, hiding it
   would slide the stack into the auto row and the entry into the 1fr row —
   the frame would still be one screen and the conversation inside it would be
   wrong. Naming the line each child sits on makes hiding the orb cost an empty
   row and nothing else. */
.ax-open__talk { display: contents; }
.ax-open__talk > .ax-open__head  { grid-column: 2; grid-row: 1; }
.ax-open__talk > .ax-open__voice { grid-column: 2; grid-row: 2; }
.ax-open__talk > .ax-open__stack { grid-column: 2; grid-row: 3; }
.ax-open__talk > .ax-open__entry { grid-column: 2; grid-row: 4; }

/* ── the face ────────────────────────────────────────────────────────── */
/* The picture is the presence when nothing can animate it; with WebGL the
   canvas draws the head on this box and the picture is hidden, not removed.
   The box spans all four rows, so the head is as tall as the conversation. */

.ax-open__face {
  position: relative;
  grid-column: 3;
  grid-row: 1 / -1;
  min-block-size: 0;
  pointer-events: none;
}
.ax-open__face picture {
  position: absolute;
  inset: 0 0 18% 0;
  display: block;
  /* the picture's black is true black and the void under it lifts to
     --ax-bg toward the bottom, so its rectangle would show: its edges fade */
  -webkit-mask-image: radial-gradient(50% 54% at 50% 44%, #000 76%, transparent 100%);
          mask-image: radial-gradient(50% 54% at 50% 44%, #000 76%, transparent 100%);
}
.ax-open__face img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  object-position: 50% 0;
}
.ax-open.is-live-gl .ax-open__face picture { visibility: hidden; }

.ax-open__head { display: grid; row-gap: var(--ax-sp-4); align-content: start; }
.ax-open.is-open .ax-open__line,
.ax-open.is-open .ax-open__sub { display: none; }

.ax-open__label {
  margin: 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  line-height: var(--ax-lh-micro);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}

.ax-open__line {
  margin: 0;
  max-inline-size: 16ch;
  font-size: var(--ax-fs-d3, var(--ax-fs-2xl));
  line-height: var(--ax-lh-display);
  letter-spacing: var(--ax-tr-hero);
  color: var(--ax-text-strong);
  text-wrap: balance;
}

.ax-open__sub {
  margin: 0;
  max-inline-size: 46ch;
  font-size: var(--ax-fs-md);
  line-height: var(--ax-lh-lead);
  color: var(--ax-text-body);
}

/* ── the four ways in ────────────────────────────────────────────────── */

/* Round 40 moved the list out of the heading and into the right-hand
   column, one choice per row, starting level with the label on the left --
   the face sits between the question and the ways to answer it. */
.ax-open__chips {
  grid-column: 4;
  grid-row: 1 / -1;
  align-self: start;
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--ax-sp-3);
  align-content: start;
}
.ax-open__chips[hidden] { display: none; }

/* THE LIST ITEM HAS TO BE A GRID TOO. The <li> is the grid item and stretches
   correctly; the <a> inside it is what a visitor sees, and a list-item is not
   a container, so its child never got told to fill it — measured at 69px
   inside a 93px box, which is exactly why the four buttons were ragged. Same
   class of bug as the unsized <picture> in round 27: an intermediate element
   between the parent that has the size and the thing that needs it. */
.ax-open__chips li { display: grid; }

.ax-open__chip {
  position: relative;
  display: grid;
  align-content: start;
  row-gap: var(--ax-sp-1);
  block-size: 100%;
  padding: var(--ax-sp-4) var(--ax-sp-5) var(--ax-sp-4) var(--ax-sp-6);
  border: 1px solid var(--ax-line);
  border-radius: var(--ax-r-lg);
  background: rgb(var(--ax-white-rgb) / .018);
  text-decoration: none;
  cursor: pointer;
  transition: border-color .18s var(--ax-ease-out), background-color .18s var(--ax-ease-out), transform .18s var(--ax-ease-out);
}
/* a point of the eyes' light, lit on the one you are about to choose */
.ax-open__chip::before {
  content: "";
  position: absolute;
  inset-block-start: calc(var(--ax-sp-4) + .62em);
  inset-inline-start: var(--ax-sp-3);
  inline-size: 5px;
  block-size: 5px;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-white-rgb) / .22);
  transition: background-color .18s var(--ax-ease-out), box-shadow .18s var(--ax-ease-out);
}
.ax-open__chip:hover::before,
.ax-open__chip:focus-visible::before {
  background: rgb(var(--ax-eye-rgb));
  box-shadow: 0 0 10px 1px rgb(var(--ax-eye-rgb) / .65);
}
.ax-open__chip:hover { border-color: var(--ax-line-strong); background: var(--ax-surface); transform: translateY(-1px); }
.ax-open__chip:focus-visible { outline: 2px solid rgb(var(--ax-accent-text-rgb)); outline-offset: 3px; }
.ax-open__cname { font-size: var(--ax-fs-md); font-weight: 600; color: var(--ax-text-strong); }
.ax-open__cwhat { font-size: var(--ax-fs-sm); line-height: var(--ax-lh-body); color: var(--ax-text-muted); }

/* ROUND 70 · THE CUE. "Start a project" is on every page and it lands here,
   and the first thing the channel does for someone who asked to start is
   show them where. The point of the eyes' light that marks the chip you are
   about to choose runs down the four ways in, twice, and each chip's edge
   catches it as it passes: the light the face's eyes are made of, so it
   reads as the thing looking at the options with you. arxeon.open.js sets
   .is-cue for 4.4s and says the line that goes with it.

   The edge is its own layer (::after) and only its opacity moves. A chip you
   point at or tab to drops out of the cue at once, so the cue never holds
   back the hover or focus state underneath it. */
.ax-open__chip::after {
  content: "";
  position: absolute;
  inset: -1px;
  border: 1px solid rgb(var(--ax-eye-rgb) / .40);
  border-radius: inherit;
  box-shadow: 0 0 24px -8px rgb(var(--ax-eye-rgb) / .50);
  opacity: 0;
  pointer-events: none;
}
.ax-open__chips li:nth-child(2) > .ax-open__chip { --cue-at: 1; }
.ax-open__chips li:nth-child(3) > .ax-open__chip { --cue-at: 2; }
.ax-open__chips li:nth-child(4) > .ax-open__chip { --cue-at: 3; }
.ax-open.is-cue .ax-open__chip::before {
  animation: ax-open-cue-eye 1.8s var(--ax-ease-in-out) calc(var(--cue-at, 0) * 160ms) 2 backwards;
}
.ax-open.is-cue .ax-open__chip::after {
  animation: ax-open-cue-edge 1.8s var(--ax-ease-in-out) calc(var(--cue-at, 0) * 160ms) 2 backwards;
}
.ax-open.is-cue .ax-open__chip:hover::before,
.ax-open.is-cue .ax-open__chip:hover::after,
.ax-open.is-cue .ax-open__chip:focus-visible::before,
.ax-open.is-cue .ax-open__chip:focus-visible::after { animation: none; }
@keyframes ax-open-cue-eye {
  0%, 100% { background: rgb(var(--ax-white-rgb) / .22); box-shadow: 0 0 0 0 rgb(var(--ax-eye-rgb) / 0); }
  30%, 46% { background: rgb(var(--ax-eye-rgb)); box-shadow: 0 0 10px 1px rgb(var(--ax-eye-rgb) / .65); }
}
@keyframes ax-open-cue-edge {
  0%, 100% { opacity: 0; }
  30%, 46% { opacity: 1; }
}
/* where focus lands on arrival: the list itself, so one Tab reaches the
   first choice. It is a landing point, not a control, and draws no ring. */
.ax-open__chips:focus,
.ax-open__chips:focus-visible { outline: none; box-shadow: none; }
/* less motion: nothing runs; the four are simply lit while the cue lasts */
@media (prefers-reduced-motion: reduce) {
  .ax-open.is-cue .ax-open__chip::before,
  .ax-open.is-cue .ax-open__chip::after { animation: none; }
  .ax-open.is-cue .ax-open__chip::before { background: rgb(var(--ax-eye-rgb)); box-shadow: 0 0 10px 1px rgb(var(--ax-eye-rgb) / .65); }
  .ax-open.is-cue .ax-open__chip::after { opacity: .8; }
}
@media print, (forced-colors: active) {
  .ax-open__chip::after { display: none; }
}

/* ── the stack ───────────────────────────────────────────────────────── */
/* The fixed frame in two declarations: bottom-aligned, clipped. New messages
   push old ones out of the top and the section height never moves. */

.ax-open__stack {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  row-gap: var(--ax-sp-5);
  min-block-size: 0;
  overflow: clip;
}
.ax-open__stack:empty { display: none; }

.ax-open__msg {
  display: grid;
  row-gap: var(--ax-sp-2);
  flex: 0 0 auto;
  transform-origin: left bottom;
  transition: opacity .55s var(--ax-ease-out), transform .55s var(--ax-ease-out);
}
/* (round 30 receded the older exchanges here, .is-back-1/-2 and .is-gone;
   round 96 keeps every one: the channel's transcript, below) */
/* round 70: the cue's line is placed before it is said -- in the layout, so
   the page can glide to where it will be, and unseen until it is typed */
.ax-open__msg.is-waiting { visibility: hidden; }

.ax-open__who {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
.ax-open__msg--arxeon .ax-open__who { color: rgb(var(--ax-accent-text-rgb)); }
/* its lines carry a point of the eyes' light, so what the face is saying and
   what is written here are visibly the same voice */
.ax-open__msg--arxeon .ax-open__who::before {
  content: "";
  display: inline-block;
  inline-size: 5px;
  block-size: 5px;
  margin-inline-end: .7em;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-eye-rgb));
  box-shadow: 0 0 8px 1px rgb(var(--ax-eye-rgb) / .55);
  vertical-align: .12em;
}
.ax-open__text {
  margin: 0;
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-lead);
  color: var(--ax-text-strong);
  min-block-size: 1lh;
}
/* you answer a size down from what it says. (Round 40 tried it a size UP,
   at the head's tighter leading: the glyphs overhung the line box by 2px,
   which is 2px of overflow in a frame that must never overflow, and a size
   up in a narrower column costs the stack an exchange.) */
.ax-open__msg--you .ax-open__text { font-size: var(--ax-fs-md); color: var(--ax-text-body); }

/* ── THE ORB — the same instrument as section 1, fed by a microphone ───── */
/* arxeon.signal.js turns the track into eleven numbers and section 1 is CSS
   reading them. arxeon.voice.js does the identical thing to the microphone
   with the identical constants — 1024-point FFT, -80/-20 dB window, squared
   band means, adaptive ceiling seeded at the floor — and this is CSS reading
   those. So the orb is not a second visualiser that happens to look similar;
   it is the same instrument with a different input.

   NINE PROPERTIES, ONE ELEMENT, ONCE A FRAME. --vl and --vb0..--vb7 are set
   on .ax-open__orb and every rule below reads them. Custom properties inherit,
   so writing them on <html> invalidates the whole document: round 25 measured
   53ms a frame doing exactly that. Scoped here it is a subtree of nineteen
   elements.

   THE COLOURS ARE THE SPECTRUM. --ax-spec-0 cyan through --ax-spec-4 azure to
   --ax-spec-8 violet is the Arxeon ramp already in the tokens. The trails are
   the brand set moving, not a new palette. */

.ax-open__voice {
  --orb: clamp(72px, 11svh, 124px);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: var(--ax-sp-5);
  min-block-size: 0;
}
.ax-open__voice[hidden] { display: none; }

.ax-open__orb {
  --vl: 0;
  position: relative;
  display: block;
  inline-size: var(--orb);
  block-size: var(--orb);
  border-radius: var(--ax-r-full);
}

/* the halo. Its own element and its own layer: nothing masked, nothing
   clipped, so the compositor can scale and fade it on its own. */
.ax-open__orbglow {
  position: absolute;
  inset: -16%;
  border-radius: var(--ax-r-full);
  background: radial-gradient(circle,
              rgb(var(--ax-spec-4-rgb) / .30) 0%,
              rgb(var(--ax-spec-6-rgb) / .15) 44%,
              transparent 70%);
  opacity: calc(.26 + var(--vl, 0) * .74);
  transform: scale(calc(.94 + var(--vl, 0) * .20));
  transition: opacity .1s linear, transform .1s linear;
  will-change: opacity, transform;
}

/* THE ACCRETION RING. The mask is on this element; the gradient that turns is
   its child. Round 25 measured 47ms a frame with both on one element. */
.ax-open__orbring {
  position: absolute;
  inset: 7%;
  border-radius: var(--ax-r-full);
  overflow: hidden;
  -webkit-mask: radial-gradient(circle, transparent 0 62%, #000 66%);
          mask: radial-gradient(circle, transparent 0 62%, #000 66%);
}
.ax-open__orbring > i {
  position: absolute;
  inset: -50%;
  background: conic-gradient(from 0deg,
              rgb(var(--ax-spec-0-rgb) / 0)   0deg,
              rgb(var(--ax-spec-0-rgb) / .95) 38deg,
              rgb(var(--ax-spec-4-rgb) / .82) 96deg,
              rgb(var(--ax-spec-6-rgb) / .62) 150deg,
              rgb(var(--ax-spec-8-rgb) / .26) 212deg,
              rgb(var(--ax-spec-8-rgb) / 0)   300deg,
              rgb(var(--ax-spec-0-rgb) / 0)   360deg);
  animation: ax-orb-spin 7.4s linear infinite;
  will-change: transform;
}
@keyframes ax-orb-spin { to { transform: rotate(360deg); } }

/* the hole itself — the one place on this page that is darker than the page */
.ax-open__orbcore {
  position: absolute;
  inset: 22%;
  border-radius: var(--ax-r-full);
  background: radial-gradient(circle at 50% 42%, #0B0B0B 0 44%, var(--ax-ink-000) 100%);
  box-shadow: 0 0 0 1px rgb(var(--ax-spec-3-rgb) / .30),
              0 0 22px -6px rgb(var(--ax-spec-4-rgb) / .50),
              inset 0 0 20px -4px rgb(var(--ax-spec-6-rgb) / .45);
  transform: scale(calc(1 - var(--vl, 0) * .14));
  transition: transform .1s linear;
  will-change: transform;
}

/* eight spokes on the ring, one per band. transform-origin is the centre of
   the orb, so scaleY grows each spoke outward from the disc rather than about
   its own middle. Transform and opacity only: no spoke ever triggers layout. */
.ax-open__orbbar {
  position: absolute;
  inset-inline-start: 50%;
  inset-block-start: 50%;
  inline-size: 2px;
  block-size: calc(var(--orb) * .15);
  margin-inline-start: -1px;
  margin-block-start: calc(var(--orb) * -.15);
  border-radius: 1px;
  background: linear-gradient(to top,
              rgb(var(--ax-spec-0-rgb) / .10),
              rgb(var(--ax-spec-0-rgb) / .92));
  transform-origin: 50% 100%;
  transform: rotate(calc(var(--i, 0) * 45deg))
             translateY(calc(var(--orb) * -.30))
             scaleY(calc(.22 + var(--v, 0) * 1.05));
  opacity: calc(.30 + var(--v, 0) * .70);
  transition: transform .09s linear, opacity .09s linear;
  will-change: transform, opacity;
}
.ax-open__orbbar:nth-of-type(1) { --i: 0; --v: var(--vb0, 0); }
.ax-open__orbbar:nth-of-type(2) { --i: 1; --v: var(--vb1, 0); }
.ax-open__orbbar:nth-of-type(3) { --i: 2; --v: var(--vb2, 0); }
.ax-open__orbbar:nth-of-type(4) { --i: 3; --v: var(--vb3, 0); }
.ax-open__orbbar:nth-of-type(5) { --i: 4; --v: var(--vb4, 0); }
.ax-open__orbbar:nth-of-type(6) { --i: 5; --v: var(--vb5, 0); }
.ax-open__orbbar:nth-of-type(7) { --i: 6; --v: var(--vb6, 0); }
.ax-open__orbbar:nth-of-type(8) { --i: 7; --v: var(--vb7, 0); }

/* ── the four states ─────────────────────────────────────────────────── */
/* rest · hearing · working · saying. One attribute carries all four, which is
   one write when the state changes and nothing at all in between. */

.ax-open__voice[data-ax-vstate="rest"] .ax-open__orbglow {
  animation: ax-orb-breathe 4.4s var(--ax-ease-in-out) infinite;
}
@keyframes ax-orb-breathe {
  0%, 100% { opacity: .22; transform: scale(.95); }
  50%      { opacity: .50; transform: scale(1.05); }
}

.ax-open__voice[data-ax-vstate="hearing"] .ax-open__orbring > i { animation-duration: 3.2s; }
.ax-open__voice[data-ax-vstate="hearing"] .ax-open__orbcore {
  box-shadow: 0 0 0 1px rgb(var(--ax-spec-0-rgb) / .55),
              0 0 34px -6px rgb(var(--ax-spec-0-rgb) / .60),
              inset 0 0 22px -4px rgb(var(--ax-spec-4-rgb) / .55);
}

/* thinking is the hole pulling inward — the ring speeds up and the core
   collapses. It is the one state with no live numbers behind it, so it is the
   one state that has to be an animation. */
.ax-open__voice[data-ax-vstate="working"] .ax-open__orbring > i { animation-duration: 1.35s; }
.ax-open__voice[data-ax-vstate="working"] .ax-open__orbcore {
  animation: ax-orb-collapse 1.35s var(--ax-ease-in-out) infinite;
}
@keyframes ax-orb-collapse {
  0%, 100% { transform: scale(1);   }
  50%      { transform: scale(.74); }
}

/* speaking runs the ring the other way, so listening and answering are told
   apart from across the room */
.ax-open__voice[data-ax-vstate="saying"] .ax-open__orbring > i {
  animation-duration: 5.0s;
  animation-direction: reverse;
}
.ax-open__voice[data-ax-vstate="saying"] .ax-open__orbcore {
  box-shadow: 0 0 0 1px rgb(var(--ax-spec-8-rgb) / .55),
              0 0 34px -6px rgb(var(--ax-spec-6-rgb) / .60),
              inset 0 0 22px -4px rgb(var(--ax-spec-8-rgb) / .50);
}

.ax-open__vcol { display: grid; row-gap: var(--ax-sp-3); justify-items: start; min-inline-size: 0; }

/* ROUND 40: WHERE THE FACE IS ALIVE, IT IS THE METER. The eyes follow the
   voice and the Arxeon mark under the head fills band by band, so the orb
   here would be a second copy of the same numbers. It stands down only while
   the presence is animating (.is-live-voice); a still presence -- reduced
   motion, no graphics card, no WebGL -- keeps the orb exactly as it was. */
.ax-open.is-live-voice .ax-open__orb { display: none; }
.ax-open.is-live-voice .ax-open__voice { grid-template-columns: minmax(0, 1fr); }

.ax-open__picker[hidden] { display: none; }
.ax-open__mics {
  max-inline-size: min(100%, 34ch);
  padding: var(--ax-sp-2) var(--ax-sp-3);
  border: 1px solid var(--ax-line);
  border-radius: var(--ax-r-sm);
  background: var(--ax-bg-sunken);
  color: var(--ax-text-body);
  font: inherit;
  font-size: var(--ax-fs-xs);
}
.ax-open__mics:focus-visible { outline: 2px solid rgb(var(--ax-accent-text-rgb)); outline-offset: 2px; }

.ax-open__vstate {
  margin: 0;
  min-block-size: 1lh;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  line-height: var(--ax-lh-body);
  color: var(--ax-text-muted);
}
.ax-open__voice[data-ax-vstate="hearing"] .ax-open__vstate { color: rgb(var(--ax-accent-text-rgb)); }

/* ── saying something ────────────────────────────────────────────────── */

/* ROUND 96 · THE ANSWER BOX. Round 40 laid the microphone and Send over the
   field's trailing edge, and they read as forced in. It is one rounded
   console now: the words on top, and under them, inside the same edge, a row
   of tools -- the microphone, the hint (the voice meter while it listens),
   Send. It grows with what is typed, to six lines, then scrolls; Send lights
   once there is something to send. The light trail runs round the whole
   console, and its edge is the focus. */
.ax-open__entry {
  display: grid;
  row-gap: var(--ax-sp-4);
}
.ax-open__entry[hidden] { display: none; }

.ax-open__field {
  --field-r: 22px;
  position: relative;
  display: grid;
  border: 1px solid var(--ax-line);
  border-radius: var(--field-r);
  background:
    linear-gradient(180deg, rgb(var(--ax-white-rgb) / .055), rgb(var(--ax-white-rgb) / .02)),
    rgb(var(--ax-black-rgb) / .62);
  box-shadow: inset 0 1px 0 rgb(var(--ax-white-rgb) / .07), 0 30px 70px -32px rgb(var(--ax-black-rgb) / .95);
  transition: border-color .2s var(--ax-ease-out), opacity .2s var(--ax-ease-out);
}
.ax-open__field:hover { border-color: var(--ax-line-strong); }
.ax-open__field:focus-within { border-color: rgb(var(--ax-accent-text-rgb) / .45); }
.ax-open__field:has(.ax-open__field-input:disabled) { opacity: .6; }

.ax-open__field-input {
  display: block;
  inline-size: 100%;
  min-block-size: calc(3em + 18px);
  max-block-size: calc(9em + 18px);
  padding: 16px 20px 2px;
  border: 0;
  background: transparent;
  color: var(--ax-text-strong);
  font: inherit;
  font-size: var(--ax-fs-lg);
  line-height: 1.5;
  resize: none;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgb(var(--ax-white-rgb) / .18) transparent;
}
.ax-open__field-input::placeholder { color: var(--ax-text-subtle); }
/* the console's edge (and its trail) is this field's focus ring */
.ax-open__field-input:focus,
.ax-open__field-input:focus-visible { outline: none; box-shadow: none; }
.ax-open__field-input:disabled { cursor: not-allowed; }

.ax-open__tools {
  display: flex;
  align-items: center;
  gap: var(--ax-sp-5);
  min-inline-size: 0;
  padding: 6px 10px 10px 12px;
}
.ax-open__hint {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
/* a phone's return key is not the Enter it describes */
@media (hover: none), (pointer: coarse) { .ax-open__hint { visibility: hidden; } }
/* a console too narrow for all of it keeps the first half */
.ax-open__field { container-type: inline-size; }
@container (max-width: 479px) { .ax-open__hmore { display: none; } }

/* THE METER. The same nine numbers as the orb (arxeon.voice.js), on this
   element alone: sixteen bars, the eight bands mirrored out from the middle,
   in the eyes' red -- it is the robot hearing you. Shown only while it
   listens, in the hint's place. */
.ax-open__meter {
  flex: 1 1 auto;
  display: none;
  align-items: center;
  justify-content: center;
  gap: 3px;
  block-size: 26px;
  min-inline-size: 0;
}
.ax-open__meter i {
  flex: none;
  inline-size: 3px;
  block-size: 100%;
  border-radius: 2px;
  background: linear-gradient(to top, rgb(var(--ax-eye-rgb) / .45), rgb(var(--ax-eye-rgb)));
  transform: scaleY(calc(.12 + var(--v, 0) * .88));
  transition: transform .08s linear;
  will-change: transform;
}
.ax-open__meter i:nth-child(8),  .ax-open__meter i:nth-child(9)  { --v: var(--vb0, 0); }
.ax-open__meter i:nth-child(7),  .ax-open__meter i:nth-child(10) { --v: var(--vb1, 0); }
.ax-open__meter i:nth-child(6),  .ax-open__meter i:nth-child(11) { --v: var(--vb2, 0); }
.ax-open__meter i:nth-child(5),  .ax-open__meter i:nth-child(12) { --v: var(--vb3, 0); }
.ax-open__meter i:nth-child(4),  .ax-open__meter i:nth-child(13) { --v: var(--vb4, 0); }
.ax-open__meter i:nth-child(3),  .ax-open__meter i:nth-child(14) { --v: var(--vb5, 0); }
.ax-open__meter i:nth-child(2),  .ax-open__meter i:nth-child(15) { --v: var(--vb6, 0); }
.ax-open__meter i:nth-child(1),  .ax-open__meter i:nth-child(16) { --v: var(--vb7, 0); }
.ax-open__voice[data-ax-vstate="hearing"] ~ .ax-open__entry .ax-open__meter { display: flex; }
.ax-open__voice[data-ax-vstate="hearing"] ~ .ax-open__entry .ax-open__hint { display: none; }

.ax-open__send {
  flex: none;
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  margin-inline-start: auto;
  border: 1px solid var(--ax-line);
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-white-rgb) / .06);
  color: var(--ax-text-muted);
  cursor: pointer;
  transition: background-color .18s var(--ax-ease-out), color .18s var(--ax-ease-out),
              border-color .18s var(--ax-ease-out), box-shadow .18s var(--ax-ease-out), transform .18s var(--ax-ease-out);
}
.ax-open__entry.is-ready .ax-open__send:not(:disabled) {
  border-color: transparent;
  background: var(--ax-accent);
  color: rgb(var(--ax-white-rgb));
  box-shadow: 0 0 0 1px rgb(var(--ax-accent-text-rgb) / .40), 0 10px 28px -10px rgb(var(--ax-accent-text-rgb) / .85);
}
.ax-open__entry.is-ready .ax-open__send:hover:not(:disabled) { transform: translateY(-1px); }
.ax-open__send:hover:not(:disabled) { color: var(--ax-text-strong); border-color: var(--ax-line-strong); }
.ax-open__send:disabled { opacity: .45; cursor: not-allowed; }

.ax-open__count {
  margin: 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}


/* ── THE LIGHT TRAIL ─────────────────────────────────────────────────── */
/* A 1px ring of the Arxeon spectrum running around the field, turning the
   OTHER way from the orb. Same construction rule as the accretion ring: the
   mask lives on .ax-open__trail and the conic gradient that rotates is its
   child. Round 25 measured 47ms a frame with those two on one element.

   The mask subtracts the content box from the padding box, which leaves
   exactly the 1px padding as the visible ring. -webkit-mask-composite: xor is
   the same operation under the older WebKit spelling. */

.ax-open__field { position: relative; }

.ax-open__trail {
  position: absolute;
  inset: -1px;
  padding: 1px;
  border-radius: calc(var(--field-r, 22px) + 1px);
  overflow: hidden;
  pointer-events: none;
  opacity: .30;
  transition: opacity .25s var(--ax-ease-out);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.ax-open__trail > i {
  position: absolute;
  inset: -60%;
  background: conic-gradient(from 0deg,
              transparent                     0deg,
              rgb(var(--ax-spec-0-rgb) / .90) 24deg,
              rgb(var(--ax-spec-4-rgb) / .80) 72deg,
              rgb(var(--ax-spec-8-rgb) / .52) 124deg,
              transparent                     192deg,
              transparent                     360deg);
  animation: ax-trail-spin 5.6s linear infinite;
  will-change: transform;
}
@keyframes ax-trail-spin { to { transform: rotate(-360deg); } }

.ax-open__field:focus-within .ax-open__trail { opacity: 1; }
.ax-open__voice[data-ax-vstate="hearing"] ~ .ax-open__entry .ax-open__trail { opacity: 1; }

/* ── the microphone ──────────────────────────────────────────────────── */
/* Typing is the interface; this is the option. It is removed outright where a
   microphone cannot work rather than sitting there disabled. Round 96: it
   sits first in the console's tool row, and while it listens it is the eyes'
   red, because it is the robot hearing you. */

.ax-open__mic {
  flex: none;
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  border: 1px solid var(--ax-line);
  border-radius: var(--ax-r-full);
  background: transparent;
  color: var(--ax-text-body);
  cursor: pointer;
  transition: background-color .18s var(--ax-ease-out),
              border-color .18s var(--ax-ease-out),
              color .18s var(--ax-ease-out),
              box-shadow .18s var(--ax-ease-out);
}
.ax-open__mic:hover:not(:disabled) { border-color: rgb(var(--ax-eye-rgb) / .55); color: rgb(var(--ax-eye-rgb)); }
.ax-open__mic:disabled { opacity: .45; cursor: not-allowed; }
.ax-open__mic[aria-pressed="true"] {
  border-color: transparent;
  background: rgb(var(--ax-eye-rgb));
  color: rgb(var(--ax-white-rgb));
  box-shadow: 0 0 24px -4px rgb(var(--ax-eye-rgb) / .85);
}
/* the gap between the click and the first sample — acknowledged, but not
   dressed up as listening, because nothing is being heard yet */
.ax-open__mic[data-ax-arming] {
  border-color: rgb(var(--ax-eye-rgb) / .6);
  color: rgb(var(--ax-eye-rgb));
}
.ax-open__mic[aria-pressed="true"]::after,
.ax-open__mic[data-ax-arming]::after {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: var(--ax-r-full);
  border: 1px solid rgb(var(--ax-eye-rgb) / .55);
  animation: ax-mic-ping 1.6s var(--ax-ease-out) infinite;
}
@keyframes ax-mic-ping {
  0%   { opacity: .85; transform: scale(.96); }
  100% { opacity: 0;   transform: scale(1.18); }
}

/* ── the footer row: exchanges left, and whether it talks back ───────── */
/* Reading replies aloud is OFF until asked. A page that starts talking on its
   own is a page closed with the volume key. */

.ax-open__erow {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ax-sp-3);
  flex-wrap: wrap;
}

.ax-open__hear {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-2);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
  transition: color .18s var(--ax-ease-out);
}
.ax-open__hear:hover { color: var(--ax-text-body); }
.ax-open__hear:focus-visible { outline: 2px solid rgb(var(--ax-accent-text-rgb)); outline-offset: 3px; border-radius: 2px; }
.ax-open__hear[aria-pressed="true"] { color: rgb(var(--ax-accent-text-rgb)); }

.ax-open__hdot {
  flex: none;
  inline-size: 8px;
  block-size: 8px;
  border: 1px solid currentColor;
  border-radius: var(--ax-r-full);
  transition: background-color .18s var(--ax-ease-out);
}
.ax-open__hear[aria-pressed="true"] .ax-open__hdot { background: currentColor; }

/* ── THE PANEL — the brief, assembling ───────────────────────────────── */

/* ROUND 40 · NOT A PANEL. The brief used to be a box -- border, radius,
   surface -- which made it one more card on a page of cards. It is what the
   presence is working out, so it is written straight onto the dark, and its
   only edge is a SPINE: one line of light down its left side, brightest at
   the top where the heading is, fading out below. Every rule it had is kept;
   only the box is gone. */
.ax-open__panel {
  position: relative;
  grid-column: 4;
  grid-row: 1 / -1;
  align-self: stretch;
  display: grid;
  grid-template-rows: auto auto 1fr auto auto auto;
  row-gap: var(--ax-sp-4);
  padding: var(--ax-sp-1) 0 0 var(--ax-sp-6);
  min-block-size: 0;
  overflow: clip;
}
.ax-open__panel[hidden] { display: none; }
.ax-open__panel::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 1px;
  background: linear-gradient(to bottom,
              rgb(var(--ax-white-rgb) / 0),
              rgb(var(--ax-white-rgb) / .26) 6%,
              rgb(var(--ax-white-rgb) / .10) 58%,
              rgb(var(--ax-white-rgb) / 0));
  transition: background-color .4s var(--ax-ease-out);
}
.ax-open.is-closed .ax-open__panel::before {
  background: linear-gradient(to bottom,
              rgb(var(--ax-white-rgb) / 0),
              rgb(var(--ax-white-rgb) / .42) 6%,
              rgb(var(--ax-white-rgb) / .16) 70%,
              rgb(var(--ax-white-rgb) / 0));
}

/* a widening is an event, not a slide: the spine and the band flash the
   eyes' red, once */
.ax-open__panel.is-wider::before { animation: ax-open-wider .9s var(--ax-ease-out); }
@keyframes ax-open-wider {
  0%   { background-color: rgb(var(--ax-eye-rgb) / .85); box-shadow: 0 0 14px rgb(var(--ax-eye-rgb) / .6); }
  100% { background-color: transparent; box-shadow: none; }
}
.ax-open__panel.is-wider .ax-open__pspan { animation: ax-open-wider-band .9s var(--ax-ease-out); }
@keyframes ax-open-wider-band {
  0%   { background: rgb(var(--ax-eye-rgb)); box-shadow: 0 0 14px 1px rgb(var(--ax-eye-rgb) / .7); }
  100% { }
}

.ax-open__pstate {
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--ax-sp-3);
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgb(var(--ax-accent-text-rgb));
}
.ax-open__pstate::before {
  content: "";
  inline-size: 5px;
  block-size: 5px;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-eye-rgb));
  box-shadow: 0 0 8px 1px rgb(var(--ax-eye-rgb) / .55);
}
.ax-open.is-thinking .ax-open__pstate::before { animation: ax-open-breathe 1.1s var(--ax-ease-in-out) infinite; }

.ax-open__phead {
  margin: 0;
  font-size: var(--ax-fs-xl);
  line-height: var(--ax-lh-head);
  color: var(--ax-text-strong);
  text-wrap: balance;
}
.ax-open__phead:focus-visible { outline: 2px solid rgb(var(--ax-accent-text-rgb)); outline-offset: 4px; }

.ax-open__pscope {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  row-gap: var(--ax-sp-2);
  align-content: start;
  min-block-size: 0;
  overflow: clip;
}
.ax-open__pscope li {
  position: relative;
  flex: 0 0 auto;
  padding-inline-start: var(--ax-sp-5);
  font-size: var(--ax-fs-sm);
  line-height: var(--ax-lh-body);
  color: var(--ax-text-body);
  animation: ax-open-land .5s var(--ax-ease-out);
}
.ax-open__pscope li::before {
  content: "";
  position: absolute;
  inset-block-start: .62em;
  inset-inline-start: 0;
  inline-size: 10px;
  block-size: 1px;
  background: rgb(var(--ax-accent-text-rgb));
}
@keyframes ax-open-land {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* the figures, and the bar that makes the narrowing geometric */

.ax-open__pfigs {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--ax-sp-6);
  row-gap: var(--ax-sp-3);
  padding-block-start: var(--ax-sp-4);
  border-block-start: 1px solid transparent;
  border-image: linear-gradient(to right, var(--ax-line-strong), rgb(var(--ax-white-rgb) / 0)) 1;
}
.ax-open__pfigs dt {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
.ax-open__pfigs dd {
  margin: var(--ax-sp-1) 0 0;
  font-size: var(--ax-fs-xl);
  line-height: var(--ax-lh-head);
  letter-spacing: -.015em;
  color: var(--ax-text-strong);
  font-variant-numeric: tabular-nums;
}

/* THE INSTRUMENT. The bar under the figures is a ruler now: a hairline with
   a tick at each round number on the same log axis the band is placed on
   (5k, 10k, 20k, 50k+ at 0, 30.10, 60.21 and 100 per cent), and the band
   itself is light lying on it. The positions are ln(v/5000) /
   ln(50000/5000) -- the formula pos() in arxeon.open.js uses. Round 105:
   the floor is 5,000, the smallest project Arxeon takes. Round 106: the
   ruler grows past 50k a decade at a time, so the marks are drawn by the
   labels themselves (.ax-open__pticks i::before) and stand under them
   whatever the scale; the hairline is all that is left here. */
.ax-open__pscale {
  position: relative;
  block-size: 24px;
}
.ax-open__pscale::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-start: 6px;
  block-size: 7px;
  background:
    linear-gradient(var(--ax-line-strong), var(--ax-line-strong)) 0 3px / 100% 1px no-repeat;
}
.ax-open__pspan {
  position: absolute;
  inset-block-start: 8px;
  block-size: 3px;
  inset-inline-start: calc(var(--lo, 0) * 100%);
  inline-size: calc(max(var(--hi, 1) - var(--lo, 0), .012) * 100%);
  border-radius: var(--ax-r-full);
  background: linear-gradient(to right, rgb(var(--ax-accent-text-rgb)), rgb(var(--ax-white-rgb)) 50%, rgb(var(--ax-accent-text-rgb)));
  box-shadow: 0 0 12px 0 rgb(var(--ax-accent-text-rgb) / .55);
  transition: inset-inline-start .65s var(--ax-ease-out), inline-size .65s var(--ax-ease-out);
}
.ax-open__pticks {
  position: absolute;
  inset: 15px 0 auto 0;
  block-size: 10px;
}
.ax-open__pticks i {
  position: absolute;
  inset-inline-start: var(--at);
  translate: -50% 0;
  font-family: var(--ax-font-mono);
  font-size: 9px;
  font-style: normal;
  line-height: 10px;
  letter-spacing: .06em;
  color: var(--ax-text-subtle);
  white-space: nowrap;
}
.ax-open__pticks i:first-child { translate: 0 0; }
.ax-open__pticks i:last-child  { translate: -100% 0; }
/* each label carries its own mark, 7px tall across the hairline (the ruler's
   6px from the top, the labels' 15px) */
.ax-open__pticks i::before {
  content: "";
  position: absolute;
  inset-block-start: -9px;
  inset-inline-start: calc(50% - .5px);
  inline-size: 1px;
  block-size: 7px;
  background: var(--ax-line-strong);
}
.ax-open__pticks i:first-child::before { inset-inline-start: 0; }
.ax-open__pticks i:last-child::before  { inset-inline-start: auto; inset-inline-end: 0; }

/* round 106: the three biggest costs, as shares of the whole -- a caption
   under the ruler that wraps like a sentence (two lines on a phone, three on
   the narrowest), never a list */
.ax-open__pdrivers {
  margin: 0;
  font-size: var(--ax-fs-2xs);
  line-height: var(--ax-lh-micro);
  color: var(--ax-text-muted);
}
.ax-open__pdrivers[hidden] { display: none; }
.ax-open__pdk {
  margin-inline-end: .35em;
  font-family: var(--ax-font-mono);
  font-size: 9px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
.ax-open__pds { color: var(--ax-text-subtle); }
.ax-open__pdi b { font-weight: 600; color: var(--ax-text-body); }

.ax-open__pcare { margin: 0; font-size: var(--ax-fs-sm); line-height: var(--ax-lh-body); color: var(--ax-text-muted); }

/* The disclaimer is not fine print. An estimate a client can screenshot is a
   commercial commitment, so this is readable at a glance and measured like
   body text. */
.ax-open__pnote {
  position: relative;
  margin: 0;
  padding-inline-start: var(--ax-sp-5);
  font-size: var(--ax-fs-sm);
  line-height: var(--ax-lh-body);
  color: var(--ax-text-body);
}
/* no box round it any more; a short bar of the accent in front of it says
   "read this" the way the box used to */
.ax-open__pnote::before {
  content: "";
  position: absolute;
  inset-block: .3em;
  inset-inline-start: 0;
  inline-size: 2px;
  border-radius: 1px;
  background: rgb(var(--ax-accent-text-rgb) / .6);
}

/* ── the hand-off ────────────────────────────────────────────────────── */
/* The address is asked for AFTER the estimate. ROUND 96: it used to be three
   cramped fields and a button squeezed under the brief; it stands where the
   answer box was now, once the brief is done -- labelled fields at full size
   and one wide button. Still no <form>: Site.Master owns the only one on the
   page and a second breaks every postback. */

.ax-open__hand {
  display: grid;
  row-gap: var(--ax-sp-6);
  align-content: start;
}
.ax-open__hand[hidden] { display: none; }
.ax-open__hlead { margin: 0; font-size: var(--ax-fs-md); line-height: var(--ax-lh-body); color: var(--ax-text-body); }
.ax-open__hrow {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--ax-sp-6) var(--ax-sp-5);
}
.ax-open__hf { display: grid; row-gap: var(--ax-sp-3); min-inline-size: 0; }
.ax-open__hf--wide { grid-column: 1 / -1; }
.ax-open__hl {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}

.ax-open__hin {
  inline-size: 100%;
  min-block-size: 52px;
  padding: 0 var(--ax-sp-7);
  border: 1px solid var(--ax-line);
  border-radius: 14px;
  background: rgb(var(--ax-white-rgb) / .035);
  color: var(--ax-text-strong);
  font: inherit;
  font-size: var(--ax-fs-md);
  transition: border-color .18s var(--ax-ease-out), background-color .18s var(--ax-ease-out), box-shadow .18s var(--ax-ease-out);
}
.ax-open__hin::placeholder { color: var(--ax-text-subtle); }
.ax-open__hin:hover { border-color: var(--ax-line-strong); }
/* the focus is the field's own edge in the accent and a soft ring round it:
   plainly visible, never a second thick box drawn outside the first */
.ax-open__hin:focus,
.ax-open__hin:focus-visible {
  outline: none;
  border-color: rgb(var(--ax-accent-text-rgb));
  background: rgb(var(--ax-white-rgb) / .05);
  box-shadow: 0 0 0 3px rgb(var(--ax-accent-text-rgb) / .22);
}

/* out of the layout, not display:none — a field that is display:none is one
   every competent bot skips */
.ax-open__pot {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.ax-open__bcta { inline-size: 100%; justify-content: center; }
.ax-open__hsaid:empty { display: none; }
.ax-open__hsaid { margin: 0; font-size: var(--ax-fs-sm); line-height: var(--ax-lh-body); color: var(--ax-text-body); text-align: center; }

/* sent: the confirmation, a check in the accent, and where to go next */
.ax-open__hdone {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--ax-sp-4);
  align-items: center;
  margin: 0;
  font-size: var(--ax-fs-md);
  font-weight: 600;
  line-height: var(--ax-lh-body);
  color: var(--ax-text-strong);
}
/* Heroicons 2.2.0, 24/outline/check-circle.svg, as a mask */
.ax-open__hdone::before {
  content: "";
  inline-size: 24px;
  block-size: 24px;
  background: rgb(var(--ax-accent-text-rgb));
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.ax-open__hnext { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--ax-sp-5); }
.ax-open.is-sent .ax-open__hand { justify-items: center; row-gap: var(--ax-sp-6); }

/* ── narrow ──────────────────────────────────────────────────────────── */

@media (max-width: 1099px) {
  /* ONE COLUMN: the question, the face, the four ways in, then the
     conversation and the brief under it. The frame stops being fixed -- on a
     phone a clipped stack means a visitor cannot re-read the question they
     are halfway through answering. Round 40 moved this from 1023 to 1099px:
     below that there is no room for three columns and a face worth having. */
  .ax-open { --op-h: auto; padding-block: var(--ax-sp-10); }
  .ax-open__stage {
    grid-template-columns: 22px minmax(0, 1fr);
    grid-template-rows: none;
    row-gap: var(--ax-sp-6);
    block-size: auto;
  }
  .ax-open__rail { grid-row: 1 / span 3; }
  .ax-open__talk > .ax-open__head  { grid-column: 2; grid-row: 1; }
  .ax-open__face  { grid-column: 1 / -1; grid-row: 2; justify-self: center;
                    inline-size: min(78%, 400px); aspect-ratio: 452 / 848; }
  .ax-open__chips { grid-column: 2; grid-row: 3; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ax-open__talk > .ax-open__voice { grid-column: 2; grid-row: 4; }
  .ax-open__talk > .ax-open__stack { grid-column: 2; grid-row: 5; }
  .ax-open__talk > .ax-open__entry { grid-column: 2; grid-row: 6; }
  .ax-open__panel { grid-column: 2; grid-row: 7; }
  .ax-open__stack { overflow: visible; }
  .ax-open__ticks { block-size: 180px; }
  .ax-open__voice { --orb: 84px; }
}

@media (max-width: 639px) {
  .ax-open__chips { grid-template-columns: 1fr; }
  .ax-open__panel { padding-inline-start: var(--ax-sp-5); }
  .ax-open__pfigs { column-gap: var(--ax-sp-5); }
}

/* ── still ───────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .ax-open__eye > i { animation: none !important; opacity: .5 !important; transition: none !important; }
  .ax-open__pstate::before { animation: none !important; }
  .ax-open__panel.is-wider::before, .ax-open__panel.is-wider .ax-open__pspan { animation: none; }
  .ax-open__pscope li { animation: none; }
  .ax-open__chip, .ax-open__msg, .ax-open__pspan, .ax-open__ticks li { transition: none; }
  .ax-open__chip:hover { transform: none; }

  /* A LIVE METER IS MOTION. Somebody who has asked the system for less of it
     does not want eight spokes twitching at their voice either, so the orb
     goes still rather than slow: the trails stop turning, the core stops
     breathing, and the spokes hold one shape whatever the microphone hears.
     The channel still listens and still answers — only the picture is quiet. */
  .ax-open__orbring > i,
  .ax-open__trail > i,
  .ax-open__orbglow,
  .ax-open__orbcore,
  .ax-open__mic[aria-pressed="true"]::after,
  .ax-open__mic[data-ax-arming]::after { animation: none !important; }
  .ax-open__orbglow, .ax-open__orbcore, .ax-open__orbbar, .ax-open__trail { transition: none !important; }
  .ax-open__orbglow { opacity: .30 !important; transform: none !important; }
  .ax-open__orbcore { transform: none !important; }
  .ax-open__orbbar {
    opacity: .5 !important;
    transform: rotate(calc(var(--i, 0) * 45deg))
               translateY(calc(var(--orb) * -.30))
               scaleY(.55) !important;
  }
}

@media print, (forced-colors: active) {
  .ax-open__dark, .ax-open__scene { display: none; }
  .ax-open.is-live-gl .ax-open__face picture { visibility: visible; }
}
@media print {
  .ax-open__entry { display: none; }
  .ax-open__voice { display: none; }
  .ax-open__stack { overflow: visible; }
}

/* ===========================================================================
   20b · THE CHANNEL, LOCKED IN — section 3 once a topic is picked (round 96)
   ---------------------------------------------------------------------------
   Round 30 kept the conversation inside one fixed screen of the page: a stack
   at the bottom left whose older lines receded and went, a small answer box,
   the brief down the right. Farhad, round 96: picking a topic did not feel
   like entering anything, the answer box was small and its two buttons looked
   forced in, the history vanished and left a dark empty column, and the
   finished brief drew a fat outline round its heading.

   SO PICKING A TOPIC LOCKS THE CHANNEL OVER THE PAGE (.is-locked): fixed,
   full screen, the site's header and everything else inert behind it, the
   page under it held by a stand-in of the section's height (.ax-open__holder).
   It opens out from where the section stood on screen. Leave, Esc and the
   browser's Back get out; the conversation is kept, the section shows it in
   place (.is-open without .is-locked) and its bar offers the way back in.

   A WIDE SCREEN is three columns under one bar: the transcript (every
   exchange, scrolling, the newest at the bottom), the robot with what it is
   asking written large under its face (the caption) and the answer box under
   that, and the brief. A PHONE is a chat: the bar, the face small, the
   estimate in one bar that opens the brief as a sheet, the transcript, and
   the answer box over the keyboard.

   ROUND 97 · STEADY. Farhad: the robot changed size as a reply was typed
   and as he typed, and shook with every reply. Every row under the face now
   has a fixed size (the caption's three lines, the voice line, the answer
   box), so the face keeps one size for the whole conversation. And leaving
   puts the section back as it was, with the way back in (below).
   ======================================================================== */

/* the page under a locked channel does not scroll */
html.ax-channel-locked,
html.ax-channel-locked body { overflow: hidden; }
.ax-open__holder { display: block; }

/* ── the bar ─────────────────────────────────────────────────────────── */

.ax-open__bar { display: none; }
.ax-open.is-open .ax-open__bar {
  grid-area: bar;
  display: flex;
  align-items: center;
  gap: var(--ax-sp-8);
  min-block-size: 64px;
  min-inline-size: 0;
  padding-block: var(--ax-sp-4);
  border-block-end: 1px solid transparent;
  border-image: linear-gradient(to right, rgb(var(--ax-white-rgb) / 0), var(--ax-line) 10%, var(--ax-line) 90%, rgb(var(--ax-white-rgb) / 0)) 1;
}
.ax-open__btitle {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: var(--ax-sp-5);
  min-inline-size: 0;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
}
.ax-open__bdot {
  flex: none;
  inline-size: 7px;
  block-size: 7px;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-eye-rgb));
  box-shadow: 0 0 10px 1px rgb(var(--ax-eye-rgb) / .6);
  animation: ax-open-breathe 3.6s var(--ax-ease-in-out) infinite;
}
.ax-open.is-thinking .ax-open__bdot { animation-duration: 1.1s; }
.ax-open__blabel {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}
.ax-open__btopic {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: var(--ax-fs-sm);
  font-weight: 600;
  color: var(--ax-text-strong);
}
.ax-open__btopic:not(:empty)::before {
  content: "/";
  margin-inline-end: var(--ax-sp-5);
  font-weight: 400;
  color: var(--ax-text-subtle);
}

/* the exchanges, as marks: twelve since round 106, so narrower */
.ax-open__pips {
  flex: none;
  display: flex;
  gap: 5px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.ax-open__pips li {
  inline-size: 14px;
  block-size: 3px;
  border-radius: 2px;
  background: var(--ax-line-strong);
  transition: background-color .4s var(--ax-ease-out), box-shadow .4s var(--ax-ease-out);
}
.ax-open__pips li.is-done { background: rgb(var(--ax-accent-text-rgb)); box-shadow: 0 0 8px rgb(var(--ax-accent-text-rgb) / .5); }
.ax-open__pips li.is-now { background: rgb(var(--ax-accent-text-rgb) / .45); }

.ax-open__leave {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  min-block-size: 40px;
  padding: 0 var(--ax-sp-5) 0 var(--ax-sp-5);
  border: 1px solid var(--ax-line);
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-white-rgb) / .03);
  color: var(--ax-text-body);
  font: inherit;
  font-size: var(--ax-fs-sm);
  cursor: pointer;
  transition: border-color .18s var(--ax-ease-out), background-color .18s var(--ax-ease-out), color .18s var(--ax-ease-out);
}
.ax-open__leave:hover { border-color: var(--ax-line-strong); background: rgb(var(--ax-white-rgb) / .07); color: var(--ax-text-strong); }
.ax-open__leave[hidden] { display: none; }
.ax-open__kbd {
  margin-inline-start: var(--ax-sp-2);
  padding: 1px 6px;
  border: 1px solid var(--ax-line);
  border-radius: 6px;
  font-family: var(--ax-font-mono);
  font-size: 10px;
  letter-spacing: .06em;
  color: var(--ax-text-subtle);
  background: transparent;
  box-shadow: none;
}

/* ── open: the parts of the invitation step aside ────────────────────── */

.ax-open.is-open .ax-open__rail,
.ax-open.is-open .ax-open__head { display: none; }

/* ── the transcript ──────────────────────────────────────────────────── */

.ax-open.is-open .ax-open__talk > .ax-open__stack {
  grid-area: log;
  display: flex;
  justify-content: flex-start;
  row-gap: var(--ax-sp-8);
  min-block-size: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgb(var(--ax-white-rgb) / .16) transparent;
  padding: var(--ax-sp-10) var(--ax-sp-4) var(--ax-sp-8) 0;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 52px, #000 calc(100% - 20px), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 52px, #000 calc(100% - 20px), transparent 100%);
}
.ax-open.is-open .ax-open__msg { flex: none; animation: ax-open-msg-in .45s var(--ax-ease-out) both; }
.ax-open.is-open .ax-open__talk > .ax-open__stack > :first-child { margin-block-start: auto; }
@keyframes ax-open-msg-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
.ax-open.is-open .ax-open__msg--arxeon .ax-open__text { font-size: var(--ax-fs-md); line-height: var(--ax-lh-lead); }
.ax-open.is-open .ax-open__msg--you {
  align-self: flex-end;
  max-inline-size: min(92%, 36em);
  padding: var(--ax-sp-5) var(--ax-sp-6) var(--ax-sp-6);
  border: 1px solid var(--ax-line);
  border-radius: 16px 16px 5px 16px;
  background: rgb(var(--ax-white-rgb) / .045);
}
.ax-open.is-open .ax-open__msg--you .ax-open__text { color: var(--ax-text-strong); }

/* ── the caption ─────────────────────────────────────────────────────── */

.ax-open__said { display: none; }
.ax-open__est { display: none; }
.ax-open__saidwho {
  display: inline-flex;
  align-items: center;
  gap: .7em;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgb(var(--ax-accent-text-rgb));
}
.ax-open__saidwho::before {
  content: "";
  inline-size: 5px;
  block-size: 5px;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-eye-rgb));
  box-shadow: 0 0 8px 1px rgb(var(--ax-eye-rgb) / .55);
}
.ax-open { --said-fs: clamp(1.25rem, .78rem + .82vw, 1.75rem); }
.ax-open__saidtext {
  max-inline-size: 40ch;
  font-size: var(--said-fs);
  line-height: 1.3;
  letter-spacing: -.012em;
  color: var(--ax-text-strong);
  text-align: center;
  text-wrap: balance;
}
.ax-open__saidtext:empty { display: none; }
/* round 97: a long question steps down, to stay in the caption's three lines */
.ax-open__said.is-long .ax-open__saidtext { font-size: calc(var(--said-fs) * .86); max-inline-size: 46ch; }
.ax-open__said.is-longer .ax-open__saidtext { font-size: calc(var(--said-fs) * .74); max-inline-size: 54ch; }
/* thinking: three points of the eyes' light where the words will be */
.ax-open__saiddots { display: none; gap: 7px; padding-block: .55em; }
.ax-open.is-thinking .ax-open__saiddots { display: inline-flex; }
.ax-open__saiddots i {
  inline-size: 6px;
  block-size: 6px;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-eye-rgb));
  box-shadow: 0 0 8px rgb(var(--ax-eye-rgb) / .6);
  animation: ax-open-dot 1.2s var(--ax-ease-in-out) infinite;
}
.ax-open__saiddots i:nth-child(2) { animation-delay: .16s; }
.ax-open__saiddots i:nth-child(3) { animation-delay: .32s; }
@keyframes ax-open-dot { 0%, 100% { opacity: .25; transform: scale(.8); } 45% { opacity: 1; transform: scale(1); } }

/* ── the voice line, and the answer box's row under it ───────────────── */

.ax-open.is-open .ax-open__voice { grid-template-columns: minmax(0, 1fr); justify-items: center; }
.ax-open.is-open .ax-open__orb { display: none; }
.ax-open.is-open .ax-open__vcol { justify-items: center; text-align: center; row-gap: var(--ax-sp-3); }
.ax-open.is-open .ax-open__vstate { min-block-size: 0; text-wrap: balance; }
.ax-open.is-open .ax-open__vstate:empty { display: none; }
/* done: nothing more to say out loud, and the caption has said what the
   lead line under it used to */
.ax-open.is-closed .ax-open__voice,
.ax-open.is-open .ax-open__hlead { display: none; }
.ax-open.is-open .ax-open__erow { padding-inline: var(--ax-sp-4); }

/* ── the brief ───────────────────────────────────────────────────────── */

.ax-open.is-open .ax-open__panel {
  grid-area: brief;
  grid-template-rows: none;
  grid-auto-rows: auto;
  align-content: start;
  align-self: stretch;
  row-gap: var(--ax-sp-5);
  padding: var(--ax-sp-8) var(--ax-sp-6) var(--ax-sp-8) var(--ax-sp-8);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgb(var(--ax-white-rgb) / .16) transparent;
}
.ax-open.is-open .ax-open__pfigs { margin-block-start: var(--ax-sp-4); }
.ax-open.is-open .ax-open__pscope { overflow: visible; min-block-size: auto; }
.ax-open__pclose { display: none; }

/* THE SEAL. Four corner marks close on the brief when it is done, as section
   2's lock closes on its object, after the one flare the face gives. */
.ax-open__seal { position: absolute; inset: 0; pointer-events: none; }
.ax-open__seal i {
  position: absolute;
  inline-size: 18px;
  block-size: 18px;
  border: 0 solid rgb(var(--ax-accent-text-rgb) / .9);
  opacity: 0;
  transition: translate .7s cubic-bezier(.2, .9, .2, 1) .2s, opacity .35s var(--ax-ease-out) .2s;
}
.ax-open__seal i:nth-child(1) { inset-block-start: 0; inset-inline-start: 0; border-block-start-width: 1px; border-inline-start-width: 1px; translate: -16px -16px; }
.ax-open__seal i:nth-child(2) { inset-block-start: 0; inset-inline-end: 0;   border-block-start-width: 1px; border-inline-end-width: 1px;   translate: 16px -16px; }
.ax-open__seal i:nth-child(3) { inset-block-end: 0;   inset-inline-start: 0; border-block-end-width: 1px;   border-inline-start-width: 1px; translate: -16px 16px; }
.ax-open__seal i:nth-child(4) { inset-block-end: 0;   inset-inline-end: 0;   border-block-end-width: 1px;   border-inline-end-width: 1px;   translate: 16px 16px; }
.ax-open.is-closed .ax-open__seal i { opacity: 1; translate: 0 0; }
.ax-open.is-closed .ax-open__pstate { color: rgb(var(--ax-accent-text-rgb)); }

/* ── locked over the page ────────────────────────────────────────────── */

.ax-open.is-open.is-locked {
  position: fixed;
  inset-inline: 0;
  inset-block-start: var(--ax-vvt, 0px);
  block-size: var(--ax-vvh, 100dvh);
  z-index: var(--ax-z-modal);
  min-block-size: 0;
  padding-block: 0;
  overscroll-behavior: contain;
}
.ax-open.is-locked .ax-open__dark {
  background:
    radial-gradient(56% 50% at 50% 30%, rgb(var(--ax-white-rgb) / .03), transparent 72%),
    var(--ax-ink-000);
}
/* it opens out from where the section stood: the clip starts at the
   section's own edges on screen (--lk-t, --lk-b, set by the script) */
.ax-open.is-locking { animation: ax-open-lockin .75s cubic-bezier(.2, .9, .2, 1); }
@keyframes ax-open-lockin {
  from { clip-path: inset(var(--lk-t, 0px) 0 var(--lk-b, 0px) 0); }
  to   { clip-path: inset(0 0 0 0); }
}
.ax-open.is-locking .ax-open__bar { animation: ax-open-in-down .6s var(--ax-ease-out) .15s both; }
@keyframes ax-open-in-down { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: none; } }

/* ── a wide screen: three columns under the bar ──────────────────────── */

@media (min-width: 1100px) {
  .ax-open.is-open {
    block-size: var(--op-h);
    /* the answer box's own height: two lines of its type, its padding, the
       row of tools, its edge, and the line under it */
    --voice-h: 30px;
    --entry-h: calc(3 * var(--ax-fs-lg) + 18px + 62px + var(--ax-sp-4) + 1.65 * var(--ax-fs-3xs));
  }
  .ax-open.is-open .ax-open__stage {
    grid-template-columns: minmax(220px, 1fr) minmax(400px, 1.42fr) minmax(260px, 1fr);
    /* ROUND 97 · STEADY. Every row under the face has a fixed size, so the
       face -- and the head drawn on it -- keeps one size for the whole
       conversation: while a reply is typed into the caption, while the
       answer box grows, when the brief is done and the send form comes.
       What is taller than its room grows upward, over the room above it. */
    grid-template-rows: auto minmax(150px, 1fr) var(--said-h) var(--voice-h) var(--entry-h);
    grid-template-areas:
      "bar  bar   bar"
      "log  face  brief"
      "log  said  brief"
      "log  voice brief"
      "log  entry brief";
    column-gap: clamp(28px, 3.2vw, 56px);
    row-gap: 0;
  }
  .ax-open.is-locked .ax-open__stage { block-size: 100%; padding-block-end: clamp(14px, 2.6vh, 30px); }
  .ax-open.is-open .ax-open__face { grid-area: face; }
  .ax-open.is-open .ax-open__panel { align-self: start; max-block-size: calc(100% - var(--ax-sp-8)); margin-block-start: var(--ax-sp-8); }
  .ax-open.is-open .ax-open__talk > .ax-open__voice { grid-area: voice; padding-block-end: var(--ax-sp-5); align-self: end; }
  .ax-open.is-open .ax-open__field-input { max-block-size: calc(6em + 18px); }
  .ax-open.is-open .ax-open__talk > .ax-open__entry,
  .ax-open.is-open .ax-open__talk > .ax-open__hand { grid-area: entry; align-self: end; }
}

/* the caption, wherever the robot has room to stand over it: a wide screen,
   and a tablet or small laptop (the middle layout, below) */
@media (min-width: 1100px), (min-width: 820px) and (min-height: 560px) {
  /* the caption's room: its label and three lines of its type */
  .ax-open.is-open { --said-h: calc(2 * var(--ax-sp-5) + var(--ax-sp-8) + 1.65 * var(--ax-fs-3xs) + 3 * 1.3 * var(--said-fs)); }
  .ax-open.is-open .ax-open__talk > .ax-open__said {
    grid-area: said;
    display: grid;
    justify-items: center;
    align-content: start;
    row-gap: var(--ax-sp-5);
    min-block-size: 0;
    margin: 0;
    padding-block: var(--ax-sp-5) var(--ax-sp-8);
  }
  /* THE SEND FORM IN THE ANSWER BOX'S ROOM: the name and the company side
     by side, the address and the button under them (three fields in a row
     and the button under them where the column is wide enough, below) */
  .ax-open.is-open:not(.is-sent) .ax-open__hand {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas: "name co" "mail go" "said said";
    gap: var(--ax-sp-5);
    align-items: end;
    padding-block-start: 0;
  }
  .ax-open.is-open .ax-open__hrow { display: contents; }
  .ax-open.is-open .ax-open__hrow > .ax-open__hf:nth-child(1) { grid-area: name; }
  .ax-open.is-open .ax-open__hrow > .ax-open__hf:nth-child(2) { grid-area: co; }
  .ax-open.is-open .ax-open__hf--wide { grid-area: mail; }
  .ax-open.is-open .ax-open__bcta { grid-area: go; min-block-size: 52px; }
  .ax-open.is-open .ax-open__hsaid { grid-area: said; }
  /* the answer box grows to four lines here, then scrolls; the caption and
     the voice line rise by what it has grown (--ax-grow, set by the script),
     over the foot of the face's room, where the mark is */
  .ax-open.is-open .ax-open__talk > .ax-open__said,
  .ax-open.is-open .ax-open__talk > .ax-open__voice {
    transform: translateY(calc(-1 * var(--ax-grow, 0px)));
    transition: transform .2s var(--ax-ease-out);
  }
  /* the line the caption is saying stays in the transcript for a screen
     reader, and is not shown twice */
  .ax-open.is-open .ax-open__msg.is-said {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    animation: none;
  }
}

@media (min-width: 1220px) {
  .ax-open.is-open:not(.is-sent) .ax-open__hand {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.35fr);
    grid-template-areas: "name co mail" "go go go" "said said said";
  }
}

/* ── a phone, and anything under 1100px: a chat ──────────────────────── */

@media (max-width: 1099px) {
  .ax-open.is-open { --op-h: auto; padding-block: var(--ax-sp-6); }
  .ax-open.is-open .ax-open__stage {
    row-gap: 0;
    block-size: min(calc(100svh - 84px - 2 * var(--ax-sp-6)), 900px);
  }
  .ax-open.is-open.is-locked { padding-block: 0; }
  .ax-open.is-locked .ax-open__stage { block-size: 100%; padding-block-end: max(10px, env(safe-area-inset-bottom)); }
  .ax-open.is-open .ax-open__bar { min-block-size: 56px; gap: var(--ax-sp-5); }
  .ax-open.is-open .ax-open__kbd { display: none; }
  .ax-open.is-open .ax-open__face { grid-area: face; justify-self: stretch; inline-size: auto; aspect-ratio: auto; }
  .ax-open.is-open .ax-open__talk > .ax-open__voice { grid-area: voice; padding-block: var(--ax-sp-3); }
  .ax-open.is-open .ax-open__talk > .ax-open__entry,
  .ax-open.is-open .ax-open__talk > .ax-open__hand { grid-area: entry; }
  /* (a little room at the end of the line, so your words never touch a
     scrollbar where the system draws one) */
  .ax-open.is-open .ax-open__talk > .ax-open__stack { padding: var(--ax-sp-8) var(--ax-sp-3) var(--ax-sp-6) 0; }
  .ax-open.is-open .ax-open__field { --field-r: 18px; }
  .ax-open.is-open .ax-open__field-input {
    font-size: var(--ax-fs-md);
    min-block-size: calc(1.5em + 16px);
    max-block-size: calc(6em + 16px);
    padding: 12px 16px 0;
  }
  .ax-open.is-open .ax-open__tools { padding: 4px 8px 8px 10px; }
  .ax-open.is-open .ax-open__erow { padding-block-start: 0; }

  /* the estimate, one bar under the face, opening the brief */
  .ax-open.is-open .ax-open__talk > .ax-open__est:not([hidden]) {
    grid-area: est;
    display: flex;
    align-items: center;
    gap: var(--ax-sp-5);
    min-block-size: 48px;
    margin: 0;
    padding: var(--ax-sp-4) var(--ax-sp-6);
    border: 1px solid var(--ax-line);
    border-radius: 14px;
    background: rgb(var(--ax-white-rgb) / .04);
    color: var(--ax-text-strong);
    font: inherit;
    text-align: start;
    cursor: pointer;
  }
  .ax-open__estk { font-family: var(--ax-font-mono); font-size: var(--ax-fs-3xs); letter-spacing: .14em; text-transform: uppercase; color: rgb(var(--ax-accent-text-rgb)); }
  .ax-open__estv { font-size: var(--ax-fs-sm); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .ax-open__estw { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--ax-fs-xs); color: var(--ax-text-muted); }
  .ax-open__esto {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-sp-2);
    margin-inline-start: auto;
    font-family: var(--ax-font-mono);
    font-size: var(--ax-fs-3xs);
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--ax-text-muted);
  }
  .ax-open.is-sheet .ax-open__esto svg { transform: rotate(180deg); }

  /* THE SHEET. The brief stands over the transcript, in its place, and
     slides away when it is not wanted. */
  .ax-open.is-open .ax-open__panel {
    grid-area: log;
    z-index: 3;
    margin-block-start: var(--ax-sp-4);
    padding: var(--ax-sp-8) var(--ax-sp-7) var(--ax-sp-8) var(--ax-sp-8);
    border: 1px solid var(--ax-line);
    border-radius: 18px;
    background: rgb(10 10 12 / .96);
    transform: translateY(14px);
    opacity: 0;
    visibility: hidden;
    transition: transform .4s var(--ax-ease-out), opacity .3s var(--ax-ease-out), visibility 0s linear .4s;
  }
  .ax-open.is-open.is-sheet .ax-open__panel {
    transform: none;
    opacity: 1;
    visibility: visible;
    transition: transform .4s var(--ax-ease-out), opacity .3s var(--ax-ease-out), visibility 0s;
  }
  .ax-open.is-open .ax-open__panel::before { display: none; }
  .ax-open.is-open .ax-open__pclose {
    position: absolute;
    inset-block-start: var(--ax-sp-5);
    inset-inline-end: var(--ax-sp-5);
    z-index: 1;
    display: grid;
    place-items: center;
    inline-size: 40px;
    block-size: 40px;
    border: 1px solid var(--ax-line);
    border-radius: var(--ax-r-full);
    background: transparent;
    color: var(--ax-text-body);
    cursor: pointer;
  }
  .ax-open.is-open .ax-open__phead { padding-inline-end: 44px; }

}

/* A PHONE (and a short landscape screen): one column, a chat. The face is a
   strip at the top, the conversation sits on the answer box. */
@media (max-width: 819px), (max-width: 1099px) and (max-height: 559px) {
  .ax-open.is-open .ax-open__stage {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto minmax(0, 1fr) auto auto;
    grid-template-areas: "bar" "face" "est" "log" "voice" "entry";
  }
  .ax-open.is-open .ax-open__pips { gap: 4px; }
  .ax-open.is-open .ax-open__pips li { inline-size: 7px; }
  .ax-open.is-open .ax-open__face { block-size: clamp(88px, 15svh, 148px); margin-block: var(--ax-sp-4) var(--ax-sp-2); }
  .ax-open.is-open .ax-open__stack > :first-child { margin-block-start: auto; }
  /* done: the face gives its room to the brief and the send form */
  .ax-open.is-open.is-closed .ax-open__face { display: none; }
}
@media (max-width: 1099px) and (max-height: 479px) {
  .ax-open.is-open .ax-open__face { display: none; }
}
/* THE KEYBOARD (26 Oct 2026). A phone keyboard takes half the screen but
   leaves the CSS height alone, so the tall layout stayed and the transcript
   was squeezed to one line. While it is up (.is-keyboard, set from
   visualViewport by arxeon.open.js) the face steps aside, the bar, the
   estimate and the small print tighten, and the transcript gets the room:
   the question stays in view while you answer. The shadow paints the
   chat's own black under it, where Safari's floating address bar shows. */
@media (max-width: 819px), (max-width: 1099px) and (max-height: 559px) {
  .ax-open.is-open.is-keyboard .ax-open__face { display: none; }
  .ax-open.is-open.is-keyboard .ax-open__bar { min-block-size: 46px; }
  .ax-open.is-open.is-keyboard .ax-open__talk > .ax-open__est:not([hidden]) { min-block-size: 40px; padding-block: var(--ax-sp-2); }
  .ax-open.is-open.is-keyboard .ax-open__talk > .ax-open__stack { padding-block-start: var(--ax-sp-3); }
  .ax-open.is-open.is-keyboard .ax-open__erow { display: none; }
  .ax-open.is-open.is-locked.is-keyboard { box-shadow: 0 40vh 0 0 var(--ax-ink-000); }
}

/* A TABLET OR A SMALL LAPTOP: two columns. The robot stands on the right
   with its caption and the answer box under it; the estimate and the
   transcript are on the left, and the brief opens over the transcript. */
@media (min-width: 820px) and (max-width: 1099px) and (min-height: 560px) {
  /* round 97: fixed rooms under the face here too (the answer box's room
     is the send form's, which is the taller of the two) */
  .ax-open.is-open { --voice-h: 12px; --entry-h: 164px; }
  .ax-open.is-open .ax-open__stage {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.12fr);
    grid-template-rows: auto auto minmax(0, 1fr) var(--said-h) var(--voice-h) var(--entry-h);
    grid-template-areas:
      "bar  bar"
      "est  face"
      "log  face"
      "log  said"
      "log  voice"
      "log  entry";
    column-gap: clamp(24px, 3vw, 40px);
  }
  .ax-open.is-open .ax-open__face { margin-block-start: var(--ax-sp-5); }
  .ax-open.is-open .ax-open__talk > .ax-open__est:not([hidden]) { margin-block-start: var(--ax-sp-6); }
  .ax-open.is-open .ax-open__talk > .ax-open__voice,
  .ax-open.is-open .ax-open__talk > .ax-open__entry,
  .ax-open.is-open .ax-open__talk > .ax-open__hand { align-self: end; }
}

@media (max-width: 339px) {
  .ax-open.is-open .ax-open__hrow { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 639px) {
  .ax-open.is-open .ax-open__blabel { display: none; }
  .ax-open.is-open .ax-open__btopic::before { display: none; }
  .ax-open.is-open .ax-open__leave { padding-inline: var(--ax-sp-5); }
  .ax-open.is-open .ax-open__hand { row-gap: var(--ax-sp-5); padding-block-start: var(--ax-sp-4); }
  .ax-open.is-open .ax-open__hlead { display: none; }
}
@media (max-width: 419px) {
  .ax-open.is-open .ax-open__estk { display: none; }
}

/* ── left: the section as it was, and the way back in ─────────────────── */
/* ROUND 97. Leave, Esc or Back put the section back as it stood before a
   topic was picked -- the question, the face at its full size, the rail with
   the exchanges so far -- and where the four ways in stood, one way back in.
   Nothing of the conversation shows here; all of it is kept for the channel. */

.ax-open__resume { display: none; }
.ax-open.is-away .ax-open__stack,
.ax-open.is-away .ax-open__voice,
.ax-open.is-away .ax-open__entry,
.ax-open.is-away .ax-open__hand,
.ax-open.is-away .ax-open__panel { display: none; }
.ax-open.is-away .ax-open__resume:not([hidden]) {
  grid-column: 4;
  grid-row: 1 / -1;
  align-self: start;
  position: relative;
  display: grid;
  justify-items: start;
  row-gap: var(--ax-sp-4);
  margin: 0;
  padding: var(--ax-sp-7) var(--ax-sp-8) var(--ax-sp-8);
  border: 1px solid rgb(var(--ax-accent-text-rgb) / .38);
  border-radius: var(--ax-r-lg);
  background:
    radial-gradient(120% 90% at 0% 0%, rgb(var(--ax-accent-text-rgb) / .10), transparent 62%),
    rgb(var(--ax-white-rgb) / .025);
  box-shadow: 0 24px 60px -30px rgb(var(--ax-accent-text-rgb) / .55);
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
  transition: border-color .18s var(--ax-ease-out), background-color .18s var(--ax-ease-out), transform .18s var(--ax-ease-out);
}
.ax-open__resume:hover { border-color: rgb(var(--ax-accent-text-rgb) / .7); transform: translateY(-1px); }
.ax-open.is-away .ax-open__resume:focus-visible { outline: 2px solid rgb(var(--ax-accent-text-rgb)); outline-offset: 3px; }
.ax-open__rlabel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4em .9em;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}
/* the eyes' light, still on: the conversation is waiting */
.ax-open__rtopic { display: inline-flex; align-items: center; gap: .9em; color: rgb(var(--ax-accent-text-rgb)); }
.ax-open__rtopic::before {
  content: "";
  inline-size: 6px;
  block-size: 6px;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-eye-rgb));
  box-shadow: 0 0 10px 1px rgb(var(--ax-eye-rgb) / .6);
  animation: ax-open-breathe 3.6s var(--ax-ease-in-out) infinite;
}
.ax-open__rstate:not(:empty)::before { content: "/"; margin-inline-end: .9em; color: var(--ax-text-subtle); }
.ax-open__rname {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-sp-4);
  font-size: var(--ax-fs-xl);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: var(--ax-text-strong);
}
.ax-open__rname svg { flex: none; color: rgb(var(--ax-accent-text-rgb)); transition: transform .18s var(--ax-ease-out); }
.ax-open__resume:hover .ax-open__rname svg { transform: translateX(3px); }
.ax-open__rwhat { font-size: var(--ax-fs-sm); line-height: var(--ax-lh-body); color: var(--ax-text-muted); }
.ax-open__rfig {
  padding-block-start: var(--ax-sp-4);
  border-block-start: 1px solid var(--ax-line);
  inline-size: 100%;
  font-size: var(--ax-fs-md);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ax-text-strong);
}
.ax-open__rfig[hidden] { display: none; }
@media (max-width: 639px) { .ax-open__rname { font-size: var(--ax-fs-lg); } }
/* one column: the way back in comes before the face, where it is seen
   without scrolling */
@media (max-width: 1099px) {
  .ax-open.is-away .ax-open__resume:not([hidden]) { grid-column: 2; grid-row: 2; }
  .ax-open.is-away .ax-open__face { grid-row: 3; }
}
/* arriving back: the section comes up from the dark */
.ax-open.is-away-in .ax-open__stage { animation: ax-open-away-in .6s var(--ax-ease-out) both; }
@keyframes ax-open-away-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ── still ───────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .ax-open.is-away-in .ax-open__stage,
  .ax-open__rtopic::before,
  .ax-open.is-locking,
  .ax-open.is-locking .ax-open__bar,
  .ax-open.is-open .ax-open__msg,
  .ax-open__bdot,
  .ax-open__saiddots i { animation: none !important; }
  .ax-open__seal i, .ax-open__meter i, .ax-open__send, .ax-open__panel, .ax-open__pips li { transition: none !important; }
  .ax-open__meter i { transform: scaleY(.5) !important; }
}

/* printed, the channel is part of the page again: the whole transcript and
   the brief, none of the controls */
@media print {
  html.ax-channel-locked,
  html.ax-channel-locked body { overflow: visible; }
  .ax-open__holder { display: none; }
  .ax-open.is-open { block-size: auto; }
  .ax-open.is-open.is-locked { position: static; block-size: auto; }
  .ax-open.is-open .ax-open__stage { block-size: auto; }
  .ax-open.is-open .ax-open__talk > .ax-open__stack,
  .ax-open.is-open .ax-open__panel { overflow: visible; max-block-size: none; -webkit-mask-image: none; mask-image: none; }
  .ax-open.is-open .ax-open__msg.is-said { position: static; inline-size: auto; block-size: auto; overflow: visible; clip-path: none; white-space: normal; }
  .ax-open__bar, .ax-open__said, .ax-open__est, .ax-open__hand, .ax-open__seal { display: none !important; }
  .ax-open.is-open .ax-open__panel { opacity: 1; visibility: visible; transform: none; }
}
/* a high-contrast mode keeps every control; only the seal is ornament */
@media (forced-colors: active) {
  .ax-open__seal { display: none; }
}

/* ===========================================================================
   21 · THE BUILD — section 4

   ROUND 41 · FROM BROKEN TO BUILT. Sections 1, 2 and 3 are each one screen,
   words on the dark at the left and one living thing on the right: the
   continent, the tower, the face. Section 4 is now the same: the seven
   phases on the left, and on the right Astra's broken glass, which the
   build puts back together. It floats while the scope is locked, its cracks
   are drawn while it is designed, its pieces fly home during the build, the
   Arxeon mark inside it fills with light when your data goes in, it is hit
   and holds when you try to break it, and when it goes live the light
   comes through it as the spectrum. Then care keeps it lit, and it lets go
   and builds again. Scripts/arxeon.glass.js draws it and runs that clock.

   THE RAIL IS THE THROUGH-LINE, STILL. Section 1's hairline, section 2's
   tuner, section 3's conversation; here it is the build itself, one segment
   per phase, each as long as that phase's share of the weeks. Build is 45%
   of the line because it is 45% of the job -- round 35's law, kept.

   NOTHING HERE DEPENDS ON JAVASCRIPT TO BE READABLE. Without it, or
   without WebGL, the section is one column: every phase, every sentence.
   The two-column frame, the rail and the one-phase-at-a-time list are
   gated behind .is-live-glass, which only the renderer sets.

   THE SPECTRUM NEVER BECOMES TEXT. Round 2 measured the mark's own stops as
   type: spec-6 at 3.19:1 and spec-8 at 2.80:1, both failures. The stops are
   carried by the rail and the dots -- graphics -- and every glyph in here
   uses the ordinary text tokens.

   ROUND 98 · THE LIST KEEPS ITS ROOM. One phase open at a time, sentences
   of one to three lines: the list changed height with every phase, and
   the sections under it jumped. Each sentence now opens to its own height
   (--say-h) as the last one closes at the same pace, and the list keeps
   the room of its longest sentence (--ladder-room), both measured by
   arxeon.glass.js.
   ======================================================================== */

.ax-build {
  --bd-h: clamp(660px, calc(100svh - 84px), 1080px);
  --bd-lens: clamp(340px, 44vw, 780px);
  position: relative;
  display: grid;
  min-block-size: var(--bd-h);
  padding-block: var(--ax-sp-11);
  background: var(--ax-bg);
  overflow: clip;
  isolation: isolate;
}

.ax-build__dark {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(46% 38% at 50% 8%, rgb(var(--ax-white-rgb) / .045), transparent 70%),
    radial-gradient(60% 50% at 50% 100%, rgb(var(--ax-spec-8-rgb) / .050), transparent 72%);
  /* ROUND 40: the glow's centre sits 8% down, so at the section's top edge
     it was already lit -- a hard line under section 3. It fades in now.
     ROUND 41: and out again at the bottom, for the same reason: the violet
     glow is centred ON the bottom edge, and section 5 starts dark. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 160px, #000 calc(100% - 200px), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 160px, #000 calc(100% - 200px), transparent 100%);
}

/* the glass, drawn under everything else */
.ax-build__scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.ax-build__gl {
  position: absolute;
  inset: 0;
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.ax-build__stage {
  position: relative;
  z-index: 1;
  display: grid;
  row-gap: var(--ax-sp-8);
  align-content: start;
}

/* the lens's place: only the renderer draws in it */
.ax-build__lens { display: none; }

/* ── the head ─────────────────────────────────────────────────────────── */

.ax-build__head { display: grid; row-gap: var(--ax-sp-4); justify-items: start; align-content: start; }

.ax-build__label {
  margin: 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  line-height: var(--ax-lh-micro);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ax-text-muted);
}

.ax-build__line {
  margin: 0;
  max-inline-size: 16ch;
  font-size: var(--ax-fs-d3, var(--ax-fs-2xl));
  line-height: var(--ax-lh-display);
  letter-spacing: var(--ax-tr-hero);
  color: var(--ax-text-strong);
  text-wrap: balance;
}

.ax-build__sub {
  margin: 0;
  max-inline-size: 46ch;
  font-size: var(--ax-fs-md);
  line-height: var(--ax-lh-lead);
  color: var(--ax-text-body);
}

/* the one line that changes when somebody has actually talked to section 3 */
.ax-build__meter {
  display: inline-flex;
  align-items: baseline;
  gap: var(--ax-sp-3);
  margin: var(--ax-sp-1) 0 0;
  padding: var(--ax-sp-2) var(--ax-sp-5);
  border: 1px solid var(--ax-line);
  border-radius: var(--ax-r-full);
  background: var(--ax-bg-sunken);
}
.ax-build__for {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
.ax-build__span {
  font-size: var(--ax-fs-md);
  font-weight: 600;
  color: var(--ax-text-strong);
}
/* it earned the accent by being theirs */
.ax-build[data-ax-mine="1"] .ax-build__meter { border-color: rgb(var(--ax-accent-text-rgb) / .45); }
.ax-build[data-ax-mine="1"] .ax-build__for  { color: rgb(var(--ax-accent-text-rgb)); }

/* ── the seven phases ─────────────────────────────────────────────────── */

.ax-build__ladder {
  position: relative;
  margin: 0;
  padding: 0 0 0 var(--ax-sp-5);
  list-style: none;
  display: grid;
  row-gap: var(--ax-sp-6);
}

/* the hairline the phases hang from; it grows down when the section is
   first seen, as round 35's beam did */
.ax-build__ladder::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 1px;
  background: linear-gradient(to bottom, rgb(var(--ax-white-rgb) / .55), rgb(var(--ax-white-rgb) / .10));
  transform-origin: 50% 0;
}
.ax-build.is-armed .ax-build__ladder::before {
  transform: scaleY(0);
  transition: transform 1.9s var(--ax-ease-out);
}
.ax-build.is-armed[data-ax-lit="1"] .ax-build__ladder::before { transform: scaleY(1); }

.ax-build__step {
  position: relative;
  display: block;
  /* round 35's law, kept for the one-column section: a phase's space is
     its share of the weeks (build.js sets --w from data-ax-w) */
  padding-block: calc(var(--w, .14) * 90px);
}
.ax-build.is-live-glass .ax-build__step { padding-block: 0; }
.ax-build.is-armed .ax-build__step {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .62s var(--ax-ease-out), transform .62s var(--ax-ease-out);
}
.ax-build.is-armed .ax-build__step.is-lit { opacity: 1; transform: none; }

/* round 35's blade and ray: the rail carries the stops now */
.ax-build__blade, .ax-build__ray { display: none; }

.ax-build__card {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 2.6em minmax(0, 1fr) auto;
  column-gap: var(--ax-sp-3);
  row-gap: var(--ax-sp-1);
  align-items: baseline;
}

.ax-build__no {
  margin: 0;
  grid-column: 1;
  grid-row: 1;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  color: var(--ax-text-subtle);
}
.ax-build__what {
  margin: 0;
  grid-column: 2;
  grid-row: 1;
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-head);
  color: var(--ax-text-strong);
}
.ax-build__when {
  margin: 0;
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgb(var(--ax-accent-text-rgb));
}
.ax-build__say {
  margin: 0;
  grid-column: 2 / -1;
  grid-row: 2;
  max-inline-size: 52ch;
  font-size: var(--ax-fs-sm);
  line-height: var(--ax-lh-body);
  color: var(--ax-text-body);
}

.ax-build__note {
  margin: 0;
  max-inline-size: 62ch;
  font-size: var(--ax-fs-xs);
  line-height: var(--ax-lh-body);
  color: var(--ax-text-subtle);
}

/* the seven stops, carried by graphics only: sampled across the whole ramp
   so seven phases still travel cyan to violet the way eleven blades do */
.ax-build__step:nth-child(1) { --st: var(--ax-spec-0-rgb); }
.ax-build__step:nth-child(2) { --st: var(--ax-spec-1-rgb); }
.ax-build__step:nth-child(3) { --st: var(--ax-spec-3-rgb); }
.ax-build__step:nth-child(4) { --st: var(--ax-spec-4-rgb); }
.ax-build__step:nth-child(5) { --st: var(--ax-spec-5-rgb); }
.ax-build__step:nth-child(6) { --st: var(--ax-spec-6-rgb); }
.ax-build__step:nth-child(7) { --st: var(--ax-spec-8-rgb); }

/* ── the frame: live ──────────────────────────────────────────────────── */

.ax-build.is-live-glass {
  min-block-size: var(--bd-h);
}
.ax-build.is-live-glass .ax-build__stage {
  grid-template-columns: 34px minmax(0, 1fr) var(--bd-lens);
  grid-template-rows: auto minmax(0, 1fr) auto;
  column-gap: var(--ax-sp-8);
  row-gap: var(--ax-sp-6);
  align-content: stretch;
  block-size: 100%;
}
.ax-build.is-live-glass .ax-build__head   { grid-column: 2; grid-row: 1; }
.ax-build.is-live-glass .ax-build__ladder { grid-column: 2; grid-row: 2; align-self: start; row-gap: 0; padding: 0; block-size: var(--ladder-room, auto); align-content: start; }
.ax-build.is-live-glass .ax-build__ladder::before { display: none; }
.ax-build.is-live-glass .ax-build__note   { grid-column: 2; grid-row: 3; align-self: end; }
.ax-build.is-live-glass .ax-build__lens {
  display: block;
  grid-column: 3;
  grid-row: 1 / -1;
  align-self: center;
  justify-self: center;
  inline-size: 100%;
  max-block-size: 100%;
  aspect-ratio: 1;
}

/* THE RAIL: one segment a phase, each as long as its share of the weeks,
   and the playhead that runs down it with the build. Built by glass.js. */
.ax-build__rail {
  position: relative;
  grid-column: 1;
  grid-row: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-block-size: 0;
  padding-block: 2px 0;
}
.ax-build__rail > i {
  position: relative;
  flex: var(--w) 1 0;
  inline-size: 2px;
  margin-inline-start: 4px;
  margin-block-end: 3px;
  border-radius: 1px;
  background: rgb(var(--st) / .30);
  transition: background-color .5s var(--ax-ease-out), box-shadow .5s var(--ax-ease-out);
}
.ax-build__rail > i.is-now { background: rgb(var(--st)); box-shadow: 0 0 10px rgb(var(--st) / .7); }
.ax-build__rail > i.is-done { background: rgb(var(--st) / .62); }
/* care has no length: it is a point, and it keeps going */
.ax-build__rail > i.is-care {
  flex: 0 0 auto;
  inline-size: 7px;
  block-size: 7px;
  margin-inline-start: 1px;
  border-radius: var(--ax-r-full);
}
.ax-build__now {
  position: absolute;
  inset-inline-start: 2px;
  inset-block-start: 0;
  inline-size: 6px;
  block-size: 6px;
  margin: -3px 0 0 0;
  border-radius: var(--ax-r-full);
  background: rgb(var(--ax-white-rgb));
  box-shadow: 0 0 12px rgb(var(--ax-white-rgb) / .8);
  transform: translateY(var(--y, 0px));
  will-change: transform;
}

/* one phase at a time: the one the glass is on opens, the rest are a line */
.ax-build.is-live-glass .ax-build__step { border-block-start: 1px solid var(--ax-line); }
.ax-build.is-live-glass .ax-build__step:last-child { border-block-end: 1px solid var(--ax-line); }
.ax-build.is-live-glass .ax-build__card { padding-block: 9px; }
.ax-build.is-live-glass .ax-build__what { font-size: var(--ax-fs-md); color: var(--ax-text-muted); transition: color .35s var(--ax-ease-out); }
/* round 98: a sentence opens to its own measured height and the last one
   closes at the same pace, so the two always add up to the same */
.ax-build.is-live-glass .ax-build__say {
  block-size: 0;
  overflow: hidden;
  opacity: 0;
  transition: block-size .55s var(--ax-ease-out), opacity .4s var(--ax-ease-out);
}
.ax-build.is-live-glass .ax-build__step.is-now .ax-build__what { color: var(--ax-text-strong); }
.ax-build.is-live-glass .ax-build__step.is-now .ax-build__say { block-size: var(--say-h, auto); opacity: 1; }
.ax-build.is-live-glass .ax-build__step.is-now .ax-build__no { color: var(--ax-text-body); }
.ax-build.is-live-glass .ax-build__step.is-now .ax-build__no::before {
  content: "";
  display: inline-block;
  inline-size: 5px;
  block-size: 5px;
  margin-inline-end: 7px;
  vertical-align: 1px;
  border-radius: var(--ax-r-full);
  background: rgb(var(--st));
  box-shadow: 0 0 8px rgb(var(--st));
}
/* the title is the button that takes the glass to that phase */
.ax-build__pick {
  all: unset;
  cursor: pointer;
  border-radius: var(--ax-r-sm);
}
.ax-build__pick:hover { color: var(--ax-text-strong); }
.ax-build__pick:focus-visible { outline: 2px solid rgb(var(--ax-accent-text-rgb)); outline-offset: 3px; }

/* a short screen: the same frame, tighter, so all seven still fit in it */
@media (min-width: 1100px) and (max-height: 820px) {
  .ax-build.is-live-glass { padding-block: var(--ax-sp-8); }
  .ax-build.is-live-glass .ax-build__stage { row-gap: var(--ax-sp-4); }
  .ax-build.is-live-glass .ax-build__head { row-gap: var(--ax-sp-3); }
  .ax-build.is-live-glass .ax-build__line { font-size: var(--ax-fs-d4, var(--ax-fs-xl)); max-inline-size: 20ch; }
  .ax-build.is-live-glass .ax-build__card { padding-block: 6px; }
  .ax-build.is-live-glass .ax-build__say { font-size: var(--ax-fs-xs); }
}

/* ── narrow ───────────────────────────────────────────────────────────── */

@media (max-width: 1099px) {
  .ax-build { --bd-h: auto; padding-block: var(--ax-sp-10); }
  .ax-build.is-live-glass .ax-build__stage {
    grid-template-columns: 22px minmax(0, 1fr);
    grid-template-rows: none;
    row-gap: var(--ax-sp-6);
    block-size: auto;
  }
  .ax-build.is-live-glass .ax-build__rail   { grid-row: 1 / span 4; }
  .ax-build.is-live-glass .ax-build__head   { grid-column: 2; grid-row: 1; }
  .ax-build.is-live-glass .ax-build__lens   { grid-column: 1 / -1; grid-row: 2; inline-size: min(100%, 520px); }
  .ax-build.is-live-glass .ax-build__ladder { grid-column: 2; grid-row: 3; }
  .ax-build.is-live-glass .ax-build__note   { grid-column: 2; grid-row: 4; }
  /* a phone has no room for the share beside the title: it goes under it,
     and may wrap ("ongoing, from the day it goes live" is 38 characters) */
  .ax-build__when { grid-column: 2 / -1; grid-row: 2; justify-self: start; white-space: normal; }
  .ax-build__say  { grid-row: 3; }
}

/* ── still ────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  /* Nothing travels and nothing fades in: every phase is there at once,
     and the glass is one still frame of the finished, lit lens. Every
     sentence stays open -- there is no build running to follow. */
  .ax-build.is-armed .ax-build__ladder::before,
  .ax-build.is-armed .ax-build__step,
  .ax-build.is-armed .ax-build__blade,
  .ax-build.is-armed .ax-build__ray,
  .ax-build.is-live-glass .ax-build__say,
  .ax-build.is-live-glass .ax-build__what { transition: none !important; }
  .ax-build.is-armed .ax-build__ladder::before { transform: scaleY(1) !important; }
  .ax-build.is-armed .ax-build__step { opacity: 1 !important; transform: none !important; }
  .ax-build.is-live-glass .ax-build__say { block-size: auto; max-block-size: none; opacity: 1; }
  .ax-build.is-live-glass .ax-build__ladder { block-size: auto; }
  .ax-build.is-live-glass .ax-build__what { color: var(--ax-text-strong); }
}

@media print, (forced-colors: active) {
  .ax-build__dark, .ax-build__scene, .ax-build__rail, .ax-build__lens { display: none !important; }
  .ax-build__ladder::before { display: none; }
  .ax-build.is-armed .ax-build__step { opacity: 1 !important; transform: none !important; }
  .ax-build .ax-build__say { block-size: auto !important; max-block-size: none !important; opacity: 1 !important; transition: none !important; }
  .ax-build .ax-build__ladder { block-size: auto !important; }
}

/* ===========================================================================
   22 · THE YEAR AFTER — section 5

   CARE, DRAWN AS THE TIME IT TAKES. The floor the section stands on is the
   first year after launch. The hand running along it is the uptime monitor
   and never stops. Behind it, seven lit ticks are the seven daily backups
   that exist at any moment; the ninety-day warranty is the arch over the
   first quarter; reports, reviews and roadmap sessions are marks at the
   times they happen, and ping as the hand reaches them.

   ROUND 43 · THE GYROSCOPE. Above the floor turns a gyroscope, drawn in real
   3D by arxeon.engine.js into .ax-care__machine: three nested rings of black
   metal round a core of light, and the rings are the plans. The light in the
   air behind it never reaches the words: the canvas keeps its own dark
   behind the head, the plans and the floor.

   ONE CLOCK. The hand, the backups and every ping are CSS animations with the
   same duration, started by the same class, so they cannot drift apart. The
   machine reads the hand's own animation for its day, as the printed day
   does. Everything on the floor that moves is a page-level layer moved by
   transform or opacity -- NOTHING INSIDE THE SVG ANIMATES, the round-17 rule.

   THE PLANS NEST, SO THE LANES NEST. Essential is the floor itself, Active the
   lane under it, Partner the lane under that. Choosing a plan lights its lane
   and every lane above it; the rest stay as ghosts at a fifth of their
   strength, so the floor always shows what the next plan up would add.

   THE SPECTRUM NEVER BECOMES TEXT. The three stops are the ramp's two ends
   and its middle, carried by marks, lanes and edges. Every glyph uses the
   ordinary text tokens.
   ======================================================================== */

.ax-care {
  --cr-year: 36s;                   /* one run of the floor: one year      */
  --cr-p1: var(--ax-spec-0-rgb);    /* Essential — the floor               */
  --cr-p2: var(--ax-spec-4-rgb);    /* Active    — the lane under it       */
  --cr-p3: var(--ax-spec-8-rgb);    /* Partner   — the lane under that     */
  --cr-h: clamp(660px, calc(100svh - 84px), 1080px);
  --cr-pad-t: clamp(28px, 4.2vh, 52px);
  --cr-pad-b: clamp(18px, 2.8vh, 34px);
  --cr-year-h: 112px;               /* the floor block: labels, rail, lanes */
  position: relative;
  display: grid;
  min-block-size: var(--cr-h);
  padding-block: var(--cr-pad-t) var(--cr-pad-b);
  background: var(--ax-bg);
  overflow: clip;
  isolation: isolate;
}

.ax-care__dark {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(30% 42% at 50% 56%, rgb(var(--cr-p2) / .055), transparent 72%),
    radial-gradient(48% 36% at 50% 0%, rgb(var(--ax-white-rgb) / .035), transparent 70%);
  /* ROUND 41: the white glow is centred ON the top edge, so it drew a line
     under section 4 (2.7 of 255, measured). It fades in, as section 4's does. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 180px);
          mask-image: linear-gradient(to bottom, transparent 0, #000 180px);
}

/* the gyroscope and the air it stands in: one canvas over the whole
   section, under the words. arxeon.engine.js sizes it and keeps it off the
   text. */
.ax-care__scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.ax-care__gl { display: block; inline-size: 100%; block-size: 100%; }

.ax-care__stage {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.18fr) minmax(0, 1fr);
  grid-template-rows: auto auto auto minmax(0, 1fr) auto;
  column-gap: clamp(28px, 3.2vw, 60px);
  align-self: stretch;
}

/* ── the head — section 4's voice, one register on ────────────────────── */

.ax-care__head {
  grid-column: 1;
  grid-row: 1;
  display: grid;
  row-gap: var(--ax-sp-4);
  justify-items: start;
  align-content: start;
}

.ax-care__label {
  margin: 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgb(var(--ax-accent-text-rgb));
}

.ax-care__line {
  margin: 0;
  max-inline-size: 13ch;
  font-size: var(--ax-fs-d3, var(--ax-fs-3xl));
  line-height: var(--ax-lh-display);
  letter-spacing: -.02em;
  color: var(--ax-text-strong);
  text-wrap: balance;
}

.ax-care__sub {
  margin: 0;
  max-inline-size: 40ch;
  font-size: var(--ax-fs-md);
  line-height: var(--ax-lh-body);
  color: var(--ax-text-muted);
}

/* ── the picker and the readout ───────────────────────────────────────── */

.ax-care__pick {
  grid-column: 1;
  grid-row: 2;
  display: grid;
  row-gap: var(--ax-sp-4);
  justify-items: start;
  align-content: start;
  margin-block-start: var(--ax-sp-9);
}

/* the one line that exists only when somebody has talked to section 3 */
.ax-care__mine {
  margin: 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(var(--ax-accent-text-rgb));
}
.ax-care__mine:empty { display: none; }

/* What the dial's hub said, as one line: the plan, its floor, the day. */
.ax-care__hub {
  grid-column: 1;
  grid-row: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--ax-sp-5);
  row-gap: var(--ax-sp-2);
  margin-block-start: var(--ax-sp-7);
  /* a line box is shorter than its glyphs' own box: a few pixels of room
     keep every glyph inside the readout, measured (r37) */
  padding-block: 3px;
  padding-inline-start: var(--ax-sp-5);
  border-inline-start: 2px solid rgb(var(--cr-p2) / .7);
  transition: border-color .5s var(--ax-ease-out);
}
.ax-care.is-armed[data-ax-plan="1"] .ax-care__hub { border-color: rgb(var(--cr-p1) / .75); }
.ax-care.is-armed[data-ax-plan="3"] .ax-care__hub { border-color: rgb(var(--cr-p3) / .85); }

.ax-care__hname {
  font-size: var(--ax-fs-lg);
  font-weight: 700;
  line-height: var(--ax-lh-head);
  letter-spacing: -.01em;
  color: var(--ax-text-strong);
}
.ax-care__hprice {
  font-size: var(--ax-fs-xs);
  color: var(--ax-text-muted);
}
.ax-care__day {
  inline-size: 100%;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--ax-text-subtle);
}

/* ── the machine ──────────────────────────────────────────────────────── */

/* Its box keeps round 42's size and place, so nothing around it moves: it
   stands on the floor, as tall as the stage allows above it, and the
   gyroscope is drawn whole inside it, floating just clear of the floor. */
.ax-care__machine {
  grid-column: 2;
  grid-row: 1 / 5;
  align-self: end;
  justify-self: center;
  position: relative;
  inline-size: min(100%, calc((var(--cr-h) - var(--cr-pad-t) - var(--cr-pad-b) - var(--cr-year-h) - 12px) * 920 / 945));
  aspect-ratio: 920 / 945;
  margin-block-end: -6px;
}
/* with no JavaScript, or no WebGL: the gyroscope's own still picture */
.ax-care__machine picture,
.ax-care__machine img { display: block; inline-size: 100%; block-size: 100%; }

/* ── the plans: the content, and the floor's legend ───────────────────── */

.ax-care__tiers {
  grid-column: 3;
  grid-row: 1 / 5;
  align-self: center;
  display: grid;
  max-inline-size: 30rem;
}

.ax-care__tier {
  --tc: var(--cr-p1);
  position: relative;
  display: grid;
  row-gap: var(--ax-sp-3);
  padding: var(--ax-sp-6) 0 var(--ax-sp-6) var(--ax-sp-7);
  border-block-start: 1px solid var(--ax-line);
}
.ax-care__tier:last-child { border-block-end: 1px solid var(--ax-line); }
.ax-care__tier[data-ax-tier="2"] { --tc: var(--cr-p2); }
.ax-care__tier[data-ax-tier="3"] { --tc: var(--cr-p3); }

/* the plan's stop touches the list as an EDGE, never as type */
.ax-care__tier::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block: var(--ax-sp-6);
  inline-size: 2px;
  border-radius: 1px;
  background: rgb(var(--tc) / .85);
  transition: opacity .45s var(--ax-ease-out);
}

.ax-care__thead {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  column-gap: var(--ax-sp-6);
  row-gap: var(--ax-sp-2);
}
.ax-care__tname {
  margin: 0;
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-head);
  color: var(--ax-text-strong);
  transition: color .45s var(--ax-ease-out);
}
.ax-care__tprice {
  margin: 0;
  font-size: var(--ax-fs-xs);
  color: var(--ax-text-muted);
}
.ax-care__tprice b {
  font-size: var(--ax-fs-lg);
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--ax-text-strong);
  transition: color .45s var(--ax-ease-out);
}
.ax-care__plus {
  margin: 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}

.ax-care__items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  row-gap: var(--ax-sp-2);
}
.ax-care__items li {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  column-gap: var(--ax-sp-5);
  align-items: start;
  font-size: var(--ax-fs-sm);
  line-height: var(--ax-lh-body);
  color: var(--ax-text-body);
  transition: color .45s var(--ax-ease-out);
}

/* a plan not chosen stays readable -- quieter, never below the text floor */
.ax-care__tier[data-ax-on="0"]::before { opacity: .22; }
.ax-care__tier[data-ax-on="0"] .ax-care__tname,
.ax-care__tier[data-ax-on="0"] .ax-care__tprice b { color: var(--ax-text-muted); }
.ax-care__tier[data-ax-on="0"] .ax-care__items li { color: var(--ax-text-subtle); }
.ax-care__tier[data-ax-on="0"] .ax-care__g { opacity: .32; }

/* THE LEGEND IS THE LIST. Each line carries the mark it draws on the floor,
   in its plan's stop; a line with nothing on the floor carries a short rule. */
.ax-care__g {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 18px;
  block-size: calc(1em * var(--ax-lh-body));
  color: rgb(var(--tc, var(--cr-p1)));
  transition: opacity .45s var(--ax-ease-out);
}
.ax-care__g::before { content: ""; display: block; }
.ax-care__g--line::before    { inline-size: 9px; block-size: 2px; border-radius: 1px; background: currentColor; opacity: .7; }
.ax-care__g--tick::before    { inline-size: 2px; block-size: 10px; border-radius: 1px; background: currentColor;
                               margin-inline-start: 8px;
                               box-shadow: -4px 0 0 rgb(var(--tc, var(--cr-p1)) / .62), -8px 0 0 rgb(var(--tc, var(--cr-p1)) / .34); }
.ax-care__g--hand { position: relative; }
.ax-care__g--hand::before    { inline-size: 2px; block-size: 13px; border-radius: 1px; margin-block-start: 5px;
                               background: linear-gradient(to top, rgb(var(--ax-white-rgb) / .12), rgb(var(--ax-white-rgb) / .9)); }
/* the bead, as on the floor's own hand */
.ax-care__g--hand::after     { content: ""; position: absolute; left: 50%; top: 50%; inline-size: 5px; block-size: 5px;
                               margin: -7px 0 0 -2.5px; border-radius: 50%; background: rgb(var(--ax-white-rgb));
                               box-shadow: 0 0 6px 1px rgb(var(--cr-p1) / .7); }
.ax-care__g--dot::before     { inline-size: 7px; block-size: 7px; border-radius: 50%; background: currentColor; box-shadow: 0 0 8px -1px currentColor; }
.ax-care__g--ring::before    { inline-size: 12px; block-size: 12px; border-radius: 50%; border: 1.5px solid currentColor; }
.ax-care__g--diamond::before { inline-size: 7px; block-size: 7px; border-radius: 1px; transform: rotate(45deg);
                               background: color-mix(in oklab, currentColor 70%, rgb(var(--ax-white-rgb))); }
.ax-care__g--frame::before   { inline-size: 11px; block-size: 11px; border-radius: 1.5px; transform: rotate(45deg);
                               border: 1.5px solid color-mix(in oklab, currentColor 70%, rgb(var(--ax-white-rgb))); }
.ax-care__g--arc::before     { inline-size: 14px; block-size: 14px; border-radius: 50%; transform: rotate(45deg);
                               border: 2px solid transparent; border-block-start-color: currentColor; }

.ax-care__note {
  grid-column: 1;
  grid-row: 4;
  align-self: end;
  margin: 0 0 var(--ax-sp-7);
  max-inline-size: 42ch;
  font-size: var(--ax-fs-xs);
  line-height: var(--ax-lh-body);
  color: var(--ax-text-subtle);
}
.ax-care__note .ax-care__g {
  color: rgb(var(--ax-accent-text-rgb));
  inline-size: 16px;
  block-size: 1em;
  margin-inline-end: var(--ax-sp-3);
  vertical-align: -.1em;
}

/* ── the floor: the year ──────────────────────────────────────────────── */

/* Every position below is a share of the floor's own width, so one number
   sizes the whole year from a phone to a 2560 screen: day d of 365 is at
   d / 365 of the floor, month k at k / 12. */
.ax-care__year {
  grid-column: 1 / -1;
  grid-row: 5;
  position: relative;
  block-size: var(--cr-year-h);
  display: grid;
  grid-template-rows: 18px 40px 26px 26px;
  align-content: end;
}

.ax-care__mark {
  position: absolute;
  z-index: 4;
  top: 0;
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  line-height: 18px;
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ax-text-subtle);
}
.ax-care__mark--live { left: 0; color: var(--ax-text-body); }
.ax-care__mark--half { left: 50%; transform: translateX(-50%); }
.ax-care__mark--end  { right: 0; }

.ax-care__floor {
  grid-row: 2;
  position: relative;
  overflow: clip;
}

.ax-care__face {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  overflow: visible;
}
.ax-care__face path,
.ax-care__face line { fill: none; }

/* 365 ticks from one line: pathLength makes a dash exactly one day long */
.ax-care__days {
  stroke: rgb(var(--ax-white-rgb) / .15);
  stroke-width: 10;
  stroke-dasharray: .4 .6;
}
/* twelve longer ticks, centred on each month's end */
.ax-care__months {
  stroke: rgb(var(--ax-white-rgb) / .42);
  stroke-width: 18;
  stroke-dasharray: .012 .988;
  stroke-dashoffset: .006;
}
/* ninety days of warranty from the moment it goes live -- to scale, so the
   arch spans 90 of the floor's 365 days, not a round quarter */
.ax-care__warranty {
  stroke: rgb(var(--ax-accent-text-rgb) / .78);
  stroke-width: 2;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* ── the lanes: Active and Partner ────────────────────────────────────── */

.ax-care__layer {
  position: relative;
  z-index: 1;
  transition: opacity .5s var(--ax-ease-out);
}
.ax-care__layer--2 { grid-row: 3; --pc: var(--cr-p2); }
.ax-care__layer--3 { grid-row: 4; --pc: var(--cr-p3); }

.ax-care__ring {
  position: absolute;
  inset-inline: 0;
  top: 50%;
  block-size: 1px;
  background: rgb(var(--pc) / .40);
}

/* A mark k months in, on its own lane. */
.ax-care__node {
  position: absolute;
  left: calc(var(--k) / 12 * 100%);
  top: 50%;
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  color: rgb(var(--pc));
  background: currentColor;
  box-shadow: 0 0 10px -1px currentColor;
  transform: translate(-50%, -50%);
}
/* a UI review: the month's report, ringed */
.ax-care__node--review {
  inline-size: 17px;
  block-size: 17px;
  background: transparent;
  border: 1.5px solid currentColor;
  box-shadow: 0 0 10px -3px currentColor;
}
/* Partner's quarter: a roadmap session */
.ax-care__node--roadmap {
  inline-size: 9px;
  block-size: 9px;
  border-radius: 1.5px;
  background: color-mix(in oklab, currentColor 70%, rgb(var(--ax-white-rgb)));
  box-shadow: 0 0 12px 0 currentColor;
  transform: translate(-50%, -50%) rotate(45deg);
}
/* and once a year, around the fourth: the UI refresh */
.ax-care__node--refresh {
  inline-size: 21px;
  block-size: 21px;
  border-radius: 2px;
  background: transparent;
  border: 1.5px solid color-mix(in oklab, currentColor 70%, rgb(var(--ax-white-rgb)));
  box-shadow: 0 0 12px -3px currentColor;
  transform: translate(-50%, -50%) rotate(45deg);
}
/* THE PING. A ring leaves the mark when the hand reaches it. Its delay is the
   mark's own month on the shared clock, so the ping lands under the hand on
   every run without anything being scheduled. */
.ax-care__node::after {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: inherit;
  border: 1px solid currentColor;
  opacity: 0;
}
.ax-care.is-armed .ax-care__node::after {
  animation: ax-care-ping var(--cr-year) linear infinite;
  animation-delay: calc(var(--k) * var(--cr-year) / 12);
}
@keyframes ax-care-ping {
  0%   { opacity: .95; transform: scale(1); }
  5%   { opacity: 0;   transform: scale(2.8); }
  100% { opacity: 0;   transform: scale(2.8); }
}

/* the ghosts: what the next plan up would add */
.ax-care.is-armed[data-ax-plan="1"] .ax-care__layer--2,
.ax-care.is-armed[data-ax-plan="1"] .ax-care__layer--3,
.ax-care.is-armed[data-ax-plan="2"] .ax-care__layer--3 { opacity: .2; }

/* ── the backups and the hand ─────────────────────────────────────────── */

/* THE BACKUPS STEP BY THE DAY, THE HAND GLIDES. A backup is taken once a
   day, so the seven of them move along in whole days (steps(365)); the
   monitor never stops looking, so the hand sweeps. Both run the width of the
   floor: a layer as wide as the floor, moved by its own width. At rest both
   are parked on day 137, the still picture with scripting off or motion
   reduced. */
.ax-care__trail {
  position: absolute;
  inset: 0;
  z-index: 2;
  transform: translateX(calc(136 / 365 * 100%));
}
.ax-care__bk {
  position: absolute;
  top: 22px;
  left: calc((var(--d) * -1 + .1) / 365 * 100%);
  inline-size: 2px;
  block-size: 12px;
  border-radius: 1px;
  background: rgb(var(--cr-p1));
  box-shadow: 0 0 8px rgb(var(--cr-p1) / .8);
  opacity: calc(1 - var(--d) * .113);
}
.ax-care.is-armed .ax-care__trail {
  animation: ax-care-walk var(--cr-year) steps(365, end) infinite;
}
@keyframes ax-care-walk { from { transform: translateX(0); } to { transform: translateX(100%); } }

.ax-care__hand {
  position: absolute;
  z-index: 3;
  left: 0;
  top: 18px;
  bottom: 0;
  inline-size: 100%;
  pointer-events: none;
  transform: translateX(calc(136.5 / 365 * 100%));
}
.ax-care__hand::before {
  content: "";
  position: absolute;
  left: -1px;
  top: 0;
  bottom: 4px;
  inline-size: 2px;
  border-radius: 1px;
  background: linear-gradient(to bottom,
              rgb(var(--ax-white-rgb) / .92) 0%,
              rgb(var(--ax-white-rgb) / .35) 42%,
              rgb(var(--ax-white-rgb) / 0) 100%);
}
.ax-care.is-armed .ax-care__hand {
  animation: ax-care-sweep var(--cr-year) linear infinite;
}
@keyframes ax-care-sweep { from { transform: translateX(0); } to { transform: translateX(100%); } }

/* the bead where the hand meets the floor; it answers the track's band */
.ax-care__hand::after {
  content: "";
  position: absolute;
  left: -4px;
  top: 24px;
  inline-size: 8px;
  block-size: 8px;
  border-radius: 50%;
  background: rgb(var(--ax-white-rgb));
  box-shadow: 0 0 14px 2px rgb(var(--cr-p1) / .8);
  opacity: .85;
}
.ax-care.is-live.is-in .ax-care__hand::after {
  opacity: calc(.45 + var(--ax-sig-st, 0) * .55);
  transition: opacity .09s linear;
}

/* one clock, paused as one */
.ax-care.is-armed:not([data-ax-run="1"]) .ax-care__hand,
.ax-care.is-armed:not([data-ax-run="1"]) .ax-care__trail,
.ax-care.is-armed:not([data-ax-run="1"]) .ax-care__node::after { animation-play-state: paused; }

/* ── short screens ────────────────────────────────────────────────────── */

@media (min-width: 1100px) and (max-height: 820px) {
  .ax-care { --cr-year-h: 100px; }
  .ax-care__year { grid-template-rows: 16px 40px 22px 22px; }
  .ax-care__head { row-gap: var(--ax-sp-3); }
  .ax-care__line { font-size: var(--ax-fs-d4, var(--ax-fs-2xl)); }
  .ax-care__sub { font-size: var(--ax-fs-sm); }
  .ax-care__pick { margin-block-start: var(--ax-sp-7); }
  .ax-care__hub { margin-block-start: var(--ax-sp-5); }
  .ax-care__tier { padding-block: var(--ax-sp-4); row-gap: var(--ax-sp-2); }
  .ax-care__tier::before { inset-block: var(--ax-sp-4); }
  .ax-care__items { row-gap: 0; }
  .ax-care__items li { font-size: var(--ax-fs-xs); }
}

/* ── narrow ───────────────────────────────────────────────────────────── */

@media (max-width: 1099px) {
  .ax-care { min-block-size: auto; padding-block: var(--ax-sp-10) var(--ax-sp-11); }
  .ax-care__stage {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    row-gap: var(--ax-sp-8);
  }
  .ax-care__head,
  .ax-care__pick,
  .ax-care__hub,
  .ax-care__machine,
  .ax-care__tiers,
  .ax-care__year,
  .ax-care__note { grid-column: 1; grid-row: auto; }
  /* the machine stands on the floor here too: the year comes straight
     under it, then the plans it is the legend of */
  .ax-care__machine { order: 1; }
  .ax-care__year    { order: 2; }
  .ax-care__tiers   { order: 3; }
  .ax-care__note    { order: 4; }
  .ax-care__line { max-inline-size: none; }
  .ax-care__pick { margin-block-start: 0; justify-items: stretch; }
  .ax-care__pick .ax-seg { display: flex; }
  .ax-care__pick .ax-seg button { flex: 1 1 0; }
  .ax-care__hub { margin-block-start: 0; }
  .ax-care__machine {
    inline-size: min(100%, 460px);
    align-self: auto;
    margin-block: var(--ax-sp-4) calc(var(--ax-sp-8) * -1 + 4px);
  }
  .ax-care__tiers { max-inline-size: none; align-self: auto; }
  .ax-care__note { align-self: auto; margin: 0; max-inline-size: 64ch; }
}

@media (max-width: 479px) {
  .ax-care__tier { padding-inline-start: var(--ax-sp-6); }
  .ax-care__mark { letter-spacing: .08em; }
}

/* ── still ────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  /* Nothing moves and nothing pings. The hand and the backups rest on day
     137 with every mark in place: the whole year readable as one picture. */
  .ax-care.is-armed .ax-care__hand,
  .ax-care.is-armed .ax-care__trail,
  .ax-care.is-armed .ax-care__node::after { animation: none !important; }
  .ax-care__layer,
  .ax-care__hub,
  .ax-care__tier::before,
  .ax-care__tname,
  .ax-care__tprice b,
  .ax-care__items li,
  .ax-care__g { transition: none !important; }
}

@media print, (forced-colors: active) {
  /* The machine and the floor are pictures of the list, and the picker only
     changes emphasis that neither medium can show; what is left is every
     plan, in full. */
  .ax-care__dark, .ax-care__scene, .ax-care__machine, .ax-care__year, .ax-care__pick { display: none !important; }
  .ax-care__stage { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .ax-care__head, .ax-care__hub, .ax-care__tiers, .ax-care__note { grid-column: 1; grid-row: auto; }
  .ax-care__tier[data-ax-on="0"]::before,
  .ax-care__tier[data-ax-on="0"] .ax-care__g { opacity: 1; }
  .ax-care__tier[data-ax-on="0"] .ax-care__tname,
  .ax-care__tier[data-ax-on="0"] .ax-care__tprice b { color: var(--ax-text-strong); }
  .ax-care__tier[data-ax-on="0"] .ax-care__items li { color: var(--ax-text-body); }
}

/* ===========================================================================
   20c · THE MONTH AFTER — section 3's brief (round 119)
   ---------------------------------------------------------------------------
   The range is the build alone. Under it now stands what keeping it running
   costs once it is live -- the care plan, Azure, the paid services the
   software uses and the domain -- which Arxeon bills every month. The server's
   price engine works it out (EstimateBook.MonthlyFor); arxeon.open.js only
   draws it, and keeps it hidden until an answer brings a month.

   ONE BEAM THROUGH A PRISM. The month is a single line of light split into
   the four colours of the section dividers, --ax-div-1 to --ax-div-4, each
   as wide as its share: care, which is Arxeon's own work, in the cyan and a
   hair apart from what the providers charge, in the azure, the lavender and
   the violet. Light runs through the glass left to right, colour after
   colour, and each colour glows its own hue onto the dark. The parts are
   named under it in the type of the drivers' caption, each by its colour.

   Every selector here is new: nothing above this line was changed for it.
   ======================================================================== */

.ax-open__pmonth {
  display: grid;
  row-gap: var(--ax-sp-4);
  padding-block-start: var(--ax-sp-4);
  border-block-start: 1px solid transparent;
  border-image: linear-gradient(to right, var(--ax-line-strong), rgb(var(--ax-white-rgb) / 0)) 1;
}
.ax-open__pmonth[hidden] { display: none; }

.ax-open__pmhead {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  column-gap: var(--ax-sp-5);
  row-gap: var(--ax-sp-1);
}
.ax-open__pmk {
  font-family: var(--ax-font-mono);
  font-size: var(--ax-fs-3xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
.ax-open__pmv {
  font-size: var(--ax-fs-lg);
  line-height: var(--ax-lh-head);
  letter-spacing: -.01em;
  color: var(--ax-text-strong);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ax-open__pmv small {
  font-size: var(--ax-fs-2xs);
  letter-spacing: 0;
  color: var(--ax-text-muted);
}

/* the prism: the ruler's hairline, with the beam lying on it */
.ax-open__prism {
  position: relative;
  display: flex;
  align-items: center;
  gap: 2px;
  block-size: 8px;
}
.ax-open__prism::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-start: calc(50% - .5px);
  block-size: 1px;
  background: var(--ax-line);
}
.ax-open__pmseg {
  --c: var(--ax-div-1);
  position: relative;
  flex: var(--w, 0) 1 0%;
  min-inline-size: 4px;
  block-size: 4px;
  border-radius: 1px;
  overflow: hidden;
  background: var(--c);
  box-shadow: 0 0 10px 0 var(--c);
  box-shadow: 0 0 10px 0 color-mix(in srgb, var(--c) 55%, transparent);
  transition: flex-grow .65s var(--ax-ease-out);
}
.ax-open__pmseg[hidden] { display: none; }
.ax-open__pmseg[data-part="care"]     { --c: var(--ax-div-1); margin-inline-end: 3px; }
.ax-open__pmseg[data-part="azure"]    { --c: var(--ax-div-2); }
.ax-open__pmseg[data-part="services"] { --c: var(--ax-div-3); }
.ax-open__pmseg[data-part="domain"]   { --c: var(--ax-div-4); }

/* the light running through the glass, colour after colour */
.ax-open__pmseg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgb(var(--ax-white-rgb) / 0), rgb(var(--ax-white-rgb) / .8) 50%, rgb(var(--ax-white-rgb) / 0));
  translate: -100% 0;
  animation: ax-open-refract 7s var(--ax-ease-in-out) infinite;
}
.ax-open__pmseg[data-part="azure"]::after    { animation-delay: .3s; }
.ax-open__pmseg[data-part="services"]::after { animation-delay: .6s; }
.ax-open__pmseg[data-part="domain"]::after   { animation-delay: .9s; }
@keyframes ax-open-refract {
  0%   { translate: -100% 0; }
  16%  { translate: 100% 0; }
  100% { translate: 100% 0; }
}

/* the parts, named by their colours */
.ax-open__pmparts {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--ax-sp-5);
  row-gap: var(--ax-sp-2);
  font-size: var(--ax-fs-2xs);
  line-height: var(--ax-lh-micro);
  color: var(--ax-text-muted);
  font-variant-numeric: tabular-nums;
}
.ax-open__pmpart {
  display: inline-flex;
  align-items: center;
  gap: .45em;
  white-space: nowrap;
}
.ax-open__pmpart i {
  --c: var(--ax-div-1);
  flex: 0 0 auto;
  inline-size: 10px;
  block-size: 2px;
  border-radius: 1px;
  background: var(--c);
  box-shadow: 0 0 6px 0 var(--c);
  box-shadow: 0 0 6px 0 color-mix(in srgb, var(--c) 60%, transparent);
}
.ax-open__pmpart[data-part="azure"] i    { --c: var(--ax-div-2); }
.ax-open__pmpart[data-part="services"] i { --c: var(--ax-div-3); }
.ax-open__pmpart[data-part="domain"] i   { --c: var(--ax-div-4); }
.ax-open__pmpart b { font-weight: 600; color: var(--ax-text-body); }

@media (prefers-reduced-motion: reduce) {
  /* the beam holds still: the colours and their widths say it all */
  .ax-open__pmseg { transition: none; }
  .ax-open__pmseg::after { animation: none; display: none; }
}
@media print {
  .ax-open__pmseg { box-shadow: none; }
  .ax-open__pmseg::after { display: none; }
}
@media (forced-colors: active) {
  /* colour is not there to carry it: the beam keeps its widths, and the
     parts their words */
  .ax-open__pmseg { background: CanvasText; box-shadow: none; }
  .ax-open__pmseg::after { display: none; }
  .ax-open__pmpart i { background: CanvasText; box-shadow: none; }
}

/* ===========================================================================
   20c · THE SLATE — section 3's face (28 October 2026)
   ---------------------------------------------------------------------------
   A black glass slate in a studio of its own (drawn live by
   Scripts/arxeon.slate-studio.js, 29 October 2026), the brief printed on its
   glass as the channel works it out. Three pictures in one frame
   (Media/slate): a still of that studio, the seams' glow (it breathes and
   flares with the state) and the glass's own reflection, laid OVER the
   screen so the type sits under the glass and not on it.
   Scripts/arxeon.slate.js fits the frame to the face's box and lays the
   screen on the glass in perspective. With no script the pictures stand on
   their own, the glass dark.
   =========================================================================== */

.ax-open__face--slate {
  overflow: clip;
}
.ax-slate {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
/* in the channel the box crops the frame: its own edges fade too */
.ax-open.is-open .ax-slate {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 12%, #000 88%, transparent),
                      linear-gradient(to bottom, transparent, #000 5%, #000 95%, transparent);
  -webkit-mask-composite: source-in;
          mask-image: linear-gradient(to right, transparent, #000 12%, #000 88%, transparent),
                      linear-gradient(to bottom, transparent, #000 5%, #000 95%, transparent);
          mask-composite: intersect;
}
/* the picture's black is true black and the section lifts to --ax-bg at the
   foot, so the picture's rectangle must never show: the frame's own edges
   fade, whatever the box crops (the mask is the frame's, so it moves with it) */
.ax-slate__frame {
  position: absolute;
  inset: 0;
  -webkit-mask-image: radial-gradient(50% 50% at 50% 54%, #000 34%, rgb(0 0 0 / .62) 66%, rgb(0 0 0 / .18) 86%, transparent 100%);
          mask-image: radial-gradient(50% 50% at 50% 54%, #000 34%, rgb(0 0 0 / .62) 66%, rgb(0 0 0 / .18) 86%, transparent 100%);
}
/* the face's own picture rules (inset, mask, top alignment, hidden under the
   presence's canvas) are the robot's; the slate's pictures fill the frame */
.ax-open .ax-open__face--slate .ax-slate picture,
.ax-open .ax-open__face--slate .ax-slate__frame > img {
  position: absolute;
  inset: 0;
  display: block;
  inline-size: 100%;
  block-size: 100%;
  visibility: visible;
  -webkit-mask-image: none;
          mask-image: none;
}
.ax-open .ax-open__face--slate .ax-slate img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  object-position: 50% 62%;
}
.ax-slate__glow,
.ax-slate__sheen {
  mix-blend-mode: screen;
}

/* ── the seams: they breathe at rest, quicken while it works, flare on the lock ── */
.ax-slate__glow { opacity: .42; }
.ax-slate.is-fit .ax-slate__glow { animation: ax-slate-breathe 5.6s var(--ax-ease-in-out) infinite; }
.ax-slate.is-thinking .ax-slate__glow { animation-duration: 1.15s; }
.ax-slate.is-hearing .ax-slate__glow,
.ax-slate.is-listening .ax-slate__glow { animation: none; opacity: .85; }
.ax-slate.is-closed .ax-slate__glow,
.ax-slate.is-sent .ax-slate__glow { animation: none; opacity: .9; }
.ax-slate.is-locking .ax-slate__glow { animation: ax-slate-flare 1.6s var(--ax-ease-out) both; }
@keyframes ax-slate-breathe { 0%, 100% { opacity: .30; } 50% { opacity: .70; } }
@keyframes ax-slate-flare { 0% { opacity: .5; } 18% { opacity: 1; filter: brightness(1.9); } 100% { opacity: .9; filter: none; } }

/* ── the studio (Scripts/arxeon.slate-studio.js): a live WebGL scene under the
   whole section, the wet floor, the fog in the beam and the slate itself.
   Once its first frame is drawn the section gets is-live-studio: the canvas
   fades in, the slate's own picture and glow step back (the scene draws
   them, so the fog can pass in front of its foot) and the frame's edge
   fades come off (no picture edge is left to hide). Without the script, or
   without WebGL2, none of this applies and the pictures stand as before. ── */
.ax-slate-studio {
  position: absolute;
  inset: 0;
  display: block;
  inline-size: 100%;
  block-size: 100%;
  opacity: 0;
  transition: opacity .9s var(--ax-ease-out);
}
.ax-open.is-live-studio .ax-slate-studio { opacity: 1; }
/* (0,4,0): over the frame's own picture rules, (0,3,1) */
.ax-open.is-live-studio .ax-slate .ax-slate__base { opacity: 0; transition: opacity .9s var(--ax-ease-out); }
.ax-open.is-live-studio .ax-slate .ax-slate__glow { display: none; }
.ax-open.is-live-studio .ax-slate__frame,
.ax-open.is-live-studio.is-open .ax-slate {
  -webkit-mask-image: none;
          mask-image: none;
}

/* ── the screen: a page of the glass's own proportions, set in perspective ── */
.ax-slate__screen {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  box-sizing: border-box;
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  row-gap: 1.05em;
  padding: 1.5em 1.3em calc(var(--cut-h, 19%) * .62) 1.3em;
  color: rgb(236 244 255 / .94);
  font-family: var(--ax-font-sans);
  font-size: 16px;
  line-height: 1.18;
  text-shadow: 0 0 .5em rgb(var(--ax-accent-text-rgb) / .38);
  opacity: 0;
  transition: opacity .9s var(--ax-ease-out);
}
.ax-slate.is-fit .ax-slate__screen { opacity: 1; }

.ax-slate__status {
  display: flex;
  align-items: center;
  gap: .55em;
  margin: 0;
  font-family: var(--ax-font-mono);
  font-size: .4em;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: rgb(var(--ax-accent-text-rgb) / .9);
  white-space: nowrap;
}
.ax-slate__chan { opacity: .62; }
.ax-slate__state::before { content: "\00b7"; margin-inline-end: .6em; opacity: .5; }
.ax-slate__dot {
  inline-size: .78em;
  block-size: .78em;
  flex: none;
  border-radius: 50%;
  background: rgb(var(--ax-accent-text-rgb));
  box-shadow: 0 0 .9em .1em rgb(var(--ax-accent-text-rgb) / .75);
  opacity: .5;
}
.ax-slate.is-fit .ax-slate__dot { animation: ax-slate-dot 3.2s var(--ax-ease-in-out) infinite; }
.ax-slate.is-open .ax-slate__dot,
.ax-slate.is-hearing .ax-slate__dot,
.ax-slate.is-listening .ax-slate__dot { animation: none; opacity: 1; }
.ax-slate.is-thinking .ax-slate__dot { animation-duration: .9s; }
.ax-slate.is-closed .ax-slate__dot,
.ax-slate.is-sent .ax-slate__dot { animation: none; opacity: 1; background: #fff; }
@keyframes ax-slate-dot { 0%, 100% { opacity: .28; } 50% { opacity: 1; } }

.ax-slate__field { display: grid; row-gap: .32em; min-inline-size: 0; }
.ax-slate__k {
  font-family: var(--ax-font-mono);
  font-size: .36em;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: rgb(var(--ax-accent-text-rgb) / .72);
  text-shadow: none;
}
.ax-slate__v {
  font-weight: 600;
  letter-spacing: -.012em;
  overflow-wrap: anywhere;
}
.ax-slate__project {
  font-size: 1.06em;
  line-height: 1.12;
  text-wrap: balance;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ax-slate__what {
  font-size: .5em;
  line-height: 1.35;
  color: rgb(236 244 255 / .62);
  text-shadow: none;
}
.ax-slate__what:empty { display: none; }
/* before a pick the brief is empty: its labels show, faintly, as a form */
.ax-slate:not(.is-channel) .ax-slate__v { color: rgb(236 244 255 / .2); text-shadow: none; }
.ax-slate.is-ready .ax-slate__project { color: rgb(236 244 255 / .78); text-shadow: 0 0 .5em rgb(var(--ax-accent-text-rgb) / .3); }

.ax-slate__scope {
  align-self: start;
  display: grid;
  row-gap: .5em;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: .54em;
  line-height: 1.3;
  color: rgb(236 244 255 / .84);
  text-shadow: none;
  overflow: hidden;
}
.ax-slate__scope li {
  position: relative;
  padding-inline-start: 1.1em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ax-slate__scope li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: .55em;
  inline-size: .45em;
  block-size: 1px;
  background: rgb(var(--ax-accent-text-rgb) / .9);
}

/* the figures stand on the foot of the glass, right of the cut corner */
.ax-slate__figs {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  row-gap: .8em;
  padding-block-start: .9em;
  border-block-start: 1px solid rgb(var(--ax-accent-text-rgb) / .28);
}
.ax-slate__figs .ax-slate__v { font-size: .84em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ax-slate.is-closed .ax-slate__figs .ax-slate__v,
.ax-slate.is-sent .ax-slate__figs .ax-slate__v {
  color: #fff;
  text-shadow: 0 0 .45em rgb(var(--ax-accent-text-rgb) / .9), 0 0 1.4em rgb(var(--ax-accent-text-rgb) / .45);
}

/* printed in light: a value that changes comes up out of the glass */
.ax-slate__v.is-new,
.ax-slate__scope li.is-new { animation: ax-slate-print .9s var(--ax-ease-out) both; }
@keyframes ax-slate-print {
  from { opacity: 0; filter: blur(.25em); letter-spacing: .06em; }
  60%  { opacity: 1; filter: blur(0); }
  to   { opacity: 1; filter: none; }
}

/* working it out: one line of light down the glass */
.ax-slate__scan {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 0;
  block-size: 18%;
  background: linear-gradient(to bottom, transparent, rgb(var(--ax-accent-text-rgb) / .1) 70%, rgb(var(--ax-accent-text-rgb) / .38) 98%, transparent);
  opacity: 0;
  pointer-events: none;
}
.ax-slate.is-thinking .ax-slate__scan { animation: ax-slate-scan 1.5s cubic-bezier(.45, 0, .55, 1) infinite; }
@keyframes ax-slate-scan {
  0%   { opacity: 0; transform: translateY(-100%); }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(560%); }
}

/* the lock: four corners close on the glass, as section 2's lock on its object */
.ax-slate__seal { position: absolute; inset: .42em; pointer-events: none; }
.ax-slate__seal i {
  position: absolute;
  inline-size: 1.1em;
  block-size: 1.1em;
  border: 0 solid rgb(var(--ax-accent-text-rgb) / .95);
  opacity: 0;
  transition: opacity .6s var(--ax-ease-out), translate .8s var(--ax-ease-out);
}
.ax-slate__seal i:nth-child(1) { inset-block-start: 0; inset-inline-start: 0; border-block-start-width: 2px; border-inline-start-width: 2px; translate: -.6em -.6em; }
.ax-slate__seal i:nth-child(2) { inset-block-start: 0; inset-inline-end: 0; border-block-start-width: 2px; border-inline-end-width: 2px; translate: .6em -.6em; }
.ax-slate__seal i:nth-child(3) { inset-block-end: 0; inset-inline-end: 0; border-block-end-width: 2px; border-inline-end-width: 2px; translate: .6em .6em; }
.ax-slate__seal i:nth-child(4) { inset-block-end: 0; inset-inline-start: var(--cut-w, 22%); border-block-end-width: 2px; border-inline-start-width: 2px; translate: -.6em .6em; }
.ax-slate.is-closed .ax-slate__seal i,
.ax-slate.is-sent .ax-slate__seal i { opacity: 1; translate: 0 0; }

/* small on screen (a phone at rest): the status and the project */
.ax-slate.is-small .ax-slate__scope,
.ax-slate.is-small .ax-slate__figs,
.ax-slate.is-small .ax-slate__what { display: none; }
/* tinier still (the phone's strip over the chat): the glass stays dark */
.ax-slate.is-tiny .ax-slate__screen { visibility: hidden; }

/* ── the narrow layout: the face's box takes the picture's proportions ── */
@media (max-width: 1099px) {
  .ax-open__face.ax-open__face--slate { aspect-ratio: 1008 / 1412; inline-size: min(84%, 440px); }
  .ax-open.is-open .ax-open__face.ax-open__face--slate { aspect-ratio: auto; inline-size: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .ax-slate__glow,
  .ax-slate__dot,
  .ax-slate__scan,
  .ax-slate__v.is-new,
  .ax-slate__scope li.is-new { animation: none !important; }
  .ax-slate__glow { opacity: .55; }
  .ax-slate__seal i { transition: none; }
  .ax-slate__screen { transition: none; }
}
@media print, (forced-colors: active) {
  .ax-slate__screen, .ax-slate__glow, .ax-slate__sheen, .ax-slate-studio { display: none; }
  .ax-open.is-live-studio .ax-slate .ax-slate__base { opacity: 1; }
}
