/* ─────────────────────────────────────────────────────────────
   Noveriq - live hero demo
   A macOS session drawn in the DOM: wallpaper, menu bar, notch,
   windows and dock. No video, no canvas, no build step, no images
   beyond our own sprite strips.

   ── how it is driven ──────────────────────────────────────────
   Two attributes on the root do everything:

       <div class="ct-stage" data-state="approval" data-autoplay="true">

   Every visual difference below is a selector off [data-state].
   Choreography inside a scene (the pointer walking to Allow, the
   tab handing over) is CSS animation whose duration is var(--ct-dwell),
   which hero-demo.js sets from the same per-scene dwell map that
   drives autoplay - retune a dwell and its choreography rescales.
   Scenes restart their animations on entry for free, because the
   selector stops matching and starts matching again.

   A third attribute, data-size, is set by the script from the
   mount's width: "full" is the desktop scene, "compact" (under
   700px) is a different composition, not the same one shrunk.

   The only visuals the script owns are --ct-scale (fit to the box)
   and --ct-h (the notch's height): CSS cannot interpolate a height
   to `auto`, and the notch must grow to exactly the card it shows.

   ── how it is sized ───────────────────────────────────────────
   .ct-screen is a canvas authored in fixed "design pixels", sized
   to 100%/scale and scaled back down, so it holds exactly as many
   design pixels as the container can fit: an ultrawide box gets a
   wider desktop, a portrait box a taller one. Nothing is
   letterboxed, nothing is cropped. Everything inside is placed
   from the centre line or from an edge, never from a canvas size.

   Geometry is the app's own, in points, multiplied by 1.5 so the
   pixel-art mascots land on whole-number scales:
     notch bar     32pt -> 48px      centre gap  190pt -> 285px
     wing         128pt -> 192px     collapsed   446pt -> 669px
     expanded     760pt -> 1140px
   669/2270 is the real 29.5% of a MacBook's width, which is what
   the canvas works out to on a full-bleed hero.

   Everything is namespaced ct- to stay out of styles.css's way.
   ───────────────────────────────────────────────────────────── */

.ct-demo, .ct-demo *, .ct-demo *::before, .ct-demo *::after,
.ct-stage, .ct-stage *, .ct-stage *::before, .ct-stage *::after {
  box-sizing: border-box;
}

/* The app's palette. Declared at the document root rather than on the stage
   because the notch fragments in the features section reuse the same brand
   marks, pips and rings outside any stage, and a second copy of these values
   would be free to drift from the app's. Everything below inherits it. */
:root {
  --ct-working:   var(--working,   #4ec97f);
  --ct-attention: var(--attention, #ff9f2e);
  --ct-asking:    var(--asking,    #59a6ff);
  --ct-done:      var(--done,      #6ee7c0);
  --ct-ok:        var(--ctx-ok,    #5cd18c);
  /* Pip palette, after the app gave green to "done" and let "working" go
     quiet. Working is announced by its spinning mark, so it needs no hue;
     idle is that same neutral turned down. The achromatic axis reads as
     "nothing for you here", which frees green to mean finished well. */
  --ct-pip-working: #e8e8e8;
  --ct-pip-done:    #30d158;
  --ct-pip-idle:    #5c5c5c;
  --ct-high:      var(--ctx-high,  #ffb847);
  --ct-crit:      var(--ctx-crit,  #ff6b47);
}

.ct-stage {
  --ct-sans:    var(--sans, ui-sans-serif, -apple-system, "Segoe UI", sans-serif);
  --ct-mono:    var(--mono, ui-monospace, "SF Mono", Menlo, monospace);
  --ct-display: var(--font-display, "Inter", ui-sans-serif, system-ui, sans-serif);

  --ct-scale: 1;        /* design px -> css px, set by hero-demo.js */
  --ct-dwell: 6000ms;   /* how long the current scene lasts */
  --ct-collapsed: 669px;/* notch body width, collapsed */
  --ct-br-collapsed: 18px;
  --ct-br-open: 45px;
  --ct-w: var(--ct-collapsed);
  --ct-h: 48px;         /* notch body height, bar + whatever card is open */
  --ct-br: var(--ct-br-collapsed);
  --ct-open: 0;         /* 0 collapsed, 1 expanded */
  --ct-panel: 1140px;   /* expanded panel width */

  /* The collapsed bar's geometry, so every part of it scales together
     rather than being pinned in px. The app's own numbers x1.5:
       collapsed 446pt -> 669px, gap 190pt -> 285px, bar 32pt -> 48px,
     which is an aspect of 669/48 = 13.94 : 1.
     hero-demo.js recomputes these for the phone composition from
     --ct-notch-ratio so the notch stays the same share of the screen as
     it is on a Mac. Raise the ratio if you want the character legible on
     a phone; it is the one knob that trades the two off. */
  --ct-notch-ratio: .295;
  --ct-bar: 48px;       /* bar height */
  --ct-gap: 285px;      /* the camera housing: always empty */
  --ct-mascot-k: 1;     /* mascot scale inside the bar */

  position: relative;
  width: 100%;
  height: 100%;         /* the mount must be sized; the fold decides how */
  min-height: 320px;    /* so it can never collapse to nothing */
  overflow: hidden;
  isolation: isolate;
}

/* Wrapped in .ct-demo the stage takes the room the
   control strip does not, so both fit whatever height the wrapper is given. */
.ct-demo { display: flex; flex-direction: column; height: 100%; }
.ct-demo > .ct-stage { height: auto; flex: 1 1 0; }

/* The panel is open in exactly these scenes - which is all of them bar the
   character, the one beat that is about the collapsed bar. */
.ct-stage[data-state="crew"],
.ct-stage[data-state="approval"],
.ct-stage[data-state="ask"],
.ct-stage[data-state="plan"],
.ct-stage[data-state="quota"] {
  --ct-w: var(--ct-panel);
  --ct-br: var(--ct-br-open);
  --ct-open: 1;
}

.ct-screen {
  position: absolute;
  top: 0;
  left: 0;
  width: calc(100% / var(--ct-scale));
  height: calc(100% / var(--ct-scale));
  transform: scale(var(--ct-scale));
  transform-origin: top left;
  overflow: hidden;
  font-family: var(--ct-sans);
  color: #fff;
  -webkit-font-smoothing: antialiased;
}

/* ── wallpaper ───────────────────────────────────────────────── */
/* Ours, not Apple's: six layered radial fields at different radii and
   opacities over a deep vertical bed, a vignette to weight the edges,
   and a grain layer - a big flat gradient bands without one, and the
   banding is what makes these look cheap. */

/* A bright Sequoia-style desktop: cool blue on the left sweeping through
   violet into warm amber on the right, with soft rays fanning from the lower
   right. The wallpaper has to be LIGHT - the whole point of the composition is
   a dark Noveriq panel sitting on a bright desktop. A dark wallpaper makes
   the product disappear into its own background. */
/* Published at the document root, not on the stage, because the page paints
   a blurred copy of this same wallpaper behind the screen to make it glow.
   Custom properties only inherit downwards, and that glow lives on .product,
   which is the stage's parent. Every stop here is a percentage, so the one
   declaration works at both sizes. */
:root {
  --ct-wallpaper:
    /* the rays */
    repeating-conic-gradient(from 196deg at 78% 116%,
      rgba(255, 255, 255, .10) 0deg 4deg,
      rgba(255, 255, 255, 0)   4deg 11deg),
    /* colour fields */
    radial-gradient(72% 84% at 96% 88%, rgba(255, 186, 92, .95), transparent 62%),
    radial-gradient(58% 72% at 74% 96%, rgba(255, 148, 96, .70), transparent 66%),
    radial-gradient(64% 78% at 40% 92%, rgba(168, 122, 240, .62), transparent 68%),
    radial-gradient(72% 86% at 6%  74%, rgba(58, 118, 232, .88), transparent 66%),
    radial-gradient(80% 60% at 30% 4%,  rgba(126, 176, 255, .70), transparent 70%),
    linear-gradient(160deg, #5b8de6 0%, #7b7ae0 34%, #b884d8 58%, #f0a271 82%, #ffc98a 100%);
}

.ct-wall {
  position: absolute;
  inset: 0;
  background: var(--ct-wallpaper);
}

/* Three slow fields drifting over the bed. Transform and opacity only,
   so they live on the compositor; 40s+ periods so it reads as light
   moving rather than an animation playing. */
.ct-aurora {
  position: absolute;
  border-radius: 50%;
  will-change: transform;
  pointer-events: none;
}
.ct-aurora-1 {
  left: 2%; top: -34%;
  width: 62%; height: 108%;
  background: radial-gradient(closest-side, rgba(86, 170, 255, .34), transparent 72%);
  filter: blur(70px);
  animation: ct-drift-a 46s ease-in-out infinite;
}
.ct-aurora-2 {
  right: -6%; top: -26%;
  width: 58%; height: 96%;
  background: radial-gradient(closest-side, rgba(30, 200, 190, .26), transparent 74%);
  filter: blur(80px);
  animation: ct-drift-b 61s ease-in-out infinite;
}
.ct-aurora-3 {
  left: 28%; top: 6%;
  width: 52%; height: 78%;
  background: radial-gradient(closest-side, rgba(126, 108, 255, .20), transparent 76%);
  filter: blur(90px);
  animation: ct-drift-c 53s ease-in-out infinite;
}
@keyframes ct-drift-a {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(6%, 4%, 0) scale(1.12); }
}
@keyframes ct-drift-b {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1.08); }
  50%      { transform: translate3d(-7%, 3%, 0) scale(1); }
}
@keyframes ct-drift-c {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); opacity: .9; }
  50%      { transform: translate3d(4%, -3%, 0) scale(1.1); opacity: .6; }
}

/* Grain. Not optional: it is what stops the gradients banding. */
.ct-grain {
  position: absolute;
  inset: -10%;
  opacity: .055;
  pointer-events: none;
  background-repeat: repeat;
  background-size: 200px 200px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}

.ct-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(128% 92% at 50% 26%, transparent 40%, rgba(0, 0, 0, .30) 74%, rgba(0, 0, 0, .62) 100%),
    linear-gradient(to bottom, rgba(0, 0, 0, .28), transparent 22%);
}

/* ── windows ─────────────────────────────────────────────────── */
/* Held to the right of the centre line so the left of the scene stays
   clear for the statement, at every canvas width. */

/* A real macOS terminal: translucent dark glass over the desktop, a hairline
   light edge along the top where the window catches the light, and a deep
   soft shadow. The desktop showing faintly through is what makes it read as
   a window rather than a black rectangle. */
.ct-win {
  position: absolute;
  left: 50%;
  border-radius: 12px;
  overflow: hidden;
  background: rgba(22, 20, 30, .74);
  backdrop-filter: blur(28px) saturate(150%);
  -webkit-backdrop-filter: blur(28px) saturate(150%);
  box-shadow:
    0 34px 80px rgba(24, 14, 44, .46),
    0 8px 22px rgba(24, 14, 44, .28),
    inset 0 1px 0 rgba(255, 255, 255, .14),
    0 0 0 .5px rgba(0, 0, 0, .45);
  will-change: transform;
}

/* Both windows have to finish inside the canvas. The canvas is 1700 design
   px wide, so anything past +850 is sliced off by the frame and the window
   ends on a hard square edge instead of its own rounded corner - which is
   exactly what made these read as broken rectangles. Right edges now stop at
   +780 and the pair sits closer to the middle. */
.ct-win-term   { margin-left: -300px; width: 900px; height: 318px; top: max(486px, 50%); z-index: 3; }
.ct-win-editor { margin-left: 60px;   width: 720px; height: 300px; top: max(452px, 46%); z-index: 2; }

/* The window you are not in sits back a touch and loses its contrast. */
.ct-win-editor { transform: scale(.985) translate3d(0, 6px, 0); filter: brightness(.7) saturate(.85); }

.ct-win-title {
  height: 42px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 16px;
  /* the title bar is part of the same glass, just a shade lighter */
  background: linear-gradient(rgba(255, 255, 255, .07), rgba(255, 255, 255, .03));
  border-bottom: 1px solid rgba(0, 0, 0, .28);
}
.ct-lights { display: flex; gap: 8px; }
.ct-light { width: 13px; height: 13px; border-radius: 50%; background: #3a3f48; }
.ct-win-term .ct-light-r { background: #ff5f57; }
.ct-win-term .ct-light-y { background: #febc2e; }
.ct-win-term .ct-light-g { background: #28c840; }
/* macOS centres the window title over the whole bar, not beside the lights */
.ct-win-name {
  position: absolute;
  left: 0; right: 0;
  text-align: center;
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: -.01em;
  color: rgba(255, 255, 255, .68);
  pointer-events: none;
}
.ct-win-title { position: relative; }

.ct-editor-body {
  height: calc(100% - 42px);
  background: #0e1116;
  padding: 18px 22px;
  font-family: var(--ct-mono);
  font-size: 14px;
  line-height: 1.75;
  color: rgba(255, 255, 255, .30);
}
.ct-editor-body span { color: rgba(120, 170, 255, .45); }
.ct-editor-body em { color: rgba(255, 184, 71, .45); font-style: normal; }

/* ── terminal tabs ───────────────────────────────────────────── */

.ct-tabs {
  display: flex;
  gap: 2px;
  height: 41px;
  padding: 6px 8px 0;
  background: rgba(0, 0, 0, .18);
  border-bottom: 1px solid rgba(0, 0, 0, .3);
}
.ct-tab {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 0 10px;
  border-radius: 8px 8px 0 0;
  font-size: 14px;
  color: rgba(255, 255, 255, .45);
  background: transparent;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ct-tab i {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ct-working);
  flex: none;
}
.ct-tab::after {
  content: "";
  position: absolute;
  left: 10px; right: 10px; bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--ct-high);
  opacity: 0;
}
.ct-tab-0 { background: #1d2129; color: rgba(255, 255, 255, .95); }
.ct-tab-0::after { opacity: 1; }

/* jump: the tab hands over partway through the scene */
.ct-stage[data-state="crew"] .ct-tab-0        { animation: ct-tab-off var(--ct-dwell) both; }
.ct-stage[data-state="crew"] .ct-tab-0::after { animation: ct-under-off var(--ct-dwell) both; }
.ct-stage[data-state="crew"] .ct-tab-1        { animation: ct-tab-on var(--ct-dwell) both; }
.ct-stage[data-state="crew"] .ct-tab-1::after { animation: ct-under-on var(--ct-dwell) both; }
@keyframes ct-tab-off {
  0%, 44%   { background: #1d2129; color: rgba(255, 255, 255, .95); }
  56%, 100% { background: rgba(29, 33, 41, 0); color: rgba(255, 255, 255, .45); }
}
@keyframes ct-tab-on {
  0%, 44%   { background: rgba(29, 33, 41, 0); color: rgba(255, 255, 255, .45); }
  56%, 100% { background: #1d2129; color: rgba(255, 255, 255, .95); }
}
@keyframes ct-under-off { 0%, 44% { opacity: 1; } 56%, 100% { opacity: 0; } }
@keyframes ct-under-on  { 0%, 44% { opacity: 0; } 56%, 100% { opacity: 1; } }

.ct-term-body {
  position: relative;
  height: calc(100% - 42px - 41px);
  background: #0d1015;
  overflow: hidden;
}
.ct-pane {
  position: absolute;
  inset: 0;
  padding: 16px 20px;
  font-family: var(--ct-mono);
  font-size: 15px;
  line-height: 1.62;
  color: rgba(238, 235, 250, .9);
  text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
  opacity: 0;
}
.ct-pane-0 { opacity: 1; }
.ct-stage[data-state="crew"] .ct-pane-0 { animation: ct-pane-off var(--ct-dwell) both; }
.ct-stage[data-state="crew"] .ct-pane-1 { animation: ct-pane-on  var(--ct-dwell) both; }
@keyframes ct-pane-off { 0%, 44% { opacity: 1; } 52%, 100% { opacity: 0; } }
@keyframes ct-pane-on  { 0%, 48% { opacity: 0; } 56%, 100% { opacity: 1; } }

.ct-pane b { color: var(--ct-ok); font-weight: 500; }
.ct-pane i { color: rgba(255, 255, 255, .38); font-style: normal; }
.ct-pane u { color: var(--ct-high); text-decoration: none; }
.ct-line {
  height: 24px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Output that only exists once the request has been made and answered.
   Hidden lines take no room, so the caret rides up with them. */
.ct-line-ask, .ct-line-wait, .ct-line-done { height: 0; opacity: 0; }
.ct-stage[data-state="approval"] .ct-line-ask  { animation: ct-line-in var(--ct-dwell) both; }
.ct-stage[data-state="approval"] .ct-line-wait { animation: ct-line-in var(--ct-dwell) both; animation-delay: calc(var(--ct-dwell) * .05); }
.ct-stage[data-state="approval"] .ct-line-done { animation: ct-line-late var(--ct-dwell) both; }
@keyframes ct-line-in   { 0% { height: 0; opacity: 0; } 6%, 100% { height: 24px; opacity: 1; } }
@keyframes ct-line-late { 0%, 62% { height: 0; opacity: 0; } 70%, 100% { height: 24px; opacity: 1; } }

.ct-caret {
  display: inline-block;
  width: 9px;
  height: 17px;
  vertical-align: -3px;
  background: rgba(255, 255, 255, .75);
  animation: ct-blink 1.1s steps(1) infinite;
}
@keyframes ct-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* jump also brings the terminal forward */
.ct-stage[data-state="crew"] .ct-win-term   { animation: ct-raise var(--ct-dwell) both; }
.ct-stage[data-state="crew"] .ct-win-editor { animation: ct-lower var(--ct-dwell) both; }
@keyframes ct-raise {
  0%, 40%   { transform: scale(.985) translate3d(0, 6px, 0); filter: brightness(.72) saturate(.85); }
  52%       { transform: scale(1.012) translate3d(0, -2px, 0); filter: none; }
  60%, 100% { transform: none; filter: none; }
}
@keyframes ct-lower {
  0%, 40%   { transform: none; filter: none; }
  60%, 100% { transform: scale(.985) translate3d(0, 6px, 0); filter: brightness(.7) saturate(.85); }
}

/* ── menu bar ────────────────────────────────────────────────── */

.ct-menubar {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: var(--ct-bar);
  display: flex;
  align-items: center;
  padding: 0 22px;
  /* No fill. A real Mac menu bar is fully transparent - the wallpaper runs
     straight under it and the labels carry their own legibility. The tinted
     strip we had was the single most obvious tell that this was a drawing. */
  background: none;
  font-size: 18px;
  z-index: 10;
}
.ct-mb-l, .ct-mb-r { display: flex; align-items: center; gap: 22px; }
.ct-mb-r { margin-left: auto; }
/* with nothing behind them, the labels need their own shadow */
.ct-menubar span,
.ct-menubar i { text-shadow: 0 1px 3px rgba(8, 12, 28, .45); }
.ct-mb-app { font-weight: 600; color: #fff; }
.ct-mb-l span:not(.ct-mb-app) { color: rgba(255, 255, 255, .8); }
.ct-mb-clock { color: rgba(255, 255, 255, .92); font-variant-numeric: tabular-nums; }

/* ── the notch ───────────────────────────────────────────────── */
/* Flush with the very top edge of the container: square above the
   flare, rounded only below. */

.ct-notch {
  position: absolute;
  top: 0;
  left: 50%;
  width: var(--ct-w);
  margin-left: calc(var(--ct-w) / -2);
  z-index: 30;
  transition: width .46s cubic-bezier(.22, 1, .28, 1), margin-left .46s cubic-bezier(.22, 1, .28, 1);
}
/* Opening the panel is an animation; being resized is not. Without this
   the notch spends half a second sliding to its new geometry every time
   the container changes, which reads as lag. */
.ct-stage.is-fitting .ct-notch,
.ct-stage.is-fitting .ct-notch-body,
.ct-stage.is-fitting .ct-statements { transition: none !important; }
.ct-notch-body {
  position: relative;
  height: var(--ct-h);
  background: #000;
  border-radius: 0 0 var(--ct-br) var(--ct-br);
  overflow: hidden;
  transition: height .46s cubic-bezier(.22, 1, .28, 1), border-radius .46s ease;
}
.ct-notch::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 0 0 var(--ct-br) var(--ct-br);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .62);
  opacity: var(--ct-open);
  transition: opacity .4s ease;
  pointer-events: none;
  z-index: -1;
}

/* NotchShape's outward flare: a quarter circle carved out of a black
   square sitting beside the body. */
.ct-flare { position: absolute; top: 0; width: 16px; height: 16px; }
.ct-flare-l { right: 100%; background: radial-gradient(circle at 0 100%, transparent 15.5px, #000 16px); }
.ct-flare-r { left: 100%;  background: radial-gradient(circle at 100% 100%, transparent 15.5px, #000 16px); }

/* Everything in the bar is a fraction of the bar's height, so the wings,
   the gap, the dots and the character all scale with the notch. */
.ct-bar {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: var(--ct-bar);
  display: flex;
  align-items: center;
}
.ct-wing { display: flex; align-items: center; height: var(--ct-bar); }
.ct-wing-l {
  flex: 1;
  gap: calc(var(--ct-bar) * .167);
  padding-left: calc(var(--ct-bar) * .44);
  opacity: calc(1 - var(--ct-open));
  transition: opacity .3s ease;
}
.ct-gap { width: var(--ct-gap); flex: none; }
.ct-wing-r { flex: 1; justify-content: flex-end; padding-right: calc(var(--ct-bar) * .44); }

/* ── agent brand marks ───────────────────────────────────────── */
/* The app retired the status dot. Every session now wears its agent's own
   logo, and a coloured pip on the corner says what that session wants.
   Ported from AgentIcon / AgentBadge / StatusPip at the scene's 1.5x scale,
   so the app's 20pt mark reads as 30 design px here.

   The logos are template-rendered in SwiftUI, which is a mask: the asset's
   alpha is the shape and the tint is painted through it. A CSS mask does
   exactly the same thing, so the shipped SVGs are reused untouched.

   The mark carries the mask, never the wrapper: a masked element clips its
   own children, and the badge and pip deliberately hang off the corner. */

/* The app draws these at 20pt in a 32pt bar, which is 62.5% of its height
   and leaves 6pt of air. That ratio is right at 1x on a real Mac; here the
   whole scene is scaled to about 0.6, so the same 6pt lands as ~5 css px and
   the bar reads cramped. The mark comes down to 54% of the bar, which is the
   one dimension that can flex: the notch's own height and width are
   calibrated against the implied screen and must not move. */
.ct-agent {
  --ct-agent-size: 26px;
  position: relative;
  flex: none;
  display: block;
  width: var(--ct-agent-size);
  height: var(--ct-agent-size);
}
.ct-agent-mark {
  position: absolute;
  inset: 0;
  background-color: var(--ct-tint, #fff);
  -webkit-mask: var(--ct-src) center / contain no-repeat;
          mask: var(--ct-src) center / contain no-repeat;
}
/* Rotation means "this session is working" and nothing else. A session
   blocked on your answer is not working, so it holds still. */
.ct-agent.is-spinning .ct-agent-mark { animation: ct-agent-spin 4s linear infinite; }
@keyframes ct-agent-spin { to { transform: rotate(360deg); } }

/* The roster, matching AgentIconStyle exactly. Three of the six are white,
   which is what keeps the strip from turning into a fruit salad. */
.ct-agent-claude   { --ct-tint: #d97757; --ct-src: url("assets/brand/claude.svg"); }
.ct-agent-codex    { --ct-tint: #ffffff; --ct-src: url("assets/brand/codex.svg"); }
.ct-agent-cursor   { --ct-tint: #ffffff; --ct-src: url("assets/brand/cursor.svg"); }
.ct-agent-gemini   { --ct-tint: #3186ff; --ct-src: url("assets/brand/gemini.svg"); }
.ct-agent-qwen     { --ct-tint: #6f69f7; --ct-src: url("assets/brand/qwen.svg"); }
.ct-agent-opencode { --ct-tint: #ffffff; --ct-src: url("assets/brand/opencode.svg"); }
.ct-agent-unknown  { --ct-tint: #9e9e9e; --ct-src: url("assets/brand/unknown.svg"); }
/* our own pixel art, so it must not be smoothed */
.ct-agent-unknown .ct-agent-mark { -webkit-mask-size: contain; mask-size: contain; image-rendering: pixelated; }

/* The pip: what this one session is doing, worn on the mark's corner.
   Colours are SessionSignalColors after the app gave green to "done" and
   let "working" go quiet, so only the three states that want something
   from you carry a hue. */
/* Badge and pip are sized off the mark, not in fixed px, so the app's
   proportions survive any change to the mark's size. */
.ct-agent-pip {
  position: absolute;
  top: calc(var(--ct-agent-size) * -.15);
  right: calc(var(--ct-agent-size) * -.2);
  width: calc(var(--ct-agent-size) * .4);
  height: calc(var(--ct-agent-size) * .4);
  border-radius: 50%;
  background: var(--ct-pip, var(--ct-pip-working));
  /* a dark collar, so the pip reads as an object sitting on the mark */
  box-shadow: 0 0 0 2.25px #000;
}
.ct-pip-working { --ct-pip: var(--ct-pip-working); }
.ct-pip-perm    { --ct-pip: var(--ct-attention); }
.ct-pip-ask     { --ct-pip: var(--ct-asking); }
.ct-pip-done    { --ct-pip: var(--ct-pip-done); }
.ct-pip-idle    { --ct-pip: var(--ct-pip-idle); }

/* The badge: how many of this brand's sessions want you. Never drawn at
   zero, so a busy-but-not-blocked brand stays quiet. */
.ct-badge {
  position: absolute;
  top: calc(var(--ct-agent-size) * -.2);
  right: calc(var(--ct-agent-size) * -.25);
  min-width: calc(var(--ct-agent-size) * .55);
  height: calc(var(--ct-agent-size) * .55);
  padding: 0 calc(var(--ct-agent-size) * .1);
  border-radius: 999px;
  font-size: calc(var(--ct-agent-size) * .4);
  font-weight: 700;
  line-height: 1;
  background: #ff5f57;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 0 2.25px #000;
  opacity: 0;
  transform: scale(.6);
}
.ct-stage[data-state="approval"] .ct-badge-claude,
.ct-stage[data-state="plan"] .ct-badge-claude,
.ct-stage[data-state="ask"] .ct-badge-cursor { animation: ct-badge var(--ct-dwell) both; }
@keyframes ct-badge {
  0%        { opacity: 0; transform: scale(.6); }
  4%, 62%   { opacity: 1; transform: scale(1); }
  70%, 100% { opacity: 0; transform: scale(.6); }
}

/* The blocked session stops spinning and its pip takes the state's colour,
   for exactly as long as the badge is up. */
.ct-stage[data-state="approval"] .ct-card-permission .ct-agent-pip,
.ct-stage[data-state="approval"] .ct-agent-claude .ct-agent-pip,
.ct-stage[data-state="plan"] .ct-card-plan .ct-agent-pip,
.ct-stage[data-state="plan"] .ct-agent-claude .ct-agent-pip {
  animation: ct-pip-perm var(--ct-dwell) both;
}
.ct-stage[data-state="ask"] .ct-card-question .ct-agent-pip,
.ct-stage[data-state="ask"] .ct-agent-cursor .ct-agent-pip {
  animation: ct-pip-ask var(--ct-dwell) both;
}
@keyframes ct-pip-perm {
  0%, 62%   { background: var(--ct-attention); }
  70%, 100% { background: var(--ct-pip-done); }
}
@keyframes ct-pip-ask {
  0%, 62%   { background: var(--ct-asking); }
  70%, 100% { background: var(--ct-pip-done); }
}

/* ── mascots ─────────────────────────────────────────────────── */
/* Mood follows the crew, exactly as CharacterDirector does in the app:
     any session working        -> active
     a session needs attention  -> alert (resting if that character has
                                   no alert strip, which is the app's
                                   own fallback)
     a request just answered    -> celebrate, briefly
     nothing running            -> resting
   Since each scene *is* a crew state, the moods below are that mapping:
     crew      every session working          -> active
     approval  one blocked, then answered     -> alert, then celebrate
     ask       one asking, then answered      -> alert, then celebrate
     plan      one blocked, then answered     -> alert, then celebrate
     quota     every session working          -> active
     character every session working          -> active, cast rotating

   Each strip is cropped to its alpha content box, unioned across that
   character's moods so it cannot jump when the mood changes - the same
   thing CharacterFrames.contentBox does - and drawn at 1x, a whole
   number, never a fraction. Measured off the shipped PNGs:
     cat 58x46 @(0,18)   bunny 32x26 @(0,6)    ghost 25x29 @(1,3)
     mushroom 31x35 @(24,29)                   samurai 69x48 @(27,21)
   The samurai carries scale 1.3 in its manifest and is duly the
   tallest of the five at 48px. */

.ct-mascot {
  position: relative;
  width: 69px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: scale(var(--ct-mascot-k));
  transform-origin: center right;
}
.ct-sprite {
  position: absolute;
  display: block;
  image-rendering: pixelated;
  background-repeat: no-repeat;
  opacity: 0;
  will-change: background-position;
}

/* cat - 64x64 cell */
.ct-cat { width: 58px; height: 46px; background-position: 0 -18px; }
.ct-cat-idle  { background-image: url("assets/characters/cat-idle.png");    background-size: 384px 64px; animation: ct-cat-6 1s    steps(6) infinite; }
.ct-cat-run   { background-image: url("assets/characters/cat-running.png"); background-size: 384px 64px; animation: ct-cat-6 .5s   steps(6) infinite; }
.ct-cat-alert { background-image: url("assets/characters/cat-alert.png");   background-size: 256px 64px; animation: ct-cat-4 .5s   steps(4) infinite; }
.ct-cat-happy { background-image: url("assets/characters/cat-happy.png");   background-size: 640px 64px; animation: ct-cat-10 .833s steps(10) infinite; }
@keyframes ct-cat-6  { from { background-position-x: 0; } to { background-position-x: -384px; } }
@keyframes ct-cat-4  { from { background-position-x: 0; } to { background-position-x: -256px; } }
@keyframes ct-cat-10 { from { background-position-x: 0; } to { background-position-x: -640px; } }

/* bunny - 32x32 cell, no alert strip: falls back to resting */
.ct-bunny { width: 32px; height: 26px; background-position: 0 -6px; }
.ct-bunny-idle { background-image: url("assets/characters/bunny-idle.png");    background-size: 384px 32px; animation: ct-bun-12 1.5s  steps(12) infinite; }
.ct-bunny-run  { background-image: url("assets/characters/bunny-running.png"); background-size: 256px 32px; animation: ct-bun-8  .667s steps(8)  infinite; }
@keyframes ct-bun-12 { from { background-position-x: 0; } to { background-position-x: -384px; } }
@keyframes ct-bun-8  { from { background-position-x: 0; } to { background-position-x: -256px; } }

/* ghost - 32x32 cell */
.ct-ghost { width: 25px; height: 29px; background-position: -1px -3px; }
.ct-ghost-idle  { background-image: url("assets/characters/ghost-idle.png");    background-size: 256px 32px; animation: ct-gh-8  1.333s steps(8)  infinite; }
.ct-ghost-run   { background-image: url("assets/characters/ghost-running.png"); background-size: 256px 32px; animation: ct-gh-8  .8s    steps(8)  infinite; }
.ct-ghost-alert { background-image: url("assets/characters/ghost-alert.png");   background-size: 480px 32px; animation: ct-gh-15 1.5s   steps(15) infinite; }
@keyframes ct-gh-8  { from { background-position-x: -1px; } to { background-position-x: -257px; } }
@keyframes ct-gh-15 { from { background-position-x: -1px; } to { background-position-x: -481px; } }

/* mushroom - 80x64 cell, no alert strip */
.ct-mushroom { width: 31px; height: 35px; background-position: -24px -29px; }
.ct-mushroom-idle { background-image: url("assets/characters/mushroom-idle.png");    background-size: 560px 64px; animation: ct-mu-7 1s  steps(7) infinite; }
.ct-mushroom-run  { background-image: url("assets/characters/mushroom-running.png"); background-size: 640px 64px; animation: ct-mu-8 .8s steps(8) infinite; }
@keyframes ct-mu-7 { from { background-position-x: -24px; } to { background-position-x: -584px; } }
@keyframes ct-mu-8 { from { background-position-x: -24px; } to { background-position-x: -664px; } }

/* samurai - 96x96 cell */
.ct-samurai { width: 69px; height: 48px; background-position: -27px -21px; }
.ct-samurai-idle  { background-image: url("assets/characters/samurai-idle.png");    background-size: 480px 96px; animation: ct-sa-5 .833s steps(5) infinite; }
.ct-samurai-run   { background-image: url("assets/characters/samurai-running.png"); background-size: 768px 96px; animation: ct-sa-8 .667s steps(8) infinite; }
.ct-samurai-alert { background-image: url("assets/characters/samurai-alert.png");   background-size: 576px 96px; animation: ct-sa-6 .429s steps(6) infinite; }
@keyframes ct-sa-5 { from { background-position-x: -27px; } to { background-position-x: -507px; } }
@keyframes ct-sa-8 { from { background-position-x: -27px; } to { background-position-x: -795px; } }
@keyframes ct-sa-6 { from { background-position-x: -27px; } to { background-position-x: -603px; } }

/* The crew is working: the cat runs. */
.ct-stage[data-state="crew"] .ct-cat-run,
.ct-stage[data-state="quota"]   .ct-cat-run { opacity: 1; }

/* One is blocked: alert, then delighted the moment it is answered. */
.ct-stage[data-state="approval"] .ct-cat-alert,
.ct-stage[data-state="ask"]      .ct-cat-alert,
.ct-stage[data-state="plan"]     .ct-cat-alert {
  animation: ct-cat-4 .5s steps(4) infinite, ct-mood-out var(--ct-dwell) both;
}
.ct-stage[data-state="approval"] .ct-cat-happy,
.ct-stage[data-state="ask"]      .ct-cat-happy,
.ct-stage[data-state="plan"]     .ct-cat-happy {
  animation: ct-cat-10 .833s steps(10) infinite, ct-mood-in var(--ct-dwell) both;
}
@keyframes ct-mood-out { 0%, 62% { opacity: 1; } 68%, 100% { opacity: 0; } }
@keyframes ct-mood-in  { 0%, 62% { opacity: 0; } 68%, 100% { opacity: 1; } }

/* The character scene hands the wing round the whole cast - all of them
   in their active mood, because the crew is working the whole time. */
.ct-stage[data-state="character"] .ct-cat-run      { animation: ct-cat-6 .5s steps(6) infinite,   ct-char-1 var(--ct-dwell) both; }
.ct-stage[data-state="character"] .ct-bunny-run    { animation: ct-bun-8 .667s steps(8) infinite, ct-char-2 var(--ct-dwell) both; }
.ct-stage[data-state="character"] .ct-mushroom-run { animation: ct-mu-8 .8s steps(8) infinite,    ct-char-3 var(--ct-dwell) both; }
.ct-stage[data-state="character"] .ct-ghost-run    { animation: ct-gh-8 .8s steps(8) infinite,    ct-char-4 var(--ct-dwell) both; }
.ct-stage[data-state="character"] .ct-samurai-run  { animation: ct-sa-8 .667s steps(8) infinite,  ct-char-5 var(--ct-dwell) both; }
@keyframes ct-char-1 { 0%, 12% { opacity: 1; } 17%, 82% { opacity: 0; } 87%, 100% { opacity: 1; } }
@keyframes ct-char-2 { 0%, 12% { opacity: 0; } 17%, 29% { opacity: 1; } 34%, 100% { opacity: 0; } }
@keyframes ct-char-3 { 0%, 29% { opacity: 0; } 34%, 46% { opacity: 1; } 51%, 100% { opacity: 0; } }
@keyframes ct-char-4 { 0%, 46% { opacity: 0; } 51%, 63% { opacity: 1; } 68%, 100% { opacity: 0; } }
@keyframes ct-char-5 { 0%, 63% { opacity: 0; } 68%, 82% { opacity: 1; } 87%, 100% { opacity: 0; } }

/* ── the loupe ───────────────────────────────────────────────── */
/* A real notch gives the character 32pt, which is right in the app and far
   too small to introduce five of them on a web page. So the character scene
   holds a lens under the bar rather than drawing the mascot larger than one
   ever is. The copy inside it is the same markup from the same function,
   driven by the same mood selectors, so the two can never disagree.

   Placed under the right wing: the mascot's centre sits 286 design px right
   of the notch's centre line, and the lens hangs directly below it, in
   wallpaper every scene leaves empty.

   Its size is the character's, not a number of its own: the mascot's cell is
   69x48 and the lens is 72 times whatever multiple that cell is being drawn
   at, which holds the cat with air around it and lets the samurai's two
   empty corners fall outside the circle. Change --ct-lens-k and the circle
   follows; there is nothing here to keep in step by hand. */
.ct-lens {
  position: absolute;
  left: 50%;
  top: 78px;
  margin-left: calc(286px - var(--ct-lens-k, 3) * 36px);
  width: calc(var(--ct-lens-k, 3) * 72px);
  height: calc(var(--ct-lens-k, 3) * 72px);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  opacity: 0;
  z-index: 25;
  pointer-events: none;
  transform: scale(.86);
  /* Glass in a bezel: the panel's own dark material, a bright rim, and light
     gathering along the top edge. Without the rim it reads as a hole cut in
     the wallpaper rather than as something held over it. */
  background:
    radial-gradient(120% 120% at 28% 16%, rgba(255, 255, 255, .13), transparent 58%),
    rgba(16, 16, 24, .88);
  box-shadow:
    0 30px 70px rgba(0, 0, 0, .45),
    0 0 0 1px rgba(255, 255, 255, .14),
    inset 0 0 0 3px rgba(255, 255, 255, .26),
    inset 0 9px 28px rgba(255, 255, 255, .09);
}
/* the specular streak, over everything including the character */
.ct-lens::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: linear-gradient(148deg, rgba(255, 255, 255, .12) 0 22%, transparent 44%);
}
.ct-lens .ct-mascot {
  transform: scale(var(--ct-lens-k, 3));
  transform-origin: center;
}
.ct-stage[data-state="character"] .ct-lens { animation: ct-lens-in var(--ct-dwell) both; }
@keyframes ct-lens-in {
  0%       { opacity: 0; transform: scale(.86); }
  16%, 86% { opacity: 1; transform: scale(1); }
  100%     { opacity: 0; transform: scale(.93); }
}

/* ── the panel ───────────────────────────────────────────────── */

.ct-panel {
  position: absolute;
  top: var(--ct-bar); left: 0;
  width: var(--ct-panel);
  opacity: 0;
  transition: opacity .26s ease;
}
.ct-stage[data-state="crew"] .ct-panel,
.ct-stage[data-state="approval"] .ct-panel,
.ct-stage[data-state="ask"] .ct-panel,
.ct-stage[data-state="plan"] .ct-panel,
.ct-stage[data-state="quota"] .ct-panel { opacity: 1; transition-delay: .12s; }

.ct-card {
  position: absolute;
  top: 0; left: 0;
  width: var(--ct-panel);
  padding: 9px 18px 18px;
  opacity: 0;
  transition: opacity .26s ease;
}
.ct-stage[data-state="approval"] .ct-card-permission,
.ct-stage[data-state="ask"] .ct-card-question,
.ct-stage[data-state="plan"] .ct-card-plan,
.ct-stage[data-state="crew"] .ct-card-list,
.ct-stage[data-state="quota"] .ct-card-list { opacity: 1; }

.ct-row {
  padding: 12px 18px;
  border-radius: 21px;
  background: rgba(255, 255, 255, .06);
  box-shadow: inset 0 0 0 1px transparent;
}
.ct-row + .ct-row { margin-top: 9px; }

.ct-stage[data-state="approval"] .ct-card-permission .ct-row,
.ct-stage[data-state="plan"] .ct-card-plan .ct-row { animation: ct-edge-warm var(--ct-dwell) both; }
.ct-stage[data-state="ask"] .ct-card-question .ct-row { animation: ct-edge-ask var(--ct-dwell) both; }
@keyframes ct-edge-warm {
  0%, 62%   { box-shadow: inset 0 0 0 1px rgba(255, 159, 46, .55); }
  70%, 100% { box-shadow: inset 0 0 0 1px rgba(78, 201, 127, .5); }
}
@keyframes ct-edge-ask {
  0%, 62%   { box-shadow: inset 0 0 0 1px rgba(89, 166, 255, .55); }
  70%, 100% { box-shadow: inset 0 0 0 1px rgba(78, 201, 127, .5); }
}

.ct-stage[data-state="crew"] .ct-row-jump { animation: ct-row-hover var(--ct-dwell) both; }
@keyframes ct-row-hover {
  0%, 26%   { background: rgba(255, 255, 255, .06); }
  32%, 48%  { background: rgba(255, 255, 255, .12); }
  56%, 100% { background: rgba(255, 255, 255, .06); }
}

.ct-row-head { display: flex; align-items: flex-start; gap: 15px; }
.ct-row-head > .ct-agent { margin-top: 3px; }
.ct-row-main { flex: 1; min-width: 0; }

.ct-row-top { height: 24px; display: flex; align-items: center; gap: 9px; }
.ct-project { font-size: 20px; font-weight: 600; letter-spacing: -.01em; color: #fff; }
.ct-row-top .ct-spacer { flex: 1; }
.ct-chip {
  font-size: 13px;
  font-weight: 500;
  color: rgba(255, 255, 255, .7);
  background: rgba(255, 255, 255, .1);
  border-radius: 6px;
  padding: 3px 8px;
  white-space: nowrap;
}
.ct-elapsed { font-size: 15px; color: rgba(255, 255, 255, .45); white-space: nowrap; }

.ct-status {
  height: 21px;
  margin-top: 5px;
  font-family: var(--ct-mono);
  font-size: 16px;
  color: rgba(255, 255, 255, .55);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ct-status-attention { color: var(--ct-attention); }
.ct-status-asking    { color: var(--ct-asking); }
.ct-stage[data-state="approval"] .ct-status-attention,
.ct-stage[data-state="plan"] .ct-status-attention { animation: ct-cool-warm var(--ct-dwell) both; }
.ct-stage[data-state="ask"] .ct-status-asking { animation: ct-cool-ask var(--ct-dwell) both; }
@keyframes ct-cool-warm { 0%, 62% { color: var(--ct-attention); } 70%, 100% { color: rgba(255, 255, 255, .55); } }
@keyframes ct-cool-ask  { 0%, 62% { color: var(--ct-asking);    } 70%, 100% { color: rgba(255, 255, 255, .55); } }


.ct-detail { padding-left: 26px; margin-top: 9px; }
.ct-risk {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 20px;
  font-size: 15px;
  font-weight: 500;
  color: var(--ct-high);
}
.ct-stage[data-state="approval"] .ct-risk { animation: ct-risk-out var(--ct-dwell) both; }
@keyframes ct-risk-out { 0%, 62% { opacity: 1; } 70%, 100% { opacity: 0; } }

.ct-code {
  margin-top: 9px;
  padding: 12px;
  border-radius: 9px;
  background: rgba(255, 255, 255, .07);
  font-family: var(--ct-mono);
  font-size: 15px;
  color: rgba(255, 255, 255, .85);
}

.ct-actions {
  position: relative;
  height: 33px;
  margin-top: 9px;
  display: flex;
  align-items: center;
}
.ct-buttons { display: flex; align-items: center; gap: 9px; }
.ct-btn {
  height: 33px;
  padding: 0 15px;
  border-radius: 17px;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 15px;
  font-weight: 600;
  color: rgba(255, 255, 255, .85);
  background: rgba(255, 255, 255, .12);
  white-space: nowrap;
}
.ct-btn-allow { color: rgba(0, 0, 0, .9); background: var(--ct-attention); padding-right: 0; }
.ct-btn-allow .ct-btn-split { width: 1px; height: 20px; margin-left: 12px; background: rgba(0, 0, 0, .2); }
.ct-btn-allow .ct-btn-chev { padding: 0 12px; display: flex; align-items: center; }

.ct-resolved {
  position: absolute;
  left: 0; top: 0;
  height: 33px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 16px;
  color: rgba(255, 255, 255, .72);
  opacity: 0;
}
.ct-stage[data-state="approval"] .ct-card-permission .ct-buttons,
.ct-stage[data-state="ask"] .ct-card-question .ct-buttons,
.ct-stage[data-state="plan"] .ct-card-plan .ct-buttons { animation: ct-btns-out var(--ct-dwell) both; }
.ct-stage[data-state="approval"] .ct-card-permission .ct-resolved,
.ct-stage[data-state="ask"] .ct-card-question .ct-resolved,
.ct-stage[data-state="plan"] .ct-card-plan .ct-resolved { animation: ct-resolved-in var(--ct-dwell) both; }
@keyframes ct-btns-out    { 0%, 60% { opacity: 1; } 66%, 100% { opacity: 0; } }
@keyframes ct-resolved-in { 0%, 66% { opacity: 0; } 72%, 100% { opacity: 1; } }

.ct-stage[data-state="approval"] .ct-card-permission .ct-btn-allow,
.ct-stage[data-state="plan"] .ct-card-plan .ct-btn-allow { animation: ct-press var(--ct-dwell) both; }
@keyframes ct-press {
  0%, 54%   { transform: none; box-shadow: none; }
  58%       { transform: scale(.94); box-shadow: 0 0 0 5px rgba(255, 159, 46, .3); }
  62%, 100% { transform: none; box-shadow: none; }
}

.ct-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 11px;
  background: rgba(255, 255, 255, .10);
  box-shadow: inset 0 0 0 1px transparent;
}
.ct-opt + .ct-opt { margin-top: 7px; }
.ct-opt-no {
  width: 20px; height: 20px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .15);
  color: rgba(255, 255, 255, .8);
  font-size: 13px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.ct-opt-label { font-size: 16px; color: rgba(255, 255, 255, .9); }
.ct-opt-detail { font-size: 15px; color: rgba(255, 255, 255, .5); margin-left: auto; }

.ct-stage[data-state="ask"] .ct-opt-2 { animation: ct-pick var(--ct-dwell) both; }
.ct-stage[data-state="ask"] .ct-opt-2 .ct-opt-no { animation: ct-pick-no var(--ct-dwell) both; }
@keyframes ct-pick {
  0%, 52%   { background: rgba(255, 255, 255, .10); box-shadow: inset 0 0 0 1px rgba(89, 166, 255, 0); }
  58%, 100% { background: rgba(89, 166, 255, .16);  box-shadow: inset 0 0 0 1px rgba(89, 166, 255, .6); }
}
@keyframes ct-pick-no {
  0%, 52%   { background: rgba(255, 255, 255, .15); color: rgba(255, 255, 255, .8); }
  58%, 100% { background: var(--ct-asking); color: rgba(0, 0, 0, .85); }
}

/* ── the plan card ───────────────────────────────────────────── */
/* The app gives a plan the tallest well any tool detail gets - 260pt of a
   760pt panel - because a plan is meant to be read rather than glanced at.
   This crop cannot afford all of it: the statement sits 452 design px down
   the canvas, so the open notch has to finish above that, and a full-height
   well would run the card straight through the headline. The window is
   shorter here and the plan is longer than one, which is the trade that
   keeps the scrolling the point of the scene rather than a detail of it. */
.ct-plan {
  position: relative;
  height: 220px;
  border-radius: 12px;
  background: rgba(255, 255, 255, .05);
  overflow: hidden;
}
.ct-plan-scroll { padding: 10px 14px; will-change: transform; }
/* PlanMarkdown's blocks, at the app's own rhythm: one spacing between every
   block, a heading belonging to what follows it rather than what it follows. */
.ct-plan-scroll > * + * { margin-top: 10px; }
.ct-plan-h + * { margin-top: 7px; }
.ct-plan-h { font-size: 19px; font-weight: 600; line-height: 1.4; color: #fff; }
.ct-plan-p { font-size: 16px; line-height: 1.45; color: rgba(255, 255, 255, .86); }
.ct-plan-li {
  display: flex;
  gap: 9px;
  font-size: 16px;
  line-height: 1.45;
  color: rgba(255, 255, 255, .86);
}
.ct-plan-li > b {
  flex: none;
  min-width: 17px;
  text-align: right;
  font-weight: 400;
  color: rgba(255, 255, 255, .45);
}
.ct-plan-li i { font-style: normal; color: rgba(255, 255, 255, .45); }
.ct-plan-code {
  padding: 9px 13px;
  border-radius: 9px;
  background: rgba(255, 255, 255, .07);
  font-family: var(--ct-mono);
  font-size: 15px;
  line-height: 1.5;
  color: rgba(255, 255, 255, .8);
}

/* The scroll itself. Held still at either end so the plan can be read
   before it moves and the decision can land after it stops. */
.ct-stage[data-state="plan"] .ct-plan-scroll { animation: ct-plan-scroll var(--ct-dwell) both; }
@keyframes ct-plan-scroll {
  0%, 16%   { transform: translate3d(0, 0, 0); }
  50%, 100% { transform: translate3d(0, -300px, 0); }
}

/* macOS overlay scrollbar: appears with the scroll, fades once it stops. */
.ct-plan-thumb {
  position: absolute;
  top: 6px; right: 5px;
  width: 5px;
  /* The thumb is the window's share of the plan, and it travels the same
     share of its track that the plan travels of its own length. */
  height: 78px;
  border-radius: 3px;
  background: rgba(255, 255, 255, .28);
  opacity: 0;
}
.ct-stage[data-state="plan"] .ct-plan-thumb { animation: ct-plan-thumb var(--ct-dwell) both; }
@keyframes ct-plan-thumb {
  0%, 12%   { opacity: 0; transform: translate3d(0, 0, 0); }
  18%       { opacity: 1; transform: translate3d(0, 0, 0); }
  50%       { opacity: 1; transform: translate3d(0, 107px, 0); }
  64%, 100% { opacity: 0; transform: translate3d(0, 107px, 0); }
}

/* ── the quota strip ─────────────────────────────────────────── */
/* UsageStrip: the account it is reporting, then one gauge per window. It is
   the footer of the open panel in the app, so it is the footer of the list
   card here - present in the crew scene too, not summoned for its own. */
.ct-usage {
  position: relative;
  display: flex;
  align-items: center;
  gap: 18px;
  height: 18px;
  margin-top: 8px;
  /* aligned with the row content above it, not with the card's edge */
  padding: 0 18px;
  /* the corner it is pinned to, so magnifying it in the quota scene grows it
     into the panel rather than off the bottom edge of the notch */
  transform-origin: left bottom;
}
/* The light that comes up with it. Sized off the strip, so it tracks
   whatever the strip's own scale is doing. */
.ct-usage::before {
  content: "";
  position: absolute;
  inset: -16px -28px -14px -8px;
  border-radius: 22px;
  background: radial-gradient(58% 150% at 26% 50%, rgba(255, 255, 255, .12), transparent 72%);
  opacity: 0;
}
.ct-usage-account { font-size: 14px; font-weight: 600; color: rgba(255, 255, 255, .5); }
.ct-gauge { display: flex; align-items: center; gap: 9px; }
.ct-gauge-name { font-size: 14px; font-weight: 500; color: rgba(255, 255, 255, .62); }
.ct-gauge-track {
  width: 66px; height: 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, .10);
  overflow: hidden;
}
.ct-gauge-fill {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: rgba(255, 255, 255, .35);
  transform-origin: left center;
}
/* The same bands the context ring uses, so a full week and a full context
   window read as the same kind of warning. */
.ct-gauge-fill.is-warm { background: var(--ct-attention); }
.ct-gauge-num {
  font-size: 14px;
  font-weight: 500;
  color: rgba(255, 255, 255, .62);
  font-variant-numeric: tabular-nums;
}
/* The strip stands in for part of the card's bottom air, the way the app's
   footer does - but not all of it: the open notch's corner radius is 45px,
   and a strip run right into that curve reads as something that fell out. */
.ct-card-list { padding-bottom: 14px; }

/* The quota scene is the same panel as the crew scene; only the eye moves.
   The strip is a wide, short thing, so this is where the magnifying happens
   in place rather than under a round lens: it grows out of the corner it is
   pinned to while the list behind it recedes. The list stays legible rather
   than leaving, because a strip pinned under a list is exactly what it has
   to compete with, and a panel that emptied itself would be a different
   panel than the one the app shows. */
.ct-stage[data-state="quota"] .ct-card-list .ct-row { animation: ct-recede var(--ct-dwell) both; }
@keyframes ct-recede { 0%, 12% { opacity: 1; } 36%, 100% { opacity: .28; } }
.ct-stage[data-state="quota"] .ct-usage { animation: ct-usage-up var(--ct-dwell) both; }
@keyframes ct-usage-up {
  0%, 12%   { opacity: .7; transform: scale(1); }
  40%, 100% { opacity: 1; transform: scale(1.7); }
}
.ct-stage[data-state="quota"] .ct-usage::before { animation: ct-usage-glow var(--ct-dwell) both; }
@keyframes ct-usage-glow { 0%, 12% { opacity: 0; } 40%, 100% { opacity: 1; } }
.ct-stage[data-state="quota"] .ct-gauge-fill { animation: ct-gauge-fill var(--ct-dwell) both; }
@keyframes ct-gauge-fill { 0%, 12% { transform: scaleX(0); } 46%, 100% { transform: scaleX(1); } }

.ct-ring { display: flex; align-items: center; gap: 6px; }
.ct-ring svg { width: 17px; height: 17px; }
.ct-ring circle { fill: none; stroke-width: 3; }
.ct-ring .ct-ring-bg { stroke: rgba(255, 255, 255, .14); }
.ct-ring .ct-ring-fg { stroke: var(--ct-ok); stroke-linecap: round; }
.ct-ring-num { font-size: 15px; font-weight: 500; color: rgba(255, 255, 255, .5); font-variant-numeric: tabular-nums; }
.ct-ring-high .ct-ring-fg { stroke: var(--ct-high); }
.ct-ring-high .ct-ring-num { color: var(--ct-high); }

/* The Allow scope menu is a real menu: it floats over the panel, and it
   is positioned from the centre line like everything else in the card. */
.ct-scopemenu {
  position: absolute;
  left: 50%;
  top: 250px;
  margin-left: -307px;
  width: 258px;
  padding: 6px;
  border-radius: 14px;
  background: rgba(38, 38, 42, .98);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .55), inset 0 0 0 1px rgba(255, 255, 255, .09);
  opacity: 0;
  transform: translate3d(0, -8px, 0) scale(.97);
  transform-origin: top left;
  pointer-events: none;
  z-index: 40;
}
.ct-scopemenu div {
  height: 32px;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 12px;
  border-radius: 9px;
  font-size: 16px;
  color: rgba(255, 255, 255, .9);
}
.ct-scopemenu i { width: 6px; height: 6px; border-radius: 50%; background: var(--ct-attention); }
.ct-stage[data-state="approval"] .ct-scopemenu { animation: ct-scope var(--ct-dwell) both; }
@keyframes ct-scope {
  0%, 18%   { opacity: 0; transform: translate3d(0, -8px, 0) scale(.97); }
  24%, 40%  { opacity: 1; transform: none; }
  46%, 100% { opacity: 0; transform: translate3d(0, -8px, 0) scale(.97); }
}

/* ── pointer ─────────────────────────────────────────────────── */
/* Everything it aims at sits inside the centred panel, so every target
   is a fixed offset from the canvas centre line at any aspect ratio.
   Keep these in step with the card layout above. */

.ct-cursor {
  position: absolute;
  left: 50%; top: 0;
  width: 24px; height: 34px;
  opacity: 0;
  z-index: 50;
  pointer-events: none;
  transform: translate3d(340px, 560px, 0);
  will-change: transform;
}
.ct-cursor svg { filter: drop-shadow(0 2px 5px rgba(0, 0, 0, .6)); }

.ct-stage[data-state="approval"] .ct-cursor { animation: ct-path-approve var(--ct-dwell) both; }
@keyframes ct-path-approve {
  0%        { opacity: 0; transform: translate3d(340px, 560px, 0); }
  8%        { opacity: 1; transform: translate3d(340px, 560px, 0); }
  20%, 46%  { opacity: 1; transform: translate3d(-295px, 224px, 0); }  /* the chevron */
  56%, 76%  { opacity: 1; transform: translate3d(-360px, 224px, 0); }  /* Allow */
  90%, 100% { opacity: 0; transform: translate3d(-344px, 250px, 0); }
}

.ct-stage[data-state="ask"] .ct-cursor { animation: ct-path-ask var(--ct-dwell) both; }
@keyframes ct-path-ask {
  0%        { opacity: 0; transform: translate3d(340px, 560px, 0); }
  10%       { opacity: 1; transform: translate3d(340px, 560px, 0); }
  50%, 76%  { opacity: 1; transform: translate3d(-400px, 192px, 0); }  /* option 2 */
  90%, 100% { opacity: 0; transform: translate3d(-384px, 218px, 0); }
}

.ct-stage[data-state="crew"] .ct-cursor { animation: ct-path-jump var(--ct-dwell) both; }
@keyframes ct-path-jump {
  0%        { opacity: 0; transform: translate3d(340px, 560px, 0); }
  8%        { opacity: 1; transform: translate3d(340px, 560px, 0); }
  30%, 52%  { opacity: 1; transform: translate3d(-400px, 177px, 0); }  /* the api-gateway row */
  70%, 100% { opacity: 0; transform: translate3d(-384px, 203px, 0); }
}

/* The plan pointer rests over the well while it scrolls - which is where a
   trackpad scroll happens - and only then goes for the decision. */
.ct-stage[data-state="plan"] .ct-cursor { animation: ct-path-plan var(--ct-dwell) both; }
@keyframes ct-path-plan {
  0%        { opacity: 0; transform: translate3d(340px, 560px, 0); }
  6%        { opacity: 1; transform: translate3d(340px, 560px, 0); }
  16%, 50%  { opacity: 1; transform: translate3d(-120px, 240px, 0); }  /* over the plan */
  58%, 78%  { opacity: 1; transform: translate3d(-263px, 369px, 0); }  /* Approve */
  90%, 100% { opacity: 0; transform: translate3d(-247px, 395px, 0); }
}

/* ── the statement ───────────────────────────────────────────── */
/* The loudest thing in the scene, and the reason the windows are held
   to the right of the centre line: this column of wallpaper is kept
   clear for it at every canvas width. */

.ct-statements {
  position: absolute;
  left: max(56px, calc(50% - 840px));
  top: 452px;
  width: min(660px, calc(50% - 130px));
  z-index: 20;
  pointer-events: none;
}
.ct-statement {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition: opacity .45s ease, transform .45s cubic-bezier(.22, 1, .28, 1);
}
.ct-statement-head {
  margin: 0;
  font-family: var(--ct-display);
  font-weight: 500;
  font-size: 50px;
  letter-spacing: -.026em;
  line-height: 1.06;
  letter-spacing: -.015em;
  color: #fff;
  text-wrap: balance;
  text-shadow: 0 2px 30px rgba(0, 0, 0, .45);
}
.ct-statement-sub {
  margin: 16px 0 0;
  font-family: var(--ct-sans);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.5;
  color: rgba(255, 255, 255, .62);
  max-width: 34em;
  text-shadow: 0 1px 16px rgba(0, 0, 0, .5);
}
.ct-stage[data-state="crew"]     .ct-statement[data-scene="crew"],
.ct-stage[data-state="approval"]  .ct-statement[data-scene="approval"],
.ct-stage[data-state="ask"]       .ct-statement[data-scene="ask"],
.ct-stage[data-state="plan"]      .ct-statement[data-scene="plan"],
.ct-stage[data-state="quota"]     .ct-statement[data-scene="quota"],
.ct-stage[data-state="character"] .ct-statement[data-scene="character"] {
  opacity: 1;
  transform: none;
  transition-delay: .16s;
}

/* ── compact: a crop, not a smaller scene ────────────────────── */
/* Under 700px - or wherever the desktop stops being legible - the frame
   becomes a zoomed view of the top-centre of a Mac display. The implied
   screen runs off both edges, so the menu bar continues past the frame
   the way a crop does; the notch keeps its authored 669x48 geometry and
   its sprites keep drawing at 1x, and the card is sized to the frame.
   hero-demo.js sets --ct-screen-w, --ct-panel and --ct-gutter here. */

.ct-stage[data-size="compact"] .ct-win-editor,
.ct-stage[data-size="compact"] .ct-scopemenu,
.ct-stage[data-size="compact"] .ct-cursor { display: none; }

/* The crop has no room beside the notch, and it needs the loupe more than
   the desktop does, not less: a phone draws the character at 11 css px. So
   here the lens sits below the statement, on the centre line, in the
   wallpaper the crop has going spare underneath. It follows the notch the
   way the statement does, clearing the statement's own two lines. */
/* No transition on `top`: the lens is only ever seen in the character scene,
   where the notch is closed and this resolves to the same number every time.
   A transition here would only ever be caught mid-flight by a resize. */
.ct-stage[data-size="compact"] .ct-lens {
  top: calc(var(--ct-h) + 308px);
  margin-left: calc(var(--ct-lens-k, 2) * -36px);
}

/* the menu bar belongs to the implied screen, not to the frame */
.ct-stage[data-size="compact"] .ct-menubar {
  width: var(--ct-screen-w, 2230px);
  left: 50%;
  margin-left: calc(var(--ct-screen-w, 2230px) / -2);
  padding: 0 40px;
}

/* The terminal stays, but only as a suggestion along the bottom edge -
   enough to keep the tab bar visible, which is the whole point of the
   jump scene, without asking anyone to read a terminal on a phone. */
.ct-stage[data-size="compact"] .ct-win-term {
  width: 94%;
  margin-left: -47%;
  height: 340px;
  top: auto;
  bottom: -186px;
  animation: none !important;
  transform: none !important;
  filter: none !important;
}
.ct-stage[data-size="compact"] .ct-tab-3 { display: none; }
.ct-stage[data-size="compact"] .ct-tab { font-size: 21px; }
.ct-stage[data-size="compact"] .ct-tabs { height: 56px; padding: 8px 10px 0; }
.ct-stage[data-size="compact"] .ct-tab { height: 48px; }
.ct-stage[data-size="compact"] .ct-win-title { height: 56px; }
.ct-stage[data-size="compact"] .ct-win-name { font-size: 21px; }
.ct-stage[data-size="compact"] .ct-light { width: 17px; height: 17px; }
.ct-stage[data-size="compact"] .ct-term-body { height: calc(100% - 56px - 56px); }
.ct-stage[data-size="compact"] .ct-pane { font-size: 22px; padding: 18px 20px; line-height: 1.55; }
.ct-stage[data-size="compact"] .ct-line { height: 34px; }
@keyframes ct-line-in-compact   { 0% { height: 0; opacity: 0; } 6%, 100% { height: 34px; opacity: 1; } }
@keyframes ct-line-late-compact { 0%, 62% { height: 0; opacity: 0; } 70%, 100% { height: 34px; opacity: 1; } }
.ct-stage[data-size="compact"][data-state="approval"] .ct-line-ask,
.ct-stage[data-size="compact"][data-state="approval"] .ct-line-wait { animation-name: ct-line-in-compact; }
.ct-stage[data-size="compact"][data-state="approval"] .ct-line-done { animation-name: ct-line-late-compact; }

/* cards: fewer ornaments, and type sized for the crop's scale */
.ct-stage[data-size="compact"] .ct-card { padding: 12px 14px 20px; }
.ct-stage[data-size="compact"] .ct-row { padding: 18px 20px; border-radius: 26px; }
.ct-stage[data-size="compact"] .ct-row + .ct-row { margin-top: 12px; }
.ct-stage[data-size="compact"] .ct-row-head { gap: 16px; }
.ct-stage[data-size="compact"] .ct-row-head > .ct-agent { --ct-agent-size: 35px; margin-top: 2px; }
.ct-stage[data-size="compact"] .ct-chip,
.ct-stage[data-size="compact"] .ct-elapsed { display: none; }
.ct-stage[data-size="compact"] .ct-row-top { height: 34px; }
.ct-stage[data-size="compact"] .ct-project { font-size: 30px; }
.ct-stage[data-size="compact"] .ct-status { font-size: 24px; height: 32px; margin-top: 7px; }
.ct-stage[data-size="compact"] .ct-detail { padding-left: 0; margin-top: 14px; }
.ct-stage[data-size="compact"] .ct-risk { font-size: 22px; height: 30px; gap: 10px; }
.ct-stage[data-size="compact"] .ct-risk svg { width: 22px; height: 22px; }
.ct-stage[data-size="compact"] .ct-code { font-size: 24px; padding: 18px; border-radius: 13px; margin-top: 14px; }
.ct-stage[data-size="compact"] .ct-actions { height: 52px; margin-top: 14px; }
.ct-stage[data-size="compact"] .ct-buttons { gap: 13px; }
.ct-stage[data-size="compact"] .ct-btn { font-size: 23px; height: 52px; padding: 0 22px; border-radius: 26px; gap: 9px; }
.ct-stage[data-size="compact"] .ct-btn svg { width: 20px; height: 20px; }
.ct-stage[data-size="compact"] .ct-btn-allow { padding-right: 0; }
.ct-stage[data-size="compact"] .ct-btn-allow .ct-btn-split { height: 30px; margin-left: 17px; }
.ct-stage[data-size="compact"] .ct-btn-allow .ct-btn-chev { padding: 0 17px; }
.ct-stage[data-size="compact"] .ct-resolved { height: 52px; font-size: 23px; gap: 11px; }
.ct-stage[data-size="compact"] .ct-opt { padding: 14px 17px; border-radius: 16px; gap: 14px; }
.ct-stage[data-size="compact"] .ct-opt + .ct-opt { margin-top: 10px; }
.ct-stage[data-size="compact"] .ct-opt-no { width: 29px; height: 29px; font-size: 19px; }
.ct-stage[data-size="compact"] .ct-opt-label { font-size: 24px; }
.ct-stage[data-size="compact"] .ct-opt-detail { display: none; }
.ct-stage[data-size="compact"] .ct-ring svg { width: 25px; height: 25px; }
.ct-stage[data-size="compact"] .ct-ring-num { font-size: 23px; }
.ct-stage[data-size="compact"] .ct-ring { gap: 9px; }
/* four rows do not fit a phone; the two that carry the point do. The quota
   strip is not a row, so it stays - it is the footer of whatever list is
   above it, however short that list has become. */
.ct-stage[data-size="compact"] .ct-card-list .ct-row:nth-child(n+3) { display: none; }

.ct-stage[data-size="compact"] .ct-usage { height: 26px; gap: 22px; margin-top: 16px; }
.ct-stage[data-size="compact"] .ct-usage-account,
.ct-stage[data-size="compact"] .ct-gauge-name,
.ct-stage[data-size="compact"] .ct-gauge-num { font-size: 21px; }
.ct-stage[data-size="compact"] .ct-gauge { gap: 12px; }
.ct-stage[data-size="compact"] .ct-gauge-track { width: 96px; height: 8px; border-radius: 4px; }
.ct-stage[data-size="compact"] .ct-card-list { padding-bottom: 14px; }

/* The plan window is shorter again on a phone, so the card still lands at
   the height COMPACT_H budgets for the tallest one. The plan itself is not
   shortened: fewer lines visible over the same scroll is more of the point,
   not less. */
.ct-stage[data-size="compact"] .ct-plan { height: 168px; border-radius: 14px; }
.ct-stage[data-size="compact"] .ct-plan-scroll { padding: 14px 18px; }
.ct-stage[data-size="compact"] .ct-plan-scroll > * + * { margin-top: 13px; }
.ct-stage[data-size="compact"] .ct-plan-h + * { margin-top: 9px; }
.ct-stage[data-size="compact"] .ct-plan-h { font-size: 27px; }
.ct-stage[data-size="compact"] .ct-plan-p,
.ct-stage[data-size="compact"] .ct-plan-li { font-size: 24px; }
.ct-stage[data-size="compact"] .ct-plan-li > b { min-width: 25px; }
.ct-stage[data-size="compact"] .ct-plan-code { font-size: 22px; padding: 12px 16px; }
.ct-stage[data-size="compact"] .ct-plan-thumb { width: 7px; height: 34px; right: 7px; }
.ct-stage[data-size="compact"][data-state="plan"] .ct-plan-thumb { animation-name: ct-plan-thumb-compact; }
@keyframes ct-plan-thumb-compact {
  0%, 8%    { opacity: 0; transform: translate3d(0, 0, 0); }
  14%       { opacity: 1; transform: translate3d(0, 0, 0); }
  48%       { opacity: 1; transform: translate3d(0, 60px, 0); }
  62%, 100% { opacity: 0; transform: translate3d(0, 60px, 0); }
}

/* The statement moves below the panel and stays the loudest text. The
   gutter has to live on the statement itself: an absolutely positioned
   child is laid out against its ancestor's padding box, so padding on
   .ct-statements would do nothing. */
.ct-stage[data-size="compact"] .ct-statements {
  left: 0;
  width: 100%;
  padding: 0;
  top: calc(var(--ct-h) + 48px);
  transition: top .46s cubic-bezier(.22, 1, .28, 1);
}
.ct-stage[data-size="compact"] .ct-statement {
  left: var(--ct-gutter, 24px);
  right: var(--ct-gutter, 24px);
  width: auto;
  max-width: none;
}
.ct-stage[data-size="compact"] .ct-statement-head { font-size: 62px; }
.ct-stage[data-size="compact"] .ct-statement-sub { font-size: 26px; margin-top: 18px; max-width: none; }

/* ── the scene control strip ─────────────────────────────────── */
/* Real controls: buttons, focusable, labelled, current one marked. */

.ct-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px 12px 0;
}
.ct-chip-btn {
  font: inherit;
  font-size: .8125rem;
  font-weight: 500;
  line-height: 1;
  color: var(--text-dim, #9aa0a9);
  background: rgba(255, 255, 255, .045);
  border: 1px solid var(--hair, rgba(255, 255, 255, .09));
  border-radius: 999px;
  /* 44px is the smallest comfortable touch target */
  min-height: 44px;
  padding: 12px 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: color .2s ease, background .2s ease, border-color .2s ease;
}
.ct-chip-btn:hover { color: var(--text, #e9e6e1); background: rgba(255, 255, 255, .09); }
.ct-chip-btn:focus-visible { outline: 2px solid var(--ctx-high, #ffb847); outline-offset: 3px; }
.ct-chip-btn[aria-current="true"] {
  color: #0d0f13;
  background: var(--ctx-high, #ffb847);
  border-color: transparent;
}
/* The autoplay control is a real toggle that is always present and always
   the same size - Pause while it is playing, Resume once you have taken
   over. A control that hides itself measures 0x0, which is
   indistinguishable from a broken one. */
.ct-chip-play { gap: 9px; }
.ct-chip-play::before {
  content: "";
  width: 9px; height: 11px;
  border-left: 3px solid currentColor;
  border-right: 3px solid currentColor;
}
.ct-chips.is-manual .ct-chip-play::before {
  width: 0; height: 0;
  border-left: 9px solid currentColor;
  border-right: 0;
  border-top: 5.5px solid transparent;
  border-bottom: 5.5px solid transparent;
}
.ct-chips.is-manual .ct-chip-play {
  color: #0d0f13;
  background: var(--ctx-high, #ffb847);
  border-color: transparent;
}

/* ── paused / reduced motion ─────────────────────────────────── */

.ct-stage.is-paused *,
.ct-stage.is-paused *::before,
.ct-stage.is-paused *::after { animation-play-state: paused !important; }

/* Held on one scene - a chip was clicked, or the page took control -
   the scene keeps demonstrating itself instead of freezing. */
.ct-stage[data-autoplay="false"] .ct-screen *,
.ct-stage[data-autoplay="false"] .ct-screen *::before,
.ct-stage[data-autoplay="false"] .ct-screen *::after { animation-iteration-count: infinite; }

/* There is no video behind this any more, so the still frame has to
   carry the product on its own: the permission card, mid-decision,
   pointer on Allow, statement in place. */
@media (prefers-reduced-motion: reduce) {
  .ct-stage *,
  .ct-stage *::before,
  .ct-stage *::after {
    animation: none !important;
    transition: none !important;
  }
  .ct-stage .ct-cat-alert { opacity: 1; }
  .ct-stage .ct-badge { opacity: 1; transform: none; }
  .ct-stage .ct-line-ask, .ct-stage .ct-line-wait { height: 24px; opacity: 1; }
  .ct-stage .ct-card-permission .ct-row { box-shadow: inset 0 0 0 1px rgba(255, 159, 46, .55); }
  .ct-stage .ct-card-permission .ct-agent-pip { background: var(--ct-attention); }
  /* nothing turns: rotation is the one motion the brand marks carry */
  .ct-stage .ct-agent.is-spinning .ct-agent-mark { animation: none; }
  .ct-stage .ct-cursor { opacity: 1; transform: translate3d(-360px, 224px, 0); }
  .ct-stage .ct-scopemenu { opacity: 0; }
  .ct-stage .ct-chips { display: none; }
}
