/* ==========================================================================
   ai-hub.css — /ai/ and /ai/sample/
   ==========================================================================
   A futuristic treatment built entirely from CSS transforms, gradients and
   masks. No WebGL, no Three.js, no tilt library.

   THE FOUR THINGS THAT MAKE IT READ AS "FUTURE"
   ---------------------------------------------
   1. DEPTH THAT RESPONDS. Real perspective with panels at genuinely different
      Z, and a stage that yaws to the pointer. Depth you can move is what
      separates 3D from a drop shadow.
   2. LIGHT THAT IS NOT WHITE. Every surface is lit by its own hue, carried in
      --h and set once per panel, so seven services are seven colours of glass
      rather than seven grey cards.
   3. HARDWARE ARTEFACTS. Scanlines, a noise plate, corner brackets, a sweeping
      scan bar. Cheap to draw, and they are what the eye reads as "a display"
      rather than "a web page".
   4. RESTRAINT AT THE TEXT. The chrome is loud; the type is not. Copy sits on
      near-solid panels because a holographic paragraph is an unreadable one.

   TRANSFORM DISCIPLINE
   --------------------
   Nothing in this file is animated by writing `transform` from JavaScript.
   Every moving element composes custom properties — --px/--py for parallax,
   --rx/--ry for pointer yaw — inside a single `transform` declared here. GSAP's
   reveals write `transform` on their own targets, and the two would overwrite
   each other silently. This codebase has already paid for that lesson twice.
   ========================================================================== */

.page-aix {
  --aix-ink:   #05060a;
  --aix-line:  rgb(140 190 255 / .16);
  --aix-glass: rgb(14 18 30 / .72);
  --aix-cyan:  190;
  color-scheme: dark;
}
.page-aix .container { position: relative; z-index: 1; }

/* The page owns its own ground colour: the futuristic palette only works
   against something close to black, and the site's --surface-0 is a warm grey
   that turns every cyan glow muddy. */
body.page-aix { background: var(--aix-ink); }

/* ── THE ATMOSPHERE ─────────────────────────────────────────────────────────
   Five fixed layers. Fixed rather than absolute so each costs exactly one
   transform write per frame no matter how long the page grows. */
.aixSky { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.aixSky > * { position: absolute; inset: -25% -10%; will-change: transform; }
.aixSky__aurora,
.aixSky__floor,
.aixSky__stars { transform: translate3d(0, var(--py, 0px), 0); }

/* Aurora — four drifting wells of colour. The animation moves the gradient
   positions, not the element, so it never fights the parallax transform. */
.aixSky__aurora {
  background:
    radial-gradient(42% 38% at 14% 18%, hsl(265 85% 55% / .28), transparent 66%),
    radial-gradient(38% 34% at 84% 12%, hsl(190 90% 50% / .24), transparent 64%),
    radial-gradient(46% 42% at 70% 78%, hsl(320 80% 55% / .20), transparent 68%),
    radial-gradient(40% 40% at 26% 86%, hsl(210 90% 55% / .18), transparent 66%);
  filter: blur(60px);
  animation: aixDrift 24s ease-in-out infinite alternate;
}
@keyframes aixDrift {
  to {
    background-position: 6% -4%, -5% 5%, -4% -6%, 5% 4%;
    filter: blur(76px);
  }
}

/* The floor. A perspective-warped grid receding to a horizon, masked out
   before it reaches the top so there is no hard edge. */
.aixSky__floor {
  inset: 46% -60% -34% -60%;
  background-image:
    linear-gradient(hsl(190 90% 60% / .16) 1px, transparent 1px),
    linear-gradient(90deg, hsl(190 90% 60% / .16) 1px, transparent 1px);
  background-size: 72px 72px;
  transform: translate3d(0, var(--py, 0px), 0) perspective(300px) rotateX(62deg);
  transform-origin: 50% 0;
  mask-image: linear-gradient(to bottom, black, transparent 66%);
}
.aixSky__stars {
  background-image:
    radial-gradient(1.7px 1.7px at 12% 22%, rgb(255 255 255 / .55), transparent),
    radial-gradient(1.5px 1.5px at 68% 14%, hsl(190 90% 75% / .6), transparent),
    radial-gradient(2.1px 2.1px at 42% 72%, hsl(320 85% 78% / .5), transparent),
    radial-gradient(1.5px 1.5px at 88% 58%, rgb(255 255 255 / .4), transparent),
    radial-gradient(1.7px 1.7px at 24% 54%, hsl(265 85% 80% / .5), transparent),
    radial-gradient(1.4px 1.4px at 78% 88%, rgb(255 255 255 / .35), transparent);
}
/* Scanlines and noise. Both are what make the whole thing read as a SCREEN;
   without them the gradients just look like a gradient. */
.aixSky__scan {
  inset: 0;
  background: repeating-linear-gradient(
    to bottom, rgb(255 255 255 / .028) 0 1px, transparent 1px 3px);
  mix-blend-mode: overlay;
}
.aixSky__noise {
  inset: 0; opacity: .045;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ── ICONS ──────────────────────────────────────────────────────────────────
   Masks, not images: they inherit the panel's hue, stay sharp at any size, and
   cannot be the asset that fails to load. */
.aixArt {
  display: block; width: 1.5rem; height: 1.5rem;
  background: currentColor;
  mask-repeat: no-repeat; mask-size: contain; mask-position: center;
}
.aixArt--wave   { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M3 12h2M8 6v12M13 3v18M18 8v8M22 11h-1'/%3E%3C/svg%3E"); }
.aixArt--call   { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7'%3E%3Crect x='2' y='5' width='14' height='14' rx='3'/%3E%3Cpath d='M16 10.5 22 7v10l-6-3.5z'/%3E%3C/svg%3E"); }
.aixArt--clone  { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7'%3E%3Ccircle cx='9' cy='8' r='3.4'/%3E%3Cpath d='M3 20a6 6 0 0 1 12 0'/%3E%3Cpath d='M15.5 5.2a3.4 3.4 0 0 1 0 5.6M18 20a6 6 0 0 0-2.2-4.6' stroke-dasharray='2.4 2'/%3E%3C/svg%3E"); }
.aixArt--cap    { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7'%3E%3Cpath d='M12 4 2 9l10 5 10-5-10-5z'/%3E%3Cpath d='M6 11.5V17c0 1.7 2.7 3 6 3s6-1.3 6-3v-5.5M22 9v6'/%3E%3C/svg%3E"); }
.aixArt--spark  { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7' stroke-linejoin='round'%3E%3Cpath d='M12 2.5 14 9l6.5 2-6.5 2-2 6.5-2-6.5L3.5 11 10 9z'/%3E%3Cpath d='M19 3v3M20.5 4.5h-3'/%3E%3C/svg%3E"); }
.aixArt--flow   { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7'%3E%3Crect x='2.5' y='3' width='6' height='5' rx='1.5'/%3E%3Crect x='15.5' y='3' width='6' height='5' rx='1.5'/%3E%3Crect x='9' y='16' width='6' height='5' rx='1.5'/%3E%3Cpath d='M5.5 8v3.5h13V8M12 11.5V16'/%3E%3C/svg%3E"); }
.aixArt--window { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7'%3E%3Crect x='2.5' y='4' width='19' height='16' rx='2.5'/%3E%3Cpath d='M2.5 9h19M5.6 6.5h.01M8.2 6.5h.01'/%3E%3C/svg%3E"); }

/* ── BUTTONS ────────────────────────────────────────────────────────────── */
.aixBtn {
  display: inline-flex; align-items: center; justify-content: center; gap: .7ch;
  padding: .85rem 1.5rem; border-radius: 999px; border: 1px solid transparent;
  font: inherit; font-size: var(--fs-sm); font-weight: 500;
  text-decoration: none; cursor: pointer; position: relative; overflow: hidden;
  transition: transform .3s cubic-bezier(.22,1,.36,1), box-shadow .35s, border-color .3s, background .3s;
}
.aixBtn--sm { padding: .55rem 1.05rem; }
.aixBtn--primary {
  background: linear-gradient(120deg, hsl(190 95% 52%), hsl(265 85% 62%));
  color: #04060c; font-weight: 600;
  box-shadow: 0 10px 34px -12px hsl(190 95% 52% / .8);
}
.aixBtn--primary:hover { transform: translateY(-2px); box-shadow: 0 16px 42px -12px hsl(190 95% 52% / .95); }
.aixBtn--ghost {
  border-color: var(--aix-line); color: var(--text-hi);
  background: rgb(255 255 255 / .04); backdrop-filter: blur(8px);
}
.aixBtn--ghost:hover { border-color: hsl(190 90% 60% / .6); transform: translateY(-2px); background: rgb(255 255 255 / .07); }
.aixBtn__play {
  width: 0; height: 0; flex: none;
  border-left: 8px solid hsl(190 95% 62%);
  border-top: 5px solid transparent; border-bottom: 5px solid transparent;
}

/* ── HERO ───────────────────────────────────────────────────────────────────
   Deliberately compact. The brief is that all seven services are visible the
   moment the page opens, and every pixel the hero copy takes is a pixel the
   console's second row loses — at the first sizing this hero was 371px tall
   and pushed row two entirely below the fold, which defeated the whole design.
   The copy is therefore sized to fit, not to fill. */
.aixHero { position: relative; z-index: 1; padding-block: clamp(var(--s-4), 1.8vw, var(--s-6)) clamp(var(--s-10), 6vw, var(--s-20)); }
/* The sample banner is temporary furniture, but while it is here it is eating
   the console's bottom row. */
.page-aix .sample-flag { margin-bottom: var(--s-2); }
/* Copy left, Yuna right. The right half was empty on a page whose headline
   product is a face that talks — an argument made in words and then not
   shown. Her column is sized to the copy's own height rather than to the
   portrait's natural ratio, because anything taller pushes the console's
   second row below the fold and the whole "all seven at once" premise with it. */
.aixHero__top {
  display: grid; align-items: center;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(var(--s-6), 4vw, var(--s-12));
}
.aixHero__copy { max-width: 44rem; }
.aixHero__eyebrow {
  display: inline-flex; align-items: center; gap: .7ch; margin: 0 0 var(--s-3);
  font-family: var(--font-mono); font-size: .64rem; color: hsl(190 80% 72%);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
}
.aixHero__pulse {
  width: .5rem; height: .5rem; border-radius: 50%; background: hsl(150 80% 55%);
  box-shadow: 0 0 0 0 hsl(150 80% 55% / .6); animation: aixPulse 2.4s ease-out infinite;
}
@keyframes aixPulse { 70%, 100% { box-shadow: 0 0 0 .7rem hsl(150 80% 55% / 0); } }

.aixHero__h1 {
  margin: 0 0 var(--s-4);
  font-size: clamp(2rem, 1.05rem + 3vw, 3.15rem);
  line-height: 1.05; letter-spacing: -.035em; color: #fff;
}
/* The decoding line. JS scrambles it into place on load; the gradient and the
   chromatic ghost behind it are what make it read as a readout rather than as
   a heading that happens to animate. */
.aixHero__decode {
  position: relative; display: inline-block;
  background: linear-gradient(100deg, hsl(190 95% 62%), hsl(265 90% 72%) 45%, hsl(320 85% 70%));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.aixHero__decode::after {
  content: attr(data-ghost); position: absolute; inset: 0;
  color: hsl(320 90% 60% / .32); transform: translate(2px, -1px);
  z-index: -1; pointer-events: none;
}
.aixHero__sub { margin: 0; max-width: 58ch; color: var(--text-mid); font-size: var(--fs-body); line-height: 1.55; }
.aixHero__cta { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-5); }

/* ── YUNA, THE GUIDE ────────────────────────────────────────────────────────
   A button, not a decorated <div>: it starts the walkthrough, so it has to be
   reachable by keyboard and announce itself. The speech bubble is part of the
   affordance rather than flavour — a portrait with a play triangle on it could
   mean "watch a showreel", and this needs to say what pressing it does. */
.aixGuide {
  position: relative; display: block; padding: 0; border: 0; background: none;
  cursor: pointer; font: inherit; text-align: left;
  width: clamp(11rem, 17vw, 15rem);
}
.aixGuide__plate {
  position: relative; display: block; overflow: hidden;
  aspect-ratio: 4 / 5; border-radius: 16px;
  border: 1px solid hsl(190 90% 62% / .4);
  background: rgb(8 12 22 / .6);
  box-shadow: 0 26px 60px -26px #000;
  transition: transform .5s cubic-bezier(.22,1,.36,1), border-color .35s, box-shadow .4s;
}
.aixGuide:hover .aixGuide__plate,
.aixGuide:focus-visible .aixGuide__plate {
  transform: translateY(-4px);
  border-color: hsl(190 95% 68% / .95);
  box-shadow: 0 0 0 1px hsl(190 95% 62% / .35), 0 34px 74px -24px hsl(190 90% 40% / .8);
}
.aixGuide:focus-visible { outline: 2px solid hsl(190 95% 65%); outline-offset: 6px; border-radius: 18px; }
.aixGuide__plate img {
  display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 12%;
  filter: saturate(.95) brightness(.92);
  transition: transform 1s cubic-bezier(.22,1,.36,1), filter .5s;
}
.aixGuide:hover .aixGuide__plate img { transform: scale(1.05); filter: saturate(1.05) brightness(1); }
.aixGuide__scan {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(to bottom, hsl(190 95% 70% / .07) 0 1px, transparent 1px 4px);
}
.aixGuide__halo {
  position: absolute; inset: auto -20% -30%; height: 60%;
  background: radial-gradient(50% 100% at 50% 100%, hsl(190 90% 55% / .5), transparent 70%);
  filter: blur(24px); z-index: -1;
}
.aixGuide__live {
  position: absolute; left: .6rem; top: .6rem; z-index: 2;
  padding: .16rem .5rem .16rem 1.1rem; border-radius: 999px;
  background: rgb(4 6 12 / .82); border: 1px solid hsl(150 80% 55% / .5);
  background-image: radial-gradient(circle at .55rem 50%, hsl(150 85% 58%) 2.2px, transparent 2.4px);
  font-family: var(--font-mono); font-size: .5rem; letter-spacing: .16em; color: hsl(150 80% 70%);
}
/* Bottom-right, not centred. Centred it sat squarely on her mouth and chin —
   which on a card whose entire subject is a face is the one place it cannot
   go. In the corner it reads as a player control instead, and she stays
   looking at you. */
.aixGuide__play {
  position: absolute; right: .7rem; bottom: 3.6rem; z-index: 2;
  display: grid; place-items: center; width: 3rem; height: 3rem; border-radius: 50%;
  background: rgb(6 10 18 / .68); border: 1px solid hsl(190 95% 70% / .8);
  backdrop-filter: blur(6px);
  box-shadow: 0 0 0 0 hsl(190 95% 60% / .5);
  animation: aixRipple 2.8s ease-out infinite;
  transition: transform .35s cubic-bezier(.34,1.56,.64,1);
}
.aixGuide__play::after {
  content: ''; margin-left: 3px;
  border-left: 11px solid hsl(190 95% 75%);
  border-top: 7px solid transparent; border-bottom: 7px solid transparent;
}
.aixGuide:hover .aixGuide__play { transform: scale(1.1); }
@keyframes aixRipple { 70%, 100% { box-shadow: 0 0 0 1.3rem hsl(190 95% 60% / 0); } }
.aixGuide__foot {
  position: absolute; inset: auto 0 0; z-index: 2;
  display: grid; gap: 1px; padding: 1.6rem .8rem .7rem;
  background: linear-gradient(transparent, rgb(4 6 12 / .92) 55%);
}
.aixGuide__foot b { font-size: var(--fs-sm); color: #fff; }
.aixGuide__foot i {
  font-style: normal; font-family: var(--font-mono); font-size: .52rem;
  color: hsl(190 80% 72%); letter-spacing: .1em; text-transform: uppercase;
}
/* The bubble. Anchored to the plate's top-left and pointing at her. */
/* Clear of the plate entirely. Overlapping it by 18% put the bubble straight
   on top of the LIVE badge, so both were unreadable. */
.aixGuide__say {
  position: absolute; right: calc(100% + .7rem); top: .4rem; z-index: 3;
  width: max-content; max-width: 12rem;
  padding: .55rem .8rem; border-radius: 12px 12px 2px 12px;
  border: 1px solid hsl(190 90% 62% / .45);
  background: rgb(10 16 28 / .95); backdrop-filter: blur(8px);
  font-size: .78rem; line-height: 1.35; color: var(--text-hi);
  box-shadow: 0 14px 34px -16px #000;
  animation: aixSay 5.5s ease-in-out 1.2s infinite;
}
.aixGuide__say::after {
  content: ''; position: absolute; right: -5px; bottom: 8px;
  width: 9px; height: 9px; rotate: 45deg;
  background: rgb(10 16 28 / .95);
  border-right: 1px solid hsl(190 90% 62% / .45); border-bottom: 1px solid hsl(190 90% 62% / .45);
}
@keyframes aixSay { 0%, 88%, 100% { transform: translateY(0); } 94% { transform: translateY(-4px); } }

/* ── THE CONSOLE ────────────────────────────────────────────────────────────
   The centrepiece. Seven panels, 4 over 3, curved by each panel's signed
   distance from its row centre. The stage yaws to the pointer as one body, so
   the array feels like an object rather than seven independent hovers. */
.aixConsole {
  margin-top: clamp(var(--s-4), 2.2vw, var(--s-6));
  display: grid; gap: clamp(var(--s-3), 1.4vw, var(--s-4));
  perspective: 1500px; perspective-origin: 50% 42%;
  transform-style: preserve-3d;
  position: relative;
}
.aixConsole__row {
  display: grid; gap: clamp(var(--s-3), 1.4vw, var(--s-4));
  transform-style: preserve-3d;
  /* The pointer yaw. Written by JS as --rx/--ry, composed here so it can never
     clobber a panel's own curve transform. */
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform .6s cubic-bezier(.22,1,.36,1);
}
.aixConsole__row--1 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.aixConsole__row--2 { grid-template-columns: repeat(3, minmax(0, 1fr)); width: 76%; margin-inline: auto; }
/* A lit rail under the array — the console's "shelf". */
.aixConsole__rail {
  position: absolute; left: 8%; right: 8%; bottom: -1.6rem; height: 1px;
  background: linear-gradient(90deg, transparent, hsl(190 90% 60% / .55), hsl(265 85% 65% / .5), transparent);
  filter: blur(.5px);
}
.aixConsole__rail::after {
  content: ''; position: absolute; inset: -1.4rem 0 auto;
  height: 3rem;
  background: radial-gradient(60% 100% at 50% 0, hsl(190 90% 55% / .16), transparent 70%);
}

.aixPanel {
  position: relative; display: grid; align-content: start; gap: .35rem;
  padding: var(--s-3) var(--s-4) var(--s-4);
  border-radius: 14px; border: 1px solid var(--aix-line);
  background:
    linear-gradient(165deg, hsl(var(--h) 80% 60% / .13), transparent 58%),
    var(--aix-glass);
  backdrop-filter: blur(14px);
  text-decoration: none; color: inherit; overflow: hidden;
  transform-style: preserve-3d;
  /* THE CURVE. --o signed offset from row centre, --a its absolute value. */
  transform:
    rotateY(calc(var(--o) * -8deg))
    translateZ(calc(var(--a) * -30px))
    translateY(calc(var(--a) * 5px));
  transition: transform .55s cubic-bezier(.22,1,.36,1), border-color .3s, box-shadow .4s;
  animation: aixRise .7s cubic-bezier(.22,1,.36,1) both;
  animation-delay: calc(var(--i) * 70ms + .15s);
}
@keyframes aixRise { from { opacity: 0; transform: translateY(26px) rotateX(12deg); } }

.aixPanel:hover, .aixPanel:focus-visible {
  transform:
    rotateY(calc(var(--o) * -4deg))
    translateZ(34px)
    translateY(calc(var(--a) * 2px - 4px));
  border-color: hsl(var(--h) 90% 62% / .75);
  box-shadow:
    0 0 0 1px hsl(var(--h) 90% 62% / .35),
    0 30px 70px -24px hsl(var(--h) 90% 40% / .7);
  z-index: 3;
}
.aixPanel:focus-visible { outline: 2px solid hsl(var(--h) 90% 65%); outline-offset: 3px; }

/* An iridescent top edge — one line of light, which is most of what sells
   "glass" without turning the whole panel into a mirror. */
.aixPanel__edge {
  position: absolute; inset: 0 0 auto; height: 1px;
  background: linear-gradient(90deg, transparent, hsl(var(--h) 95% 70% / .9), transparent);
}
.aixPanel__sheen {
  position: absolute; inset: 0; opacity: 0; pointer-events: none;
  background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 50%), hsl(var(--h) 95% 65% / .22), transparent 62%);
  transition: opacity .35s;
}
.aixPanel:hover .aixPanel__sheen { opacity: 1; }

.aixPanel__n {
  font-family: var(--font-mono); font-size: .58rem; color: hsl(var(--h) 80% 68% / .8);
  letter-spacing: var(--tracking-eyebrow);
}
.aixPanel__ico {
  display: grid; place-items: center; width: 2.3rem; height: 2.3rem; margin: var(--s-2) 0 var(--s-2);
  border-radius: 10px; border: 1px solid hsl(var(--h) 85% 62% / .4);
  background: linear-gradient(150deg, hsl(var(--h) 85% 58% / .28), transparent);
  color: hsl(var(--h) 95% 76%);
  transition: transform .45s cubic-bezier(.34,1.56,.64,1), box-shadow .35s;
}
.aixPanel:hover .aixPanel__ico { transform: translateZ(26px) scale(1.06); box-shadow: 0 0 0 5px hsl(var(--h) 90% 60% / .1); }
.aixPanel__kicker {
  font-family: var(--font-mono); font-size: .6rem; color: hsl(var(--h) 85% 74%);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
}
.aixPanel__title {
  font-size: .95rem; line-height: 1.28; color: #fff; font-weight: 500;
  text-wrap: balance;
}
/* The arrow sits in the top-right corner rather than on its own line at the
   foot. As a row it cost ~28px per panel, which across two rows was 56px —
   and 56px was the difference between the second row being fully above the
   fold on a laptop and being clipped. It is an affordance, not content, so it
   can live in the corner beside the index. */
.aixPanel__go {
  position: absolute; right: var(--s-4); top: var(--s-3);
  font-size: .95rem; line-height: 1; color: hsl(var(--h) 90% 72%); opacity: .55;
  transition: transform .35s cubic-bezier(.22,1,.36,1), opacity .3s;
}
.aixPanel:hover .aixPanel__go { opacity: 1; }
.aixPanel:hover .aixPanel__go { transform: translateX(5px); }

.aixConsole__foot {
  display: flex; align-items: center; justify-content: center; gap: .8ch;
  margin: clamp(var(--s-6), 3vw, var(--s-8)) 0 0;
  font-size: var(--fs-sm); color: var(--text-lo); text-align: center;
}
.aixConsole__foot span { color: hsl(190 90% 65%); animation: aixBob 2.6s ease-in-out infinite; }
@keyframes aixBob { 50% { transform: translateY(4px); } }

/* ── SECTION FURNITURE ──────────────────────────────────────────────────── */
.aixSection { position: relative; z-index: 1; padding-block: clamp(var(--s-10), 6vw, var(--s-20)); }
.aixSection--alt { background: linear-gradient(180deg, transparent, rgb(10 14 24 / .7) 12% 88%, transparent); }
.aixHead { max-width: 44rem; margin: 0 auto clamp(var(--s-8), 4vw, var(--s-12)); text-align: center; }
.aixHead__k {
  margin: 0 0 var(--s-3); font-family: var(--font-mono); font-size: .62rem;
  color: hsl(190 80% 70%); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
}
.aixHead h2 { margin: 0 0 var(--s-3); font-size: clamp(1.8rem, 1.2rem + 2.4vw, 2.9rem); letter-spacing: -.03em; color: #fff; }
.aixHead p { margin: 0; color: var(--text-mid); }
.aixAccent {
  background: linear-gradient(100deg, hsl(190 95% 62%), hsl(265 90% 72%));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ── THE SEVEN ──────────────────────────────────────────────────────────── */
.aixSvc { padding-block: clamp(var(--s-8), 4vw, var(--s-12)); }
.aixSvc__in {
  display: grid; gap: clamp(var(--s-6), 4vw, var(--s-12));
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  align-items: center;
}
.aixSvc:nth-child(even) .aixSvc__media { order: 2; }

.aixSvc__media { position: relative; }
.aixSvc__frame {
  position: relative; overflow: hidden; border-radius: 16px;
  border: 1px solid var(--aix-line); aspect-ratio: 16 / 10;
  background: rgb(8 10 18 / .8);
  box-shadow: 0 34px 80px -34px #000;
  transform: translate3d(0, var(--py, 0px), 0) rotateY(7deg) rotateX(2deg);
  transition: transform .8s cubic-bezier(.22,1,.36,1);
}
.aixSvc:nth-child(even) .aixSvc__frame { transform: translate3d(0, var(--py, 0px), 0) rotateY(-7deg) rotateX(2deg); }
.aixSvc__frame:hover,
.aixSvc:nth-child(even) .aixSvc__frame:hover { transform: translate3d(0, var(--py, 0px), 0) rotateY(0deg) rotateX(0deg); }
.aixSvc__frame img, .aixSvc__frame video {
  display: block; width: 100%; height: 100%; object-fit: cover;
  /* Biased upward, not centred. Three of the seven sources are PORTRAIT video
     of a person, and a centred crop into a 16:10 frame lands on the collarbone
     — it cut Allie's head off entirely. Favouring the top keeps faces in shot
     and costs the landscape screenshots nothing. */
  object-position: 50% 24%;
  filter: saturate(.9) contrast(1.04) brightness(.86);
  transition: filter .5s, transform 1.1s cubic-bezier(.22,1,.36,1);
}
.aixSvc__frame:hover img, .aixSvc__frame:hover video { filter: saturate(1.05) brightness(.98); transform: scale(1.03); }
/* The clip is appended AFTER the readout grid and the HUD chip, so at equal
   z-index it paints over both and the frame loses its instrumentation the
   moment the video attaches. Explicit stacking instead. */
.aixSvc__frame video { position: absolute; inset: 0; z-index: 1; }
/* A faint readout grid over the footage — the cheapest possible way to say
   "this is a feed, not a photograph". */
.aixSvc__grid {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  background-image:
    linear-gradient(hsl(var(--h) 90% 70% / .09) 1px, transparent 1px),
    linear-gradient(90deg, hsl(var(--h) 90% 70% / .09) 1px, transparent 1px);
  background-size: 42px 42px;
  mask-image: radial-gradient(120% 100% at 50% 50%, black 30%, transparent 78%);
}
.aixSvc__hud {
  position: absolute; left: var(--s-4); top: var(--s-4); z-index: 3;
  display: flex; align-items: baseline; gap: .7ch;
  padding: .3rem .7rem; border-radius: 999px;
  border: 1px solid hsl(var(--h) 85% 65% / .4);
  background: rgb(4 6 12 / .68); backdrop-filter: blur(6px);
}
.aixSvc__hud b { font-family: var(--font-mono); font-size: .68rem; color: hsl(var(--h) 95% 74%); }
.aixSvc__hud i { font-style: normal; font-size: .6rem; color: rgb(255 255 255 / .66); letter-spacing: .06em; text-transform: uppercase; }
/* The glow used to bleed 6% past the media box on each side. A blurred
   decoration extending beyond the container is layout overflow, and below
   900px that became real horizontal page scroll on every one of the seven
   rows. Kept inside the box: blur() already paints ~46px past its own edges,
   and painted overflow does not add to scrollWidth. */
/* A YouTube play button, on the two sections whose proof is a published film.
   The iframe is not built until this is pressed: a raw embed costs every
   visitor ~1MB of third-party JavaScript and a cookie whether or not they ever
   watch, and there are two of them on this page. */
.aixSvc__play {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: 3;
  display: grid; place-items: center; width: 4.6rem; height: 3.2rem;
  border: 0; border-radius: 13px; background: #ff3d3d; cursor: pointer;
  box-shadow: 0 14px 38px -10px rgb(255 61 61 / .75);
  transition: transform .3s cubic-bezier(.34,1.56,.64,1), background .3s;
}
.aixSvc__play::after {
  content: ''; margin-left: 4px;
  border-left: 16px solid #fff; border-top: 10px solid transparent; border-bottom: 10px solid transparent;
}
.aixSvc__play:hover { transform: translate(-50%, -50%) scale(1.08); background: #ff2020; }
.aixSvc__play:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.aixSvc__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; z-index: 4; }
/* Once it is a real player the tilt has to go — a rotated iframe makes the
   YouTube controls hard to hit and the captions soft. */
.aixSvc__frame.is-live,
.aixSvc__frame.is-live:hover,
.aixSvc:nth-child(even) .aixSvc__frame.is-live,
.aixSvc:nth-child(even) .aixSvc__frame.is-live:hover { transform: none; }

.aixSvc__glow {
  position: absolute; inset: 12% 0 -10%; z-index: -1;
  background: radial-gradient(70% 60% at 50% 60%, hsl(var(--h) 90% 50% / .4), transparent 70%);
  filter: blur(46px);
}

.aixSvc__k {
  display: flex; align-items: center; gap: .8ch; margin: 0 0 var(--s-3);
  font-family: var(--font-mono); font-size: .62rem; color: hsl(var(--h) 85% 74%);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
}
.aixSvc__badge {
  display: grid; place-items: center; width: 2.2rem; height: 2.2rem; flex: none;
  border-radius: 8px; border: 1px solid hsl(var(--h) 85% 62% / .4);
  background: linear-gradient(150deg, hsl(var(--h) 85% 58% / .26), transparent);
  color: hsl(var(--h) 95% 76%);
}
.aixSvc__copy h3 {
  margin: 0 0 var(--s-4); font-size: clamp(1.5rem, 1.1rem + 1.7vw, 2.2rem);
  letter-spacing: -.028em; color: #fff; text-wrap: balance;
}
.aixSvc__items { list-style: none; margin: 0 0 var(--s-5); padding: 0; display: grid; gap: var(--s-3); }
.aixSvc__items li {
  position: relative; padding-left: 1.7rem;
  color: var(--text-mid); font-size: var(--fs-body); line-height: var(--lh-body);
}
.aixSvc__items li::before {
  content: ''; position: absolute; left: 0; top: .55em;
  width: .8rem; height: 1px; background: hsl(var(--h) 90% 65%);
  box-shadow: 0 0 8px hsl(var(--h) 90% 60% / .9);
}
.aixSvc__helps {
  margin: 0 0 var(--s-4); padding-left: var(--s-4);
  border-left: 2px solid hsl(var(--h) 85% 60% / .5);
  color: var(--text-hi); font-size: var(--fs-body-lg); line-height: var(--lh-snug);
}
.aixSvc__proof {
  display: flex; align-items: center; gap: .7ch; margin: 0 0 var(--s-5);
  font-size: var(--fs-sm); color: var(--text-lo);
}
.aixSvc__proof span { color: hsl(150 75% 55%); font-size: .6rem; }
.aixSvc__cta {
  display: inline-flex; align-items: center; gap: .7ch;
  padding: .7rem 1.3rem; border-radius: 999px;
  border: 1px solid hsl(var(--h) 85% 62% / .45);
  background: hsl(var(--h) 85% 55% / .1);
  color: hsl(var(--h) 92% 78%); font-size: var(--fs-sm); text-decoration: none;
  transition: background .3s, border-color .3s, transform .3s;
}
.aixSvc__cta span { transition: transform .35s cubic-bezier(.22,1,.36,1); }
.aixSvc__cta:hover { background: hsl(var(--h) 85% 55% / .2); border-color: hsl(var(--h) 90% 68% / .85); transform: translateY(-2px); }
.aixSvc__cta:hover span { transform: translateX(4px); }

/* ── THE PROCESS ────────────────────────────────────────────────────────── */
.aixFlow {
  list-style: none; margin: 0; padding: 0; position: relative;
  display: grid; gap: var(--s-5); grid-template-columns: repeat(4, minmax(0, 1fr));
}
.aixFlow::before {
  content: ''; position: absolute; left: 0; right: 0; top: 1.55rem; height: 1px;
  background: linear-gradient(90deg, hsl(190 90% 60%), hsl(265 85% 65%), hsl(320 85% 65%), transparent);
  transform: scaleX(var(--p, 0)); transform-origin: 0 50%;
  transition: transform 1.5s cubic-bezier(.22,1,.36,1);
}
.aixFlow__step { animation: aixRise .6s cubic-bezier(.22,1,.36,1) both; animation-delay: calc(var(--i) * 90ms); }
.aixFlow__n {
  position: relative; z-index: 1;
  display: grid; place-items: center; width: 3.1rem; height: 3.1rem;
  border-radius: 50%; border: 1px solid hsl(190 90% 60% / .45);
  background: rgb(8 10 18 / .95);
  box-shadow: 0 0 0 6px hsl(190 90% 55% / .07);
  font-family: var(--font-mono); font-size: .8rem; color: hsl(190 92% 72%);
}
.aixFlow__step h3 { margin: var(--s-4) 0 var(--s-2); font-size: var(--fs-h3); color: #fff; }
.aixFlow__step p { margin: 0; color: var(--text-mid); font-size: var(--fs-sm); line-height: var(--lh-body); }

/* ── CLOSING ────────────────────────────────────────────────────────────── */
.aixClose { position: relative; z-index: 1; padding-block: clamp(var(--s-12), 7vw, var(--s-24)); text-align: center; }
.aixClose__in { max-width: 46rem; margin-inline: auto; }
.aixClose h2 { margin: 0 0 var(--s-4); font-size: clamp(1.9rem, 1.2rem + 2.8vw, 3rem); letter-spacing: -.03em; color: #fff; }
.aixClose p { margin: 0 auto; max-width: 46ch; color: var(--text-mid); }
.aixClose .aixHero__cta { justify-content: center; margin-top: var(--s-7); }
.aixClose__note { margin-top: var(--s-6); font-size: var(--fs-sm); color: var(--text-lo); }

/* ══════════════════════════════════════════════════════════════════════════
   THE BRIEFING
   ══════════════════════════════════════════════════════════════════════════
   A visual-novel cutscene. The veil is deliberately NOT opaque: Yuna spends
   the whole sequence pointing at panels, so the panels have to stay visible.
   ========================================================================== */
.aixBrief { position: fixed; inset: 0; z-index: 900; }
.aixBrief[hidden] { display: none; }
/* The veil is TRANSPARENT whenever the reticle is up, and only paints when
   there is no target to point at.

   The reticle dims the page itself, with a box-shadow spread wide enough to
   cover any viewport; the lit rectangle is the shadow's hole. Painting a veil
   underneath as well meant the hole revealed the veil instead of the page, so
   the spotlight was a 6% brightness difference nobody could see. It exists
   here purely to catch clicks. */
.aixBrief__veil {
  position: absolute; inset: 0;
  background: transparent;
  animation: aixFade .4s ease both;
}
.aixBrief.is-blind .aixBrief__veil { background: rgb(3 4 9 / .8); backdrop-filter: blur(3px); }
@keyframes aixFade { from { opacity: 0; } }

/* The spotlight. One element moved between targets, with the hole punched by
   an enormous spread box-shadow — the same trick the notes tour uses, but the
   ring here is drawn as corner brackets and a sweep so it reads as targeting
   reticle rather than as a highlighter. */
.aixBrief__ring {
  position: absolute; border-radius: 16px; pointer-events: none;
  box-shadow: 0 0 0 100vmax rgb(3 4 9 / .8), 0 0 60px hsl(190 95% 60% / .35) inset;
  border: 1px solid hsl(190 95% 65% / .7);
  /* NO transition by default. The reticle is re-measured every frame while
     the page scrolls, and an eased position means it is permanently chasing
     the card instead of sitting on it — during a beat change it lagged far
     enough behind to be drawn around empty space. The ease is added back
     for the half-second it takes to move BETWEEN targets, which is the only
     time it is wanted. */
  transition: none;
}
.aixBrief__ring.is-moving {
  transition: left .5s cubic-bezier(.22,1,.36,1), top .5s cubic-bezier(.22,1,.36,1),
              width .5s cubic-bezier(.22,1,.36,1), height .5s cubic-bezier(.22,1,.36,1);
}
.aixBrief__ring[hidden] { display: none; }
.aixBrief__corner {
  position: absolute; width: 15px; height: 15px;
  border: 2px solid hsl(190 95% 68%);
}
.aixBrief__corner--tl { left: -2px; top: -2px; border-right: 0; border-bottom: 0; border-radius: 5px 0 0 0; }
.aixBrief__corner--tr { right: -2px; top: -2px; border-left: 0; border-bottom: 0; border-radius: 0 5px 0 0; }
.aixBrief__corner--bl { left: -2px; bottom: -2px; border-right: 0; border-top: 0; border-radius: 0 0 0 5px; }
.aixBrief__corner--br { right: -2px; bottom: -2px; border-left: 0; border-top: 0; border-radius: 0 0 5px 0; }
.aixBrief__sweep {
  position: absolute; inset: 0; overflow: hidden; border-radius: inherit;
}
.aixBrief__sweep::after {
  content: ''; position: absolute; left: 0; right: 0; height: 34%;
  background: linear-gradient(hsl(190 95% 60% / 0), hsl(190 95% 60% / .22), hsl(190 95% 60% / 0));
  animation: aixSweep 2.6s ease-in-out infinite;
}
@keyframes aixSweep { 0% { top: -34%; } 100% { top: 100%; } }

/* The stage: character on the left, dialogue box on the right. */
.aixBrief__stage {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  align-items: end; gap: 0;
  padding: 0 clamp(var(--s-4), 3vw, var(--s-10)) clamp(var(--s-4), 2.5vw, var(--s-8));
  max-width: 78rem; margin-inline: auto;
  pointer-events: none;
}
.aixBrief__stage > * { pointer-events: auto; }

.aixBrief__char {
  position: relative; margin: 0 -2.5rem 0 0; width: clamp(9rem, 15vw, 15rem);
  animation: aixEnter .55s cubic-bezier(.22,1,.36,1) both;
  filter: drop-shadow(0 18px 40px rgb(0 0 0 / .7));
}
@keyframes aixEnter { from { opacity: 0; transform: translate(-24px, 18px); } }
/* A comms plate, not a cut-out.
   The source portrait is a studio shot on a flat teal backdrop, so masking it
   to a silhouette is not possible without a matte we do not have — and a
   hard-edged rectangle floating in space just reads as a stray photograph.
   Framing it as a lit panel with a bracket and a live dot turns the same
   asset into an incoming video call, which is both honest about what it is
   and exactly the register the rest of the page is in. */
.aixBrief__char img {
  display: block; width: 100%; height: auto;
  border-radius: 14px 14px 0 0;
  mask-image: linear-gradient(to bottom, black 84%, transparent);
}
.aixBrief__char::before {
  content: ''; position: absolute; inset: 0;
  border: 1px solid hsl(190 90% 62% / .45);
  border-bottom: 0; border-radius: 14px 14px 0 0;
  mask-image: linear-gradient(to bottom, black 62%, transparent);
  pointer-events: none;
}
/* "LIVE", because she is an avatar and the page has just said so. */
.aixBrief__char::after {
  content: 'LIVE';
  position: absolute; left: .55rem; top: .55rem;
  display: flex; align-items: center;
  padding: .16rem .5rem .16rem 1.1rem;
  border-radius: 999px; background: rgb(4 6 12 / .8);
  border: 1px solid hsl(150 80% 55% / .5);
  font-family: var(--font-mono); font-size: .5rem; letter-spacing: .16em;
  color: hsl(150 80% 70%);
  background-image: radial-gradient(circle at .55rem 50%, hsl(150 85% 58%) 2.2px, transparent 2.4px);
}
.aixBrief__halo {
  position: absolute; inset: 8% -18% -6%;
  background: radial-gradient(50% 55% at 50% 55%, hsl(190 90% 55% / .38), transparent 70%);
  filter: blur(26px); z-index: -1;
}
.aixBrief__scanline {
  position: absolute; inset: 0; border-radius: 14px 14px 0 0; overflow: hidden;
  background: repeating-linear-gradient(to bottom, hsl(190 95% 70% / .07) 0 1px, transparent 1px 4px);
  mask-image: linear-gradient(to bottom, black 78%, transparent);
}
/* She "breathes" while speaking, and settles when the line is done. It is two
   pixels of movement and it is the difference between a character and a
   cut-out. */
.aixBrief.is-typing .aixBrief__char { animation: aixEnter .55s cubic-bezier(.22,1,.36,1) both, aixBreathe 2.2s ease-in-out .55s infinite; }
@keyframes aixBreathe { 50% { transform: translateY(-3px) scale(1.006); } }

.aixBrief__box {
  position: relative; align-self: end;
  border-radius: 16px; border: 1px solid hsl(190 90% 60% / .35);
  background: linear-gradient(150deg, rgb(10 16 28 / .96), rgb(6 8 16 / .96));
  backdrop-filter: blur(16px);
  box-shadow: 0 -6px 60px -18px hsl(190 95% 50% / .45), 0 30px 70px -30px #000;
  padding: var(--s-5) clamp(var(--s-5), 2.4vw, var(--s-7));
  animation: aixBox .45s cubic-bezier(.22,1,.36,1) both;
}
@keyframes aixBox { from { opacity: 0; transform: translateY(20px); } }
.aixBrief__box::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 1px;
  background: linear-gradient(90deg, transparent, hsl(190 95% 70%), transparent);
}

.aixBrief__meta { display: flex; align-items: center; gap: var(--s-3); margin-bottom: var(--s-3); }
.aixBrief__avatar {
  display: block; width: 2.4rem; height: 2.4rem; flex: none;
  border-radius: 50%; overflow: hidden; border: 1px solid hsl(190 90% 62% / .6);
  box-shadow: 0 0 0 3px hsl(190 90% 55% / .12);
}
.aixBrief__avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.aixBrief__id { display: grid; gap: 1px; min-width: 0; }
.aixBrief__id b { font-size: var(--fs-sm); color: #fff; letter-spacing: .02em; }
.aixBrief__id i {
  font-style: normal; font-family: var(--font-mono); font-size: .58rem;
  color: hsl(190 80% 70%); letter-spacing: .1em; text-transform: uppercase;
}
.aixBrief__count {
  margin-left: auto; font-family: var(--font-mono); font-size: .68rem; color: var(--text-lo);
}
.aixBrief__count b { color: hsl(190 92% 72%); }

.aixBrief__text {
  margin: 0 0 var(--s-4); min-height: 3.9em;
  color: var(--text-hi); font-size: var(--fs-body-lg); line-height: 1.55;
}
/* The caret that trails the typewriter. */
.aixBrief__text::after {
  content: '▍'; color: hsl(190 95% 65%); opacity: 0;
}
.aixBrief.is-typing .aixBrief__text::after { opacity: 1; animation: aixBlink .8s steps(1) infinite; }
@keyframes aixBlink { 50% { opacity: 0; } }

.aixBrief__bar { height: 2px; border-radius: 2px; background: rgb(255 255 255 / .1); overflow: hidden; }
.aixBrief__bar span {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, hsl(190 95% 58%), hsl(265 90% 68%));
  transition: width .35s ease;
}
.aixBrief__acts { display: flex; align-items: center; gap: var(--s-4); margin-top: var(--s-4); }
.aixBrief__nav { margin-left: auto; display: flex; align-items: center; gap: var(--s-3); }
.aixBrief__skip, .aixBrief__back {
  border: 0; background: none; font: inherit; font-size: var(--fs-sm);
  color: var(--text-lo); cursor: pointer; padding: .4rem 0;
  transition: color .25s;
}
.aixBrief__skip:hover, .aixBrief__back:hover { color: var(--text-hi); }
.aixBrief__caret {
  width: 0; height: 0;
  border-left: 5px solid currentColor; border-top: 4px solid transparent; border-bottom: 4px solid transparent;
}

/* The replay button. Yuna's face, so it is obvious what it replays. */
.aixReplay {
  position: fixed; right: clamp(.8rem, 2vw, 1.4rem); bottom: clamp(.8rem, 2vw, 1.4rem);
  z-index: 800;
  display: inline-flex; align-items: center; gap: .7ch;
  padding: .4rem 1rem .4rem .4rem; border-radius: 999px;
  border: 1px solid hsl(190 90% 60% / .4);
  background: rgb(8 12 22 / .9); backdrop-filter: blur(10px);
  color: var(--text-hi); font: inherit; font-size: var(--fs-sm); cursor: pointer;
  box-shadow: 0 12px 34px -14px #000;
  transition: transform .3s cubic-bezier(.22,1,.36,1), border-color .3s;
}
.aixReplay:hover { transform: translateY(-2px); border-color: hsl(190 95% 65% / .9); }
.aixReplay__face { width: 2rem; height: 2rem; border-radius: 50%; overflow: hidden; flex: none; }
.aixReplay__face img { width: 100%; height: 100%; object-fit: cover; display: block; }
.aixBrief:not([hidden]) ~ .aixReplay { opacity: 0; pointer-events: none; }

/* ══════════════════════════════════════════════════════════════════════════
   RESPONSIVE
   ══════════════════════════════════════════════════════════════════════════
   The console is the thing that has to be re-thought at each width, because
   "all seven visible at once" stops being possible long before the text stops
   fitting. It steps 4+3 → 3+3+1 → 2 → 1, and the CURVE IS DROPPED below the
   point where panels are wide enough for the yaw to distort the text.
   ========================================================================== */
/* Below 64rem the two rows DISSOLVE into one flat grid via display:contents.
   They have to: --o is each panel's offset from ITS OWN ROW's centre, computed
   in PHP, so the moment the panels reflow into different positions the curve
   is describing a layout that no longer exists — panel 5 would yaw as though
   it were still the left edge of a three-wide row. The curve and the
   perspective both go with it.

   Seven items in two columns leaves a seventh on its own, so it spans the
   pair rather than sitting next to a hole. */
/* Yuna turns from a column into a bar. Below this width a portrait beside the
   copy would take a third of the screen and shove the console off the fold,
   but dropping her entirely loses the one thing that says the walkthrough
   exists — so she becomes a full-width strip under the buttons instead: face,
   the same sentence, same play button. */
@media (max-width: 72rem) {
  .aixHero__top { grid-template-columns: 1fr; gap: var(--s-6); }
  .aixHero__copy { max-width: none; }
  .aixGuide { width: 100%; }
  .aixGuide__plate {
    display: flex; align-items: center; gap: var(--s-4);
    aspect-ratio: auto; padding: var(--s-3); border-radius: 999px;
  }
  .aixGuide__plate img {
    width: 3.4rem; height: 3.4rem; flex: none; border-radius: 50%;
    object-position: 50% 8%;
  }
  .aixGuide__scan, .aixGuide__live, .aixGuide__halo { display: none; }
  .aixGuide__play {
    position: static; translate: none; order: 3; margin-left: auto;
    width: 2.4rem; height: 2.4rem; animation: none;
  }
  .aixGuide__play::after { border-left-width: 9px; border-top-width: 6px; border-bottom-width: 6px; }
  .aixGuide__foot { position: static; padding: 0; background: none; }
  /* The bubble becomes the label, in flow, because there is nothing left to
     point at once the portrait is a 3rem circle. */
  .aixGuide__say {
    position: static; max-width: none; width: auto; order: 2;
    padding: 0; border: 0; background: none; box-shadow: none; animation: none;
    font-size: var(--fs-sm); color: var(--text-mid);
  }
  .aixGuide__say::after { display: none; }
  .aixGuide:hover .aixGuide__plate { transform: none; }
  .aixGuide:hover .aixGuide__plate img { transform: none; }
}
@media (max-width: 34rem) {
  .aixGuide__say { display: none; }
  .aixGuide__foot i { font-size: .48rem; }
}

@media (max-width: 64rem) {
  .aixConsole { grid-template-columns: repeat(2, minmax(0, 1fr)); perspective: none; }
  .aixConsole__row { display: contents; }
  .aixPanel, .aixPanel:hover { transform: none; }
  /* The SECOND row's last panel — not `.aixPanel:last-child`, which also
     matches panel 04. display:contents removes the row's box but :last-child
     still resolves against the real DOM parent, so each row still has its own
     last child and panel 04 was spanning the grid too. */
  .aixConsole__row--2 .aixPanel:last-child { grid-column: span 2; }
  .aixPanel:hover { box-shadow: 0 0 0 1px hsl(var(--h) 90% 62% / .35), 0 20px 44px -20px #000; }
  .aixSvc__in { grid-template-columns: 1fr; }
  .aixSvc:nth-child(even) .aixSvc__media { order: 0; }
  .aixSvc__frame,
  .aixSvc:nth-child(even) .aixSvc__frame { transform: translate3d(0, var(--py, 0px), 0); }
  .aixFlow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .aixFlow::before { display: none; }
}
/* Tablet keeps THREE across so the array is 3+3+1 rather than 2+2+2+1 — one
   row fewer, which on a 900-tall tablet is the difference between seeing five
   services on open and four.  The seventh spans the row rather than sitting
   beside two empty cells.

   This block MUST come after the 64rem one: equal specificity resolves by
   source order, so declared first it would simply be overwritten by the
   two-column rule at every width it covers. */
@media (min-width: 48.0625rem) and (max-width: 64rem) {
  .aixConsole { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .aixConsole__row--2 .aixPanel:last-child { grid-column: span 3; }
}

@media (max-width: 40rem) {
  .aixConsole { grid-template-columns: 1fr; }
  .aixConsole__row--2 .aixPanel:last-child { grid-column: auto; }
  .aixPanel { padding: var(--s-4); }
  .aixFlow { grid-template-columns: 1fr; }
  .aixHero__cta { display: grid; }
  .aixHero__cta .aixBtn { width: 100%; }
  .aixConsole__rail { display: none; }
}

/* The briefing on a phone. The character cannot sit beside the box — there is
   not room for both — so she shrinks to a head that overlaps the box's top
   corner, which is how handheld visual novels have always solved it. */
@media (max-width: 52rem) {
  .aixBrief__stage { grid-template-columns: 1fr; padding-inline: var(--s-3); }
  .aixBrief__char {
    position: absolute; right: var(--s-3); bottom: 100%; margin: 0 0 -2.5rem;
    width: 7rem; z-index: -1;
  }
  .aixBrief__text { font-size: var(--fs-body); min-height: 5.2em; }
  .aixBrief__box { padding: var(--s-4); }
  .aixReplay__t { display: none; }
  .aixReplay { padding: .4rem; }
}
/* Very short viewports — a landscape phone — cannot afford the portrait at
   all; it would cover the thing being pointed at. */
@media (max-height: 34rem) {
  .aixBrief__char { display: none; }
  .aixBrief__text { min-height: 0; }
}

/* ── REDUCED MOTION ─────────────────────────────────────────────────────────
   Everything above is decoration. With motion off the page is a heading, seven
   links, seven explanations and a call to action — which is the whole page. */
@media (prefers-reduced-motion: reduce) {
  .aixSky__aurora, .aixSky__floor, .aixSky__stars { transform: none; animation: none; }
  .aixPanel, .aixFlow__step, .aixBrief__char, .aixBrief__box, .aixBrief__veil { animation: none; }
  .aixPanel { transform: none; }
  .aixPanel:hover { transform: none; }
  .aixConsole__row, .aixPanel, .aixSvc__frame, .aixSvc__frame img,
  .aixBrief__ring, .aixBtn, .aixSvc__cta { transition: none; }
  .aixSvc__frame, .aixSvc:nth-child(even) .aixSvc__frame { transform: none; }
  .aixHero__pulse, .aixConsole__foot span, .aixBrief__sweep::after,
  .aixBrief__text::after, .aixGuide__play, .aixGuide__say { animation: none; }
  .aixGuide__plate, .aixGuide__plate img, .aixSvc__play { transition: none; }
  .aixGuide:hover .aixGuide__plate, .aixGuide:hover .aixGuide__plate img { transform: none; }
  .aixFlow::before { transform: scaleX(1); transition: none; }
}
